home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / SRC / msdos_diskaccess.lzh / MS_DISK_ACCESS / mwrite.c < prev    next >
C/C++ Source or Header  |  1991-08-08  |  11KB  |  479 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 *outbuf;        /* The output buffer */
  28. int bufsiz;            /* Buffer size */
  29. int maxcontig;            /* Max contiguous clusters per write call */
  30. long size;            /* Size of DOS file */
  31.  
  32. int full = 0;
  33. int textmode = 0;
  34. int nowarn = 0;
  35. int need_nl = 0;
  36.  
  37. extern union bootblock bb;
  38. extern short is_tos0;
  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.         fprintf(stderr,    "mwrite: Cannot allocate I/O buffer\n");
  130.         perror("malloc") ;
  131.         exit(1);
  132.     }
  133.  
  134.     for (i=optind; i<argc-1; i++) {
  135.         if (single)
  136.             fixed = fixname(argv[argc-1], verbose);
  137.         else
  138.             fixed = fixname(argv[i], verbose);
  139.  
  140.         strncpy(tname, fixed, 8);
  141.         strncpy(text, fixed+8, 3);
  142.         tname[8] = '\0';
  143.         text[3] = '\0';
  144.  
  145.         target = unixname(tname, text);
  146.                     /* see if exists and get slot */
  147.         ismatch = 0;
  148.         slot = -1;
  149.         dot = 0;
  150.         nogo = 0;
  151.         first = 1;
  152.         for (entry=0; entry<dir_entries; entry++) {
  153.             dir = search(entry);
  154.                     /* save the '.' entry info */
  155.             if (first) {
  156.                 first = 0;
  157.                 if ((dir->attr & 0x10) && dir->name[0] == '.') {
  158.                     dot = dir->start[1]*0x100 + dir->start[0];
  159.                     continue;
  160.                 }
  161.             }
  162.                     /* is empty */
  163.             if (dir->name[0] == 0x0) {
  164.                 if (slot < 0)
  165.                     slot = entry;
  166.                 break;
  167.             }
  168.                     /* is erased */
  169.             if (dir->name[0] == 0xe5) {
  170.                 if (slot < 0)
  171.                     slot = entry;
  172.                 continue;
  173.             }
  174.                     /* is dir or volume lable */
  175.             if ((dir->attr & 0x10) || (dir->attr & 0x08))
  176.                 continue;
  177.  
  178.             strncpy(tname, (char *) dir->name, 8);
  179.             strncpy(text, (char *) dir->ext, 3);
  180.             tname[8] = '\0';
  181.             text[3] = '\0';
  182.  
  183.             newfile = unixname(tname, text);
  184.                     /* if file exists, delete it first */
  185.             if (!strcmp(target, newfile)) {
  186.                 ismatch = 1;
  187.                 start = dir->start[1]*0x100 + dir->start[0];
  188.                 if (nowarn) {
  189.                     zapit(start);
  190.                     dir->name[0] = 0xe5;
  191.                     writedir(entry, dir);
  192.                     if (slot < 0)
  193.                         slot = entry;
  194.                 } else {
  195.                     while (1) {
  196.                         printf("File \"%s\" exists, overwrite (y/n) ? ", target);
  197.                         gets(ans);
  198.                         if (ans[0] == 'n' || ans[0] == 'N') {
  199.                             nogo = 1;
  200.                             break;
  201.                         }
  202.                         if (ans[0] == 'y' || ans[0] == 'Y') {
  203.                             zapit(start);
  204.                             dir->name[0] = 0xe5;
  205.                             writedir(entry, dir);
  206.                             if (slot < 0)
  207.                                 slot = entry;
  208.                             break;
  209.                         }
  210.                     }
  211.                 }
  212.             }
  213.             free(newfile);
  214.             if (ismatch)
  215.                 break;
  216.         }
  217.         if (nogo) {        /* chickened out... */
  218.             free(fixed);
  219.             free(target);
  220.             continue;
  221.         }
  222.                     /* no '.' entry means root directory */
  223.         if (dot == 0 && slot < 0) {
  224.             fprintf(stderr, "mwrite: No directory slots\n");
  225.             exit(1);
  226.         }
  227.                     /* make the directory grow */
  228.         if (dot && slot < 0) {
  229.             if (grow(dot)) {
  230.                 fprintf(stderr, "mwrite: Disk full\n");
  231.                 exit(1);
  232.             }
  233.                     /* first entry in 'new' directory */
  234.             slot = entry;
  235.         }
  236.         if (!single)
  237.             printf("Copying %s\n", target);
  238.                     /* write the file */
  239.         if (dir = writeit(fixed, argv[i], verbose, mod_time))
  240.             writedir(slot, dir);
  241.  
  242.         free(fixed);
  243.         free(target);
  244.  
  245.         if (full) {
  246.             fprintf(stderr, "mwrite: Disk Full\n");
  247.             break;
  248.         }
  249.         if (single)
  250.             break;
  251.     }
  252.                     /* write FAT sectors */
  253.     writefat();
  254.     close(fd);
  255.     exit(0);
  256. }
  257.  
  258. /*
  259.  * Open the named file for write, create the cluster chain, return the
  260.  * directory structure or NULL on error.
  261.  */
  262.  
  263. struct directory *
  264. writeit(fixed, path, verbose, mod_time)
  265. char *fixed, *path;
  266. int verbose, mod_time;
  267. {
  268.     FILE *fp;
  269.     int fat, firstfat, oldfat, curfat, chain;
  270.     long time(), now;
  271.     struct directory *dir, *mk_entry();
  272.     struct stat stbuf;
  273.  
  274.     if (stat(path, &stbuf) < 0) {
  275.         fprintf(stderr, "mwrite: Can't stat \"%s\"\n", path);
  276.         return(NULL);
  277.     }
  278.  
  279.     if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
  280.         if (verbose)
  281.             fprintf(stderr, "mwrite: \"%s\" is a directory\n", path);
  282.         return(NULL);
  283.     }
  284.  
  285.     if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
  286.         fprintf(stderr, "mwrite: \"%s\" is not a regular file\n", path);
  287.         return(NULL);
  288.     }
  289.                     /* preserve mod time? */
  290.     if (mod_time)
  291.         now = stbuf.st_mtime;
  292.     else
  293.         time(&now);
  294.  
  295.     if (!(fp = fopen(path, "r"))) {
  296.         fprintf(stderr, "mwrite: Can't open \"%s\" for read\n", path);
  297.         return(NULL);
  298.     }
  299. #ifdef OSK
  300.     fp->_bufsiz = 20480;
  301. #endif
  302. #ifdef HAVE_SETBUFFER
  303.     setbuffer(fp,inbuf,bufsiz) ;
  304. #endif
  305.  
  306.     fat = oldfat = firstfat = nextfat(size=0); 
  307.     for(;;) {
  308.         if (fat == -1) {
  309.             full = 1;
  310.             if(size) 
  311.                 zapit(firstfat) ;
  312.             return(NULL) ;
  313.         }
  314.  
  315.         /*
  316.          * grab a bunch of contiguous FAT slots
  317.          * curfat -> 1 + last grabbed slot.
  318.          * FIX ME!
  319.          * someone should try to read and cache a cylinder on
  320.          * first write access, do write to memory until a new
  321.          * cylinder is requested.
  322.          * The overhead is higher,  but should be more robust under
  323.          * fragmentation.
  324.          * In mread this may even be a win!  (Also see comments
  325.          * in putclusters() )
  326.          */
  327.         for(curfat=fat; 
  328.             ++curfat < fat + maxcontig  &&
  329.             nextfat(curfat-1) == curfat;) ;
  330.             
  331.         if((oldfat=putclusters(oldfat,fat, curfat, fp)) == 0)
  332.             break ;
  333.  
  334.         fat = nextfat(oldfat);
  335.     }
  336.     fclose(fp);
  337.     dir = mk_entry(fixed, 0x20, firstfat, size, now);
  338.     return(dir);
  339. }
  340.  
  341. /*
  342.  * Write to the cluster chain from the named Unix file descriptor.
  343.  * N.B. all the clusters in the chain are contiguous.
  344.  */
  345.  
  346.  
  347. static int writepos = -1;
  348.  
  349. int
  350. putclusters(chain,start,end,fp)
  351. FILE *fp;
  352. {
  353.     static int blk;
  354.     int c, nclust, current, eof=0;
  355.     int buflen = ( end - start ) * MSECSIZ * clus_size ;
  356.     register char *tbuf=outbuf;
  357.  
  358.     blk = (start - 2)*clus_size + dir_start + dir_len;
  359.  
  360.     if (textmode) { /* '\n' to '\r\n' translation */
  361.         current = 0;
  362.         if (need_nl) {
  363.             tbuf[current++] = '\l';
  364.             need_nl = 0;
  365.         }
  366.         while (current < buflen) {
  367.             if ((c = fgetc(fp)) == EOF) {
  368.                     /* put a file EOF marker */
  369.                 tbuf[current++] = 0x1a;
  370.                 ++eof;
  371.                 break;
  372.             }
  373.             if (c == '\n') {
  374.                 tbuf[current++] = c;
  375.                 c = '\l';
  376.                 /* if at the end of the buffer */
  377.                 if (current == buflen) {
  378.                     need_nl++;
  379.                     break;
  380.                 }
  381.             }
  382.             tbuf[current++] = c;
  383.         }
  384.     }
  385.     else {
  386.         /*
  387.          * FIX ME!
  388.          * The kernel guarantees to satisfy REGULAR file
  389.          * read requests unless EOF,
  390.          * This code will break on pipes,  sockets,  etc.
  391.          * To fix one should do something akin to the
  392.          * "atomic" I/O of Berkeley multiprocess dump,  which loops
  393.          * on read/write requests until EOF or enough data has been
  394.          * gathered.  If you want to do this please change
  395.          * all instances of  read/write with Read/Write and
  396.          * add an offset parameter to allow arbitrary sorting/queuing
  397.          * etc,  behind the back of the DOS code.  This will
  398.          * make the overall code much cleaner,  and we 
  399.          * can put Read/Write in a sysdep.c where they belong.
  400.          * Also one may want to memory map the input file.  Avoiding
  401.          * redundant copying to user space,  this is for perfectionists
  402.          * as the floppy is much slower than UNIX disks,  so gains
  403.          * here are small.
  404.          */
  405.         if ( (current = fread(outbuf, 1, buflen, fp)) < 0) {
  406.             perror("putcluster: fread");
  407.             exit(1);
  408.         }
  409.         if ( current != buflen ) 
  410.             ++eof;
  411.     }
  412.  
  413.     size += current;
  414.  
  415.     if (current == 0) {
  416.         putfat(chain,0xfff) ;
  417.         return(0) ;
  418.     }
  419.  
  420.     putfat(chain,start) ;
  421.  
  422.     /*
  423.      * chain the clusters, we are about to overwrite
  424.      * making sure to terminate the chain.
  425.      */
  426.     for(end=start; current > clus_len ; ++end) {
  427.         putfat(end,end+1);
  428.         current -= clus_len ;
  429.     }
  430.     putfat(end, 0xfff) ;
  431.  
  432.     if ( blk != writepos )
  433.         move(blk);
  434.  
  435.     nclust=(end-start)+1;
  436.     writepos = eof ? -1 : blk + nclust*clus_size;
  437.     buflen = nclust * clus_size * MSECSIZ;
  438.  
  439.     if (is_tos0) {
  440.         unsigned rp, pos;
  441.         
  442.         pos = lseek(fd, 0, 1);
  443.         for(rp = 0; rp < buflen; rp += 1024) {
  444.             lseek(fd, pos+rp, 0); 
  445.             write(fd, outbuf+pos, 512);
  446.         }
  447.         for(rp = 512; rp < buflen; rp += 1024) {
  448.             lseek(fd, pos+rp, 0); 
  449.             write(fd, outbuf+pos, 512);
  450.         }
  451.         lseek(fd, pos+buflen, 0);
  452.     } else {
  453.         if (write(fd, outbuf, buflen) != buflen) {
  454.             perror("putclusters: write");
  455.             exit(1);
  456.         }
  457.     }
  458.  
  459.     return(eof ? 0: end) ;
  460. }
  461.  
  462. /*
  463.  * Returns next free cluster or -1 if none are available.
  464.  */
  465.  
  466. int
  467. nextfat(last)
  468. int last;
  469. {
  470.     register int i;
  471.  
  472.     for (i=last+1; i<num_clus+2; i++) {
  473.         if (!getfat(i))
  474.             return(i);
  475.     }
  476.     return(-1);
  477.  
  478. }
  479.