1: /* 2: * Read (copy) an MSDOS file to Unix 3: * 4: * Emmet P. Gray US Army, HQ III Corps & Fort Hood 5: * ...!uunet!uiucuxc!fthood!egray Attn: AFZF-DE-ENV 6: * fthood!egray@uxc.cso.uiuc.edu Directorate of Engineering & Housing 7: * Environmental Management Office 8: * Fort Hood, TX 76544-5057 9: */ 10: 11: #define LOWERCASE 12: 13: #include <stdio.h> 14: #include <ctype.h> 15: #include <sys/types.h> 16: #include <sys/stat.h> 17: #ifdef BSD 18: #include <sys/time.h> 19: #else /* BSD */ 20: #include <time.h> 21: #endif /* BSD */ 22: #include "msdos.h" 23: #include "patchlevel.h" 24: 25: int fd = -1; /* the file descriptor for the device */ 26: int dir_start; /* starting sector for directory */ 27: int dir_len; /* length of directory (in sectors) */ 28: int dir_entries; /* number of directory entries */ 29: int clus_size; /* cluster size (in sectors) */ 30: char *mcwd; /* the Current Working Directory */ 31: int fat_error; /* FAT error detected? */ 32: 33: static void set_mtime(); 34: static FILE *open_file(); 35: static long conv_stamp(); 36: 37: main(argc, argv) 38: int argc; 39: char *argv[]; 40: { 41: FILE *fp; 42: extern int optind; 43: extern char *optarg; 44: int i, ismatch, entry, single, c, oops, preserve, nowarn, textmode; 45: unsigned int fat; 46: long size, mtime; 47: char *filename, *newfile, *get_name(), *unix_name(), *pathname; 48: char *get_path(), *target, tmp[MAX_PATH], *strcat(), *strcpy(), drive; 49: char get_drive(), last_drive, *fix_mcwd(), *s; 50: void exit(); 51: struct directory *dir, *dir_read(); 52: struct stat stbuf; 53: 54: /* get command line options */ 55: oops = 0; 56: preserve = 0; 57: nowarn = 0; 58: textmode = 0; 59: while ((c = getopt(argc, argv, "tnmv")) != EOF) { 60: switch (c) { 61: case 't': 62: textmode = 1; 63: break; 64: case 'n': 65: nowarn = 1; 66: break; 67: case 'm': 68: preserve = 1; 69: break; 70: case 'v': /* dummy option for mcopy */ 71: break; 72: default: 73: oops = 1; 74: break; 75: } 76: } 77: 78: if (oops || (argc - optind) < 2) { 79: fprintf(stderr, "Mtools version %s, dated %s\n", VERSION, DATE); 80: fprintf(stderr, "Usage: %s [-tnm] msdosfile unixfile\n", argv[0]); 81: fprintf(stderr, " %s [-tnm] msdosfile [msdosfiles...] unixdirectory\n", argv[0]); 82: exit(1); 83: } 84: last_drive = 'x'; 85: mcwd = fix_mcwd(); 86: /* only 1 file to copy... */ 87: single = 1; 88: target = argv[argc - 1]; 89: /* ...unless last arg is a directory */ 90: if (!stat(target, &stbuf)) { 91: if ((stbuf.st_mode & S_IFMT) == S_IFDIR) 92: single = 0; 93: } 94: /* too many arguments */ 95: if (single && (argc - optind) != 2) { 96: fprintf(stderr, "%s: Too many arguments or destination directory omitted\n", argv[0]); 97: exit(1); 98: } 99: 100: for (i = optind; i < argc - 1; i++) { 101: drive = get_drive(argv[i]); 102: if (drive != last_drive) { 103: if (init(drive, 0)) { 104: fprintf(stderr, "%s: Cannot initialize '%c:'\n", argv[0], drive); 105: continue; 106: } 107: last_drive = drive; 108: } 109: filename = get_name(argv[i]); 110: pathname = get_path(argv[i]); 111: if (subdir(drive, pathname)) 112: continue; 113: 114: ismatch = 0; 115: for (entry = 0; entry < dir_entries; entry++) { 116: dir = dir_read(entry); 117: /* if empty */ 118: if (dir->name[0] == 0x0) 119: break; 120: /* if erased */ 121: if (dir->name[0] == 0xe5) 122: continue; 123: /* if dir or volume label */ 124: if ((dir->attr & 0x10) || (dir->attr & 0x08)) 125: continue; 126: 127: newfile = unix_name(dir->name, dir->ext); 128: 129: /* if single file */ 130: if (single) { 131: if (!strcmp(newfile, filename)) { 132: fat = dir->start[1] * 0x100 + dir->start[0]; 133: size = dir->size[3] * 0x1000000L + dir->size[2] * 0x10000L + dir->size[1] * 0x100 + dir->size[0]; 134: if (preserve) 135: mtime = conv_stamp(dir->time, dir->date); 136: else 137: mtime = 0L; 138: if ((fp = open_file(target, nowarn))) { 139: if (file_read(fp, fat, textmode, 0, size)) { 140: fclose(fp); 141: break; 142: } 143: fclose(fp); 144: set_mtime(target, mtime); 145: } 146: ismatch = 1; 147: break; 148: } 149: } 150: /* if multiple files */ 151: else { 152: if (match(newfile, filename)) { 153: fat = dir->start[1] * 0x100 + dir->start[0]; 154: size = dir->size[3] * 0x1000000L + dir->size[2] * 0x10000L + dir->size[1] * 0x100 + dir->size[0]; 155: if (preserve) 156: mtime = conv_stamp(dir->time, dir->date); 157: else 158: mtime = 0L; 159: printf("Copying %s\n", newfile); 160: #ifdef LOWERCASE 161: s = newfile; 162: while (*s) { 163: if (isupper(*s)) 164: *s = tolower(*s); 165: s++; 166: } 167: #endif /* LOWERCASE */ 168: strcpy(tmp, target); 169: strcat(tmp, "/"); 170: strcat(tmp, newfile); 171: if ((fp = open_file(tmp, nowarn))) { 172: if (file_read(fp, fat, textmode, 0, size)) { 173: fclose(fp); 174: break; 175: } 176: fclose(fp); 177: set_mtime(tmp, mtime); 178: } 179: ismatch = 1; 180: } 181: } 182: } 183: if (fat_error) 184: break; 185: 186: if (!ismatch) 187: fprintf(stderr, "%s: File \"%s\" not found\n", argv[0], filename); 188: } 189: close(fd); 190: exit(0); 191: } 192: 193: /* 194: * Open the named Unix file for write. 195: */ 196: 197: static FILE * 198: open_file(target, nowarn) 199: char *target; 200: int nowarn; 201: { 202: static FILE *fp; 203: char ans[10]; 204: struct stat stbuf; 205: 206: if (!nowarn) { 207: if (!access(target, 0)) { 208: /* CONSTCOND */ 209: while (1) { 210: printf("File \"%s\" exists, overwrite (y/n) ? ", target); 211: gets(ans); 212: if (ans[0] == 'n' || ans[0] == 'N') 213: return(NULL); 214: if (ans[0] == 'y' || ans[0] == 'Y') 215: break; 216: } 217: /* sanity checking */ 218: if (!stat(target, &stbuf)) { 219: if ((stbuf.st_mode & S_IFREG) != S_IFREG) { 220: fprintf(stderr, "\"%s\" is not a regular file\n", target); 221: return(NULL); 222: } 223: } 224: } 225: } 226: 227: if (!(fp = fopen(target, "w"))) { 228: fprintf(stderr, "Can't open \"%s\" for write\n", target); 229: return(NULL); 230: } 231: return(fp); 232: } 233: 234: /* 235: * Convert an MSDOS time & date stamp to the Unix time() format 236: */ 237: 238: static long 239: conv_stamp(time_field, date_field) 240: unsigned char *time_field, *date_field; 241: { 242: #ifdef BSD 243: struct timeval tv; 244: struct timezone tz; 245: #else /* BSD */ 246: extern long timezone; 247: void tzset(); 248: #endif /* BSD */ 249: struct tm *tmbuf, *localtime(); 250: int year, mon, mday, hour, min, sec, old_leaps; 251: long answer, sec_year, sec_mon, sec_mday, sec_hour, sec_min, sec_leap; 252: long tzone, dst; 253: static int month[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 254: 334}; 255: /* dissect the parts */ 256: year = (date_field[1] >> 1) + 1980; 257: mon = (((date_field[1] & 0x1) << 3) + (date_field[0] >> 5)); 258: mday = date_field[0] & 0x1f; 259: hour = time_field[1] >> 3; 260: min = (((time_field[1] & 0x7) << 3) + (time_field[0] >> 5)); 261: sec = (time_field[0] & 0x1f) * 2; 262: /* how many previous leap years */ 263: old_leaps = (year - 1972) / 4L; 264: sec_leap = old_leaps * 24L * 60L * 60L; 265: /* back off 1 day if before 29 Feb */ 266: if (!(year % 4) && mon < 3) 267: sec_leap -= 24L * 60L * 60L; 268: sec_year = (year - 1970) * 365L * 24L * 60L * 60L; 269: sec_mon = month[mon - 1] * 24L * 60L * 60L; 270: sec_mday = mday * 24L * 60L * 60L; 271: sec_hour = hour * 60L * 60L; 272: sec_min = min * 60L; 273: /* correct for Time Zone */ 274: #ifdef BSD 275: gettimeofday(&tv, &tz); 276: tzone = tz.tz_minuteswest * 60L; 277: #else /* BSD */ 278: tzset(); 279: tzone = timezone; 280: #endif /* BSD */ 281: 282: answer = sec_leap + sec_year + sec_mon + sec_mday + sec_hour + sec_min + sec + tzone; 283: /* correct for Daylight Saving Time */ 284: tmbuf = localtime(&answer); 285: dst = (tmbuf->tm_isdst) ? (-60L * 60L) : 0L; 286: answer += dst; 287: 288: return(answer); 289: } 290: 291: /* 292: * Preserve the file modification times after the fclose() 293: */ 294: 295: static void 296: set_mtime(target, mtime) 297: char *target; 298: long mtime; 299: { 300: #ifdef BSD 301: struct timeval tv[2]; 302: 303: if (mtime != 0L) { 304: tv[0].tv_sec = mtime; 305: tv[0].tv_usec = 0; 306: tv[1].tv_sec = mtime; 307: tv[1].tv_usec = 0; 308: utimes(target, tv); 309: } 310: #else /* BSD */ 311: struct { 312: time_t actime; 313: time_t modtime; 314: } utbuf; 315: 316: if (mtime != 0L) { 317: utbuf.actime = mtime; 318: utbuf.modtime = mtime; 319: utime(target, &utbuf); 320: } 321: #endif /* BSD */ 322: return; 323: } 324: 325: /* 326: * stubs for read-only programs 327: */ 328: 329: void 330: disk_flush() 331: { 332: extern int disk_dirty; 333: 334: disk_dirty = 0; 335: return; 336: } 337: 338: void 339: dir_flush() 340: { 341: extern int dir_dirty; 342: 343: dir_dirty = 0; 344: return; 345: }