• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*  Copyright 1986-1992 Emmet P. Gray.
2  *  Copyright 1996-1998,2000-2002,2005,2007-2009 Alain Knaff.
3  *  This file is part of mtools.
4  *
5  *  Mtools is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  Mtools is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  * mlabel.c
19  * Make an MSDOS volume label
20  */
21 
22 #include "sysincludes.h"
23 #include "msdos.h"
24 #include "mainloop.h"
25 #include "vfat.h"
26 #include "mtools.h"
27 #include "nameclash.h"
28 #include "file_name.h"
29 
_label_name(doscp_t * cp,const char * filename,int verbose UNUSEDP,int * mangled,dos_name_t * ans,int preserve_case)30 static void _label_name(doscp_t *cp, const char *filename, int verbose UNUSEDP,
31 			int *mangled, dos_name_t *ans, int preserve_case)
32 {
33 	int len;
34 	int i;
35 	int have_lower, have_upper;
36 	wchar_t wbuffer[12];
37 
38 	memset(ans, ' ', sizeof(*ans)-1);
39 	ans->sentinel = '\0';
40 	len = native_to_wchar(filename, wbuffer, 11, 0, 0);
41 	if(len > 11){
42 		*mangled = 1;
43 		len = 11;
44 	} else
45 		*mangled = 0;
46 
47 	have_lower = have_upper = 0;
48 	for(i=0; i<len; i++){
49 		if(islower(wbuffer[i]))
50 			have_lower = 1;
51 		if(isupper(wbuffer[i]))
52 			have_upper = 1;
53 		if(!preserve_case)
54 			wbuffer[i] = ch_towupper(wbuffer[i]);
55 		if(
56 #ifdef HAVE_WCHAR_H
57 		   wcschr(L"^+=/[]:,?*\\<>|\".", wbuffer[i])
58 #else
59 		   strchr("^+=/[]:,?*\\<>|\".", wbuffer[i])
60 #endif
61 		   ){
62 			*mangled = 1;
63 			wbuffer[i] = '~';
64 		}
65 	}
66 	if (have_lower && have_upper)
67 		*mangled = 1;
68 	wchar_to_dos(cp, wbuffer, ans->base, len, mangled);
69 }
70 
label_name_uc(doscp_t * cp,const char * filename,int verbose,int * mangled,dos_name_t * ans)71 void label_name_uc(doscp_t *cp, const char *filename, int verbose,
72 		   int *mangled, dos_name_t *ans)
73 {
74 	_label_name(cp, filename, verbose, mangled, ans, 0);
75 }
76 
label_name_pc(doscp_t * cp,const char * filename,int verbose,int * mangled,dos_name_t * ans)77 void label_name_pc(doscp_t *cp, const char *filename, int verbose,
78 		   int *mangled, dos_name_t *ans)
79 {
80 	_label_name(cp, filename, verbose, mangled, ans, 1);
81 }
82 
labelit(struct dos_name_t * dosname,char * longname UNUSEDP,void * arg0 UNUSEDP,direntry_t * entry)83 int labelit(struct dos_name_t *dosname,
84 	    char *longname UNUSEDP,
85 	    void *arg0 UNUSEDP,
86 	    direntry_t *entry)
87 {
88 	time_t now;
89 
90 	/* find out current time */
91 	getTimeNow(&now);
92 	mk_entry(dosname, 0x8, 0, 0, now, &entry->dir);
93 	return 0;
94 }
95 
96 static void usage(int ret) NORETURN;
usage(int ret)97 static void usage(int ret)
98 {
99 	fprintf(stderr, "Mtools version %s, dated %s\n",
100 		mversion, mdate);
101 	fprintf(stderr, "Usage: %s [-vscVn] [-N serial] drive:\n", progname);
102 	exit(ret);
103 }
104 
105 
106 void mlabel(int argc, char **argv, int type UNUSEDP) NORETURN;
mlabel(int argc,char ** argv,int type UNUSEDP)107 void mlabel(int argc, char **argv, int type UNUSEDP)
108 {
109 
110 	const char *newLabel="";
111 	int verbose, clear, interactive, show;
112 	direntry_t entry;
113 	int result=0;
114 	char longname[VBUFSIZE];
115 	char shortname[45];
116 	ClashHandling_t ch;
117 	struct MainParam_t mp;
118 	Stream_t *RootDir;
119 	int c;
120 	int mangled;
121 	enum { SER_NONE, SER_RANDOM, SER_SET }  set_serial = SER_NONE;
122 	uint32_t serial = 0;
123 	int need_write_boot = 0;
124 	int have_boot = 0;
125 	char *eptr;
126 	union bootsector boot;
127 	Stream_t *Fs=0;
128 	int r;
129 	struct label_blk_t *labelBlock;
130 	int isRo=0;
131 	int *isRop=NULL;
132 	char drive;
133 
134 	init_clash_handling(&ch);
135 	ch.name_converter = label_name_uc;
136 	ch.ignore_entry = -2;
137 	ch.is_label = 1;
138 
139 	verbose = 0;
140 	clear = 0;
141 	show = 0;
142 
143 	if(helpFlag(argc, argv))
144 		usage(0);
145 	while ((c = getopt(argc, argv, "i:vcsnN:h")) != EOF) {
146 		switch (c) {
147 			case 'i':
148 				set_cmd_line_image(optarg);
149 				break;
150 			case 'v':
151 				verbose = 1;
152 				break;
153 			case 'c':
154 				clear = 1;
155 				break;
156 			case 's':
157 				show = 1;
158 				break;
159 			case 'n':
160 				set_serial = SER_RANDOM;
161 				init_random();
162 				serial=random();
163 				break;
164 			case 'N':
165 				set_serial = SER_SET;
166 				errno=0;
167 				serial = strtou32(optarg, &eptr, 16);
168 				if(*eptr) {
169 					fprintf(stderr,
170 						"%s not a valid serial number\n",
171 						optarg);
172 					exit(1);
173 				}
174 				check_number_parse_errno(c, optarg, eptr);
175 				break;
176 			case 'h':
177 				usage(0);
178 			default:
179 				usage(1);
180 			}
181 	}
182 
183 	if (argc - optind > 1)
184 		usage(1);
185 	if(argc - optind == 1) {
186 	    if(!argv[optind][0] || argv[optind][1] != ':')
187 		usage(1);
188 	    drive = ch_toupper(argv[argc -1][0]);
189 	    newLabel = argv[optind]+2;
190 	} else {
191 	    drive = get_default_drive();
192 	}
193 
194 	init_mp(&mp);
195 	if(strlen(newLabel) > VBUFSIZE) {
196 		fprintf(stderr, "Label too long\n");
197 		FREE(&RootDir);
198 		exit(1);
199 	}
200 
201 	interactive = !show && !clear &&!newLabel[0] &&
202 		(set_serial == SER_NONE);
203 	if(!clear && !newLabel[0]) {
204 		isRop = &isRo;
205 	}
206 	if(clear && newLabel[0]) {
207 		/* Clear and new label specified both */
208 		fprintf(stderr, "Both clear and new label specified\n");
209 		FREE(&RootDir);
210 		exit(1);
211 	}
212 	RootDir = open_root_dir(drive, isRop ? 0 : O_RDWR, isRop);
213 	if(isRo) {
214 		show = 1;
215 		interactive = 0;
216 	}
217 	if(!RootDir) {
218 		fprintf(stderr, "%s: Cannot initialize drive\n", argv[0]);
219 		exit(1);
220 	}
221 
222 	initializeDirentry(&entry, RootDir);
223 	r=vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY,
224 		      shortname, sizeof(shortname),
225 		      longname, sizeof(longname));
226 	if (r == -2) {
227 		FREE(&RootDir);
228 		exit(1);
229 	}
230 
231 	if(show || interactive){
232 		if(isNotFound(&entry))
233 			printf(" Volume has no label\n");
234 		else if (*longname)
235 			printf(" Volume label is %s (abbr=%s)\n",
236 			       longname, shortname);
237 		else
238 			printf(" Volume label is %s\n",  shortname);
239 
240 	}
241 
242 	/* ask for new label */
243 	if(interactive){
244 		saved_sig_state ss;
245 		newLabel = longname;
246 		allow_interrupts(&ss);
247 		fprintf(stderr,"Enter the new volume label : ");
248 		if(fgets(longname, VBUFSIZE, stdin) == NULL) {
249 			fprintf(stderr, "\n");
250 			if(errno == EINTR) {
251 				FREE(&RootDir);
252 				exit(1);
253 			}
254 			longname[0] = '\0';
255 		}
256 		if(longname[0])
257 			longname[strlen(newLabel)-1] = '\0';
258 	}
259 
260 	if(strlen(newLabel) > 11) {
261 		fprintf(stderr,"New label too long\n");
262 		FREE(&RootDir);
263 		exit(1);
264 	}
265 
266 	if((!show || newLabel[0]) && !isNotFound(&entry)){
267 		/* if we have a label, wipe it out before putting new one */
268 		if(interactive && newLabel[0] == '\0')
269 			if(ask_confirmation("Delete volume label (y/n): ")){
270 				FREE(&RootDir);
271 				exit(0);
272 			}
273 		entry.dir.attr = 0; /* for old mlabel */
274 		wipeEntry(&entry);
275 	}
276 
277 	if (newLabel[0] != '\0') {
278 		ch.ignore_entry = 1;
279 		result = mwrite_one(RootDir,newLabel,0,labelit,NULL,&ch) ?
280 		  0 : 1;
281 	}
282 
283 	have_boot = 0;
284 	if( (!show || newLabel[0]) || set_serial != SER_NONE) {
285 		Fs = GetFs(RootDir);
286 		have_boot = (force_read(Fs,boot.characters,0,sizeof(boot)) ==
287 			     sizeof(boot));
288 	}
289 
290 	if(WORD_S(fatlen)) {
291 	    labelBlock = &boot.boot.ext.old.labelBlock;
292 	} else {
293 	    labelBlock = &boot.boot.ext.fat32.labelBlock;
294 	}
295 
296 	if(!show || newLabel[0]){
297 		dos_name_t dosname;
298 		const char *shrtLabel;
299 		doscp_t *cp;
300 		if(!newLabel[0])
301 			shrtLabel = "NO NAME    ";
302 		else
303 			shrtLabel = newLabel;
304 		cp = GET_DOSCONVERT(Fs);
305 		label_name_pc(cp, shrtLabel, verbose, &mangled, &dosname);
306 
307 		if(have_boot && boot.boot.descr >= 0xf0 && has_BPB4) {
308 			strncpy(labelBlock->label, dosname.base, 8);
309 			strncpy(labelBlock->label+8, dosname.ext, 3);
310 			need_write_boot = 1;
311 
312 		}
313 	}
314 
315 	if((set_serial != SER_NONE) & have_boot) {
316 		if(have_boot && boot.boot.descr >= 0xf0 && has_BPB4) {
317 			set_dword(labelBlock->serial, serial);
318 			need_write_boot = 1;
319 		}
320 	}
321 
322 	if(need_write_boot) {
323 		force_write(Fs, (char *)&boot, 0, sizeof(boot));
324 		/* If this is fat 32, write backup boot sector too */
325 		if(!WORD_S(fatlen)) {
326 			int backupBoot = WORD_S(ext.fat32.backupBoot);
327 			force_write(Fs, (char *)&boot,
328 				    backupBoot * WORD_S(secsiz),
329 				    sizeof(boot));
330 		}
331 	}
332 
333 	FREE(&RootDir);
334 	exit(result);
335 }
336