home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / mtools_3.6.src.lzh / MTOOLS_3.6 / vfat.c < prev    next >
Text File  |  1997-11-12  |  8KB  |  357 lines

  1. /* vfat.c
  2.  *
  3.  * Miscellaneous VFAT-related functions
  4.  */
  5.  
  6. #include "sysincludes.h"
  7. #include "msdos.h"
  8. #include "mtools.h"
  9. #include "vfat.h"
  10. #include "file.h"
  11.  
  12. /* #define DEBUG */
  13.  
  14. const char *short_illegals=";+=[]',\"*\\<>/?:|";
  15. const char *long_illegals = "\"*\\<>/?:|\005";
  16.  
  17. /* Automatically derive a new name */
  18. static void autorename(char *name,
  19.                char tilda, char dot, const char *illegals,
  20.                int limit, int bump)
  21. {
  22.     int tildapos, dotpos;
  23.     unsigned int seqnum=0, maxseq=0;
  24.     char tmp;
  25.     char *p;
  26.     
  27. #ifdef DEBUG
  28.     printf("In autorename for name=%s.\n", name);
  29. #endif
  30.     tildapos = -1;
  31.  
  32.     for(p=name; *p ; p++)
  33.         if((*p < ' ' && *p != '\005') || strchr(illegals, *p)) {
  34.             *p = '_';
  35.             bump = 0;
  36.         }
  37.  
  38.     for(dotpos=0;
  39.         name[dotpos] && dotpos < limit && name[dotpos] != dot ;
  40.         dotpos++) {
  41.         if(name[dotpos] == tilda) {
  42.             tildapos = dotpos;
  43.             seqnum = 0;
  44.             maxseq = 1;
  45.         } else if (name[dotpos] >= '0' && name[dotpos] <= '9') {
  46.             seqnum = seqnum * 10 + name[dotpos] - '0';
  47.             maxseq = maxseq * 10;
  48.         } else
  49.             tildapos = -1; /* sequence number interrupted */
  50.     }
  51.     if(tildapos == -1) {
  52.         /* no sequence number yet */
  53.         if(dotpos > limit - 2) {
  54.             tildapos = limit - 2;
  55.             dotpos = limit;
  56.         } else {
  57.             tildapos = dotpos;
  58.             dotpos += 2;
  59.         }
  60.         seqnum = 1;
  61.     } else {
  62.         if(bump)
  63.             seqnum++;
  64.         if(seqnum > 999999) {
  65.             seqnum = 1;
  66.             tildapos = dotpos - 2;
  67.             /* this matches Win95's behavior, and also guarantees
  68.              * us that the sequence numbers never get shorter */
  69.         }
  70.         if (seqnum == maxseq) {
  71.             if(dotpos >= limit)
  72.             tildapos--;
  73.             else
  74.             dotpos++;
  75.         }
  76.     }
  77.  
  78.     tmp = name[dotpos];
  79.     sprintf(name+tildapos,"%c%d",tilda, seqnum);
  80.     if(dot)
  81.         name[dotpos]=tmp;
  82.     /* replace the character if it wasn't a space */
  83. }
  84.  
  85.  
  86. void autorename_short(char *name, int bump)
  87. {
  88.     autorename(name, '~', ' ', short_illegals, 8, bump);
  89. }
  90.  
  91. void autorename_long(char *name, int bump)
  92. {
  93.     autorename(name, '-', '\0', long_illegals, 255, bump);
  94. }
  95.  
  96. void clear_vfat(struct vfat_state *v)
  97. {
  98.     v->subentries = 0;
  99.     v->status = 0;
  100. }
  101.  
  102.  
  103. /* sum_shortname
  104.  *
  105.  * Calculate the checksum that results from the short name in *dir.
  106.  *
  107.  * The sum is formed by circularly right-shifting the previous sum
  108.  * and adding in each character, from left to right, padding both
  109.  * the name and extension to maximum length with spaces and skipping
  110.  * the "." (hence always summing exactly 11 characters).
  111.  * 
  112.  * This exact algorithm is required in order to remain compatible
  113.  * with Microsoft Windows-95 and Microsoft Windows NT 3.5.
  114.  * Thanks to Jeffrey Richter of Microsoft Systems Journal for
  115.  * pointing me to the correct algorithm.
  116.  *
  117.  * David C. Niemi (niemidc@erols.com) 95.01.19
  118.  */
  119. unsigned char sum_shortname(name)
  120.     char *name;
  121. {
  122.     unsigned char sum;
  123.     int j;
  124.  
  125.     for (j=sum=0; j<11; ++j)
  126.         sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1)
  127.             + (name[j] ? name[j] : ' ');
  128.     return(sum);
  129. }
  130.  
  131. /* check_vfat
  132.  *
  133.  * Inspect a directory and any associated VSEs.
  134.  * Return 1 if the VSEs comprise a valid long file name,
  135.  * 0 if not.
  136.  */
  137. int check_vfat(struct vfat_state *v, struct directory *dir)
  138. {
  139.     char name[12];
  140.  
  141.     if (! v->subentries) {
  142. #ifdef DEBUG
  143.         fprintf(stderr, "check_vfat: no VSEs.\n");
  144. #endif
  145.         return 0;
  146.     }
  147.  
  148.     strncpy((char *)name, (char *)dir->name, 8);
  149.     strncpy((char *)name + 8, (char *)dir->ext, 3);
  150.     name[11] = '\0';
  151.  
  152.     if (v->sum != sum_shortname(name))
  153.         return 0;
  154.     
  155.     if( (v->status & ((1<<v->subentries) - 1)) != (1<<v->subentries) - 1)
  156.         return 0; /* missing entries */
  157.  
  158.     /* zero out byte following last entry, for good measure */
  159.     v->name[VSE_NAMELEN * v->subentries] = 0;
  160.  
  161.     return 1;
  162. }
  163.  
  164.  
  165. void clear_vses(Stream_t *Dir, int entry, size_t last)
  166. {
  167.     struct directory dir;
  168.  
  169.     maximize(&last, entry + MAX_VFAT_SUBENTRIES);
  170.     for (; entry <= last; ++entry) {
  171. #ifdef DEBUG
  172.         fprintf(stderr,"Clearing entry %d.\n", entry);
  173. #endif
  174.         dir_read(Dir, &dir, entry, NULL);
  175.         if(!dir.name[0] || dir.name[0] == DELMARK)
  176.             break;
  177.         dir.name[0] = DELMARK;
  178.         if (dir.attr == 0xf)
  179.             dir.attr = '\0';
  180.         dir_write(Dir, entry, &dir);
  181.     }
  182. }
  183.  
  184. int write_vfat(Stream_t *Dir, char *shortname, char *longname, int start)
  185. {
  186.     struct vfat_subentry vse;
  187.     int vse_id, num_vses;
  188.     char *c;
  189.  
  190. #ifdef DEBUG
  191. printf("Entering write_vfat with longname=\"%s\", start=%d.\n",longname,start);
  192. #endif
  193.     /* Fill in invariant part of vse */
  194.     vse.attribute = 0x0f;
  195.     vse.hash1 = vse.sector_l = vse.sector_u = 0;
  196.     vse.sum = sum_shortname(shortname);
  197. #ifdef DEBUG
  198.     printf("Wrote checksum=%d for shortname %s.\n", vse.sum,shortname);
  199. #endif
  200.  
  201.     num_vses = strlen(longname)/VSE_NAMELEN + 1;
  202.     for (vse_id = num_vses; vse_id; --vse_id) {
  203.         int end = 0;
  204.  
  205.         c = longname + (vse_id - 1) * VSE_NAMELEN;
  206.         
  207.  
  208.         c += unicode_write(c, vse.text1, VSE1SIZE, &end);
  209.         c += unicode_write(c, vse.text2, VSE2SIZE, &end);
  210.         c += unicode_write(c, vse.text3, VSE3SIZE, &end);
  211.  
  212.  
  213.         vse.id = (vse_id == num_vses) ? (vse_id | VSE_LAST) : vse_id;
  214. #ifdef DEBUG
  215. printf("Writing longname=(%s), VSE %d (%13s) at %d, end = %d.\n",
  216. longname, vse_id, longname + (vse_id-1) * VSE_NAMELEN,
  217. start + num_vses - vse_id, start + num_vses);
  218. #endif
  219.         dir_write(Dir, start + num_vses - vse_id,
  220.             (struct directory *)&vse);
  221.     }
  222.     return start + num_vses;
  223. }
  224.  
  225. /*
  226.  * vfat_lookup looks for filenames in directory dir.
  227.  * if a name if found, it is returned in outname
  228.  * if applicable, the file is opened and its stream is returned in File
  229.  */
  230.  
  231. int vfat_lookup(Stream_t *Dir, struct directory *dir,
  232.         int *entry, int *vfat_start,
  233.         const char *filename, 
  234.         int flags, char *outname, char *shortname, char *longname)
  235. {
  236.     int found;
  237.     struct vfat_state vfat;
  238.     char newfile[13];
  239.     int vfat_present = 0; /* zeroed by clear_vfat, but make GCC happy */
  240.  
  241.     if (*entry == -1)
  242.         return -1;
  243.  
  244.     found = 0;
  245.     clear_vfat(&vfat);
  246.     while(1){
  247.         if(!dir_read(Dir, dir, *entry, &vfat)){
  248.             if(vfat_start)
  249.                 *vfat_start = *entry;
  250.             break;
  251.         }
  252.         (*entry)++;
  253.  
  254.         /*---------------- Empty ---------------*/
  255.         if (dir->name[0] == '\0'){
  256.             if(!vfat_start)
  257.                 break;
  258.             continue;
  259.         }
  260.  
  261.         if (dir->attr == 0x0f) {
  262.             /* VSE, keep going */
  263.             continue;
  264.         }
  265.         
  266.         /* If we get here, it's a short name FAT entry, maybe erased.
  267.          * thus we should make sure that the vfat structure will be
  268.          * cleared before the next loop run */
  269.  
  270.         /* deleted file */
  271.         if ( (dir->name[0] == DELMARK) ||
  272.              ((dir->attr & 0x8) && !(flags & ACCEPT_LABEL))){
  273.             clear_vfat(&vfat);
  274.             continue;
  275.         }
  276.  
  277.         vfat_present = check_vfat(&vfat, dir);
  278.         if (vfat_start) {
  279.             *vfat_start = *entry - 1;
  280.             if(vfat_present)
  281.                 *vfat_start -= vfat.subentries;
  282.         }
  283.  
  284.         if (dir->attr & 0x8){
  285.             strncpy(newfile, dir->name,8);
  286.             newfile[8]='\0';
  287.             strncat(newfile, dir->ext,3);
  288.             newfile[11]='\0';
  289.         } else
  290.             unix_name(dir->name, dir->ext, dir->Case, newfile);
  291.         
  292.  
  293.         /*---------- multiple files ----------*/
  294. #ifdef DEBUG
  295.         printf(
  296.     "!single, vfat_present=%d, vfat.name=%s, newfile=%s, filename=%s.\n",
  297.             vfat_present, vfat.name, newfile, filename);
  298. #endif                        
  299.         if(!((flags & MATCH_ANY) ||
  300.              (vfat_present && match(vfat.name, filename, outname, 0)) ||
  301.              match(newfile, filename, outname, 1))) {
  302.             clear_vfat(&vfat);
  303.             continue;
  304.         }
  305.  
  306.  
  307.         /* entry of non-requested type */
  308.         if((dir->attr & 0x10) && !(flags & ACCEPT_DIR)) {
  309.             if(!(flags & (ACCEPT_LABEL|MATCH_ANY|NO_MSG)))
  310.                 fprintf(stderr,
  311.                     "Skipping \"%s\", is a directory\n",
  312.                     newfile);
  313.             clear_vfat(&vfat);
  314.             continue;
  315.         }
  316.  
  317.  
  318.         if((!(dir->attr & 0x18)) && !(flags & ACCEPT_PLAIN)) {
  319.             if(!(flags & (ACCEPT_LABEL|MATCH_ANY|NO_MSG)))
  320.                 fprintf(stderr,
  321.                     "Skipping \"%s\", is not a directory\n",
  322.                     newfile);
  323.             clear_vfat(&vfat);
  324.             continue;
  325.         }
  326.  
  327.  
  328.         found = 1;
  329.         break;
  330.     }
  331.  
  332.     if(found){
  333. #if 0
  334.         if((flags & DO_OPEN) && Fs && File){
  335.             *File = open_file(COPY(Fs), dir);
  336.             if (! *File)
  337.                 FREE( &Fs);
  338.         }
  339. #endif
  340.         if(longname){
  341.             if(vfat_present)
  342.                 strcpy(longname, vfat.name);
  343.             else
  344.                 *longname ='\0';
  345.         }
  346.         if(shortname)
  347.             strcpy(shortname, newfile);
  348.             
  349.         return 0; /* file found */
  350.     } else {
  351.         *entry = -1;
  352.         return -1; /* no file found */
  353.     }
  354. }
  355.  
  356. /* End vfat.c */
  357.