/* Copyright 1986-1992 Emmet P. Gray. * Copyright 1996-1998,2000-2002,2005,2007-2009 Alain Knaff. * This file is part of mtools. * * Mtools is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Mtools is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Mtools. If not, see . * * mlabel.c * Make an MSDOS volume label */ #include "sysincludes.h" #include "nameclash.h" #include "file_name.h" #include "vfat.h" #include "stream.h" static void _label_name(doscp_t *cp, const char *filename, int verbose UNUSEDP, int *mangled, dos_name_t *ans, int preserve_case) { size_t len; size_t i; int have_lower, have_upper; wchar_t wbuffer[12]; memset(ans, ' ', sizeof(*ans)-1); ans->sentinel = '\0'; len = native_to_wchar(filename, wbuffer, 11, 0, 0); if(len > 11){ *mangled = 1; len = 11; } else *mangled = 0; have_lower = have_upper = 0; for(i=0; i|\".", wbuffer[i]) #else strchr("^+=/[]:,?*\\<>|\".", wbuffer[i]) #endif ){ *mangled = 1; wbuffer[i] = '~'; } } if (have_lower && have_upper) *mangled = 1; wchar_to_dos(cp, wbuffer, ans->base, len, mangled); } void label_name_uc(doscp_t *cp, const char *filename, int verbose, int *mangled, dos_name_t *ans) { _label_name(cp, filename, verbose, mangled, ans, 0); } void label_name_pc(doscp_t *cp, const char *filename, int verbose, int *mangled, dos_name_t *ans) { _label_name(cp, filename, verbose, mangled, ans, 1); } int labelit(struct dos_name_t *dosname, char *longname UNUSEDP, void *arg0 UNUSEDP, direntry_t *entry) { time_t now; /* find out current time */ getTimeNow(&now); mk_entry(dosname, 0x8, 0, 0, now, &entry->dir); return 0; } static void usage(int ret) NORETURN; static void usage(int ret) { fprintf(stderr, "Mtools version %s, dated %s\n", mversion, mdate); fprintf(stderr, "Usage: %s [-vscVn] [-N serial] drive:\n", progname); exit(ret); } void mlabel(int argc, char **argv, int type UNUSEDP) NORETURN; void mlabel(int argc, char **argv, int type UNUSEDP) { const char *newLabel=""; int verbose, clear, interactive, show; direntry_t entry; int result=0; char longname[VBUFSIZE]; char shortname[45]; ClashHandling_t ch; Stream_t *RootDir; int c; int mangled; enum { SER_NONE, SER_RANDOM, SER_SET } set_serial = SER_NONE; uint32_t serial = 0; int need_write_boot = 0; int have_boot = 0; char *eptr; union bootsector boot; Stream_t *Fs=0; int r; struct label_blk_t *labelBlock; int isRo=0; int *isRop=NULL; char drive; init_clash_handling(&ch); ch.name_converter = label_name_uc; ch.ignore_entry = -2; ch.is_label = 1; verbose = 0; clear = 0; show = 0; if(helpFlag(argc, argv)) usage(0); while ((c = getopt(argc, argv, "i:vcsnN:h")) != EOF) { switch (c) { case 'i': set_cmd_line_image(optarg); break; case 'v': verbose = 1; break; case 'c': clear = 1; break; case 's': show = 1; break; case 'n': set_serial = SER_RANDOM; init_random(); serial=(uint32_t) random(); break; case 'N': set_serial = SER_SET; errno=0; serial = strtou32(optarg, &eptr, 16); if(*eptr) { fprintf(stderr, "%s not a valid serial number\n", optarg); exit(1); } check_number_parse_errno((char)c, optarg, eptr); break; case 'h': usage(0); default: usage(1); } } if (argc - optind > 1) usage(1); if(argc - optind == 1) { if(!argv[optind][0] || argv[optind][1] != ':') usage(1); drive = ch_toupper(argv[argc -1][0]); newLabel = argv[optind]+2; } else { drive = get_default_drive(); } if(strlen(newLabel) > VBUFSIZE) { fprintf(stderr, "Label too long\n"); FREE(&RootDir); exit(1); } interactive = !show && !clear &&!newLabel[0] && (set_serial == SER_NONE); if(!clear && !newLabel[0]) { isRop = &isRo; } if(clear && newLabel[0]) { /* Clear and new label specified both */ fprintf(stderr, "Both clear and new label specified\n"); FREE(&RootDir); exit(1); } RootDir = open_root_dir(drive, isRop ? 0 : O_RDWR, isRop); if(isRo) { show = 1; interactive = 0; } if(!RootDir) { fprintf(stderr, "%s: Cannot initialize drive\n", argv[0]); exit(1); } initializeDirentry(&entry, RootDir); r=vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY, shortname, sizeof(shortname), longname, sizeof(longname)); if (r == -2) { FREE(&RootDir); exit(1); } if(show || interactive){ if(isNotFound(&entry)) printf(" Volume has no label\n"); else if (*longname) printf(" Volume label is %s (abbr=%s)\n", longname, shortname); else printf(" Volume label is %s\n", shortname); } /* ask for new label */ if(interactive){ saved_sig_state ss; newLabel = longname; allow_interrupts(&ss); fprintf(stderr,"Enter the new volume label : "); if(fgets(longname, VBUFSIZE, stdin) == NULL) { fprintf(stderr, "\n"); if(errno == EINTR) { FREE(&RootDir); exit(1); } longname[0] = '\0'; } if(longname[0]) longname[strlen(newLabel)-1] = '\0'; } if(strlen(newLabel) > 11) { fprintf(stderr,"New label too long\n"); FREE(&RootDir); exit(1); } if((!show || newLabel[0]) && !isNotFound(&entry)){ /* if we have a label, wipe it out before putting new one */ if(interactive && newLabel[0] == '\0') if(ask_confirmation("Delete volume label (y/n): ")){ FREE(&RootDir); exit(0); } entry.dir.attr = 0; /* for old mlabel */ wipeEntry(&entry); } if (newLabel[0] != '\0') { ch.ignore_entry = 1; result = mwrite_one(RootDir,newLabel,0,labelit,NULL,&ch) ? 0 : 1; } have_boot = 0; if( (!show || newLabel[0]) || set_serial != SER_NONE) { Fs = GetFs(RootDir); have_boot = (force_pread(Fs,boot.characters,0,sizeof(boot)) == sizeof(boot)); } if(WORD_S(fatlen)) { labelBlock = &boot.boot.ext.old.labelBlock; } else { labelBlock = &boot.boot.ext.fat32.labelBlock; } if(!show || newLabel[0]){ dos_name_t dosname; const char *shrtLabel; doscp_t *cp; if(!newLabel[0]) shrtLabel = "NO NAME "; else shrtLabel = newLabel; cp = GET_DOSCONVERT(Fs); label_name_pc(cp, shrtLabel, verbose, &mangled, &dosname); if(have_boot && boot.boot.descr >= 0xf0 && has_BPB4) { strncpy(labelBlock->label, dosname.base, 8); strncpy(labelBlock->label+8, dosname.ext, 3); need_write_boot = 1; } } if((set_serial != SER_NONE) & have_boot) { if(have_boot && boot.boot.descr >= 0xf0 && has_BPB4) { set_dword(labelBlock->serial, serial); need_write_boot = 1; } } if(need_write_boot) { force_pwrite(Fs, (char *)&boot, 0, sizeof(boot)); /* If this is fat 32, write backup boot sector too */ if(!WORD_S(fatlen)) { int backupBoot = WORD_S(ext.fat32.backupBoot); force_pwrite(Fs, (char *)&boot, backupBoot * WORD_S(secsiz), sizeof(boot)); } } FREE(&RootDir); exit(result); }