diff options
Diffstat (limited to 'mlabel.c')
-rw-r--r-- | mlabel.c | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/mlabel.c b/mlabel.c new file mode 100644 index 0000000..4385d42 --- /dev/null +++ b/mlabel.c @@ -0,0 +1,331 @@ +/* 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 <http://www.gnu.org/licenses/>. + * + * mlabel.c + * Make an MSDOS volume label + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mainloop.h" +#include "vfat.h" +#include "mtools.h" +#include "nameclash.h" +#include "file_name.h" + +static void _label_name(doscp_t *cp, const char *filename, int verbose, + int *mangled, dos_name_t *ans, int preserve_case) +{ + int len; + int 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<len; i++){ + if(islower(wbuffer[i])) + have_lower = 1; + if(isupper(wbuffer[i])) + have_upper = 1; + if(!preserve_case) + wbuffer[i] = towupper(wbuffer[i]); + if( +#ifdef HAVE_WCHAR_H + wcschr(L"^+=/[]:,?*\\<>|\".", 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, + void *arg0, + 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) +{ + + const char *newLabel=""; + int verbose, clear, interactive, show; + direntry_t entry; + int result=0; + char longname[VBUFSIZE]; + char shortname[45]; + ClashHandling_t ch; + struct MainParam_t mp; + Stream_t *RootDir; + int c; + int mangled; + enum { SER_NONE, SER_RANDOM, SER_SET } set_serial = SER_NONE; + long 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; + + 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; + srandom((long)time (0)); + serial=random(); + break; + case 'N': + set_serial = SER_SET; + serial = strtoul(optarg, &eptr, 16); + if(*eptr) { + fprintf(stderr, + "%s not a valid serial number\n", + optarg); + exit(1); + } + 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 = toupper(argv[argc -1][0]); + newLabel = argv[optind]+2; + } else { + drive = get_default_drive(); + } + + init_mp(&mp); + 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, 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_read(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 && + labelBlock->dos4 == 0x29) { + strncpy(labelBlock->label, dosname.base, 11); + need_write_boot = 1; + + } + } + + if((set_serial != SER_NONE) & have_boot) { + if(have_boot && boot.boot.descr >= 0xf0 && + labelBlock->dos4 == 0x29) { + set_dword(labelBlock->serial, serial); + need_write_boot = 1; + } + } + + if(need_write_boot) { + force_write(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_write(Fs, (char *)&boot, + backupBoot * WORD_S(secsiz), + sizeof(boot)); + } + } + + FREE(&RootDir); + exit(result); +} |