/* * Read (copy) an MSDOS file to Unix * * Emmet P. Gray US Army, HQ III Corps & Fort Hood * ...!uunet!uiucuxc!fthood!egray Attn: AFZF-DE-ENV * fthood!egray@uxc.cso.uiuc.edu Directorate of Engineering & Housing * Environmental Management Office * Fort Hood, TX 76544-5057 */ #define LOWERCASE #include #include #include #include #ifdef BSD #include #else /* BSD */ #include #endif /* BSD */ #include "msdos.h" #include "patchlevel.h" int fd = -1; /* the file descriptor for the device */ int dir_start; /* starting sector for directory */ int dir_len; /* length of directory (in sectors) */ int dir_entries; /* number of directory entries */ int clus_size; /* cluster size (in sectors) */ char *mcwd; /* the Current Working Directory */ int fat_error; /* FAT error detected? */ static void set_mtime(); static FILE *open_file(); static long conv_stamp(); main(argc, argv) int argc; char *argv[]; { FILE *fp; extern int optind; extern char *optarg; int i, ismatch, entry, single, c, oops, preserve, nowarn, textmode; unsigned int fat; long size, mtime; char *filename, *newfile, *get_name(), *unix_name(), *pathname; char *get_path(), *target, tmp[MAX_PATH], *strcat(), *strcpy(), drive; char get_drive(), last_drive, *fix_mcwd(), *s; void exit(); struct directory *dir, *dir_read(); struct stat stbuf; /* get command line options */ oops = 0; preserve = 0; nowarn = 0; textmode = 0; while ((c = getopt(argc, argv, "tnmv")) != EOF) { switch (c) { case 't': textmode = 1; break; case 'n': nowarn = 1; break; case 'm': preserve = 1; break; case 'v': /* dummy option for mcopy */ break; default: oops = 1; break; } } if (oops || (argc - optind) < 2) { fprintf(stderr, "Mtools version %s, dated %s\n", VERSION, DATE); fprintf(stderr, "Usage: %s [-tnm] msdosfile unixfile\n", argv[0]); fprintf(stderr, " %s [-tnm] msdosfile [msdosfiles...] unixdirectory\n", argv[0]); exit(1); } last_drive = 'x'; mcwd = fix_mcwd(); /* only 1 file to copy... */ single = 1; target = argv[argc - 1]; /* ...unless last arg is a directory */ if (!stat(target, &stbuf)) { if ((stbuf.st_mode & S_IFMT) == S_IFDIR) single = 0; } /* too many arguments */ if (single && (argc - optind) != 2) { fprintf(stderr, "%s: Too many arguments or destination directory omitted\n", argv[0]); exit(1); } for (i = optind; i < argc - 1; i++) { drive = get_drive(argv[i]); if (drive != last_drive) { if (init(drive, 0)) { fprintf(stderr, "%s: Cannot initialize '%c:'\n", argv[0], drive); continue; } last_drive = drive; } filename = get_name(argv[i]); pathname = get_path(argv[i]); if (subdir(drive, pathname)) continue; ismatch = 0; for (entry = 0; entry < dir_entries; entry++) { dir = dir_read(entry); /* if empty */ if (dir->name[0] == 0x0) break; /* if erased */ if (dir->name[0] == 0xe5) continue; /* if dir or volume label */ if ((dir->attr & 0x10) || (dir->attr & 0x08)) continue; newfile = unix_name(dir->name, dir->ext); /* if single file */ if (single) { if (!strcmp(newfile, filename)) { fat = dir->start[1] * 0x100 + dir->start[0]; size = dir->size[3] * 0x1000000L + dir->size[2] * 0x10000L + dir->size[1] * 0x100 + dir->size[0]; if (preserve) mtime = conv_stamp(dir->time, dir->date); else mtime = 0L; if ((fp = open_file(target, nowarn))) { if (file_read(fp, fat, textmode, 0, size)) { fclose(fp); break; } fclose(fp); set_mtime(target, mtime); } ismatch = 1; break; } } /* if multiple files */ else { if (match(newfile, filename)) { fat = dir->start[1] * 0x100 + dir->start[0]; size = dir->size[3] * 0x1000000L + dir->size[2] * 0x10000L + dir->size[1] * 0x100 + dir->size[0]; if (preserve) mtime = conv_stamp(dir->time, dir->date); else mtime = 0L; printf("Copying %s\n", newfile); #ifdef LOWERCASE s = newfile; while (*s) { if (isupper(*s)) *s = tolower(*s); s++; } #endif /* LOWERCASE */ strcpy(tmp, target); strcat(tmp, "/"); strcat(tmp, newfile); if ((fp = open_file(tmp, nowarn))) { if (file_read(fp, fat, textmode, 0, size)) { fclose(fp); break; } fclose(fp); set_mtime(tmp, mtime); } ismatch = 1; } } } if (fat_error) break; if (!ismatch) fprintf(stderr, "%s: File \"%s\" not found\n", argv[0], filename); } close(fd); exit(0); } /* * Open the named Unix file for write. */ static FILE * open_file(target, nowarn) char *target; int nowarn; { static FILE *fp; char ans[10]; struct stat stbuf; if (!nowarn) { if (!access(target, 0)) { /* CONSTCOND */ while (1) { printf("File \"%s\" exists, overwrite (y/n) ? ", target); gets(ans); if (ans[0] == 'n' || ans[0] == 'N') return(NULL); if (ans[0] == 'y' || ans[0] == 'Y') break; } /* sanity checking */ if (!stat(target, &stbuf)) { if ((stbuf.st_mode & S_IFREG) != S_IFREG) { fprintf(stderr, "\"%s\" is not a regular file\n", target); return(NULL); } } } } if (!(fp = fopen(target, "w"))) { fprintf(stderr, "Can't open \"%s\" for write\n", target); return(NULL); } return(fp); } /* * Convert an MSDOS time & date stamp to the Unix time() format */ static long conv_stamp(time_field, date_field) unsigned char *time_field, *date_field; { #ifdef BSD struct timeval tv; struct timezone tz; #else /* BSD */ extern long timezone; void tzset(); #endif /* BSD */ struct tm *tmbuf, *localtime(); int year, mon, mday, hour, min, sec, old_leaps; long answer, sec_year, sec_mon, sec_mday, sec_hour, sec_min, sec_leap; long tzone, dst; static int month[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; /* dissect the parts */ year = (date_field[1] >> 1) + 1980; mon = (((date_field[1] & 0x1) << 3) + (date_field[0] >> 5)); mday = date_field[0] & 0x1f; hour = time_field[1] >> 3; min = (((time_field[1] & 0x7) << 3) + (time_field[0] >> 5)); sec = (time_field[0] & 0x1f) * 2; /* how many previous leap years */ old_leaps = (year - 1972) / 4L; sec_leap = old_leaps * 24L * 60L * 60L; /* back off 1 day if before 29 Feb */ if (!(year % 4) && mon < 3) sec_leap -= 24L * 60L * 60L; sec_year = (year - 1970) * 365L * 24L * 60L * 60L; sec_mon = month[mon - 1] * 24L * 60L * 60L; sec_mday = mday * 24L * 60L * 60L; sec_hour = hour * 60L * 60L; sec_min = min * 60L; /* correct for Time Zone */ #ifdef BSD gettimeofday(&tv, &tz); tzone = tz.tz_minuteswest * 60L; #else /* BSD */ tzset(); tzone = timezone; #endif /* BSD */ answer = sec_leap + sec_year + sec_mon + sec_mday + sec_hour + sec_min + sec + tzone; /* correct for Daylight Saving Time */ tmbuf = localtime(&answer); dst = (tmbuf->tm_isdst) ? (-60L * 60L) : 0L; answer += dst; return(answer); } /* * Preserve the file modification times after the fclose() */ static void set_mtime(target, mtime) char *target; long mtime; { #ifdef BSD struct timeval tv[2]; if (mtime != 0L) { tv[0].tv_sec = mtime; tv[0].tv_usec = 0; tv[1].tv_sec = mtime; tv[1].tv_usec = 0; utimes(target, tv); } #else /* BSD */ struct { time_t actime; time_t modtime; } utbuf; if (mtime != 0L) { utbuf.actime = mtime; utbuf.modtime = mtime; utime(target, &utbuf); } #endif /* BSD */ return; } /* * stubs for read-only programs */ void disk_flush() { extern int disk_dirty; disk_dirty = 0; return; } void dir_flush() { extern int dir_dirty; dir_dirty = 0; return; }