Initial import package mtools: Programs for accessing MS-DOS disks without mounting...
[profile/ivi/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 void label_name(doscp_t *cp, const char *filename, int verbose,
31                 int *mangled, dos_name_t *ans)
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                 wbuffer[i] = towupper(wbuffer[i]);
54                 if(
55 #ifdef HAVE_WCHAR_H
56                    wcschr(L"^+=/[]:,?*\\<>|\".", wbuffer[i])
57 #else
58                    strchr("^+=/[]:,?*\\<>|\".", wbuffer[i])
59 #endif
60                    ){
61                         *mangled = 1;
62                         wbuffer[i] = '~';
63                 }
64         }
65         if (have_lower && have_upper)
66                 *mangled = 1;
67         wchar_to_dos(cp, wbuffer, ans->base, len, mangled);
68 }
69
70 int labelit(struct dos_name_t *dosname,
71             char *longname,
72             void *arg0,
73             direntry_t *entry)
74 {
75         time_t now;
76
77         /* find out current time */
78         getTimeNow(&now);
79         mk_entry(dosname, 0x8, 0, 0, now, &entry->dir);
80         return 0;
81 }
82
83 static void usage(int ret) NORETURN;
84 static void usage(int ret)
85 {
86         fprintf(stderr, "Mtools version %s, dated %s\n",
87                 mversion, mdate);
88         fprintf(stderr, "Usage: %s [-vscVn] [-N serial] drive:\n", progname);
89         exit(ret);
90 }
91
92
93 void mlabel(int argc, char **argv, int type)
94 {
95
96         char *newLabel;
97         int verbose, clear, interactive, show;
98         direntry_t entry;
99         int result=0;
100         char longname[VBUFSIZE];
101         char shortname[45];
102         ClashHandling_t ch;
103         struct MainParam_t mp;
104         Stream_t *RootDir;
105         int c;
106         int mangled;
107         enum { SER_NONE, SER_RANDOM, SER_SET }  set_serial = SER_NONE;
108         long serial = 0;
109         int need_write_boot = 0;
110         int have_boot = 0;
111         char *eptr;
112         union bootsector boot;
113         Stream_t *Fs=0;
114         int r;
115         struct label_blk_t *labelBlock;
116         int isRo=0;
117         int *isRop=NULL;
118
119         init_clash_handling(&ch);
120         ch.name_converter = label_name;
121         ch.ignore_entry = -2;
122
123         verbose = 0;
124         clear = 0;
125         show = 0;
126
127         if(helpFlag(argc, argv))
128                 usage(0);
129         while ((c = getopt(argc, argv, "i:vcsnN:h")) != EOF) {
130                 switch (c) {
131                         case 'i':
132                                 set_cmd_line_image(optarg, 0);
133                                 break;
134                         case 'v':
135                                 verbose = 1;
136                                 break;
137                         case 'c':
138                                 clear = 1;
139                                 break;
140                         case 's':
141                                 show = 1;
142                                 break;
143                         case 'n':
144                                 set_serial = SER_RANDOM;
145                                 srandom((long)time (0));
146                                 serial=random();
147                                 break;
148                         case 'N':
149                                 set_serial = SER_SET;
150                                 serial = strtol(optarg, &eptr, 16);
151                                 if(*eptr) {
152                                         fprintf(stderr,
153                                                 "%s not a valid serial number\n",
154                                                 optarg);
155                                         exit(1);
156                                 }
157                                 break;
158                         case 'h':
159                                 usage(0);
160                         default:
161                                 usage(1);
162                         }
163         }
164
165         if (argc - optind != 1 || !argv[optind][0] || argv[optind][1] != ':')
166                 usage(1);
167
168         init_mp(&mp);
169         newLabel = argv[optind]+2;
170         if(strlen(newLabel) > VBUFSIZE) {
171                 fprintf(stderr, "Label too long\n");
172                 FREE(&RootDir);
173                 exit(1);
174         }
175
176         interactive = !show && !clear &&!newLabel[0] &&
177                 (set_serial == SER_NONE);
178         if(!clear && !newLabel[0]) {
179                 isRop = &isRo;
180         }
181         RootDir = open_root_dir(argv[optind][0], isRop ? 0 : O_RDWR, isRop);
182         if(isRo) {
183                 show = 1;
184                 interactive = 0;
185         }       
186         if(!RootDir) {
187                 fprintf(stderr, "%s: Cannot initialize drive\n", argv[0]);
188                 exit(1);
189         }
190
191         initializeDirentry(&entry, RootDir);
192         r=vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY,
193                       shortname, longname);
194         if (r == -2) {
195                 FREE(&RootDir);
196                 exit(1);
197         }
198
199         if(show || interactive){
200                 if(isNotFound(&entry))
201                         printf(" Volume has no label\n");
202                 else if (*longname)
203                         printf(" Volume label is %s (abbr=%s)\n",
204                                longname, shortname);
205                 else
206                         printf(" Volume label is %s\n",  shortname);
207
208         }
209
210         /* ask for new label */
211         if(interactive){
212                 newLabel = longname;
213                 fprintf(stderr,"Enter the new volume label : ");
214                 if(fgets(newLabel, VBUFSIZE, stdin) == NULL) {
215                         newLabel[0] = '\0';
216                         fprintf(stderr, "\n");
217                 }
218                 if(newLabel[0])
219                         newLabel[strlen(newLabel)-1] = '\0';
220         }
221
222         if((!show || newLabel[0]) && !isNotFound(&entry)){
223                 /* if we have a label, wipe it out before putting new one */
224                 if(interactive && newLabel[0] == '\0')
225                         if(ask_confirmation("Delete volume label (y/n): ")){
226                                 FREE(&RootDir);
227                                 exit(0);
228                         }
229                 entry.dir.attr = 0; /* for old mlabel */
230                 wipeEntry(&entry);
231         }
232
233         if (newLabel[0] != '\0') {
234                 ch.ignore_entry = 1;
235                 result = mwrite_one(RootDir,newLabel,0,labelit,NULL,&ch) ?
236                   0 : 1;
237         }
238
239         have_boot = 0;
240         if( (!show || newLabel[0]) || set_serial != SER_NONE) {
241                 Fs = GetFs(RootDir);
242                 have_boot = (force_read(Fs,boot.characters,0,sizeof(boot)) ==
243                              sizeof(boot));
244         }
245
246         if(WORD_S(fatlen)) {
247             labelBlock = &boot.boot.ext.old.labelBlock;
248         } else {
249             labelBlock = &boot.boot.ext.fat32.labelBlock;
250         }
251
252         if(!show || newLabel[0]){
253                 dos_name_t dosname;
254                 const char *shrtLabel;
255                 doscp_t *cp;
256                 if(!newLabel[0])
257                         shrtLabel = "NO NAME    ";
258                 else
259                         shrtLabel = newLabel;
260                 cp = GET_DOSCONVERT(Fs);
261                 label_name(cp, shrtLabel, verbose, &mangled, &dosname);
262
263                 if(have_boot && boot.boot.descr >= 0xf0 &&
264                    labelBlock->dos4 == 0x29) {
265                         strncpy(labelBlock->label, dosname.base, 11);
266                         need_write_boot = 1;
267
268                 }
269         }
270
271         if((set_serial != SER_NONE) & have_boot) {
272                 if(have_boot && boot.boot.descr >= 0xf0 &&
273                    labelBlock->dos4 == 0x29) {
274                         set_dword(labelBlock->serial, serial);  
275                         need_write_boot = 1;
276                 }
277         }
278
279         if(need_write_boot) {
280                 force_write(Fs, (char *)&boot, 0, sizeof(boot));
281         }
282
283         FREE(&RootDir);
284         exit(result);
285 }