diff options
Diffstat (limited to 'mmove.c')
-rw-r--r-- | mmove.c | 323 |
1 files changed, 323 insertions, 0 deletions
@@ -0,0 +1,323 @@ +/* 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/>. + * + * mmove.c + * Renames/moves an MSDOS file + * + */ + + +#define LOWERCASE + +#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 { + const char *fromname; + int verbose; + MainParam_t mp; + + direntry_t *entry; + ClashHandling_t ch; +} Arg_t; + + +/* + * Open the named file for read, create the cluster chain, return the + * directory structure or NULL on error. + */ +static int renameit(dos_name_t *dosname, + char *longname, + void *arg0, + direntry_t *targetEntry) +{ + Arg_t *arg = (Arg_t *) arg0; + int fat; + + targetEntry->dir = arg->entry->dir; + dosnameToDirentry(dosname, &targetEntry->dir); + + if(IS_DIR(targetEntry)) { + direntry_t *movedEntry; + + /* get old direntry. It is important that we do this + * on the actual direntry which is stored in the file, + * and not on a copy, because we will modify it, and the + * modification should be visible at file + * de-allocation time */ + movedEntry = getDirentry(arg->mp.File); + if(movedEntry->Dir != targetEntry->Dir) { + /* we are indeed moving it to a new directory */ + direntry_t subEntry; + Stream_t *oldDir; + /* we have a directory here. Change its parent link */ + + initializeDirentry(&subEntry, arg->mp.File); + + switch(vfat_lookup(&subEntry, "..", 2, ACCEPT_DIR, + NULL, NULL)) { + case -1: + fprintf(stderr, + " Directory has no parent entry\n"); + break; + case -2: + return ERROR_ONE; + case 0: + GET_DATA(targetEntry->Dir, 0, 0, 0, &fat); + if (fat == fat32RootCluster(targetEntry->Dir)) { + fat = 0; + } + + subEntry.dir.start[1] = (fat >> 8) & 0xff; + subEntry.dir.start[0] = fat & 0xff; + dir_write(&subEntry); + if(arg->verbose){ + fprintf(stderr, + "Easy, isn't it? I wonder why DOS can't do this.\n"); + } + break; + } + + wipeEntry(movedEntry); + + /* free the old parent, allocate the new one. */ + oldDir = movedEntry->Dir; + *movedEntry = *targetEntry; + COPY(targetEntry->Dir); + FREE(&oldDir); + return 0; + } + } + + /* wipe out original entry */ + wipeEntry(arg->mp.direntry); + return 0; +} + + + +static int rename_file(direntry_t *entry, MainParam_t *mp) +/* rename a messy DOS file to another messy DOS file */ +{ + int result; + Stream_t *targetDir; + char *shortname; + const char *longname; + + Arg_t * arg = (Arg_t *) (mp->arg); + + arg->entry = entry; + targetDir = mp->targetDir; + + if (targetDir == entry->Dir){ + arg->ch.ignore_entry = -1; + arg->ch.source = entry->entry; + arg->ch.source_entry = entry->entry; + } else { + arg->ch.ignore_entry = -1; + arg->ch.source = -2; + } + + longname = mpPickTargetName(mp); + shortname = 0; + result = mwrite_one(targetDir, longname, shortname, + renameit, (void *)arg, &arg->ch); + if(result == 1) + return GOT_ONE; + else + return ERROR_ONE; +} + + +static int rename_directory(direntry_t *entry, MainParam_t *mp) +{ + int ret; + + /* moves a DOS dir */ + if(isSubdirOf(mp->targetDir, mp->File)) { + fprintf(stderr, "Cannot move directory "); + fprintPwd(stderr, entry,0); + fprintf(stderr, " into one of its own subdirectories ("); + fprintPwd(stderr, getDirentry(mp->targetDir),0); + fprintf(stderr, ")\n"); + return ERROR_ONE; + } + + if(entry->entry == -3) { + fprintf(stderr, "Cannot move a root directory: "); + fprintPwd(stderr, entry,0); + return ERROR_ONE; + } + + ret = rename_file(entry, mp); + if(ret & ERROR_ONE) + return ret; + + return ret; +} + +static int rename_oldsyntax(direntry_t *entry, MainParam_t *mp) +{ + int result; + Stream_t *targetDir; + const char *shortname, *longname; + + Arg_t * arg = (Arg_t *) (mp->arg); + arg->entry = entry; + targetDir = entry->Dir; + + arg->ch.ignore_entry = -1; + arg->ch.source = entry->entry; + arg->ch.source_entry = entry->entry; + +#if 0 + if(!strcasecmp(mp->shortname, arg->fromname)){ + longname = mp->longname; + shortname = mp->targetName; + } else { +#endif + longname = mp->targetName; + shortname = 0; +#if 0 + } +#endif + result = mwrite_one(targetDir, longname, shortname, + renameit, (void *)arg, &arg->ch); + if(result == 1) + return GOT_ONE; + else + return ERROR_ONE; +} + + +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 [-vV] [-D clash_option] file targetfile\n", progname); + fprintf(stderr, + " %s [-vV] [-D clash_option] file [files...] target_directory\n", + progname); + exit(ret); +} + +void mmove(int argc, char **argv, int oldsyntax) +{ + Arg_t arg; + int c; + char shortname[13]; + char longname[VBUFSIZE]; + char def_drive; + int i; + + /* get command line options */ + + init_clash_handling(& arg.ch); + + /* get command line options */ + arg.verbose = 0; + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc, argv, "i:vD:oh")) != EOF) { + switch (c) { + case 'i': + set_cmd_line_image(optarg); + break; + case 'v': /* dummy option for mcopy */ + arg.verbose = 1; + break; + case 'o': + handle_clash_options(&arg.ch, c); + break; + case 'D': + if(handle_clash_options(&arg.ch, *optarg)) + usage(1); + break; + case 'h': + usage(0); + case '?': + usage(1); + default: + break; + } + } + + if (argc - optind < 2) + usage(1); + + init_mp(&arg.mp); + arg.mp.arg = (void *) &arg; + arg.mp.openflags = O_RDWR; + + /* look for a default drive */ + def_drive = '\0'; + for(i=optind; i<argc; i++) + if(argv[i][0] && argv[i][1] == ':' ){ + if(!def_drive) + def_drive = toupper(argv[i][0]); + else if(def_drive != toupper(argv[i][0])){ + fprintf(stderr, + "Cannot move files across different drives\n"); + exit(1); + } + } + + if(def_drive) + *(arg.mp.mcwd) = def_drive; + + if (oldsyntax && (argc - optind != 2 || strpbrk(":/", argv[argc-1]))) + oldsyntax = 0; + + arg.mp.lookupflags = + ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN_DIRS | NO_DOTS | NO_UNIX; + + if (!oldsyntax){ + target_lookup(&arg.mp, argv[argc-1]); + arg.mp.callback = rename_file; + arg.mp.dirCallback = rename_directory; + } else { + /* do not look up the target; it will be the same dir as the + * source */ + arg.fromname = argv[optind]; + if(arg.fromname[0] && arg.fromname[1] == ':') + arg.fromname += 2; + arg.fromname = _basename(arg.fromname); + arg.mp.targetName = strdup(argv[argc-1]); + arg.mp.callback = rename_oldsyntax; + } + + + arg.mp.longname = longname; + longname[0]='\0'; + + arg.mp.shortname = shortname; + shortname[0]='\0'; + + exit(main_loop(&arg.mp, argv + optind, argc - optind - 1)); +} |