home *** CD-ROM | disk | FTP | other *** search
- /* vfat.c
- *
- * Miscellaneous VFAT-related functions
- */
-
- #include "sysincludes.h"
- #include "msdos.h"
- #include "mtools.h"
- #include "vfat.h"
- #include "file.h"
-
- /* #define DEBUG */
-
- char *short_illegals=";+=[]',\"*\\<>/?:|";
- char *long_illegals = "\"*\\<>/?:|\005";
-
- /* Automatically derive a new name */
- static void autorename(char *name,
- char tilda, char dot, char *illegals,
- int limit, int bump)
- {
- int tildapos, dotpos;
- unsigned int seqnum=0, maxseq=0;
- char tmp;
- char *p;
-
- #ifdef DEBUG
- printf("In autorename for name=%s.\n", name);
- #endif
- tildapos = -1;
-
- for(p=name; *p ; p++)
- if((*p < ' ' && *p != '\005') || strchr(illegals, *p)) {
- *p = '_';
- bump = 0;
- }
-
- for(dotpos=0;
- name[dotpos] && dotpos < limit && name[dotpos] != dot ;
- dotpos++) {
- if(name[dotpos] == tilda) {
- tildapos = dotpos;
- seqnum = 0;
- maxseq = 1;
- } else if (name[dotpos] >= '0' && name[dotpos] <= '9') {
- seqnum = seqnum * 10 + name[dotpos] - '0';
- maxseq = maxseq * 10;
- } else
- tildapos = -1; /* sequence number interrupted */
- }
- if(tildapos == -1) {
- /* no sequence number yet */
- if(dotpos > limit - 2) {
- tildapos = limit - 2;
- dotpos = limit;
- } else {
- tildapos = dotpos;
- dotpos += 2;
- }
- seqnum = 1;
- } else {
- if(bump)
- seqnum++;
- if(seqnum > 999999) {
- seqnum = 1;
- tildapos = dotpos - 2;
- /* this matches Win95's behavior, and also guarantees
- * us that the sequence numbers never get shorter */
- }
- if (seqnum == maxseq) {
- if(dotpos >= limit)
- tildapos--;
- else
- dotpos++;
- }
- }
-
- tmp = name[dotpos];
- sprintf(name+tildapos,"%c%d",tilda, seqnum);
- if(dot)
- name[dotpos]=tmp;
- /* replace the character if it wasn't a space */
- }
-
-
- void autorename_short(char *name, int bump)
- {
- autorename(name, '~', ' ', short_illegals, 8, bump);
- }
-
- void autorename_long(char *name, int bump)
- {
- autorename(name, '-', '\0', long_illegals, 255, bump);
- }
-
- void clear_vfat(struct vfat_state *v)
- {
- v->subentries = 0;
- v->status = 0;
- }
-
-
- /* sum_shortname
- *
- * Calculate the checksum that results from the short name in *dir.
- *
- * The sum is formed by circularly right-shifting the previous sum
- * and adding in each character, from left to right, padding both
- * the name and extension to maximum length with spaces and skipping
- * the "." (hence always summing exactly 11 characters).
- *
- * This exact algorithm is required in order to remain compatible
- * with Microsoft Windows-95 and Microsoft Windows NT 3.5.
- * Thanks to Jeffrey Richter of Microsoft Systems Journal for
- * pointing me to the correct algorithm.
- *
- * David C. Niemi (niemidc@erols.com) 95.01.19
- */
- unsigned char sum_shortname(name)
- char *name;
- {
- unsigned char sum;
- int j;
-
- for (j=sum=0; j<11; ++j)
- sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1)
- + (name[j] ? name[j] : ' ');
- return(sum);
- }
-
- /* check_vfat
- *
- * Inspect a directory and any associated VSEs.
- * Return 1 if the VSEs comprise a valid long file name,
- * 0 if not.
- */
- int check_vfat(struct vfat_state *v, struct directory *dir)
- {
- char name[12];
-
- if (! v->subentries) {
- #ifdef DEBUG
- fprintf(stderr, "check_vfat: no VSEs.\n");
- #endif
- return 0;
- }
-
- strncpy((char *)name, (char *)dir->name, 8);
- strncpy((char *)name + 8, (char *)dir->ext, 3);
- name[11] = '\0';
-
- if (v->sum != sum_shortname(name))
- return 0;
-
- if( (v->status & ((1<<v->subentries) - 1)) != (1<<v->subentries) - 1)
- return 0; /* missing entries */
-
- /* zero out byte following last entry, for good measure */
- v->name[VSE_NAMELEN * v->subentries] = 0;
-
- return 1;
- }
-
-
- void clear_vses(Stream_t *Dir, int entry, int last)
- {
- struct directory dir;
-
- maximize(&last, entry + MAX_VFAT_SUBENTRIES);
- for (; entry <= last; ++entry) {
- #ifdef DEBUG
- fprintf(stderr,"Clearing entry %d.\n", entry);
- #endif
- dir_read(Dir, &dir, entry, NULL);
- if(!dir.name[0] || dir.name[0] == DELMARK)
- break;
- dir.name[0] = DELMARK;
- if (dir.attr == 0xf)
- dir.attr = '\0';
- dir_write(Dir, entry, &dir);
- }
- }
-
- int write_vfat(Stream_t *Dir, char *shortname, char *longname, int start)
- {
- struct vfat_subentry vse;
- int vse_id, num_vses;
- char *c;
-
- #ifdef DEBUG
- printf("Entering write_vfat with longname=\"%s\", start=%d.\n",longname,start);
- #endif
- /* Fill in invariant part of vse */
- vse.attribute = 0x0f;
- vse.hash1 = vse.sector_l = vse.sector_u = 0;
- vse.sum = sum_shortname(shortname);
- #ifdef DEBUG
- printf("Wrote checksum=%d for shortname %s.\n", vse.sum,shortname);
- #endif
-
- num_vses = strlen(longname)/VSE_NAMELEN + 1;
- for (vse_id = num_vses; vse_id; --vse_id) {
- int end = 0;
-
- c = longname + (vse_id - 1) * VSE_NAMELEN;
-
-
- c += unicode_write(c, vse.text1, VSE1SIZE, &end);
- c += unicode_write(c, vse.text2, VSE2SIZE, &end);
- c += unicode_write(c, vse.text3, VSE3SIZE, &end);
-
-
- vse.id = (vse_id == num_vses) ? (vse_id | VSE_LAST) : vse_id;
- #ifdef DEBUG
- printf("Writing longname=(%s), VSE %d (%13s) at %d, end = %d.\n",
- longname, vse_id, longname + (vse_id-1) * VSE_NAMELEN,
- start + num_vses - vse_id, start + num_vses);
- #endif
- dir_write(Dir, start + num_vses - vse_id,
- (struct directory *)&vse);
- }
- return start + num_vses;
- }
-
- /*
- * vfat_lookup looks for filenames in directory dir.
- * if a name if found, it is returned in outname
- * if applicable, the file is opened and its stream is returned in File
- */
-
- int vfat_lookup(Stream_t *Dir, Stream_t *Fs, struct directory *dir,
- int *entry, int *vfat_start,
- char *filename,
- int flags, char *outname, char *shortname, char *longname,
- Stream_t **File)
- {
- int found;
- struct vfat_state vfat;
- char newfile[13];
- int vfat_present = 0; /* zeroed by clear_vfat, but make GCC happy */
-
- if (*entry == -1)
- return -1;
-
- found = 0;
- clear_vfat(&vfat);
- while(1){
- if(!dir_read(Dir, dir, *entry, &vfat)){
- if(vfat_start)
- *vfat_start = *entry;
- break;
- }
- (*entry)++;
-
- /*---------------- Empty ---------------*/
- if (dir->name[0] == '\0'){
- if(!vfat_start)
- break;
- continue;
- }
-
- if (dir->attr == 0x0f) {
- /* VSE, keep going */
- continue;
- }
-
- /* If we get here, it's a short name FAT entry, maybe erased.
- * thus we should make sure that the vfat structure will be
- * cleared before the next loop run */
-
- /* entry of non-requested type */
- if ( (dir->name[0] == DELMARK) ||
- ((dir->attr & 0x10) && !(flags & ACCEPT_DIR)) ||
- ((dir->attr & 0x8) && !(flags & ACCEPT_LABEL)) ||
- (( !(dir->attr & 0x18)) && !(flags & ACCEPT_PLAIN))){
- clear_vfat(&vfat);
- continue;
- }
-
- vfat_present = check_vfat(&vfat, dir);
- if (vfat_start) {
- *vfat_start = *entry - 1;
- if(vfat_present)
- *vfat_start -= vfat.subentries;
- }
-
- if (dir->attr & 0x8){
- strncpy(newfile, dir->name,8);
- newfile[8]='\0';
- strncat(newfile, dir->ext,3);
- newfile[11]='\0';
- } else
- unix_name(dir->name, dir->ext, dir->Case, newfile);
-
-
- if(flags & MATCH_ANY){
- found = 1;
- break;
- }
-
-
- /*---------- multiple files ----------*/
- #ifdef DEBUG
- printf(
- "!single, vfat_present=%d, vfat.name=%s, newfile=%s, filename=%s.\n",
- vfat_present, vfat.name, newfile, filename);
- #endif
- if ((vfat_present && match(vfat.name, filename, outname, 0)) ||
- match(newfile, filename, outname, 1)) {
- found = 1;
- break;
- }
- clear_vfat(&vfat);
- }
-
- if(found){
- if((flags & DO_OPEN) && Fs && File){
- *File = open_file(COPY(Fs), dir);
- if (! *File)
- FREE( &Fs);
- }
- if(longname){
- if(vfat_present)
- strcpy(longname, vfat.name);
- else
- *longname ='\0';
- }
- if(shortname)
- strcpy(shortname, newfile);
-
- return 0; /* file found */
- } else {
- *entry = -1;
- return -1; /* no file found */
- }
- }
-
- /* End vfat.c */
-