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 >
Wrap
Text File
|
1997-11-12
|
8KB
|
357 lines
/* vfat.c
*
* Miscellaneous VFAT-related functions
*/
#include "sysincludes.h"
#include "msdos.h"
#include "mtools.h"
#include "vfat.h"
#include "file.h"
/* #define DEBUG */
const char *short_illegals=";+=[]',\"*\\<>/?:|";
const char *long_illegals = "\"*\\<>/?:|\005";
/* Automatically derive a new name */
static void autorename(char *name,
char tilda, char dot, const 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, size_t 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, struct directory *dir,
int *entry, int *vfat_start,
const char *filename,
int flags, char *outname, char *shortname, char *longname)
{
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 */
/* deleted file */
if ( (dir->name[0] == DELMARK) ||
((dir->attr & 0x8) && !(flags & ACCEPT_LABEL))){
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);
/*---------- 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(!((flags & MATCH_ANY) ||
(vfat_present && match(vfat.name, filename, outname, 0)) ||
match(newfile, filename, outname, 1))) {
clear_vfat(&vfat);
continue;
}
/* entry of non-requested type */
if((dir->attr & 0x10) && !(flags & ACCEPT_DIR)) {
if(!(flags & (ACCEPT_LABEL|MATCH_ANY|NO_MSG)))
fprintf(stderr,
"Skipping \"%s\", is a directory\n",
newfile);
clear_vfat(&vfat);
continue;
}
if((!(dir->attr & 0x18)) && !(flags & ACCEPT_PLAIN)) {
if(!(flags & (ACCEPT_LABEL|MATCH_ANY|NO_MSG)))
fprintf(stderr,
"Skipping \"%s\", is not a directory\n",
newfile);
clear_vfat(&vfat);
continue;
}
found = 1;
break;
}
if(found){
#if 0
if((flags & DO_OPEN) && Fs && File){
*File = open_file(COPY(Fs), dir);
if (! *File)
FREE( &Fs);
}
#endif
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 */