1: /* 2: * Write (copy) a Unix file to MSDOS 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: #include <stdio.h> 12: #include <signal.h> 13: #include <sys/types.h> 14: #include <sys/stat.h> 15: #include "msdos.h" 16: #include "patchlevel.h" 17: 18: int fd = -1; /* the file descriptor for the device */ 19: int dir_start; /* starting sector for directory */ 20: int dir_len; /* length of directory (in sectors) */ 21: int dir_entries; /* number of directory entries */ 22: int clus_size; /* cluster size (in sectors) */ 23: char *mcwd; /* the Current Working Directory */ 24: int fat_error; /* FAT error detected? */ 25: 26: int full = 0; 27: int textmode = 0; 28: int nowarn = 0; 29: static int got_signal(); 30: static struct directory *writeit(); 31: static long free_space(); 32: 33: main(argc, argv) 34: int argc; 35: char *argv[]; 36: { 37: extern int optind; 38: extern char *optarg; 39: int i, entry, ismatch, nogo, slot, single; 40: int c, oops, verbose, first, mod_time; 41: unsigned int dot, start; 42: char *filename, *newfile, *get_name(), get_drive(); 43: char *unix_name(), ans[10], *pathname, *get_path(), *fix_mcwd(); 44: char tmp[MAX_PATH], target[13], *strcat(), *strcpy(), drive; 45: unsigned char *fixed, *dos_name(); 46: void exit(), fat_write(), dir_write(), disk_flush(), dir_flush(); 47: struct directory *dir, *dir_read(); 48: /* catch signals */ 49: signal(SIGINT, (SIG_TYPE(*) ()) got_signal); 50: signal(SIGTERM, (SIG_TYPE(*) ()) got_signal); 51: signal(SIGQUIT, (SIG_TYPE(*) ()) got_signal); 52: /* get command line options */ 53: oops = 0; 54: verbose = 0; 55: mod_time = 0; 56: while ((c = getopt(argc, argv, "tnvm")) != EOF) { 57: switch (c) { 58: case 't': 59: textmode = 1; 60: break; 61: case 'n': 62: nowarn = 1; 63: break; 64: case 'v': 65: verbose = 1; 66: break; 67: case 'm': 68: mod_time = 1; 69: break; 70: default: 71: oops = 1; 72: break; 73: } 74: } 75: 76: if (oops || (argc - optind) < 2) { 77: fprintf(stderr, "Mtools version %s, dated %s\n", VERSION, DATE); 78: fprintf(stderr, "Usage: %s [-tnvm] unixfile msdosfile\n", argv[0]); 79: fprintf(stderr, " %s [-tnvm] unixfile [unixfiles...] msdosdirectory\n", argv[0]); 80: exit(1); 81: } 82: mcwd = fix_mcwd(); 83: 84: drive = get_drive(argv[argc - 1]); 85: if (init(drive, 2)) { 86: fprintf(stderr, "%s: Cannot initialize '%c:'\n", argv[0], drive); 87: exit(1); 88: } 89: 90: filename = get_name(argv[argc - 1]); 91: pathname = get_path(argv[argc - 1]); 92: 93: /* 94: * Move to "first guess" directory so we can see if filename is also 95: * a directory. 96: */ 97: if (subdir(drive, pathname)) 98: exit(1); 99: /* test if last argv is a dir */ 100: if (is_dir(filename) || *filename == '\0') { 101: if (*filename) { 102: strcpy(tmp, pathname); 103: if (tmp[strlen(tmp) -1] != '/') 104: strcat(tmp, "/"); 105: strcat(tmp, filename); 106: 107: if (subdir(drive, tmp)) 108: exit(1); 109: } 110: single = 0; 111: } 112: else { 113: single = 1; 114: /* too many arguments */ 115: if ((argc - optind) != 2) { 116: fprintf(stderr, "%s: Too many arguments or destination directory omitted\n", argv[0]); 117: exit(1); 118: } 119: } 120: 121: for (i = optind; i < argc - 1; i++) { 122: if (single) 123: fixed = dos_name(argv[argc - 1], verbose); 124: else 125: fixed = dos_name(argv[i], verbose); 126: 127: strcpy(target, unix_name(fixed, fixed + 8)); 128: /* see if exists and get slot */ 129: ismatch = 0; 130: slot = -1; 131: dot = 0; 132: nogo = 0; 133: first = 1; 134: for (entry = 0; entry < dir_entries; entry++) { 135: dir = dir_read(entry); 136: /* save the '.' entry info */ 137: if (first) { 138: first = 0; 139: if ((dir->attr & 0x10) && dir->name[0] == '.') { 140: dot = dir->start[1] * 0x100 + dir->start[0]; 141: continue; 142: } 143: } 144: /* is empty */ 145: if (dir->name[0] == 0x0) { 146: if (slot < 0) 147: slot = entry; 148: break; 149: } 150: /* is erased */ 151: if (dir->name[0] == 0xe5) { 152: if (slot < 0) 153: slot = entry; 154: continue; 155: } 156: /* is dir or volume label */ 157: if ((dir->attr & 0x10) || (dir->attr & 0x08)) 158: continue; 159: 160: newfile = unix_name(dir->name, dir->ext); 161: 162: /* if file exists, delete it first */ 163: if (!strcmp(target, newfile)) { 164: ismatch = 1; 165: start = dir->start[1] * 0x100 + dir->start[0]; 166: if (nowarn) { 167: if (fat_free(start)) 168: break; 169: dir->name[0] = 0xe5; 170: dir_write(entry, dir); 171: if (slot < 0) 172: slot = entry; 173: } 174: else { 175: /* CONSTCOND */ 176: while (1) { 177: printf("File \"%s\" exists, overwrite (y/n) ? ", target); 178: gets(ans); 179: if (ans[0] == 'n' || ans[0] == 'N') { 180: nogo = 1; 181: break; 182: } 183: if (ans[0] == 'y' || ans[0] == 'Y') { 184: if (fat_free(start)) 185: break; 186: dir->name[0] = 0xe5; 187: dir_write(entry, dir); 188: if (slot < 0) 189: slot = entry; 190: break; 191: } 192: } 193: } 194: } 195: if (ismatch) 196: break; 197: } 198: if (fat_error) 199: break; 200: 201: if (nogo) /* chickened out... */ 202: continue; 203: /* no '.' entry means root directory */ 204: if (dot == 0 && slot < 0) { 205: fprintf(stderr, "%s: No directory slots\n", argv[0]); 206: break; 207: } 208: /* make the directory grow */ 209: if (dot && slot < 0) { 210: if (dir_grow(dot)) { 211: fprintf(stderr, "%s: Disk full\n", argv[0]); 212: break; 213: } 214: /* first entry in 'new' directory */ 215: slot = entry; 216: } 217: /* write the file */ 218: if (dir = writeit(fixed, argv[i], verbose, mod_time, single, target)) 219: dir_write(slot, dir); 220: 221: if (full) { 222: fprintf(stderr, "%s: Disk full\n", argv[0]); 223: break; 224: } 225: if (single) 226: break; 227: } 228: /* write the FAT, flush the buffers */ 229: fat_write(); 230: dir_flush(); 231: disk_flush(); 232: close(fd); 233: exit(0); 234: } 235: 236: /* 237: * Open the named file for read, create the cluster chain, return the 238: * directory structure or NULL on error. 239: */ 240: 241: static struct directory * 242: writeit(fixed, path, verbose, mod_time, single, target) 243: unsigned char *fixed; 244: char *path; 245: int verbose, mod_time, single; 246: char *target; 247: { 248: FILE *fp; 249: unsigned int fat, next_fat(); 250: long filesize, file_write(), size, time(), now; 251: struct directory *dir, *mk_entry(); 252: struct stat stbuf; 253: 254: if (stat(path, &stbuf) < 0) { 255: fprintf(stderr, "Can't stat \"%s\"\n", path); 256: return(NULL); 257: } 258: 259: if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 260: if (verbose) 261: fprintf(stderr, "\"%s\" is a directory\n", path); 262: return(NULL); 263: } 264: 265: if ((stbuf.st_mode & S_IFREG) != S_IFREG) { 266: if (verbose) 267: fprintf(stderr, "\"%s\" is not a regular file\n", path); 268: return(NULL); 269: } 270: 271: if (!(fp = fopen(path, "r"))) { 272: fprintf(stderr, "Can't open \"%s\" for read\n", path); 273: return(NULL); 274: } 275: 276: if (!single) 277: printf("Copying %s\n", target); 278: 279: /* will it fit? */ 280: filesize = stbuf.st_size; 281: if (filesize > free_space()) { 282: full = 1; 283: return(NULL); 284: } 285: /* preserve mod time? */ 286: if (mod_time) 287: now = stbuf.st_mtime; 288: else 289: time(&now); 290: 291: /* if a zero length file */ 292: if (filesize == 0L) { 293: dir = mk_entry(fixed, 0x20, 0, 0L, now); 294: return(dir); 295: } 296: 297: if ((fat = next_fat(0)) == 1) { 298: full = 1; 299: fclose(fp); 300: return(NULL); 301: } 302: if ((size = file_write(fp, fat, filesize, textmode)) < 0) { 303: fclose(fp); 304: return(NULL); 305: } 306: fclose(fp); 307: 308: dir = mk_entry(fixed, 0x20, fat, size, now); 309: return(dir); 310: } 311: 312: /* 313: * Do a graceful exit if the program is interrupted. This will reduce 314: * (but not eliminate) the risk of generating a corrupted disk on 315: * a user abort. 316: */ 317: 318: static int 319: got_signal() 320: { 321: void exit(), disk_flush(), fat_write(), dir_flush(); 322: 323: if (fd < 0) 324: exit(1); 325: fat_write(); 326: dir_flush(); 327: disk_flush(); 328: close(fd); 329: exit(1); 330: } 331: 332: 333: /* 334: * Get the amount of remaining free space 335: */ 336: 337: static long 338: free_space() 339: { 340: register unsigned int i; 341: long total; 342: extern unsigned int num_clus; 343: unsigned int fat_decode(); 344: 345: total = 0L; 346: for (i = 2; i < num_clus + 2; i++) { 347: /* if fat_decode returns zero */ 348: if (!fat_decode(i)) 349: total += clus_size; 350: } 351: total *= MSECTOR_SIZE; 352: return(total); 353: }