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#define USB_VOL_NAME_FILE   "/tmp/usb_vol_name/%s"  /* Foxconn added pling 05/06/2009 */
31
32void label_name(doscp_t *cp, const char *filename, int verbose,
33		int *mangled, dos_name_t *ans)
34{
35	int len;
36	int i;
37	int have_lower, have_upper;
38	wchar_t wbuffer[12];
39
40	strcpy(ans->base,"           ");
41	len = native_to_wchar(filename, wbuffer, 11, 0, 0);
42	if(len > 11){
43		*mangled = 1;
44		len = 11;
45	} else
46		*mangled = 0;
47
48	have_lower = have_upper = 0;
49	for(i=0; i<len; i++){
50		if(islower(wbuffer[i]))
51			have_lower = 1;
52		if(isupper(wbuffer[i]))
53			have_upper = 1;
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
71int labelit(struct dos_name_t *dosname,
72	    char *longname,
73	    void *arg0,
74	    direntry_t *entry)
75{
76	time_t now;
77
78	/* find out current time */
79	getTimeNow(&now);
80	mk_entry(dosname, 0x8, 0, 0, now, &entry->dir);
81	return 0;
82}
83
84static void usage(int ret) NORETURN;
85static void usage(int ret)
86{
87	fprintf(stderr, "Mtools version %s, dated %s\n",
88		mversion, mdate);
89	fprintf(stderr, "Usage: %s [-vscVn] [-N serial] drive:\n", progname);
90	exit(ret);
91}
92
93
94void mlabel(int argc, char **argv, int type)
95{
96
97	char *newLabel;
98	int verbose, clear, interactive, show;
99	direntry_t entry;
100	int result=0;
101	char longname[VBUFSIZE];
102	char shortname[45];
103	ClashHandling_t ch;
104	struct MainParam_t mp;
105	Stream_t *RootDir;
106	int c;
107	int mangled;
108	enum { SER_NONE, SER_RANDOM, SER_SET }  set_serial = SER_NONE;
109	long serial = 0;
110	int need_write_boot = 0;
111	int have_boot = 0;
112	char *eptr;
113	struct bootsector boot;
114	Stream_t *Fs=0;
115	int r;
116	struct label_blk_t *labelBlock;
117	int isRo=0;
118	int *isRop=NULL;
119
120    /* Foxconn added start pling 05/06/2009 */
121    char sd_name[32];
122    char vol_name[64];
123
124    memset(sd_name, 0, sizeof(sd_name));
125    memset(vol_name, 0, sizeof(vol_name));
126    /* Foxconn added end pling 05/06/2009 */
127
128	init_clash_handling(&ch);
129	ch.name_converter = label_name;
130	ch.ignore_entry = -2;
131
132	verbose = 0;
133	clear = 0;
134	show = 0;
135
136	if(helpFlag(argc, argv))
137		usage(0);
138	while ((c = getopt(argc, argv, "i:vcsnN:h")) != EOF) {
139		switch (c) {
140			case 'i':
141				set_cmd_line_image(optarg, 0);
142                strcpy(sd_name, optarg);    // Foxconn added pling 05/06/2009
143				break;
144			case 'v':
145				verbose = 1;
146				break;
147			case 'c':
148				clear = 1;
149				break;
150			case 's':
151				show = 1;
152				break;
153			case 'n':
154				set_serial = SER_RANDOM;
155				srandom((long)time (0));
156				serial=random();
157				break;
158			case 'N':
159				set_serial = SER_SET;
160				serial = strtol(optarg, &eptr, 16);
161				if(*eptr) {
162					fprintf(stderr,
163						"%s not a valid serial number\n",
164						optarg);
165					exit(1);
166				}
167				break;
168			case 'h':
169				usage(0);
170			default:
171				usage(1);
172			}
173	}
174
175	if (argc - optind != 1 || !argv[optind][0] || argv[optind][1] != ':')
176		usage(1);
177
178	init_mp(&mp);
179	newLabel = argv[optind]+2;
180	if(strlen(newLabel) > VBUFSIZE) {
181		fprintf(stderr, "Label too long\n");
182		FREE(&RootDir);
183		exit(1);
184	}
185
186	interactive = !show && !clear &&!newLabel[0] &&
187		(set_serial == SER_NONE);
188	if(!clear && !newLabel[0]) {
189		isRop = &isRo;
190	}
191	RootDir = open_root_dir(argv[optind][0], isRop ? 0 : O_RDWR, isRop);
192	if(isRo) {
193		show = 1;
194		interactive = 0;
195	}
196	if(!RootDir) {
197		fprintf(stderr, "%s: Cannot initialize drive\n", argv[0]);
198		exit(1);
199	}
200
201	initializeDirentry(&entry, RootDir);
202	r=vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY,
203		      shortname, longname);
204	if (r == -2) {
205		FREE(&RootDir);
206		exit(1);
207	}
208
209	if(show || interactive){
210		if(isNotFound(&entry)) {
211			printf(" Volume has no label\n");
212            strcpy(vol_name, "");
213        }
214		else if (*longname) {
215			printf(" Volume label is %s (abbr=%s)\n",
216			       longname, shortname);
217            strcpy(vol_name, longname);
218        }
219		else {
220			printf(" Volume label is %s\n",  shortname);
221            strcpy(vol_name, shortname);
222        }
223
224        /* Foxconn added start pling 05/06/2009 */
225        /* Store the volume label in a file under /tmp */
226        FILE *fp = NULL;
227        char *devname;
228        char filename[64];
229
230        if (strlen(sd_name)) {
231            devname = strstr(sd_name, "sd");
232            if (devname) {
233                sprintf(filename, USB_VOL_NAME_FILE, devname);
234                fp = fopen(filename, "w");
235                if (fp != NULL) {
236                    fprintf(fp, "%s\n", vol_name);
237                    fclose(fp);
238                }
239            }
240        }
241        /* Foxconn added end pling 05/06/2009 */
242	}
243
244	/* ask for new label */
245	if(interactive){
246		newLabel = longname;
247		fprintf(stderr,"Enter the new volume label : ");
248		fgets(newLabel, VBUFSIZE, stdin);
249		if(newLabel[0])
250			newLabel[strlen(newLabel)-1] = '\0';
251	}
252
253	if((!show || newLabel[0]) && !isNotFound(&entry)){
254		/* if we have a label, wipe it out before putting new one */
255		if(interactive && newLabel[0] == '\0')
256			if(ask_confirmation("Delete volume label (y/n): ")){
257				FREE(&RootDir);
258				exit(0);
259			}
260		entry.dir.attr = 0; /* for old mlabel */
261		wipeEntry(&entry);
262	}
263
264	if (newLabel[0] != '\0') {
265		ch.ignore_entry = 1;
266		result = mwrite_one(RootDir,newLabel,0,labelit,NULL,&ch) ?
267		  0 : 1;
268	}
269
270	have_boot = 0;
271	if( (!show || newLabel[0]) || set_serial != SER_NONE) {
272		Fs = GetFs(RootDir);
273		have_boot = (force_read(Fs,(char *)&boot,0,sizeof(boot)) ==
274			     sizeof(boot));
275	}
276
277	if(_WORD(boot.fatlen)) {
278	    labelBlock = &boot.ext.old.labelBlock;
279	} else {
280	    labelBlock = &boot.ext.fat32.labelBlock;
281	}
282
283	if(!show || newLabel[0]){
284		dos_name_t dosname;
285		const char *shrtLabel;
286		doscp_t *cp;
287		if(!newLabel[0])
288			shrtLabel = "NO NAME    ";
289		else
290			shrtLabel = newLabel;
291		cp = GET_DOSCONVERT(Fs);
292		label_name(cp, shrtLabel, verbose, &mangled, &dosname);
293
294		if(have_boot && boot.descr >= 0xf0 &&
295		   labelBlock->dos4 == 0x29) {
296			strncpy(labelBlock->label, dosname.base, 11);
297			need_write_boot = 1;
298
299		}
300	}
301
302	if((set_serial != SER_NONE) & have_boot) {
303		if(have_boot && boot.descr >= 0xf0 &&
304		   labelBlock->dos4 == 0x29) {
305			set_dword(labelBlock->serial, serial);
306			need_write_boot = 1;
307		}
308	}
309
310	if(need_write_boot) {
311		force_write(Fs, (char *)&boot, 0, sizeof(boot));
312	}
313
314	FREE(&RootDir);
315	exit(result);
316}
317