| /* Copyright 1986-1992 Emmet P. Gray. |
| * Copyright 1996-2002,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/>. |
| * |
| * mmd.c |
| * Makes an MSDOS directory |
| */ |
| |
| |
| #include "sysincludes.h" |
| #include "msdos.h" |
| #include "mtools.h" |
| #include "vfat.h" |
| #include "mainloop.h" |
| #include "plain_io.h" |
| #include "nameclash.h" |
| #include "file.h" |
| #include "fs.h" |
| |
| /* |
| * Preserve the file modification times after the fclose() |
| */ |
| |
| typedef struct Arg_t { |
| char *target; |
| MainParam_t mp; |
| |
| Stream_t *SrcDir; |
| int entry; |
| ClashHandling_t ch; |
| Stream_t *targetDir; |
| } Arg_t; |
| |
| |
| typedef struct CreateArg_t { |
| Stream_t *Dir; |
| Stream_t *NewDir; |
| unsigned char attr; |
| time_t mtime; |
| } CreateArg_t; |
| |
| /* |
| * Open the named file for read, create the cluster chain, return the |
| * directory structure or NULL on error. |
| */ |
| static int makeit(dos_name_t *dosname, |
| char *longname UNUSEDP, |
| void *arg0, |
| direntry_t *targetEntry) |
| { |
| Stream_t *Target; |
| CreateArg_t *arg = (CreateArg_t *) arg0; |
| uint32_t fat; |
| direntry_t subEntry; |
| |
| /* will it fit? At least one cluster must be free */ |
| if (!getfreeMinClusters(targetEntry->Dir, 1)) |
| return -1; |
| |
| mk_entry(dosname, ATTR_DIR, 1, 0, arg->mtime, &targetEntry->dir); |
| Target = OpenFileByDirentry(targetEntry); |
| if(!Target){ |
| fprintf(stderr,"Could not open Target\n"); |
| return -1; |
| } |
| |
| /* this allocates the first cluster for our directory */ |
| |
| initializeDirentry(&subEntry, Target); |
| |
| subEntry.entry = 1; |
| GET_DATA(targetEntry->Dir, 0, 0, 0, &fat); |
| if (fat == fat32RootCluster(targetEntry->Dir)) { |
| fat = 0; |
| } |
| mk_entry_from_base(".. ", ATTR_DIR, fat, 0, arg->mtime, &subEntry.dir); |
| dir_write(&subEntry); |
| |
| FLUSH(Target); |
| subEntry.entry = 0; |
| GET_DATA(Target, 0, 0, 0, &fat); |
| mk_entry_from_base(". ", ATTR_DIR, fat, 0, arg->mtime, &subEntry.dir); |
| dir_write(&subEntry); |
| |
| mk_entry(dosname, ATTR_DIR | arg->attr, fat, 0, arg->mtime, |
| &targetEntry->dir); |
| arg->NewDir = Target; |
| 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 [-D clash_option] file targetfile\n", progname); |
| fprintf(stderr, |
| " %s [-D clash_option] file [files...] target_directory\n", |
| progname); |
| exit(ret); |
| } |
| |
| Stream_t *createDir(Stream_t *Dir, const char *filename, ClashHandling_t *ch, |
| unsigned char attr, time_t mtime) |
| { |
| CreateArg_t arg; |
| int ret; |
| |
| arg.Dir = Dir; |
| arg.attr = attr; |
| arg.mtime = mtime; |
| |
| if (!getfreeMinClusters(Dir, 1)) |
| return NULL; |
| |
| ret = mwrite_one(Dir, filename, 0, makeit, &arg, ch); |
| if(ret < 1) |
| return NULL; |
| else |
| return arg.NewDir; |
| } |
| |
| static int createDirCallback(direntry_t *entry UNUSEDP, MainParam_t *mp) |
| { |
| Stream_t *ret; |
| time_t now; |
| |
| ret = createDir(mp->File, mp->targetName, &((Arg_t *)(mp->arg))->ch, |
| ATTR_DIR, getTimeNow(&now)); |
| if(ret == NULL) |
| return ERROR_ONE; |
| else { |
| FREE(&ret); |
| return GOT_ONE; |
| } |
| |
| } |
| |
| void mmd(int argc, char **argv, int type UNUSEDP) NORETURN; |
| void mmd(int argc, char **argv, int type UNUSEDP) |
| { |
| Arg_t arg; |
| int c; |
| |
| /* get command line options */ |
| |
| init_clash_handling(& arg.ch); |
| |
| /* get command line options */ |
| if(helpFlag(argc, argv)) |
| usage(0); |
| while ((c = getopt(argc, argv, "i:D:oh")) != EOF) { |
| switch (c) { |
| case 'i': |
| set_cmd_line_image(optarg); |
| break; |
| case '?': |
| usage(1); |
| case 'o': |
| handle_clash_options(&arg.ch, (char) c); |
| break; |
| case 'D': |
| if(handle_clash_options(&arg.ch, *optarg)) |
| usage(1); |
| break; |
| case 'h': |
| usage(0); |
| default: |
| usage(1); |
| } |
| } |
| |
| if (argc - optind < 1) |
| usage(1); |
| |
| init_mp(&arg.mp); |
| arg.mp.arg = (void *) &arg; |
| arg.mp.openflags = O_RDWR; |
| arg.mp.callback = createDirCallback; |
| arg.mp.lookupflags = OPEN_PARENT | DO_OPEN_DIRS; |
| exit(main_loop(&arg.mp, argv + optind, argc - optind)); |
| } |