source: trunk/minix/commands/i386/mtools-3.9.7/mcopy.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 11.8 KB
Line 
1/*
2 * mcopy.c
3 * Copy an MSDOS files to and from Unix
4 *
5 */
6
7
8#define LOWERCASE
9
10#include "sysincludes.h"
11#include "msdos.h"
12#include "mtools.h"
13#include "vfat.h"
14#include "mainloop.h"
15#include "plain_io.h"
16#include "nameclash.h"
17#include "file.h"
18#include "fs.h"
19
20
21/*
22 * Preserve the file modification times after the fclose()
23 */
24
25static void set_mtime(const char *target, time_t mtime)
26{
27 if (target && strcmp(target, "-") && mtime != 0L) {
28#ifdef HAVE_UTIMES
29 struct timeval tv[2];
30 tv[0].tv_sec = mtime;
31 tv[0].tv_usec = 0;
32 tv[1].tv_sec = mtime;
33 tv[1].tv_usec = 0;
34 utimes((char *)target, tv);
35#else
36#ifdef HAVE_UTIME
37 struct utimbuf utbuf;
38
39 utbuf.actime = mtime;
40 utbuf.modtime = mtime;
41 utime(target, &utbuf);
42#endif
43#endif
44 }
45 return;
46}
47
48typedef struct Arg_t {
49 int recursive;
50 int preserveAttributes;
51 int preserveTime;
52 unsigned char attr;
53 char *path;
54 int textmode;
55 int needfilter;
56 int nowarn;
57 int verbose;
58 int type;
59 MainParam_t mp;
60 ClashHandling_t ch;
61} Arg_t;
62
63/* Write the Unix file */
64static int unix_write(direntry_t *entry, MainParam_t *mp, int needfilter)
65{
66 Arg_t *arg=(Arg_t *) mp->arg;
67 time_t mtime;
68 Stream_t *File=mp->File;
69 Stream_t *Target, *Source;
70 struct stat stbuf;
71 int ret;
72 char errmsg[80];
73 char *unixFile;
74
75 File->Class->get_data(File, &mtime, 0, 0, 0);
76
77 if (!arg->preserveTime)
78 mtime = 0L;
79
80 if(arg->type)
81 unixFile = "-";
82 else
83 unixFile = mpBuildUnixFilename(mp);
84 if(!unixFile) {
85 printOom();
86 return ERROR_ONE;
87 }
88
89 /* if we are creating a file, check whether it already exists */
90 if(!arg->type) {
91 if (!arg->nowarn && &arg->type && !access(unixFile, 0)){
92 if( ask_confirmation("File \"%s\" exists, overwrite (y/n) ? ",
93 unixFile,0)) {
94 free(unixFile);
95 return ERROR_ONE;
96 }
97
98 /* sanity checking */
99 if (!stat(unixFile, &stbuf) && !S_ISREG(stbuf.st_mode)) {
100 fprintf(stderr,"\"%s\" is not a regular file\n",
101 unixFile);
102
103 free(unixFile);
104 return ERROR_ONE;
105 }
106 }
107 }
108
109 if(!arg->type && arg->verbose) {
110 fprintf(stderr,"Copying ");
111 mpPrintFilename(stderr,mp);
112 fprintf(stderr,"\n");
113 }
114
115 if(got_signal) {
116 free(unixFile);
117 return ERROR_ONE;
118 }
119
120 if ((Target = SimpleFileOpen(0, 0, unixFile,
121 O_WRONLY | O_CREAT | O_TRUNC,
122 errmsg, 0, 0, 0))) {
123 ret = 0;
124 if(needfilter && arg->textmode){
125 Source = open_filter(COPY(File));
126 if (!Source)
127 ret = -1;
128 } else
129 Source = COPY(File);
130
131 if (ret == 0 )
132 ret = copyfile(Source, Target);
133 FREE(&Source);
134 FREE(&Target);
135 if(ret <= -1){
136 if(!arg->type) {
137 unlink(unixFile);
138 free(unixFile);
139 }
140 return ERROR_ONE;
141 }
142 if(!arg->type) {
143 set_mtime(unixFile, mtime);
144 free(unixFile);
145 }
146 return GOT_ONE;
147 } else {
148 fprintf(stderr,"%s\n", errmsg);
149 if(!arg->type)
150 free(unixFile);
151 return ERROR_ONE;
152 }
153}
154
155static int makeUnixDir(char *filename)
156{
157 if(!mkdir(filename, 0777))
158 return 0;
159 if(errno == EEXIST) {
160 struct stat buf;
161 if(stat(filename, &buf) < 0)
162 return -1;
163 if(S_ISDIR(buf.st_mode))
164 return 0;
165 errno = ENOTDIR;
166 }
167 return -1;
168}
169
170/* Copy a directory to Unix */
171static int unix_copydir(direntry_t *entry, MainParam_t *mp)
172{
173 Arg_t *arg=(Arg_t *) mp->arg;
174 time_t mtime;
175 Stream_t *File=mp->File;
176 int ret;
177 char *unixFile;
178
179 if (!arg->recursive && mp->basenameHasWildcard)
180 return 0;
181
182 File->Class->get_data(File, &mtime, 0, 0, 0);
183 if (!arg->preserveTime)
184 mtime = 0L;
185 if(!arg->type && arg->verbose) {
186 fprintf(stderr,"Copying ");
187 fprintPwd(stderr, entry,0);
188 fprintf(stderr, "\n");
189 }
190 if(got_signal)
191 return ERROR_ONE;
192 unixFile = mpBuildUnixFilename(mp);
193 if(!unixFile) {
194 printOom();
195 return ERROR_ONE;
196 }
197 if(arg->type || !*mpPickTargetName(mp) || !makeUnixDir(unixFile)) {
198 Arg_t newArg;
199
200 newArg = *arg;
201 newArg.mp.arg = (void *) &newArg;
202 newArg.mp.unixTarget = unixFile;
203 newArg.mp.targetName = 0;
204 newArg.mp.basenameHasWildcard = 1;
205
206 ret = mp->loop(File, &newArg.mp, "*");
207 set_mtime(unixFile, mtime);
208 free(unixFile);
209 return ret | GOT_ONE;
210 } else {
211 perror("mkdir");
212 fprintf(stderr,
213 "Failure to make directory %s\n",
214 unixFile);
215 free(unixFile);
216 return ERROR_ONE;
217 }
218}
219
220static int dos_to_unix(direntry_t *entry, MainParam_t *mp)
221{
222 return unix_write(entry, mp, 1);
223}
224
225
226static int unix_to_unix(MainParam_t *mp)
227{
228 return unix_write(0, mp, 0);
229}
230
231
232static int directory_dos_to_unix(direntry_t *entry, MainParam_t *mp)
233{
234 return unix_copydir(entry, mp);
235}
236
237/*
238 * Open the named file for read, create the cluster chain, return the
239 * directory structure or NULL on error.
240 */
241static int writeit(char *dosname,
242 char *longname,
243 void *arg0,
244 direntry_t *entry)
245{
246 Stream_t *Target;
247 time_t now;
248 int type, fat, ret;
249 time_t date;
250 mt_size_t filesize, newsize;
251 Arg_t *arg = (Arg_t *) arg0;
252
253
254
255 if (arg->mp.File->Class->get_data(arg->mp.File,
256 & date, &filesize, &type, 0) < 0 ){
257 fprintf(stderr, "Can't stat source file\n");
258 return -1;
259 }
260
261 if (type){
262 if (arg->verbose)
263 fprintf(stderr, "\"%s\" is a directory\n", longname);
264 return -1;
265 }
266
267 /*if (!arg->single || arg->recursive)*/
268 if(arg->verbose)
269 fprintf(stderr,"Copying %s\n", longname);
270 if(got_signal)
271 return -1;
272
273 /* will it fit? */
274 if (!getfreeMinBytes(arg->mp.targetDir, filesize))
275 return -1;
276
277 /* preserve mod time? */
278 if (arg->preserveTime)
279 now = date;
280 else
281 getTimeNow(&now);
282
283 mk_entry(dosname, arg->attr, 1, 0, now, &entry->dir);
284
285 Target = OpenFileByDirentry(entry);
286 if(!Target){
287 fprintf(stderr,"Could not open Target\n");
288 exit(1);
289 }
290 if (arg->needfilter & arg->textmode)
291 Target = open_filter(Target);
292
293
294
295 ret = copyfile(arg->mp.File, Target);
296 GET_DATA(Target, 0, &newsize, 0, &fat);
297 FREE(&Target);
298 if (arg->needfilter & arg->textmode)
299 newsize++; /* ugly hack: we gathered the size before the Ctrl-Z
300 * was written. Increment it manually */
301 if(ret < 0 ){
302 fat_free(arg->mp.targetDir, fat);
303 return -1;
304 } else {
305 mk_entry(dosname, arg->attr, fat, truncBytes32(newsize),
306 now, &entry->dir);
307 return 0;
308 }
309}
310
311
312
313static int dos_write(direntry_t *entry, MainParam_t *mp, int needfilter)
314/* write a messy dos file to another messy dos file */
315{
316 int result;
317 Arg_t * arg = (Arg_t *) (mp->arg);
318 const char *targetName = mpPickTargetName(mp);
319
320 if(entry && arg->preserveAttributes)
321 arg->attr = entry->dir.attr;
322 else
323 arg->attr = ATTR_ARCHIVE;
324
325 arg->needfilter = needfilter;
326 if (entry && mp->targetDir == entry->Dir){
327 arg->ch.ignore_entry = -1;
328 arg->ch.source = entry->entry;
329 } else {
330 arg->ch.ignore_entry = -1;
331 arg->ch.source = -2;
332 }
333 result = mwrite_one(mp->targetDir, targetName, 0,
334 writeit, (void *)arg, &arg->ch);
335 if(result == 1)
336 return GOT_ONE;
337 else
338 return ERROR_ONE;
339}
340
341static Stream_t *subDir(Stream_t *parent, const char *filename)
342{
343 direntry_t entry;
344 initializeDirentry(&entry, parent);
345
346 switch(vfat_lookup(&entry, filename, -1, ACCEPT_DIR, 0, 0)) {
347 case 0:
348 return OpenFileByDirentry(&entry);
349 case -1:
350 return NULL;
351 default: /* IO Error */
352 return NULL;
353 }
354}
355
356static int dos_copydir(direntry_t *entry, MainParam_t *mp)
357/* copyes a directory to Dos */
358{
359 Arg_t * arg = (Arg_t *) (mp->arg);
360 Arg_t newArg;
361 time_t now;
362 time_t date;
363 int ret;
364 const char *targetName = mpPickTargetName(mp);
365
366 if (!arg->recursive && mp->basenameHasWildcard)
367 return 0;
368
369 if(entry && isSubdirOf(mp->targetDir, mp->File)) {
370 fprintf(stderr, "Cannot recursively copy directory ");
371 fprintPwd(stderr, entry,0);
372 fprintf(stderr, " into one of its own subdirectories ");
373 fprintPwd(stderr, getDirentry(mp->targetDir),0);
374 fprintf(stderr, "\n");
375 return ERROR_ONE;
376 }
377
378 if (arg->mp.File->Class->get_data(arg->mp.File,
379 & date, 0, 0, 0) < 0 ){
380 fprintf(stderr, "Can't stat source file\n");
381 return ERROR_ONE;
382 }
383
384 if(!arg->type && arg->verbose)
385 fprintf(stderr,"Copying %s\n", mpGetBasename(mp));
386
387 if(entry && arg->preserveAttributes)
388 arg->attr = entry->dir.attr;
389 else
390 arg->attr = 0;
391
392 if (entry && (mp->targetDir == entry->Dir)){
393 arg->ch.ignore_entry = -1;
394 arg->ch.source = entry->entry;
395 } else {
396 arg->ch.ignore_entry = -1;
397 arg->ch.source = -2;
398 }
399
400 /* preserve mod time? */
401 if (arg->preserveTime)
402 now = date;
403 else
404 getTimeNow(&now);
405
406 newArg = *arg;
407 newArg.mp.arg = &newArg;
408 newArg.mp.targetName = 0;
409 newArg.mp.basenameHasWildcard = 1;
410 if(*targetName) {
411 /* maybe the directory already exist. Use it */
412 newArg.mp.targetDir = subDir(mp->targetDir, targetName);
413 if(!newArg.mp.targetDir)
414 newArg.mp.targetDir = createDir(mp->targetDir,
415 targetName,
416 &arg->ch, arg->attr,
417 now);
418 } else
419 newArg.mp.targetDir = mp->targetDir;
420
421 if(!newArg.mp.targetDir)
422 return ERROR_ONE;
423
424 ret = mp->loop(mp->File, &newArg.mp, "*");
425 if(*targetName)
426 FREE(&newArg.mp.targetDir);
427 return ret | GOT_ONE;
428}
429
430
431static int dos_to_dos(direntry_t *entry, MainParam_t *mp)
432{
433 return dos_write(entry, mp, 0);
434}
435
436static int unix_to_dos(MainParam_t *mp)
437{
438 return dos_write(0, mp, 1);
439}
440
441
442static void usage(void)
443{
444 fprintf(stderr,
445 "Mtools version %s, dated %s\n", mversion, mdate);
446 fprintf(stderr,
447 "Usage: %s [-/spabtnmvQB] [-D clash_option] sourcefile targetfile\n", progname);
448 fprintf(stderr,
449 " %s [-/spabtnmvQB] [-D clash_option] sourcefile [sourcefiles...] targetdirectory\n",
450 progname);
451 fprintf(stderr,
452 "\t-/ -s Recursive\n"
453 "\t-p Preserve attributes\n"
454 "\t-a -t Textmode\n"
455 "\t-n Overwrite UNIX files without confirmation\n"
456 "\t-m Preserve file time (default under Minix)\n"
457 "\t-v Verbose\n"
458 "\t-Q Quit on the first error\n"
459 "\t-b -B Batch mode (faster, but less crash resistent)\n"
460 "\t-o Overwrite DOS files without confirmation\n");
461 exit(1);
462}
463
464void mcopy(int argc, char **argv, int mtype)
465{
466 Arg_t arg;
467 int c, ret, fastquit;
468 int todir;
469
470
471 /* get command line options */
472
473 init_clash_handling(& arg.ch);
474
475 /* get command line options */
476 todir = 0;
477 arg.recursive = 0;
478#ifdef OS_Minix
479 arg.preserveTime = 1; /* Copy file time as DOS does. */
480#else
481 arg.preserveTime = 0;
482#endif
483 arg.preserveAttributes = 0;
484 arg.nowarn = 0;
485 arg.textmode = 0;
486 arg.verbose = 0;
487 arg.type = mtype;
488 fastquit = 0;
489 while ((c = getopt(argc, argv, "abB/sptnmvQD:o")) != EOF) {
490 switch (c) {
491 case 's':
492 case '/':
493 arg.recursive = 1;
494 break;
495 case 'p':
496 arg.preserveAttributes = 1;
497 break;
498 case 'a':
499 case 't':
500 arg.textmode = 1;
501 break;
502 case 'n':
503 arg.nowarn = 1;
504 break;
505 case 'm':
506 arg.preserveTime = 1;
507 break;
508 case 'v':
509 arg.verbose = 1;
510 break;
511 case 'Q':
512 fastquit = 1;
513 break;
514 case 'B':
515 case 'b':
516 batchmode = 1;
517 break;
518 case 'o':
519 handle_clash_options(&arg.ch, c);
520 break;
521 case 'D':
522 if(handle_clash_options(&arg.ch, *optarg))
523 usage();
524 break;
525 case '?':
526 usage();
527 default:
528 break;
529 }
530 }
531
532 if (argc - optind < 1)
533 usage();
534
535 init_mp(&arg.mp);
536 arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN | NO_DOTS;
537 arg.mp.fast_quit = fastquit;
538 arg.mp.arg = (void *) &arg;
539 arg.mp.openflags = O_RDONLY;
540
541 /* last parameter is "-", use mtype mode */
542 if(!mtype && !strcmp(argv[argc-1], "-")) {
543 arg.type = mtype = 1;
544 argc--;
545 }
546
547 if(mtype){
548 /* Mtype = copying to stdout */
549 arg.mp.targetName = strdup("-");
550 arg.mp.unixTarget = strdup("");
551 arg.mp.callback = dos_to_unix;
552 arg.mp.dirCallback = unix_copydir;
553 arg.mp.unixcallback = unix_to_unix;
554 } else {
555 char *target;
556 if (argc - optind == 1) {
557 /* copying to the current directory */
558 target = ".";
559 } else {
560 /* target is the last item mentioned */
561 argc--;
562 target = argv[argc];
563 }
564
565 ret = target_lookup(&arg.mp, target);
566 if(!arg.mp.targetDir && !arg.mp.unixTarget) {
567 fprintf(stderr,"Bad target %s\n", target);
568 exit(1);
569 }
570
571 /* callback functions */
572 if(arg.mp.unixTarget) {
573 arg.mp.callback = dos_to_unix;
574 arg.mp.dirCallback = directory_dos_to_unix;
575 arg.mp.unixcallback = unix_to_unix;
576 } else {
577 arg.mp.dirCallback = dos_copydir;
578 arg.mp.callback = dos_to_dos;
579 arg.mp.unixcallback = unix_to_dos;
580 }
581 }
582
583 exit(main_loop(&arg.mp, argv + optind, argc - optind));
584}
Note: See TracBrowser for help on using the repository browser.