mcopy.c

Go to the documentation of this file.
00001 /*
00002  * mcopy.c
00003  * Copy an MSDOS files to and from Unix
00004  *
00005  */
00006 
00007 
00008 #define LOWERCASE
00009 
00010 #include "sysincludes.h"
00011 #include "msdos.h"
00012 #include "mtools.h"
00013 #include "vfat.h"
00014 #include "mainloop.h"
00015 #include "plain_io.h"
00016 #include "nameclash.h"
00017 #include "file.h"
00018 #include "fs.h"
00019 
00020 
00021 /*
00022  * Preserve the file modification times after the fclose()
00023  */
00024 
00025 static void set_mtime(const char *target, time_t mtime)
00026 {
00027         if (target && strcmp(target, "-") && mtime != 0L) {
00028 #ifdef HAVE_UTIMES
00029                 struct timeval tv[2];   
00030                 tv[0].tv_sec = mtime;
00031                 tv[0].tv_usec = 0;
00032                 tv[1].tv_sec = mtime;
00033                 tv[1].tv_usec = 0;
00034                 utimes((char *)target, tv);
00035 #else
00036 #ifdef HAVE_UTIME
00037                 struct utimbuf utbuf;
00038 
00039                 utbuf.actime = mtime;
00040                 utbuf.modtime = mtime;
00041                 utime(target, &utbuf);
00042 #endif
00043 #endif
00044         }
00045         return;
00046 }
00047 
00048 typedef struct Arg_t {
00049         int recursive;
00050         int preserveAttributes;
00051         int preserveTime;
00052         unsigned char attr;
00053         char *path;
00054         int textmode;
00055         int needfilter;
00056         int nowarn;
00057         int verbose;
00058         int type;
00059         MainParam_t mp;
00060         ClashHandling_t ch;
00061 } Arg_t;
00062 
00063 /* Write the Unix file */
00064 static int unix_write(direntry_t *entry, MainParam_t *mp, int needfilter)
00065 {
00066         Arg_t *arg=(Arg_t *) mp->arg;
00067         time_t mtime;
00068         Stream_t *File=mp->File;
00069         Stream_t *Target, *Source;
00070         struct stat stbuf;
00071         int ret;
00072         char errmsg[80];
00073         char *unixFile;
00074 
00075         File->Class->get_data(File, &mtime, 0, 0, 0);
00076 
00077         if (!arg->preserveTime)
00078                 mtime = 0L;
00079 
00080         if(arg->type)
00081                 unixFile = "-";
00082         else
00083                 unixFile = mpBuildUnixFilename(mp);
00084         if(!unixFile) {
00085                 printOom();
00086                 return ERROR_ONE;
00087         }
00088 
00089         /* if we are creating a file, check whether it already exists */
00090         if(!arg->type) {
00091                 if (!arg->nowarn && &arg->type && !access(unixFile, 0)){
00092                         if( ask_confirmation("File \"%s\" exists, overwrite (y/n) ? ",
00093                                              unixFile,0)) {
00094                                 free(unixFile);
00095                                 return ERROR_ONE;
00096                         }
00097                         
00098                         /* sanity checking */
00099                         if (!stat(unixFile, &stbuf) && !S_ISREG(stbuf.st_mode)) {
00100                                 fprintf(stderr,"\"%s\" is not a regular file\n",
00101                                         unixFile);
00102                                 
00103                                 free(unixFile);
00104                                 return ERROR_ONE;
00105                         }
00106                 }
00107         }
00108 
00109         if(!arg->type && arg->verbose) {
00110                 fprintf(stderr,"Copying ");
00111                 mpPrintFilename(stderr,mp);
00112                 fprintf(stderr,"\n");
00113         }
00114         
00115         if(got_signal) {
00116                 free(unixFile);
00117                 return ERROR_ONE;
00118         }
00119 
00120         if ((Target = SimpleFileOpen(0, 0, unixFile,
00121                                      O_WRONLY | O_CREAT | O_TRUNC,
00122                                      errmsg, 0, 0, 0))) {
00123                 ret = 0;
00124                 if(needfilter && arg->textmode){
00125                         Source = open_filter(COPY(File));
00126                         if (!Source)
00127                                 ret = -1;
00128                 } else
00129                         Source = COPY(File);
00130 
00131                 if (ret == 0 )
00132                         ret = copyfile(Source, Target);
00133                 FREE(&Source);
00134                 FREE(&Target);
00135                 if(ret <= -1){
00136                         if(!arg->type) {
00137                                 unlink(unixFile);
00138                                 free(unixFile);
00139                         }
00140                         return ERROR_ONE;
00141                 }
00142                 if(!arg->type) {
00143                         set_mtime(unixFile, mtime);
00144                         free(unixFile);
00145                 }
00146                 return GOT_ONE;
00147         } else {
00148                 fprintf(stderr,"%s\n", errmsg);
00149                 if(!arg->type)
00150                         free(unixFile);
00151                 return ERROR_ONE;
00152         }
00153 }
00154 
00155 static int makeUnixDir(char *filename)
00156 {
00157         if(!mkdir(filename, 0777))
00158                 return 0;
00159         if(errno == EEXIST) {
00160                 struct stat buf;
00161                 if(stat(filename, &buf) < 0)
00162                         return -1;
00163                 if(S_ISDIR(buf.st_mode))
00164                         return 0;
00165                 errno = ENOTDIR;
00166         }
00167         return -1;
00168 }
00169 
00170 /* Copy a directory to Unix */
00171 static int unix_copydir(direntry_t *entry, MainParam_t *mp)
00172 {
00173         Arg_t *arg=(Arg_t *) mp->arg;
00174         time_t mtime;
00175         Stream_t *File=mp->File;
00176         int ret;
00177         char *unixFile;
00178 
00179         if (!arg->recursive && mp->basenameHasWildcard)
00180                 return 0;
00181 
00182         File->Class->get_data(File, &mtime, 0, 0, 0);   
00183         if (!arg->preserveTime)
00184                 mtime = 0L;
00185         if(!arg->type && arg->verbose) {
00186                 fprintf(stderr,"Copying ");
00187                 fprintPwd(stderr, entry,0);
00188                 fprintf(stderr, "\n");
00189         }
00190         if(got_signal)
00191                 return ERROR_ONE;
00192         unixFile = mpBuildUnixFilename(mp);
00193         if(!unixFile) {
00194                 printOom();
00195                 return ERROR_ONE;
00196         }
00197         if(arg->type || !*mpPickTargetName(mp) || !makeUnixDir(unixFile)) {
00198                 Arg_t newArg;
00199 
00200                 newArg = *arg;
00201                 newArg.mp.arg = (void *) &newArg;
00202                 newArg.mp.unixTarget = unixFile;
00203                 newArg.mp.targetName = 0;
00204                 newArg.mp.basenameHasWildcard = 1;
00205 
00206                 ret = mp->loop(File, &newArg.mp, "*");
00207                 set_mtime(unixFile, mtime);
00208                 free(unixFile);
00209                 return ret | GOT_ONE;           
00210         } else {
00211                 perror("mkdir");
00212                 fprintf(stderr, 
00213                         "Failure to make directory %s\n", 
00214                         unixFile);
00215                 free(unixFile);
00216                 return ERROR_ONE;
00217         }
00218 }
00219 
00220 static  int dos_to_unix(direntry_t *entry, MainParam_t *mp)
00221 {
00222         return unix_write(entry, mp, 1);
00223 }
00224 
00225 
00226 static  int unix_to_unix(MainParam_t *mp)
00227 {
00228         return unix_write(0, mp, 0);
00229 }
00230 
00231 
00232 static int directory_dos_to_unix(direntry_t *entry, MainParam_t *mp)
00233 {
00234         return unix_copydir(entry, mp);
00235 }
00236 
00237 /*
00238  * Open the named file for read, create the cluster chain, return the
00239  * directory structure or NULL on error.
00240  */
00241 static int writeit(char *dosname,
00242                    char *longname,
00243                    void *arg0,
00244                    direntry_t *entry)
00245 {
00246         Stream_t *Target;
00247         time_t now;
00248         int type, fat, ret;
00249         time_t date;
00250         mt_size_t filesize, newsize;
00251         Arg_t *arg = (Arg_t *) arg0;
00252 
00253 
00254 
00255         if (arg->mp.File->Class->get_data(arg->mp.File,
00256                                                                           & date, &filesize, &type, 0) < 0 ){
00257                 fprintf(stderr, "Can't stat source file\n");
00258                 return -1;
00259         }
00260 
00261         if (type){
00262                 if (arg->verbose)
00263                         fprintf(stderr, "\"%s\" is a directory\n", longname);
00264                 return -1;
00265         }
00266 
00267         /*if (!arg->single || arg->recursive)*/
00268         if(arg->verbose)
00269                 fprintf(stderr,"Copying %s\n", longname);
00270         if(got_signal)
00271                 return -1;
00272 
00273         /* will it fit? */
00274         if (!getfreeMinBytes(arg->mp.targetDir, filesize))
00275                 return -1;
00276         
00277         /* preserve mod time? */
00278         if (arg->preserveTime)
00279                 now = date;
00280         else
00281                 getTimeNow(&now);
00282 
00283         mk_entry(dosname, arg->attr, 1, 0, now, &entry->dir);
00284 
00285         Target = OpenFileByDirentry(entry);
00286         if(!Target){
00287                 fprintf(stderr,"Could not open Target\n");
00288                 exit(1);
00289         }
00290         if (arg->needfilter & arg->textmode)
00291                 Target = open_filter(Target);
00292 
00293 
00294 
00295         ret = copyfile(arg->mp.File, Target);
00296         GET_DATA(Target, 0, &newsize, 0, &fat);
00297         FREE(&Target);
00298         if (arg->needfilter & arg->textmode)
00299             newsize++; /* ugly hack: we gathered the size before the Ctrl-Z
00300                         * was written.  Increment it manually */
00301         if(ret < 0 ){
00302                 fat_free(arg->mp.targetDir, fat);
00303                 return -1;
00304         } else {
00305                 mk_entry(dosname, arg->attr, fat, truncBytes32(newsize),
00306                                  now, &entry->dir);
00307                 return 0;
00308         }
00309 }
00310 
00311 
00312 
00313 static int dos_write(direntry_t *entry, MainParam_t *mp, int needfilter)
00314 /* write a messy dos file to another messy dos file */
00315 {
00316         int result;
00317         Arg_t * arg = (Arg_t *) (mp->arg);
00318         const char *targetName = mpPickTargetName(mp);
00319 
00320         if(entry && arg->preserveAttributes)
00321                 arg->attr = entry->dir.attr;
00322         else
00323                 arg->attr = ATTR_ARCHIVE;
00324 
00325         arg->needfilter = needfilter;
00326         if (entry && mp->targetDir == entry->Dir){
00327                 arg->ch.ignore_entry = -1;
00328                 arg->ch.source = entry->entry;
00329         } else {
00330                 arg->ch.ignore_entry = -1;
00331                 arg->ch.source = -2;
00332         }
00333         result = mwrite_one(mp->targetDir, targetName, 0,
00334                             writeit, (void *)arg, &arg->ch);
00335         if(result == 1)
00336                 return GOT_ONE;
00337         else
00338                 return ERROR_ONE;
00339 }
00340 
00341 static Stream_t *subDir(Stream_t *parent, const char *filename)
00342 {
00343         direntry_t entry;               
00344         initializeDirentry(&entry, parent);
00345 
00346         switch(vfat_lookup(&entry, filename, -1, ACCEPT_DIR, 0, 0)) {
00347             case 0:
00348                 return OpenFileByDirentry(&entry);
00349             case -1:
00350                 return NULL;
00351             default: /* IO Error */
00352                 return NULL;
00353         }
00354 }
00355 
00356 static int dos_copydir(direntry_t *entry, MainParam_t *mp)
00357 /* copyes a directory to Dos */
00358 {
00359         Arg_t * arg = (Arg_t *) (mp->arg);
00360         Arg_t newArg;
00361         time_t now;
00362         time_t date;
00363         int ret;
00364         const char *targetName = mpPickTargetName(mp);
00365 
00366         if (!arg->recursive && mp->basenameHasWildcard)
00367                 return 0;
00368 
00369         if(entry && isSubdirOf(mp->targetDir, mp->File)) {
00370                 fprintf(stderr, "Cannot recursively copy directory ");
00371                 fprintPwd(stderr, entry,0);
00372                 fprintf(stderr, " into one of its own subdirectories ");
00373                 fprintPwd(stderr, getDirentry(mp->targetDir),0);
00374                 fprintf(stderr, "\n");
00375                 return ERROR_ONE;
00376         }
00377 
00378         if (arg->mp.File->Class->get_data(arg->mp.File,
00379                                           & date, 0, 0, 0) < 0 ){
00380                 fprintf(stderr, "Can't stat source file\n");
00381                 return ERROR_ONE;
00382         }
00383 
00384         if(!arg->type && arg->verbose)
00385                 fprintf(stderr,"Copying %s\n", mpGetBasename(mp));
00386 
00387         if(entry && arg->preserveAttributes)
00388                 arg->attr = entry->dir.attr;
00389         else
00390                 arg->attr = 0;
00391 
00392         if (entry && (mp->targetDir == entry->Dir)){
00393                 arg->ch.ignore_entry = -1;
00394                 arg->ch.source = entry->entry;
00395         } else {
00396                 arg->ch.ignore_entry = -1;
00397                 arg->ch.source = -2;
00398         }
00399 
00400         /* preserve mod time? */
00401         if (arg->preserveTime)
00402                 now = date;
00403         else
00404                 getTimeNow(&now);
00405 
00406         newArg = *arg;
00407         newArg.mp.arg = &newArg;
00408         newArg.mp.targetName = 0;
00409         newArg.mp.basenameHasWildcard = 1;
00410         if(*targetName) {
00411                 /* maybe the directory already exist. Use it */
00412                 newArg.mp.targetDir = subDir(mp->targetDir, targetName);
00413                 if(!newArg.mp.targetDir)
00414                         newArg.mp.targetDir = createDir(mp->targetDir, 
00415                                                         targetName,
00416                                                         &arg->ch, arg->attr, 
00417                                                         now);
00418         } else
00419                 newArg.mp.targetDir = mp->targetDir;
00420 
00421         if(!newArg.mp.targetDir)
00422                 return ERROR_ONE;
00423 
00424         ret = mp->loop(mp->File, &newArg.mp, "*");
00425         if(*targetName)
00426                 FREE(&newArg.mp.targetDir);
00427         return ret | GOT_ONE;
00428 }
00429 
00430 
00431 static int dos_to_dos(direntry_t *entry, MainParam_t *mp)
00432 {
00433         return dos_write(entry, mp, 0);
00434 }
00435 
00436 static int unix_to_dos(MainParam_t *mp)
00437 {
00438         return dos_write(0, mp, 1);
00439 }
00440 
00441 
00442 static void usage(void)
00443 {
00444         fprintf(stderr,
00445                 "Mtools version %s, dated %s\n", mversion, mdate);
00446         fprintf(stderr,
00447                 "Usage: %s [-/spabtnmvQB] [-D clash_option] sourcefile targetfile\n", progname);
00448         fprintf(stderr,
00449                 "       %s [-/spabtnmvQB] [-D clash_option] sourcefile [sourcefiles...] targetdirectory\n", 
00450                 progname);
00451         fprintf(stderr,
00452                 "\t-/ -s Recursive\n"
00453                 "\t-p Preserve attributes\n"
00454                 "\t-a -t Textmode\n"
00455                 "\t-n Overwrite UNIX files without confirmation\n"
00456                 "\t-m Preserve file time (default under Minix)\n"
00457                 "\t-v Verbose\n"
00458                 "\t-Q Quit on the first error\n"
00459                 "\t-b -B Batch mode (faster, but less crash resistent)\n"
00460                 "\t-o Overwrite DOS files without confirmation\n");
00461         exit(1);
00462 }
00463 
00464 void mcopy(int argc, char **argv, int mtype)
00465 {
00466         Arg_t arg;
00467         int c, ret, fastquit;
00468         int todir;
00469         
00470 
00471         /* get command line options */
00472 
00473         init_clash_handling(& arg.ch);
00474 
00475         /* get command line options */
00476         todir = 0;
00477         arg.recursive = 0;
00478 #ifdef OS_Minix
00479         arg.preserveTime = 1;   /* Copy file time as DOS does. */
00480 #else
00481         arg.preserveTime = 0;
00482 #endif
00483         arg.preserveAttributes = 0;
00484         arg.nowarn = 0;
00485         arg.textmode = 0;
00486         arg.verbose = 0;
00487         arg.type = mtype;
00488         fastquit = 0;
00489         while ((c = getopt(argc, argv, "abB/sptnmvQD:o")) != EOF) {
00490                 switch (c) {
00491                         case 's':
00492                         case '/':
00493                                 arg.recursive = 1;
00494                                 break;
00495                         case 'p':
00496                                 arg.preserveAttributes = 1;
00497                                 break;
00498                         case 'a':
00499                         case 't':
00500                                 arg.textmode = 1;
00501                                 break;
00502                         case 'n':
00503                                 arg.nowarn = 1;
00504                                 break;
00505                         case 'm':
00506                                 arg.preserveTime = 1;
00507                                 break;
00508                         case 'v':
00509                                 arg.verbose = 1;
00510                                 break;
00511                         case 'Q':
00512                                 fastquit = 1;
00513                                 break;
00514                         case 'B':
00515                         case 'b':
00516                                 batchmode = 1;
00517                                 break;
00518                         case 'o':
00519                                 handle_clash_options(&arg.ch, c);
00520                                 break;
00521                         case 'D':
00522                                 if(handle_clash_options(&arg.ch, *optarg))
00523                                         usage();
00524                                 break;
00525                         case '?':
00526                                 usage();
00527                         default:
00528                                 break;
00529                 }
00530         }
00531 
00532         if (argc - optind < 1)
00533                 usage();
00534 
00535         init_mp(&arg.mp);
00536         arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN | NO_DOTS;
00537         arg.mp.fast_quit = fastquit;
00538         arg.mp.arg = (void *) &arg;
00539         arg.mp.openflags = O_RDONLY;
00540 
00541         /* last parameter is "-", use mtype mode */
00542         if(!mtype && !strcmp(argv[argc-1], "-")) {
00543                 arg.type = mtype = 1;
00544                 argc--;
00545         }
00546 
00547         if(mtype){
00548                 /* Mtype = copying to stdout */
00549                 arg.mp.targetName = strdup("-");
00550                 arg.mp.unixTarget = strdup("");
00551                 arg.mp.callback = dos_to_unix;
00552                 arg.mp.dirCallback = unix_copydir;
00553                 arg.mp.unixcallback = unix_to_unix;             
00554         } else {
00555                 char *target;
00556                 if (argc - optind == 1) {
00557                         /* copying to the current directory */
00558                         target = ".";
00559                 } else {
00560                         /* target is the last item mentioned */
00561                         argc--;
00562                         target = argv[argc];
00563                 }
00564 
00565                 ret = target_lookup(&arg.mp, target);
00566                 if(!arg.mp.targetDir && !arg.mp.unixTarget) {
00567                         fprintf(stderr,"Bad target %s\n", target);
00568                         exit(1);
00569                 }
00570 
00571                 /* callback functions */
00572                 if(arg.mp.unixTarget) {
00573                         arg.mp.callback = dos_to_unix;
00574                         arg.mp.dirCallback = directory_dos_to_unix;
00575                         arg.mp.unixcallback = unix_to_unix;
00576                 } else {
00577                         arg.mp.dirCallback = dos_copydir;
00578                         arg.mp.callback = dos_to_dos;
00579                         arg.mp.unixcallback = unix_to_dos;
00580                 }
00581         }
00582 
00583         exit(main_loop(&arg.mp, argv + optind, argc - optind));
00584 }

Generated on Fri Apr 14 22:56:55 2006 for minix by  doxygen 1.4.6