blob: 4b087916e0233e6c7a629584311020bfbe8b238f [file] [log] [blame]
Alistair Delvabeaee832021-02-24 11:27:23 -08001/* 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
30static void _label_name(doscp_t *cp, const char *filename, int verbose UNUSEDP,
31 int *mangled, dos_name_t *ans, int preserve_case)
32{
Yi Kong39bbd962022-01-09 19:41:38 +080033 size_t len;
34 size_t i;
Alistair Delvabeaee832021-02-24 11:27:23 -080035 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
71void 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
77void 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
83int 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
96static void usage(int ret) NORETURN;
97static 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
106void mlabel(int argc, char **argv, int type UNUSEDP) NORETURN;
107void 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();
Yi Kong39bbd962022-01-09 19:41:38 +0800162 serial=(uint32_t) random();
Alistair Delvabeaee832021-02-24 11:27:23 -0800163 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 }
Yi Kong39bbd962022-01-09 19:41:38 +0800174 check_number_parse_errno((char)c, optarg, eptr);
Alistair Delvabeaee832021-02-24 11:27:23 -0800175 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);
Yi Kong39bbd962022-01-09 19:41:38 +0800211 }
Alistair Delvabeaee832021-02-24 11:27:23 -0800212 RootDir = open_root_dir(drive, isRop ? 0 : O_RDWR, isRop);
213 if(isRo) {
214 show = 1;
215 interactive = 0;
Yi Kong39bbd962022-01-09 19:41:38 +0800216 }
Alistair Delvabeaee832021-02-24 11:27:23 -0800217 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){
Yi Kong39bbd962022-01-09 19:41:38 +0800244 saved_sig_state ss;
Alistair Delvabeaee832021-02-24 11:27:23 -0800245 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);
Yi Kong39bbd962022-01-09 19:41:38 +0800286 have_boot = (force_pread(Fs,boot.characters,0,sizeof(boot)) ==
Alistair Delvabeaee832021-02-24 11:27:23 -0800287 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) {
Yi Kong39bbd962022-01-09 19:41:38 +0800317 set_dword(labelBlock->serial, serial);
Alistair Delvabeaee832021-02-24 11:27:23 -0800318 need_write_boot = 1;
319 }
320 }
321
322 if(need_write_boot) {
Yi Kong39bbd962022-01-09 19:41:38 +0800323 force_pwrite(Fs, (char *)&boot, 0, sizeof(boot));
Alistair Delvabeaee832021-02-24 11:27:23 -0800324 /* If this is fat 32, write backup boot sector too */
325 if(!WORD_S(fatlen)) {
326 int backupBoot = WORD_S(ext.fat32.backupBoot);
Yi Kong39bbd962022-01-09 19:41:38 +0800327 force_pwrite(Fs, (char *)&boot,
328 backupBoot * WORD_S(secsiz),
329 sizeof(boot));
Alistair Delvabeaee832021-02-24 11:27:23 -0800330 }
331 }
332
333 FREE(&RootDir);
334 exit(result);
335}