disk/format: implement long name support
This commit is contained in:
parent
ac98922f44
commit
a611fe20e1
1 changed files with 177 additions and 17 deletions
|
@ -108,6 +108,12 @@ struct Dosdir
|
|||
uchar length[4];
|
||||
};
|
||||
|
||||
enum {
|
||||
DOSDIRSIZE = 32,
|
||||
DOSRUNE = 13, /* runes per dosdir in a long file name */
|
||||
DOSNAMELEN = 261,
|
||||
};
|
||||
|
||||
#define DRONLY 0x01
|
||||
#define DHIDDEN 0x02
|
||||
#define DSYSTEM 0x04
|
||||
|
@ -177,7 +183,7 @@ enum
|
|||
|
||||
void dosfs(int, int, Disk*, char*, int, char*[], int);
|
||||
ulong clustalloc(int);
|
||||
void addrname(uchar*, Dir*, char*, ulong);
|
||||
uchar* addrname(uchar*, Dir*, char*, ulong);
|
||||
void sanitycheck(Disk*);
|
||||
|
||||
void
|
||||
|
@ -568,18 +574,18 @@ Tryagain:
|
|||
for(i=0;; i++){
|
||||
fatsecs = (fatbits*clusters + 8*secsize - 1)/(8*secsize);
|
||||
rootsecs = volsecs/200;
|
||||
rootfiles = rootsecs * (secsize/sizeof(Dosdir));
|
||||
rootfiles = rootsecs * (secsize/DOSDIRSIZE);
|
||||
if(rootfiles > 512){
|
||||
rootfiles = 512;
|
||||
rootsecs = rootfiles/(secsize/sizeof(Dosdir));
|
||||
rootsecs = rootfiles/(secsize/DOSDIRSIZE);
|
||||
}
|
||||
if(fatbits == 32){
|
||||
rootsecs -= (rootsecs % clustersize);
|
||||
if(rootsecs <= 0)
|
||||
rootsecs = clustersize;
|
||||
rootfiles = rootsecs * (secsize/sizeof(Dosdir));
|
||||
rootfiles = rootsecs * (secsize/DOSDIRSIZE);
|
||||
}
|
||||
data = nresrv + 2*fatsecs + (rootfiles*sizeof(Dosdir) + secsize-1)/secsize;
|
||||
data = nresrv + 2*fatsecs + (rootfiles*DOSDIRSIZE + secsize-1)/secsize;
|
||||
newclusters = 2 + (volsecs - data)/clustersize;
|
||||
if(newclusters == clusters)
|
||||
break;
|
||||
|
@ -717,7 +723,7 @@ if(chatty) print("files @%lluX\n", seek(disk->wfd, 0LL, 1));
|
|||
* If we have any arguments, process
|
||||
* them and write out.
|
||||
*/
|
||||
for(p = root; argc > 0; argc--, argv++, p += sizeof(Dosdir)){
|
||||
for(p = root; argc > 0; argc--, argv++, p += DOSDIRSIZE){
|
||||
if(p >= (root+(rootsecs*secsize)))
|
||||
fatal("too many files in root");
|
||||
/*
|
||||
|
@ -776,7 +782,7 @@ if(chatty) print("%s @%lluX\n", d->name, seek(disk->wfd, 0LL, 1));
|
|||
* Add the filename to the root.
|
||||
*/
|
||||
fprint(2, "add %s at clust %lux\n", d->name, x);
|
||||
addrname(p, d, *argv, x);
|
||||
p = addrname(p, d, *argv, x);
|
||||
free(d);
|
||||
}
|
||||
|
||||
|
@ -864,6 +870,20 @@ clustalloc(int flag)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
puttime(Dosdir *d)
|
||||
{
|
||||
Tm *t = localtime(time(0));
|
||||
ushort x;
|
||||
|
||||
x = (t->hour<<11) | (t->min<<5) | (t->sec>>1);
|
||||
d->time[0] = x;
|
||||
d->time[1] = x>>8;
|
||||
x = ((t->year-80)<<9) | ((t->mon+1)<<5) | t->mday;
|
||||
d->date[0] = x;
|
||||
d->date[1] = x>>8;
|
||||
}
|
||||
|
||||
void
|
||||
putname(char *p, Dosdir *d)
|
||||
{
|
||||
|
@ -885,21 +905,132 @@ putname(char *p, Dosdir *d)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
puttime(Dosdir *d)
|
||||
int
|
||||
islongname(char *buf)
|
||||
{
|
||||
Tm *t = localtime(time(0));
|
||||
ushort x;
|
||||
char *p, *dot;
|
||||
int c, isextended, is8dot3, ndot;
|
||||
|
||||
x = (t->hour<<11) | (t->min<<5) | (t->sec>>1);
|
||||
d->time[0] = x;
|
||||
d->time[1] = x>>8;
|
||||
x = ((t->year-80)<<9) | ((t->mon+1)<<5) | t->mday;
|
||||
d->date[0] = x;
|
||||
d->date[1] = x>>8;
|
||||
p = buf;
|
||||
isextended = 0;
|
||||
dot = nil;
|
||||
ndot = 0;
|
||||
while(c = (uchar)*p){
|
||||
if(c&0x80) /* UTF8 */
|
||||
isextended = 1;
|
||||
else if(c == '.'){
|
||||
dot = p;
|
||||
ndot++;
|
||||
}else if(strchr("+,:;=[] ", c))
|
||||
isextended = 1;
|
||||
p++;
|
||||
}
|
||||
is8dot3 = (ndot==0 && p-buf <= 8) || (ndot==1 && dot-buf <= 8 && p-(dot+1) <= 3);
|
||||
return isextended || !is8dot3;
|
||||
}
|
||||
|
||||
void
|
||||
putnamesect(uchar *slot, Rune *longname, int curslot, int first, int sum)
|
||||
{
|
||||
Rune r;
|
||||
Dosdir ds;
|
||||
int i, j;
|
||||
|
||||
memset(&ds, 0xff, sizeof ds);
|
||||
ds.attr = 0xf;
|
||||
ds.reserved[0] = 0;
|
||||
ds.reserved[1] = sum;
|
||||
ds.start[0] = 0;
|
||||
ds.start[1] = 0;
|
||||
if(first)
|
||||
ds.name[0] = 0x40 | curslot;
|
||||
else
|
||||
ds.name[0] = curslot;
|
||||
memmove(slot, &ds, DOSDIRSIZE);
|
||||
|
||||
j = (curslot-1) * DOSRUNE;
|
||||
|
||||
for(i = 1; i < 11; i += 2){
|
||||
r = longname[j++];
|
||||
slot[i] = r;
|
||||
slot[i+1] = r >> 8;
|
||||
if(r == 0)
|
||||
return;
|
||||
}
|
||||
for(i = 14; i < 26; i += 2){
|
||||
r = longname[j++];
|
||||
slot[i] = r;
|
||||
slot[i+1] = r >> 8;
|
||||
if(r == 0)
|
||||
return;
|
||||
}
|
||||
for(i = 28; i < 32; i += 2){
|
||||
r = longname[j++];
|
||||
slot[i] = r;
|
||||
slot[i+1] = r >> 8;
|
||||
if(r == 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
isdoschar(int c)
|
||||
{
|
||||
if(c <= 0)
|
||||
return 0;
|
||||
if(c >= 'a' && c <= 'z')
|
||||
return 1;
|
||||
if(c >= 'A' && c <= 'Z')
|
||||
return 1;
|
||||
if(c >= '0' && c <= '9')
|
||||
return 1;
|
||||
return strchr("$%'-_@~`!(){}^#&", c) != nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* make an alias for a valid long file name
|
||||
*/
|
||||
void
|
||||
mkalias(char *name, char *sname, int id)
|
||||
{
|
||||
Rune r;
|
||||
char *s, *e, sid[10];
|
||||
int i, esuf, v;
|
||||
|
||||
e = strrchr(name, '.');
|
||||
if(e == nil)
|
||||
e = strchr(name, '\0');
|
||||
|
||||
s = name;
|
||||
i = 0;
|
||||
while(s < e && i < 6){
|
||||
if(isdoschar(*s))
|
||||
sname[i++] = *s++;
|
||||
else
|
||||
s += chartorune(&r, s);
|
||||
}
|
||||
|
||||
v = snprint(sid, 10, "%d", id);
|
||||
if(i + 1 + v > 8)
|
||||
i = 8 - 1 - v;
|
||||
sname[i++] = '~';
|
||||
strcpy(&sname[i], sid);
|
||||
i += v;
|
||||
|
||||
sname[i++] = '.';
|
||||
esuf = i + 3;
|
||||
while(*e && i < esuf){
|
||||
if(isdoschar(*e))
|
||||
sname[i++] = *e++;
|
||||
else
|
||||
e += chartorune(&r, e);
|
||||
}
|
||||
if(sname[i-1] == '.')
|
||||
i--;
|
||||
sname[i] = '\0';
|
||||
}
|
||||
|
||||
uchar*
|
||||
addrname(uchar *entry, Dir *dir, char *name, ulong start)
|
||||
{
|
||||
char *s;
|
||||
|
@ -912,6 +1043,34 @@ addrname(uchar *entry, Dir *dir, char *name, ulong start)
|
|||
s = name;
|
||||
|
||||
d = (Dosdir*)entry;
|
||||
if(islongname(s)){
|
||||
Rune longname[DOSNAMELEN] = {0};
|
||||
char shortname[13] = {0};
|
||||
static int aliasid;
|
||||
int i, len, sum;
|
||||
uchar *slot;
|
||||
|
||||
mkalias(s, shortname, aliasid++);
|
||||
putname(shortname, d);
|
||||
|
||||
sum = 0;
|
||||
for(i = 0; i < 11; i++)
|
||||
sum = (((sum&1)<<7) | ((sum&0xfe)>>1)) + d->name[i];
|
||||
sum &= 0xFF;
|
||||
|
||||
len = 0;
|
||||
while(*s && len < DOSNAMELEN)
|
||||
s += chartorune(&longname[len++], s);
|
||||
|
||||
slot = (uchar*)d;
|
||||
len = (len + DOSRUNE-1) / DOSRUNE;
|
||||
for(i = 0; i < len; i++){
|
||||
putnamesect(slot, longname, len - i, i == 0, sum);
|
||||
slot += DOSDIRSIZE;
|
||||
}
|
||||
d = (Dosdir*)slot;
|
||||
s = shortname;
|
||||
}
|
||||
putname(s, d);
|
||||
if(cistrcmp(s, "9load") == 0 || cistrncmp(s, "9boot", 5) == 0)
|
||||
d->attr = DSYSTEM;
|
||||
|
@ -924,4 +1083,5 @@ addrname(uchar *entry, Dir *dir, char *name, ulong start)
|
|||
d->length[1] = dir->length>>8;
|
||||
d->length[2] = dir->length>>16;
|
||||
d->length[3] = dir->length>>24;
|
||||
return (uchar*)d;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue