Imported Upstream version 4.0.18
[platform/upstream/mtools.git] / mlabel.c
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
30 static void _label_name(doscp_t *cp, const char *filename, int verbose,
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] = 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
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
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
83 int labelit(struct dos_name_t *dosname,
84             char *longname,
85             void *arg0,
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;
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)
107 {
108
109         const char *newLabel="";
110         int verbose, clear, interactive, show;
111         direntry_t entry;
112         int result=0;
113         char longname[VBUFSIZE];
114         char shortname[45];
115         ClashHandling_t ch;
116         struct MainParam_t mp;
117         Stream_t *RootDir;
118         int c;
119         int mangled;
120         enum { SER_NONE, SER_RANDOM, SER_SET }  set_serial = SER_NONE;
121         long serial = 0;
122         int need_write_boot = 0;
123         int have_boot = 0;
124         char *eptr;
125         union bootsector boot;
126         Stream_t *Fs=0;
127         int r;
128         struct label_blk_t *labelBlock;
129         int isRo=0;
130         int *isRop=NULL;
131         char drive;
132
133         init_clash_handling(&ch);
134         ch.name_converter = label_name_uc;
135         ch.ignore_entry = -2;
136
137         verbose = 0;
138         clear = 0;
139         show = 0;
140
141         if(helpFlag(argc, argv))
142                 usage(0);
143         while ((c = getopt(argc, argv, "i:vcsnN:h")) != EOF) {
144                 switch (c) {
145                         case 'i':
146                                 set_cmd_line_image(optarg);
147                                 break;
148                         case 'v':
149                                 verbose = 1;
150                                 break;
151                         case 'c':
152                                 clear = 1;
153                                 break;
154                         case 's':
155                                 show = 1;
156                                 break;
157                         case 'n':
158                                 set_serial = SER_RANDOM;
159                                 srandom((long)time (0));
160                                 serial=random();
161                                 break;
162                         case 'N':
163                                 set_serial = SER_SET;
164                                 serial = strtoul(optarg, &eptr, 16);
165                                 if(*eptr) {
166                                         fprintf(stderr,
167                                                 "%s not a valid serial number\n",
168                                                 optarg);
169                                         exit(1);
170                                 }
171                                 break;
172                         case 'h':
173                                 usage(0);
174                         default:
175                                 usage(1);
176                         }
177         }
178
179         if (argc - optind > 1)
180                 usage(1);
181         if(argc - optind == 1) {
182             if(!argv[optind][0] || argv[optind][1] != ':')
183                 usage(1);
184             drive = toupper(argv[argc -1][0]);
185             newLabel = argv[optind]+2;
186         } else {
187             drive = get_default_drive();
188         }
189
190         init_mp(&mp);
191         if(strlen(newLabel) > VBUFSIZE) {
192                 fprintf(stderr, "Label too long\n");
193                 FREE(&RootDir);
194                 exit(1);
195         }
196
197         interactive = !show && !clear &&!newLabel[0] &&
198                 (set_serial == SER_NONE);
199         if(!clear && !newLabel[0]) {
200                 isRop = &isRo;
201         }
202         if(clear && newLabel[0]) {
203                 /* Clear and new label specified both */
204                 fprintf(stderr, "Both clear and new label specified\n");
205                 FREE(&RootDir);
206                 exit(1);
207         }               
208         RootDir = open_root_dir(drive, isRop ? 0 : O_RDWR, isRop);
209         if(isRo) {
210                 show = 1;
211                 interactive = 0;
212         }       
213         if(!RootDir) {
214                 fprintf(stderr, "%s: Cannot initialize drive\n", argv[0]);
215                 exit(1);
216         }
217
218         initializeDirentry(&entry, RootDir);
219         r=vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY,
220                       shortname, longname);
221         if (r == -2) {
222                 FREE(&RootDir);
223                 exit(1);
224         }
225
226         if(show || interactive){
227                 if(isNotFound(&entry))
228                         printf(" Volume has no label\n");
229                 else if (*longname)
230                         printf(" Volume label is %s (abbr=%s)\n",
231                                longname, shortname);
232                 else
233                         printf(" Volume label is %s\n",  shortname);
234
235         }
236
237         /* ask for new label */
238         if(interactive){
239                 saved_sig_state ss; 
240                 newLabel = longname;
241                 allow_interrupts(&ss);
242                 fprintf(stderr,"Enter the new volume label : ");
243                 if(fgets(longname, VBUFSIZE, stdin) == NULL) {
244                         fprintf(stderr, "\n");
245                         if(errno == EINTR) {
246                                 FREE(&RootDir);
247                                 exit(1);
248                         }
249                         longname[0] = '\0';
250                 }
251                 if(longname[0])
252                         longname[strlen(newLabel)-1] = '\0';
253         }
254
255         if(strlen(newLabel) > 11) {
256                 fprintf(stderr,"New label too long\n");
257                 FREE(&RootDir);
258                 exit(1);
259         }
260
261         if((!show || newLabel[0]) && !isNotFound(&entry)){
262                 /* if we have a label, wipe it out before putting new one */
263                 if(interactive && newLabel[0] == '\0')
264                         if(ask_confirmation("Delete volume label (y/n): ")){
265                                 FREE(&RootDir);
266                                 exit(0);
267                         }
268                 entry.dir.attr = 0; /* for old mlabel */
269                 wipeEntry(&entry);
270         }
271
272         if (newLabel[0] != '\0') {
273                 ch.ignore_entry = 1;
274                 result = mwrite_one(RootDir,newLabel,0,labelit,NULL,&ch) ?
275                   0 : 1;
276         }
277
278         have_boot = 0;
279         if( (!show || newLabel[0]) || set_serial != SER_NONE) {
280                 Fs = GetFs(RootDir);
281                 have_boot = (force_read(Fs,boot.characters,0,sizeof(boot)) ==
282                              sizeof(boot));
283         }
284
285         if(WORD_S(fatlen)) {
286             labelBlock = &boot.boot.ext.old.labelBlock;
287         } else {
288             labelBlock = &boot.boot.ext.fat32.labelBlock;
289         }
290
291         if(!show || newLabel[0]){
292                 dos_name_t dosname;
293                 const char *shrtLabel;
294                 doscp_t *cp;
295                 if(!newLabel[0])
296                         shrtLabel = "NO NAME    ";
297                 else
298                         shrtLabel = newLabel;
299                 cp = GET_DOSCONVERT(Fs);
300                 label_name_pc(cp, shrtLabel, verbose, &mangled, &dosname);
301
302                 if(have_boot && boot.boot.descr >= 0xf0 &&
303                    labelBlock->dos4 == 0x29) {
304                         strncpy(labelBlock->label, dosname.base, 11);
305                         need_write_boot = 1;
306
307                 }
308         }
309
310         if((set_serial != SER_NONE) & have_boot) {
311                 if(have_boot && boot.boot.descr >= 0xf0 &&
312                    labelBlock->dos4 == 0x29) {
313                         set_dword(labelBlock->serial, serial);  
314                         need_write_boot = 1;
315                 }
316         }
317
318         if(need_write_boot) {
319                 force_write(Fs, (char *)&boot, 0, sizeof(boot));
320                 /* If this is fat 32, write backup boot sector too */
321                 if(!WORD_S(fatlen)) {
322                         int backupBoot = WORD_S(ext.fat32.backupBoot);
323                         force_write(Fs, (char *)&boot, 
324                                     backupBoot * WORD_S(secsiz),
325                                     sizeof(boot));
326                 }
327         }
328
329         FREE(&RootDir);
330         exit(result);
331 }