00001
00002
00003
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
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
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
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
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
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
00239
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
00268 if(arg->verbose)
00269 fprintf(stderr,"Copying %s\n", longname);
00270 if(got_signal)
00271 return -1;
00272
00273
00274 if (!getfreeMinBytes(arg->mp.targetDir, filesize))
00275 return -1;
00276
00277
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++;
00300
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
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:
00352 return NULL;
00353 }
00354 }
00355
00356 static int dos_copydir(direntry_t *entry, MainParam_t *mp)
00357
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
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
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
00472
00473 init_clash_handling(& arg.ch);
00474
00475
00476 todir = 0;
00477 arg.recursive = 0;
00478 #ifdef OS_Minix
00479 arg.preserveTime = 1;
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
00542 if(!mtype && !strcmp(argv[argc-1], "-")) {
00543 arg.type = mtype = 1;
00544 argc--;
00545 }
00546
00547 if(mtype){
00548
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
00558 target = ".";
00559 } else {
00560
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
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 }