--- cfs_fh.c.orig	Thu May  3 20:24:59 2001
+++ cfs_fh.c	Sat Mar 12 20:21:46 2005
@@ -177,6 +177,13 @@
 		perror("write");
 		return -1;
 	}
+	/* due to the way the file is padded we may actually have to
+	   truncate it here. This happens when the write is at the end of
+	   the file, is shorter than CFSBLOCK and brings the file to a length
+	   which is evenly dividable by CFSBLOCK */
+	if (offset+len > dtov(sb.st_size) && vtod(offset+len) < sb.st_size) {
+		ftruncate(fd, vtod(offset+len));
+	}
 	/* iolen may contain CFSBLOCK extra chars */
 	return(dtov(iolen)-fronterr);
 }
@@ -195,30 +202,39 @@
      char *s;
 {
 	static char cryptname[NFS_MAXNAMLEN+1];
+	static const u_char hexdigit[16] = {
+		'0', '1', '2', '3', '4', '5', '6', '7',
+		'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+	};
 	u_char cryptstring[MAXCLEARNAME+CFSBLOCK+1];
-	u_char x[3];
 	u_long l;
-	int i;
+	int i, j;
 
 	if ((s==NULL) || ((l=strlen(s)+1)>MAXCLEARNAME))
 		return NULL;
 	if (!strcmp(s,".") || !strcmp(s,".."))
 		return s;
 	l=(l+(CFSBLOCK-1)) & (~(CFSBLOCK-1));
+	if (l >= (sizeof(cryptname) >> 1))
+		return NULL;
 	bzero((char *)cryptstring,l);
 	strcpy(cryptstring,s);
 	chksum(cryptstring,l);
 	doencrypt(key,cryptstring,l,10241,zerovect);
-	cryptname[0]='\0';
+	j = 0;
 	for (i=0; i<l; i++) {
-		sprintf((char *)x,"%02x",cryptstring[i]);
-		strcat(cryptname,x);
+		u_char b = cryptstring[i];
+		cryptname[j++] = hexdigit[(b >> 4) & 15];
+		cryptname[j++] = hexdigit[b & 15];
 	}
+	cryptname[j] = '\0';
 	return cryptname;
 }
 
 /*
- * set high order bits
+ * Carefully frob the high order bits of s in a way that is both easily
+ * reversible (see unchksum) and backwards-compatible (at least for 7-bit
+ * characters).
  */
 chksum(s,l)
      char *s;
@@ -229,17 +245,47 @@
 	u_char bits[8];
 
 	acc=0;
-	for (i=0; s[i]!='\0'; i++)
-		acc += s[i]*((i%6)+1);
+	/* Everything we do here must be reproducible without knowledge of
+	   bit 7 because unchksum won't have that information.  Therefore,
+	   only accumulate the lower 7 bits of each char and stop at the
+	   first occurrence of either 0x00 or 0x80.  Note that, for inputs
+	   with bit 7 constantly zero, this is equivalent to looking at the
+	   whole string. */
+	for (i=0; (s[i]&0x7f) != '\0'; i++)
+		acc += (s[i]&0x7f)*((i%6)+1);
+	for (; s[i]!='\0'; i++) /* advance i if we stopped at a 0x80 */
+		;
 	for (i++; i<l; i++)	/* fill up the end */
 		s[i] = s[i%8];
 	for (i=0; i<8; i++)
 		bits[i] = (acc<<(i%8))&0x80;
 	for (i=0; i<l; i++)
-		s[i] |= bits[i%8];
+		s[i] ^= bits[i%8];
 }
 
+void
+unchksum(s,l)
+     char *s;
+     long l;
+{
+	u_long acc;
+	int i;
+	u_char bits[8];
 
+	acc=0;
+	for (i=0; (s[i]&0x7f) != '\0'; i++)
+		acc += (s[i]&0x7f)*((i%6)+1);
+	for (i=0; i<8; i++)
+		bits[i] = (acc<<(i%8))&0x80;
+	for (i=0; i<l; i++) {
+		s[i] ^= bits[i%8];
+		/* not sure whether this actually buys any performance */
+		if(s[i]=='\0')
+			break;  /* found end of filename, can stop here */
+	}
+}
+
+
 /*
  * decrypt path component
  *  leaving "." and ".."
@@ -279,9 +325,7 @@
 	if (l%CFSBLOCK)
 		return NULL;
 	dodecrypt(key,clearstring,l,10241,zerovect);
-	for (i=0; (clearstring[i]&0x7f) !='\0'; i++)
-		clearstring[i] &= 0x7f;
-	clearstring[i]='\0';
+	unchksum(clearstring,l);
 	return clearstring;
 }
 
@@ -359,11 +403,11 @@
 
 
 static fh_u roothandle;
-cfs_fileid rootnode={1,0,"\0\0\0\0\0\0\0\0","/NOWHERE/null",NULL,NULL,0,NULL,NULL};/* fileid=1; should be unique */
+cfs_fileid rootnode={1,0,{0,0,0,0,0,0,0,0},{'/','N','O','W','H','E','R','E','/','n','u','l','l'},NULL,NULL,0,NULL,NULL};/* fileid=1; should be unique */
 nfstime roottime={0,0};
 
 /* Had to change this - someone else was using the same magic number! */
-/* PLEASE change this value if you're going to re-use this code for
+/* PLEASE change this value if you're going to re-use this code for */
 /* something else!  Otherwise your FS and CFS can't both run... */
 /* static u_char magictest[8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef}; */
 static u_char magictest[8]="M.Blaze";
@@ -514,10 +558,44 @@
 cfsno(err)
      int err;
 {
-/* 	if (err==ENOENT)
+	switch (err) {
+	case 0:
+		return NFS_OK;
+	case EPERM:
+		return NFSERR_PERM;
+	case ENOENT:
+		return NFSERR_NOENT;
+	case EIO:
+		return NFSERR_IO;
+	case ENXIO:
+		return NFSERR_NXIO;
+	case EACCES:
+		return NFSERR_ACCES;
+	case EEXIST:
+		return NFSERR_EXIST;
+	case ENODEV:
+		return NFSERR_NODEV;
+	case ENOTDIR:
+		return NFSERR_NOTDIR;
+	case EISDIR:
+		return NFSERR_ISDIR;
+	case EFBIG:
+		return NFSERR_FBIG;
+	case ENOSPC:
+		return NFSERR_NOSPC;
+	case EROFS:
+		return NFSERR_ROFS;
+	case ENAMETOOLONG:
+		return NFSERR_NAMETOOLONG;
+	case ENOTEMPTY:
+		return NFSERR_NOTEMPTY;
+	case EDQUOT:
+		return NFSERR_DQUOT;
+	case ESTALE:
 		return NFSERR_STALE;
-	else */
+	default:
 		return err;
+	}
 }
 
 
@@ -732,12 +810,17 @@
 {
 	char path[NFS_MAXPATHLEN+1];
 	struct stat sb;
+	int l;
 	
 	if (p==NULL) {
 		cfserrno=NFSERR_STALE;
 		return -2;
 	}
-	sprintf(path,"%s/%s",p->name,comp);
+	l = snprintf(path, sizeof(path), "%s/%s", p->name, comp);
+	if (l < 0 || l >= sizeof(path)) {
+		cfserrno = NFSERR_NAMETOOLONG;
+		return -2;
+	}
 	if (mkdir(path,0)<0)
 		return -1;
 	if (stat(path,&sb)<0)
@@ -766,12 +849,22 @@
 		u_long i[2];
 	} buf;
 	char linkname[NFS_MAXPATHLEN+1];
+	int l;
 	
 	if (p==NULL) {
 		cfserrno=NFSERR_STALE;
 		return -2;
 	}
-	sprintf(path,"%s/%s",p->name,comp);
+	l = snprintf(path, sizeof(path), "%s/%s", p->name, comp);
+	if (l < 0 || l >= sizeof(path)) {
+		cfserrno = NFSERR_NAMETOOLONG;
+		return -2;
+	}
+	l = snprintf(linkname, sizeof(linkname), "%s/.pvect_%s", p->name, comp);
+	if (l < 0 || l >= sizeof(linkname)) {
+		cfserrno = NFSERR_NAMETOOLONG;
+		return -2;
+	}
 
 	if ((fd=open(path,O_CREAT|O_WRONLY|O_EXCL,0))<0) {
 		if (errno==EEXIST) {
@@ -785,7 +878,6 @@
 	if (fstat(fd,&sb)<0)
 		return -1;
 	close(fd);
-	sprintf(linkname,"%s/.pvect_%s",p->name,comp);
 	if (!rs) {
 	   if (p->ins->highsec) {	/* create new pert file iff highsec */
 		/* note that there's a race condition here until the simlink */
@@ -800,8 +892,8 @@
 		/* hash. but this doesn't really matter since collisions */
 		/* are rare.  we could save all 64 bits, but the encoding */
 		/* of the link would get messy and large */
-		sprintf(vect,"%02x%02x%02x%02x",
-			buf.ch[0],buf.ch[1],buf.ch[2],buf.ch[3]);
+		(void)snprintf(vect, sizeof(vect), "%02x%02x%02x%02x",
+			       buf.ch[0], buf.ch[1], buf.ch[2], buf.ch[3]);
 		if (symlink(vect,linkname) != 0) {
 			strcpy(linkname,"/NOWHERE/null");
 			bcopy((char *)zerovect,(char *)vect,8);
@@ -839,6 +931,7 @@
 	char linkname[NFS_MAXPATHLEN+1];
 	char vect[NFS_MAXPATHLEN+1];
 	struct stat sb;
+	int l;
 	
 	if (p==NULL) {
 		cfserrno=NFSERR_STALE;
@@ -852,12 +945,20 @@
 	}
 	if ((p->parent==0) && (!strcmp(comp,"..")))
 		return fhrootlook(p->ins->name,h);
-	sprintf(path,"%s/%s",p->name,comp);
+	l = snprintf(path, sizeof(path), "%s/%s", p->name, comp);
+	if (l < 0 || l >= sizeof(path)) {
+		cfserrno = NFSERR_NAMETOOLONG;
+		return -2;
+	}
 	if (lstat(path,&sb)<0) {
 		return -1;	/* just need the inode */
 	}
 	/* check for a linkfile */
-	sprintf(linkname,"%s/.pvect_%s",p->name,comp);
+	l = snprintf(linkname, sizeof(linkname), "%s/.pvect_%s", p->name, comp);
+	if (l < 0 || l >= sizeof(linkname)) {
+		cfserrno = NFSERR_NAMETOOLONG;
+		return -2;
+	}
 	if (readlink(linkname,vect,9) != 8) {
 		bcopy((char *)zerovect,(char *)vect,8);
 		strcpy(linkname,"/NOWHERE/null");
@@ -980,13 +1081,22 @@
 	char path[NFS_MAXPATHLEN+1];
 	char linkname[NFS_MAXPATHLEN+1];
 	int ret;
+	int l;
 
 	if (f==NULL) {
 		cfserrno=NFSERR_STALE;
 		return -2;
 	}
-	sprintf(linkname,"%s/.pvect_%s",f->name,s);
-	sprintf(path,"%s/%s",f->name,s);
+	l = snprintf(path, sizeof(path), "%s/%s", f->name, s);
+	if (l < 0 || l >= sizeof(path)) {
+		cfserrno = NFSERR_NAMETOOLONG;
+		return -2;
+	}
+	l = snprintf(linkname, sizeof(linkname), "%s/.pvect_%s", f->name, s);
+	if (l < 0 || l >= sizeof(linkname)) {
+		cfserrno = NFSERR_NAMETOOLONG;
+		return -2;
+	}
 	/* note that we don't bother to check and see if there's a
 	   handle allocated for this - just wait for the inode to be
 	   reclaimed */
@@ -1001,13 +1111,21 @@
      char *s;
 {
 	char path[NFS_MAXPATHLEN+1];
+	int l;
+	int err;
 
 	if (f==NULL) {
 		cfserrno=NFSERR_STALE;
 		return -2;
 	}
-	sprintf(path,"%s/%s",f->name,s);
-	return (rmdir(path));
+	l = snprintf(path, sizeof(path), "%s/%s", f->name, s);
+	if (l < 0 || l >= sizeof(path)) {
+		cfserrno = NFSERR_NAMETOOLONG;
+		return -2;
+	}
+	if ((err = rmdir(path)) < 0)
+		cfserrno = cfsno(errno);
+	return err;
 }
 
 DIR *
@@ -1055,15 +1173,24 @@
 	char linkname[NFS_MAXPATHLEN+1];
 	char vectval[9];
 	int ret;
+	int l;
 	
 	if ((f==NULL)||(t==NULL)) {
 		cfserrno=NFSERR_STALE;
 		return -2;
 	}
-	sprintf(buf,"%s/%s",t->name,n);
+	l = snprintf(buf, sizeof(buf), "%s/%s", t->name, n);
+	if (l < 0 || l >= sizeof(buf)) {
+		cfserrno = NFSERR_NAMETOOLONG;
+		return -2;
+	}
+	l = snprintf(linkname, sizeof(linkname), "%s/.pvect_%s", t->name, n);
+	if (l < 0 || l >= sizeof(buf)) {
+		cfserrno = NFSERR_NAMETOOLONG;
+		return -2;
+	}
 	if ((ret=link(f->name,buf))!=0)
 			return ret;
-	sprintf(linkname,"%s/.pvect_%s",t->name,n);
 	unlink(linkname);
 	if (readlink(f->vectname,vectval,9) == 8) {
 		vectval[8]='\0';
@@ -1079,12 +1206,17 @@
      char *t;
 {
 	char buf[NFS_MAXPATHLEN+1];
+	int l;
 	
 	if (f==NULL) {
 		cfserrno=NFSERR_STALE;
 		return -2;
 	}
-	sprintf(buf,"%s/%s",f->name,n);
+	l = snprintf(buf, sizeof(buf), "%s/%s", f->name, n);
+	if (l < 0 || l >= sizeof(buf)) {
+		cfserrno = NFSERR_NAMETOOLONG;
+		return -2;
+	}
 	return (symlink(t,buf));
 }
 
@@ -1100,15 +1232,32 @@
 	char fblink[NFS_MAXPATHLEN+1];
 	char tblink[NFS_MAXPATHLEN+1];
 	char vectval[9];
+	int l;
 	
 	if ((f==NULL)||(t==NULL)) {
 		cfserrno=NFSERR_STALE;
 		return -2;
 	}
-	sprintf(fb,"%s/%s",f->name,fn);
-	sprintf(tb,"%s/%s",t->name,tn);
-	sprintf(fblink,"%s/.pvect_%s",f->name,fn);
-	sprintf(tblink,"%s/.pvect_%s",t->name,tn);
+	l = snprintf(fb, sizeof(fb), "%s/%s", f->name, fn);
+	if (l < 0 || l >= sizeof(fb)) {
+		cfserrno = NFSERR_NAMETOOLONG;
+		return -2;
+	}
+	l = snprintf(tb, sizeof(tb), "%s/%s", t->name, tn);
+	if (l < 0 || l >= sizeof(tb)) {
+		cfserrno = NFSERR_NAMETOOLONG;
+		return -2;
+	}
+	l = snprintf(fblink, sizeof(fblink), "%s/.pvect_%s", f->name, fn);
+	if (l < 0 || l >= sizeof(fblink)) {
+		cfserrno = NFSERR_NAMETOOLONG;
+		return -2;
+	}
+	l = snprintf(tblink, sizeof(tblink), "%s/.pvect_%s", t->name, tn);
+	if (l < 0 || l >= sizeof(tblink)) {
+		cfserrno = NFSERR_NAMETOOLONG;
+		return -2;
+	}
 	if (rename(fb,tb)==0) { /* now we have to do a lookup */
 		unlink(tblink);	/* may be a quick race cndtn here */
 		if (readlink(fblink,vectval,9)==8) {
@@ -1160,7 +1309,8 @@
 	} else while (cookie<(NINSTANCES+2)) {
 		if (instances[cookie-2] != NULL) {
 			if (instances[cookie-2]->anon)
-				sprintf(d.d_name,".ANON_%d",cookie-2);
+				(void)snprintf(d.d_name, sizeof(d.d_name),
+				               ".ANON_%ld", cookie-2);
 			else
 				strcpy(d.d_name,
 				       instances[cookie-2]->name);
