home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume11 / sparc-mtools / part03 / mwrite.c
Encoding:
C/C++ Source or Header  |  1990-03-25  |  10.4 KB  |  462 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.  *                     Directorate of Engineering & Housing
  7.  *                     Environmental Management Office
  8.  *                     Fort Hood, TX 76544-5057
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include "msdos.h"
  15.  
  16. int fd;                /* the file descriptor for the floppy */
  17. int dir_start;            /* starting sector for directory */
  18. int dir_len;            /* length of directory (in sectors) */
  19. int dir_entries;        /* number of directory entries */
  20. int dir_chain[25];        /* chain of sectors in directory */
  21. int clus_size;            /* cluster size (in sectors) */
  22. unsigned long clus_len;        /* The cluster lenght in bytes */
  23. int fat_len;            /* length of FAT table (in sectors) */
  24. int num_clus;            /* number of available clusters */
  25. unsigned char *fatbuf;        /* the File Allocation Table */
  26. char *mcwd;            /* the Current Working Directory */
  27. static char *inbuf;        /* The input buffer */
  28. static char *outbuf;        /* The output buffer */
  29. int bufsiz;            /* Buffer size */
  30. int maxcontig;            /* Max contiguous clusters per write call */
  31. long size;            /* Size of DOS file */
  32.  
  33. int full = 0;
  34. int textmode = 0;
  35. int nowarn = 0;
  36. int need_nl = 0;
  37.  
  38. extern union bootblock bb;
  39. void exit(), zapit(), writefat(), writedir(), free(), perror(), move();
  40.  
  41. main(argc, argv)
  42. int argc;
  43. char *argv[];
  44. {
  45.     extern int optind;
  46.     extern char *optarg;
  47.     int i, entry, ismatch, nogo, slot, start, dot, single;
  48.     int root, c, oops, verbose, first, mod_time;
  49.     char *filename, *newfile, tname[9], text[4], *fixname(), *getname();
  50.     char *unixname(), ans[10], *strncpy(), *pathname, *getpath(), *fixed;
  51.     char tmp[MAX_PATH], *target, *strcat(), *strcpy();
  52.     struct directory *dir, *search(), *writeit();
  53.  
  54.     if (init(2)) {
  55.         fprintf(stderr, "mwrite: Cannot initialize diskette\n");
  56.         exit(1);
  57.     }
  58.                     /* get command line options */
  59.     oops = 0;
  60.     verbose = 0;
  61.     mod_time = 0;
  62.     while ((c = getopt(argc, argv, "tnvm")) != EOF) {
  63.         switch(c) {
  64.             case 't':
  65.                 textmode = 1;
  66.                 break;
  67.             case 'n':
  68.                 nowarn = 1;
  69.                 break;
  70.             case 'v':
  71.                 verbose = 1;
  72.                 break;
  73.             case 'm':
  74.                 mod_time = 1;
  75.                 break;
  76.             default:
  77.                 oops = 1;
  78.                 break;
  79.         }
  80.     }
  81.  
  82.     if (oops || (argc - optind) < 2) {
  83.         fprintf(stderr, "Usage: mwrite [-tnv] unixfile msdosfile\n");
  84.         fprintf(stderr, "    or mwrite [-tnv] unixfile [unixfiles...] msdosdirectory\n");
  85.         exit(1);
  86.     }
  87.     root = 0;
  88.     if (!strcmp(argv[argc-1], "/") || !strcmp(argv[argc-1], "\\"))
  89.         root = 1;
  90.  
  91.     filename = getname(argv[argc-1]);
  92.     pathname = getpath(argv[argc-1]);
  93.                     /* test if path is ok first */
  94.     if (subdir(pathname))
  95.         exit(1);
  96.                     /* test if last argv is a dir */
  97.     if (isdir(filename) || root) {
  98.         if (!strlen(pathname)) {
  99.                     /* don't alter the presence or */
  100.                     /* absence of a leading separator */
  101.             strcpy(tmp, filename);
  102.         }
  103.         else {
  104.             strcpy(tmp, pathname);
  105.             strcat(tmp, "/");
  106.             strcat(tmp, filename);
  107.         }
  108.                     /* subdir is not recursive */
  109.         subdir(tmp);
  110.         single = 0;
  111.     }
  112.     else {
  113.         single = 1;
  114.                     /* too many arguments */
  115.         if ((argc - optind) != 2) {
  116.             fprintf(stderr, "mwrite: too many arguments or destination directory omitted\n");
  117.             exit(1);
  118.         }
  119.     }
  120.  
  121.  
  122.     clus_len = clus_size * MSECSIZ;
  123.     /* Round cylinder up to nearest cluster multiple */
  124.     bufsiz = NTRACK(bb.sb) * NSECT(bb.sb);
  125.     maxcontig = (bufsiz += clus_size - (--bufsiz) % clus_size) / clus_size;
  126.     bufsiz *= MSECSIZ;
  127.  
  128.     if( (outbuf = (char *)malloc(bufsiz)) == NULL ||
  129.         ( inbuf = (char *)malloc(bufsiz)) == NULL) {
  130.         fprintf(stderr,
  131.             "mwrite: Cannot allocate I/O buffers\n");
  132.         perror("malloc") ;
  133.         exit(1);
  134.     }
  135.  
  136.     for (i=optind; i<argc-1; i++) {
  137.         if (single)
  138.             fixed = fixname(argv[argc-1], verbose);
  139.         else
  140.             fixed = fixname(argv[i], verbose);
  141.  
  142.         strncpy(tname, fixed, 8);
  143.         strncpy(text, fixed+8, 3);
  144.         tname[8] = '\0';
  145.         text[3] = '\0';
  146.  
  147.         target = unixname(tname, text);
  148.                     /* see if exists and get slot */
  149.         ismatch = 0;
  150.         slot = -1;
  151.         dot = 0;
  152.         nogo = 0;
  153.         first = 1;
  154.         for (entry=0; entry<dir_entries; entry++) {
  155.             dir = search(entry);
  156.                     /* save the '.' entry info */
  157.             if (first) {
  158.                 first = 0;
  159.                 if ((dir->attr & 0x10) && dir->name[0] == '.') {
  160.                     dot = dir->start[1]*0x100 + dir->start[0];
  161.                     continue;
  162.                 }
  163.             }
  164.                     /* is empty */
  165.             if (dir->name[0] == 0x0) {
  166.                 if (slot < 0)
  167.                     slot = entry;
  168.                 break;
  169.             }
  170.                     /* is erased */
  171.             if (dir->name[0] == 0xe5) {
  172.                 if (slot < 0)
  173.                     slot = entry;
  174.                 continue;
  175.             }
  176.                     /* is dir or volume lable */
  177.             if ((dir->attr & 0x10) || (dir->attr & 0x08))
  178.                 continue;
  179.  
  180.             strncpy(tname, (char *) dir->name, 8);
  181.             strncpy(text, (char *) dir->ext, 3);
  182.             tname[8] = '\0';
  183.             text[3] = '\0';
  184.  
  185.             newfile = unixname(tname, text);
  186.                     /* if file exists, delete it first */
  187.             if (!strcmp(target, newfile)) {
  188.                 ismatch = 1;
  189.                 start = dir->start[1]*0x100 + dir->start[0];
  190.                 if (nowarn) {
  191.                     zapit(start);
  192.                     dir->name[0] = 0xe5;
  193.                     writedir(entry, dir);
  194.                     if (slot < 0)
  195.                         slot = entry;
  196.                 } else {
  197.                     while (1) {
  198.                         printf("File \"%s\" exists, overwrite (y/n) ? ", target);
  199.                         gets(ans);
  200.                         if (ans[0] == 'n' || ans[0] == 'N') {
  201.                             nogo = 1;
  202.                             break;
  203.                         }
  204.                         if (ans[0] == 'y' || ans[0] == 'Y') {
  205.                             zapit(start);
  206.                             dir->name[0] = 0xe5;
  207.                             writedir(entry, dir);
  208.                             if (slot < 0)
  209.                                 slot = entry;
  210.                             break;
  211.                         }
  212.                     }
  213.                 }
  214.             }
  215.             free(newfile);
  216.             if (ismatch)
  217.                 break;
  218.         }
  219.         if (nogo) {        /* chickened out... */
  220.             free(fixed);
  221.             free(target);
  222.             continue;
  223.         }
  224.                     /* no '.' entry means root directory */
  225.         if (dot == 0 && slot < 0) {
  226.             fprintf(stderr, "mwrite: No directory slots\n");
  227.             exit(1);
  228.         }
  229.                     /* make the directory grow */
  230.         if (dot && slot < 0) {
  231.             if (grow(dot)) {
  232.                 fprintf(stderr, "mwrite: Disk full\n");
  233.                 exit(1);
  234.             }
  235.                     /* first entry in 'new' directory */
  236.             slot = entry;
  237.         }
  238.         if (!single)
  239.             printf("Copying %s\n", target);
  240.                     /* write the file */
  241.         if (dir = writeit(fixed, argv[i], verbose, mod_time))
  242.             writedir(slot, dir);
  243.  
  244.         free(fixed);
  245.         free(target);
  246.  
  247.         if (full) {
  248.             fprintf(stderr, "mwrite: Disk Full\n");
  249.             break;
  250.         }
  251.         if (single)
  252.             break;
  253.     }
  254.                     /* write FAT sectors */
  255.     writefat();
  256.     close(fd);
  257.     exit(0);
  258. }
  259.  
  260. /*
  261.  * Open the named file for write, create the cluster chain, return the
  262.  * directory structure or NULL on error.
  263.  */
  264.  
  265. struct directory *
  266. writeit(fixed, path, verbose, mod_time)
  267. char *fixed, *path;
  268. int verbose, mod_time;
  269. {
  270.     FILE *fp;
  271.     int fat, firstfat, oldfat, curfat, chain;
  272.     long time(), now;
  273.     struct directory *dir, *mk_entry();
  274.     struct stat stbuf;
  275.  
  276.     if (stat(path, &stbuf) < 0) {
  277.         fprintf(stderr, "mwrite: Can't stat \"%s\"\n", path);
  278.         return(NULL);
  279.     }
  280.  
  281.     if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
  282.         if (verbose)
  283.             fprintf(stderr, "mwrite: \"%s\" is a directory\n", path);
  284.         return(NULL);
  285.     }
  286.  
  287.     if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
  288.         fprintf(stderr, "mwrite: \"%s\" is not a regular file\n", path);
  289.         return(NULL);
  290.     }
  291.                     /* preserve mod time? */
  292.     if (mod_time)
  293.         now = stbuf.st_mtime;
  294.     else
  295.         time(&now);
  296.  
  297.     if (!(fp = fopen(path, "r"))) {
  298.         fprintf(stderr, "mwrite: Can't open \"%s\" for read\n", path);
  299.         return(NULL);
  300.     }
  301. #ifdef HAVE_SETBUFFER
  302.     setbuffer(fp,inbuf,bufsiz) ;
  303. #endif
  304.  
  305.     fat = oldfat = firstfat = nextfat(size=0); 
  306.     for(;;) {
  307.         if (fat == -1) {
  308.             full = 1;
  309.             if(size) 
  310.                 zapit(firstfat) ;
  311.             return(NULL) ;
  312.         }
  313.  
  314.         /*
  315.          * grab a bunch of contiguous FAT slots
  316.          * curfat -> 1 + last grabbed slot.
  317.          * FIX ME!
  318.          * someone should try to read and cache a cylinder on
  319.          * first write access, do write to memory until a new
  320.          * cylinder is requested.
  321.          * The overhead is higher,  but should be more robust under
  322.          * fragmentation.
  323.          * In mread this may even be a win!  (Also see comments
  324.          * in putclusters() )
  325.          */
  326.         for(curfat=fat; 
  327.             ++curfat < fat + maxcontig  &&
  328.             nextfat(curfat-1) == curfat;) ;
  329.             
  330.         if((oldfat=putclusters(oldfat,fat, curfat, fp)) == 0)
  331.             break ;
  332.  
  333.         fat = nextfat(oldfat);
  334.     }
  335.     fclose(fp);
  336.     dir = mk_entry(fixed, 0x20, firstfat, size, now);
  337.     return(dir);
  338. }
  339.  
  340. /*
  341.  * Write to the cluster chain from the named Unix file descriptor.
  342.  * N.B. all the clusters in the chain are contiguous.
  343.  */
  344.  
  345.  
  346. static int writepos = -1;
  347.  
  348. int
  349. putclusters(chain,start,end,fp)
  350. FILE *fp;
  351. {
  352.     static int blk;
  353.     int c, nclust, current, eof=0;
  354.     int buflen = ( end - start ) * MSECSIZ ;
  355.     register char *tbuf=outbuf;
  356.  
  357.     blk = (start - 2)*clus_size + dir_start + dir_len;
  358.  
  359.     if (textmode) { /* '\n' to '\r\n' translation */
  360.         current = 0;
  361.         if (need_nl) {
  362.             tbuf[current++] = '\n';
  363.             need_nl = 0;
  364.         }
  365.         while (current < buflen) {
  366.             if ((c = fgetc(fp)) == EOF) {
  367.                     /* put a file EOF marker */
  368.                 tbuf[current++] = 0x1a;
  369.                 ++eof;
  370.                 break;
  371.             }
  372.             if (c == '\n') {
  373.                 tbuf[current++] = '\r';
  374.                 /* if at the end of the buffer */
  375.                 if (current == buflen) {
  376.                     need_nl++;
  377.                     break;
  378.                 }
  379.             }
  380.             tbuf[current++] = c;
  381.         }
  382.     }
  383.     else {
  384.         /*
  385.          * FIX ME!
  386.          * The kernel guarantees to satisfy REGULAR file
  387.          * read requests unless EOF,
  388.          * This code will break on pipes,  sockets,  etc.
  389.          * To fix one should do something akin to the
  390.          * "atomic" I/O of Berkeley multiprocess dump,  which loops
  391.          * on read/write requests until EOF or enough data has been
  392.          * gathered.  If you want to do this please change
  393.          * all instances of  read/write with Read/Write and
  394.          * add an offset parameter to allow arbitrary sorting/queuing
  395.          * etc,  behind the back of the DOS code.  This will
  396.          * make the overall code much cleaner,  and we 
  397.          * can put Read/Write in a sysdep.c where they belong.
  398.          * Also one may want to memory map the input file.  Avoiding
  399.          * redundant copying to user space,  this is for perfectionists
  400.          * as the floppy is much slower than UNIX disks,  so gains
  401.          * here are small.
  402.          */
  403.         if ( (current = fread(outbuf, 1, buflen, fp)) < 0) {
  404.             perror("putcluster: fread");
  405.             exit(1);
  406.         }
  407.         if ( current != buflen ) 
  408.             ++eof;
  409.     }
  410.  
  411.     size += current;
  412.  
  413.     if (current == 0) {
  414.         putfat(chain,0xfff) ;
  415.         return(0) ;
  416.     }
  417.  
  418.     putfat(chain,start) ;
  419.  
  420.     /*
  421.      * chain the clusters, we are about to overwrite
  422.      * making sure to terminate the chain.
  423.      */
  424.     for(end=start; current > clus_len ; ++end) {
  425.         putfat(end,end+1);
  426.         current -= clus_len ;
  427.     }
  428.     putfat(end, 0xfff) ;
  429.  
  430.     if ( blk != writepos )
  431.         move(blk);
  432.  
  433.     nclust=(end-start)+1;
  434.     writepos = eof ? -1 : blk + nclust*clus_size;
  435.     buflen = nclust * clus_size * MSECSIZ;
  436.  
  437.     if (write(fd, outbuf, buflen) != buflen) {
  438.         perror("putclusters: write");
  439.         exit(1);
  440.     }
  441.  
  442.     return(eof ? 0: end) ;
  443. }
  444.  
  445. /*
  446.  * Returns next free cluster or -1 if none are available.
  447.  */
  448.  
  449. int
  450. nextfat(last)
  451. int last;
  452. {
  453.     register int i;
  454.  
  455.     for (i=last+1; i<num_clus+2; i++) {
  456.         if (!getfat(i))
  457.             return(i);
  458.     }
  459.     return(-1);
  460.  
  461. }
  462.