shithub: riscv

Download patch

ref: a611fe20e16318b4b61dc52b4f71e59ccbc203d5
parent: ac98922f44c3df8839f1bdd07f23fcccf27d0cba
author: cinap_lenrek <[email protected]>
date: Sun Aug 18 21:09:24 EDT 2019

disk/format: implement long name support

--- a/sys/src/cmd/disk/format.c
+++ b/sys/src/cmd/disk/format.c
@@ -108,6 +108,12 @@
 	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 @@
 
 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 @@
 		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 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 @@
 		 * 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);
 	}
 
@@ -865,6 +871,20 @@
 }
 
 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)
 {
 	int i;
@@ -885,21 +905,132 @@
 	}
 }
 
+int
+islongname(char *buf)
+{
+	char *p, *dot;
+	int c, isextended, is8dot3, ndot;
+
+	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
-puttime(Dosdir *d)
+putnamesect(uchar *slot, Rune *longname, int curslot, int first, int sum)
 {
-	Tm *t = localtime(time(0));
-	ushort x;
+	Rune r;
+	Dosdir ds;
+	int i, j;
 
-	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;
+	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 @@
 		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 @@
 	d->length[1] = dir->length>>8;
 	d->length[2] = dir->length>>16;
 	d->length[3] = dir->length>>24;
+	return (uchar*)d;
 }