home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / diskutil / mtools / mwrite.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-05  |  7.6 KB  |  354 lines

  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. }
  354.