xref: /plan9/sys/src/cmd/dossrv/dosfs.c (revision b85a83648eec38fe82b6f00adfd7828ceec5ee8d)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <auth.h>
43e12c5d1SDavid du Colombier #include <fcall.h>
53e12c5d1SDavid du Colombier #include "iotrack.h"
63e12c5d1SDavid du Colombier #include "dat.h"
79a747e4fSDavid du Colombier #include "dosfs.h"
83e12c5d1SDavid du Colombier #include "fns.h"
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier void
rversion(void)119a747e4fSDavid du Colombier rversion(void)
123e12c5d1SDavid du Colombier {
139a747e4fSDavid du Colombier 	if(req->msize > Maxiosize)
149a747e4fSDavid du Colombier 		rep->msize = Maxiosize;
159a747e4fSDavid du Colombier 	else
169a747e4fSDavid du Colombier 		rep->msize = req->msize;
179a747e4fSDavid du Colombier 	rep->version = "9P2000";
183e12c5d1SDavid du Colombier }
197dd7cddfSDavid du Colombier 
203e12c5d1SDavid du Colombier void
rauth(void)219a747e4fSDavid du Colombier rauth(void)
223e12c5d1SDavid du Colombier {
239a747e4fSDavid du Colombier 	errno = Enoauth;
243e12c5d1SDavid du Colombier }
257dd7cddfSDavid du Colombier 
263e12c5d1SDavid du Colombier void
rflush(void)273e12c5d1SDavid du Colombier rflush(void)
283e12c5d1SDavid du Colombier {
293e12c5d1SDavid du Colombier }
307dd7cddfSDavid du Colombier 
313e12c5d1SDavid du Colombier void
rattach(void)323e12c5d1SDavid du Colombier rattach(void)
333e12c5d1SDavid du Colombier {
34219b2ee8SDavid du Colombier 	Xfs *xf;
35219b2ee8SDavid du Colombier 	Xfile *root;
363e12c5d1SDavid du Colombier 	Dosptr *dp;
373e12c5d1SDavid du Colombier 
389a747e4fSDavid du Colombier 	root = xfile(req->fid, Clean);
393e12c5d1SDavid du Colombier 	if(!root){
403e12c5d1SDavid du Colombier 		errno = Enomem;
413e12c5d1SDavid du Colombier 		goto error;
423e12c5d1SDavid du Colombier 	}
439a747e4fSDavid du Colombier 	root->xf = xf = getxfs(req->uname, req->aname);
443e12c5d1SDavid du Colombier 	if(!xf)
453e12c5d1SDavid du Colombier 		goto error;
463e12c5d1SDavid du Colombier 	if(xf->fmt == 0 && dosfs(xf) < 0){
473e12c5d1SDavid du Colombier 		errno = Eformat;
483e12c5d1SDavid du Colombier 		goto error;
493e12c5d1SDavid du Colombier 	}
509a747e4fSDavid du Colombier 	root->qid.type = QTDIR;
519a747e4fSDavid du Colombier 	root->qid.path = 0;
523e12c5d1SDavid du Colombier 	root->qid.vers = 0;
533e12c5d1SDavid du Colombier 	root->xf->rootqid = root->qid;
543e12c5d1SDavid du Colombier 	dp = malloc(sizeof(Dosptr));
557dd7cddfSDavid du Colombier 	if(dp == nil){
567dd7cddfSDavid du Colombier 		errno = Enomem;
577dd7cddfSDavid du Colombier 		goto error;
587dd7cddfSDavid du Colombier 	}
593e12c5d1SDavid du Colombier 	root->ptr = dp;
607dd7cddfSDavid du Colombier 	rootfile(root);
619a747e4fSDavid du Colombier 	rep->qid = root->qid;
623e12c5d1SDavid du Colombier 	return;
633e12c5d1SDavid du Colombier error:
643e12c5d1SDavid du Colombier 	if(root)
659a747e4fSDavid du Colombier 		xfile(req->fid, Clunk);
663e12c5d1SDavid du Colombier }
677dd7cddfSDavid du Colombier 
689a747e4fSDavid du Colombier Xfile*
doclone(Xfile * of,int newfid)699a747e4fSDavid du Colombier doclone(Xfile *of, int newfid)
703e12c5d1SDavid du Colombier {
719a747e4fSDavid du Colombier 	Xfile *nf, *next;
727dd7cddfSDavid du Colombier 	Dosptr *dp;
733e12c5d1SDavid du Colombier 
749a747e4fSDavid du Colombier 	nf = xfile(newfid, Clean);
757dd7cddfSDavid du Colombier 	if(!nf){
763e12c5d1SDavid du Colombier 		errno = Enomem;
779a747e4fSDavid du Colombier 		return nil;
787dd7cddfSDavid du Colombier 	}
797dd7cddfSDavid du Colombier 	dp = malloc(sizeof(Dosptr));
807dd7cddfSDavid du Colombier 	if(dp == nil){
817dd7cddfSDavid du Colombier 		errno = Enomem;
829a747e4fSDavid du Colombier 		return nil;
837dd7cddfSDavid du Colombier 	}
847dd7cddfSDavid du Colombier 	next = nf->next;
853e12c5d1SDavid du Colombier 	*nf = *of;
863e12c5d1SDavid du Colombier 	nf->next = next;
879a747e4fSDavid du Colombier 	nf->fid = req->newfid;
883e12c5d1SDavid du Colombier 	nf->ptr = dp;
893e12c5d1SDavid du Colombier 	refxfs(nf->xf, 1);
903e12c5d1SDavid du Colombier 	memmove(dp, of->ptr, sizeof(Dosptr));
917dd7cddfSDavid du Colombier 	dp->p = nil;
927dd7cddfSDavid du Colombier 	dp->d = nil;
939a747e4fSDavid du Colombier 	return nf;
943e12c5d1SDavid du Colombier }
957dd7cddfSDavid du Colombier 
963e12c5d1SDavid du Colombier void
rwalk(void)973e12c5d1SDavid du Colombier rwalk(void)
983e12c5d1SDavid du Colombier {
999a747e4fSDavid du Colombier 	Xfile *f, *nf;
1009a747e4fSDavid du Colombier 	Dosptr dp[1], savedp[1];
1019a747e4fSDavid du Colombier 	int r, longtype;
1029a747e4fSDavid du Colombier 	Qid saveqid;
1033e12c5d1SDavid du Colombier 
1049a747e4fSDavid du Colombier 	rep->nwqid = 0;
1059a747e4fSDavid du Colombier 	nf = nil;
1069a747e4fSDavid du Colombier 	f = xfile(req->fid, Asis);
1079a747e4fSDavid du Colombier 	if(f == nil){
1089a747e4fSDavid du Colombier 		chat("\tno xfile\n");
109*3ff48bf5SDavid du Colombier 		goto error2;
1103e12c5d1SDavid du Colombier 	}
1119a747e4fSDavid du Colombier 	if(req->fid != req->newfid){
1129a747e4fSDavid du Colombier 		nf = doclone(f, req->newfid);
1139a747e4fSDavid du Colombier 		if(nf == nil){
1149a747e4fSDavid du Colombier 			chat("\tclone failed\n");
115*3ff48bf5SDavid du Colombier 			goto error2;
1163e12c5d1SDavid du Colombier 		}
1179a747e4fSDavid du Colombier 		f = nf;
1183e12c5d1SDavid du Colombier 	}
1199a747e4fSDavid du Colombier 
1209a747e4fSDavid du Colombier 	saveqid = f->qid;
1219a747e4fSDavid du Colombier 	memmove(savedp, f->ptr, sizeof(Dosptr));
1229a747e4fSDavid du Colombier 	for(; rep->nwqid < req->nwname && rep->nwqid < MAXWELEM; rep->nwqid++){
1239a747e4fSDavid du Colombier 		chat("\twalking %s\n", req->wname[rep->nwqid]);
1249a747e4fSDavid du Colombier 		if(!(f->qid.type & QTDIR)){
1259a747e4fSDavid du Colombier 			chat("\tnot dir: type=%#x\n", f->qid.type);
1269a747e4fSDavid du Colombier 			goto error;
1279a747e4fSDavid du Colombier 		}
1289a747e4fSDavid du Colombier 		if(strcmp(req->wname[rep->nwqid], ".") == 0){
1299a747e4fSDavid du Colombier 			;
1309a747e4fSDavid du Colombier 		}else if(strcmp(req->wname[rep->nwqid], "..") == 0){
1319a747e4fSDavid du Colombier 			if(f->qid.path != f->xf->rootqid.path){
1323e12c5d1SDavid du Colombier 				r = walkup(f, dp);
1333e12c5d1SDavid du Colombier 				if(r < 0)
1343e12c5d1SDavid du Colombier 					goto error;
1353e12c5d1SDavid du Colombier 				memmove(f->ptr, dp, sizeof(Dosptr));
1367dd7cddfSDavid du Colombier 				if(isroot(dp->addr))
1373e12c5d1SDavid du Colombier 					f->qid.path = f->xf->rootqid.path;
1387dd7cddfSDavid du Colombier 				else
1399a747e4fSDavid du Colombier 					f->qid.path = QIDPATH(dp);
1409a747e4fSDavid du Colombier 			}
1413e12c5d1SDavid du Colombier 		}else{
1429a747e4fSDavid du Colombier 			fixname(req->wname[rep->nwqid]);
1439a747e4fSDavid du Colombier 			longtype = classifyname(req->wname[rep->nwqid]);
1449a747e4fSDavid du Colombier 			if(longtype==Invalid || getfile(f) < 0)
1453e12c5d1SDavid du Colombier 				goto error;
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier 			/*
1487dd7cddfSDavid du Colombier 			 * always do a search for the long name,
1497dd7cddfSDavid du Colombier 			 * because it could be filed as such
1507dd7cddfSDavid du Colombier 			 */
1519a747e4fSDavid du Colombier 			r = searchdir(f, req->wname[rep->nwqid], dp, 0, longtype);
1523e12c5d1SDavid du Colombier 			putfile(f);
1533e12c5d1SDavid du Colombier 			if(r < 0)
1543e12c5d1SDavid du Colombier 				goto error;
1553e12c5d1SDavid du Colombier 			memmove(f->ptr, dp, sizeof(Dosptr));
1567dd7cddfSDavid du Colombier 			f->qid.path = QIDPATH(dp);
1579a747e4fSDavid du Colombier 			f->qid.type = QTFILE;
1587dd7cddfSDavid du Colombier 			if(isroot(dp->addr))
1593e12c5d1SDavid du Colombier 				f->qid.path = f->xf->rootqid.path;
1603e12c5d1SDavid du Colombier 			else if(dp->d->attr & DDIR)
1619a747e4fSDavid du Colombier 				f->qid.type = QTDIR;
1629a747e4fSDavid du Colombier 			else if(dp->d->attr & DSYSTEM){
1639a747e4fSDavid du Colombier 				f->qid.type |= QTEXCL;
1649a747e4fSDavid du Colombier 				if(iscontig(f->xf, dp->d))
1659a747e4fSDavid du Colombier 					f->qid.type |= QTAPPEND;
1669a747e4fSDavid du Colombier 			}
1679a747e4fSDavid du Colombier //ZZZ maybe use other bits than qtexcl & qtapppend
1683e12c5d1SDavid du Colombier 			putfile(f);
1693e12c5d1SDavid du Colombier 		}
1709a747e4fSDavid du Colombier 		rep->wqid[rep->nwqid] = f->qid;
1719a747e4fSDavid du Colombier 	}
1723e12c5d1SDavid du Colombier 	return;
1733e12c5d1SDavid du Colombier error:
1749a747e4fSDavid du Colombier 	f->qid = saveqid;
1759a747e4fSDavid du Colombier 	memmove(f->ptr, savedp, sizeof(Dosptr));
1769a747e4fSDavid du Colombier 	if(nf != nil)
1779a747e4fSDavid du Colombier 		xfile(req->newfid, Clunk);
178*3ff48bf5SDavid du Colombier error2:
1799a747e4fSDavid du Colombier 	if(!errno && !rep->nwqid)
1803e12c5d1SDavid du Colombier 		errno = Enonexist;
1813e12c5d1SDavid du Colombier }
1827dd7cddfSDavid du Colombier 
1833e12c5d1SDavid du Colombier void
ropen(void)1843e12c5d1SDavid du Colombier ropen(void)
1853e12c5d1SDavid du Colombier {
1863e12c5d1SDavid du Colombier 	Xfile *f;
1879a747e4fSDavid du Colombier 	Iosect *p;
1883e12c5d1SDavid du Colombier 	Dosptr *dp;
1897dd7cddfSDavid du Colombier 	int attr, omode;
1903e12c5d1SDavid du Colombier 
1919a747e4fSDavid du Colombier 	f = xfile(req->fid, Asis);
1923e12c5d1SDavid du Colombier 	if(!f || (f->flags&Omodes)){
1933e12c5d1SDavid du Colombier 		errno = Eio;
1943e12c5d1SDavid du Colombier 		return;
1953e12c5d1SDavid du Colombier 	}
1963e12c5d1SDavid du Colombier 	dp = f->ptr;
1977dd7cddfSDavid du Colombier 	omode = 0;
1989a747e4fSDavid du Colombier 	if(!isroot(dp->paddr) && (req->mode & ORCLOSE)){
1993e12c5d1SDavid du Colombier 		/*
2003e12c5d1SDavid du Colombier 		 * check on parent directory of file to be deleted
2013e12c5d1SDavid du Colombier 		 */
2029a747e4fSDavid du Colombier 		p = getsect(f->xf, dp->paddr);
2039a747e4fSDavid du Colombier 		if(p == nil){
2043e12c5d1SDavid du Colombier 			errno = Eio;
2053e12c5d1SDavid du Colombier 			return;
2063e12c5d1SDavid du Colombier 		}
2073e12c5d1SDavid du Colombier 		attr = ((Dosdir *)&p->iobuf[dp->poffset])->attr;
2083e12c5d1SDavid du Colombier 		putsect(p);
2093e12c5d1SDavid du Colombier 		if(attr & DRONLY){
2103e12c5d1SDavid du Colombier 			errno = Eperm;
2113e12c5d1SDavid du Colombier 			return;
2123e12c5d1SDavid du Colombier 		}
2133e12c5d1SDavid du Colombier 		omode |= Orclose;
2149a747e4fSDavid du Colombier 	}else if(req->mode & ORCLOSE)
2153e12c5d1SDavid du Colombier 		omode |= Orclose;
2163e12c5d1SDavid du Colombier 	if(getfile(f) < 0){
2173e12c5d1SDavid du Colombier 		errno = Enonexist;
2183e12c5d1SDavid du Colombier 		return;
2193e12c5d1SDavid du Colombier 	}
2207dd7cddfSDavid du Colombier 	if(!isroot(dp->addr))
2213e12c5d1SDavid du Colombier 		attr = dp->d->attr;
2223e12c5d1SDavid du Colombier 	else
2233e12c5d1SDavid du Colombier 		attr = DDIR;
2249a747e4fSDavid du Colombier 	switch(req->mode & 7){
2253e12c5d1SDavid du Colombier 	case OREAD:
2263e12c5d1SDavid du Colombier 	case OEXEC:
2273e12c5d1SDavid du Colombier 		omode |= Oread;
2283e12c5d1SDavid du Colombier 		break;
2293e12c5d1SDavid du Colombier 	case ORDWR:
2303e12c5d1SDavid du Colombier 		omode |= Oread;
2313e12c5d1SDavid du Colombier 		/* fall through */
2323e12c5d1SDavid du Colombier 	case OWRITE:
2333e12c5d1SDavid du Colombier 		omode |= Owrite;
2343e12c5d1SDavid du Colombier 		if(attr & DRONLY){
2353e12c5d1SDavid du Colombier 			errno = Eperm;
2363e12c5d1SDavid du Colombier 			goto out;
2373e12c5d1SDavid du Colombier 		}
2383e12c5d1SDavid du Colombier 		break;
2393e12c5d1SDavid du Colombier 	default:
2403e12c5d1SDavid du Colombier 		errno = Eio;
2413e12c5d1SDavid du Colombier 		goto out;
2423e12c5d1SDavid du Colombier 	}
2439a747e4fSDavid du Colombier 	if(req->mode & OTRUNC){
2443e12c5d1SDavid du Colombier 		if(attr & DDIR || attr & DRONLY){
2453e12c5d1SDavid du Colombier 			errno = Eperm;
2463e12c5d1SDavid du Colombier 			goto out;
2473e12c5d1SDavid du Colombier 		}
2489a747e4fSDavid du Colombier 		if(truncfile(f, 0) < 0){
2493e12c5d1SDavid du Colombier 			errno = Eio;
2503e12c5d1SDavid du Colombier 			goto out;
2513e12c5d1SDavid du Colombier 		}
2523e12c5d1SDavid du Colombier 	}
2533e12c5d1SDavid du Colombier 	f->flags |= omode;
2549a747e4fSDavid du Colombier 	rep->qid = f->qid;
2559a747e4fSDavid du Colombier 	rep->iounit = 0;
2563e12c5d1SDavid du Colombier out:
2573e12c5d1SDavid du Colombier 	putfile(f);
2583e12c5d1SDavid du Colombier }
2597dd7cddfSDavid du Colombier 
2607dd7cddfSDavid du Colombier static int
mk8dot3name(Xfile * f,Dosptr * ndp,char * name,char * sname)2619a747e4fSDavid du Colombier mk8dot3name(Xfile *f, Dosptr *ndp, char *name, char *sname)
2627dd7cddfSDavid du Colombier {
2637dd7cddfSDavid du Colombier 	Dosptr tmpdp;
2649a747e4fSDavid du Colombier 	int i, longtype;
2657dd7cddfSDavid du Colombier 
2667dd7cddfSDavid du Colombier 	if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
2679a747e4fSDavid du Colombier 		return Invalid;
2687dd7cddfSDavid du Colombier 
2697dd7cddfSDavid du Colombier 	/*
2707dd7cddfSDavid du Colombier 	 * always do a search for the long name,
2717dd7cddfSDavid du Colombier 	 * because it could be filed as such
2727dd7cddfSDavid du Colombier 	 */
2739a747e4fSDavid du Colombier 	fixname(name);
2749a747e4fSDavid du Colombier 	longtype = classifyname(name);
2759a747e4fSDavid du Colombier 	if(longtype==Invalid || searchdir(f, name, ndp, 1, longtype) < 0)
2769a747e4fSDavid du Colombier 		return Invalid;
2777dd7cddfSDavid du Colombier 
2789a747e4fSDavid du Colombier 	if(longtype==Short)
2799a747e4fSDavid du Colombier 		return Short;
2809a747e4fSDavid du Colombier 
2819a747e4fSDavid du Colombier 	if(longtype==ShortLower){
2829a747e4fSDavid du Colombier 		/*
2839a747e4fSDavid du Colombier 		 * alias is the upper-case version, which we
2849a747e4fSDavid du Colombier 		 * already know does not exist.
2859a747e4fSDavid du Colombier 		 */
2869a747e4fSDavid du Colombier 		strcpy(sname, name);
2879a747e4fSDavid du Colombier 		for(i=0; sname[i]; i++)
2889a747e4fSDavid du Colombier 			if('a' <= sname[i] && sname[i] <= 'z')
2899a747e4fSDavid du Colombier 				sname[i] += 'A'-'a';
2909a747e4fSDavid du Colombier 		return ShortLower;
2919a747e4fSDavid du Colombier 	}
2927dd7cddfSDavid du Colombier 
2937dd7cddfSDavid du Colombier 	/*
2947dd7cddfSDavid du Colombier 	 * find alias for the long name
2957dd7cddfSDavid du Colombier 	 */
2967dd7cddfSDavid du Colombier 	for(i=1;; i++){
2977dd7cddfSDavid du Colombier 		mkalias(name, sname, i);
2987dd7cddfSDavid du Colombier 		if(searchdir(f, sname, &tmpdp, 0, 0) < 0)
2999a747e4fSDavid du Colombier 			return Long;
3007dd7cddfSDavid du Colombier 		putsect(tmpdp.p);
3017dd7cddfSDavid du Colombier 	}
3027dd7cddfSDavid du Colombier }
3037dd7cddfSDavid du Colombier 
3047dd7cddfSDavid du Colombier /*
3057dd7cddfSDavid du Colombier  * fill in a directory entry for a new file
3067dd7cddfSDavid du Colombier  */
3077dd7cddfSDavid du Colombier static int
mkdentry(Xfs * xf,Dosptr * ndp,char * name,char * sname,int longtype,int nattr,long start,long length)3089a747e4fSDavid du Colombier mkdentry(Xfs *xf, Dosptr *ndp, char *name, char *sname, int longtype, int nattr, long start, long length)
3097dd7cddfSDavid du Colombier {
3107dd7cddfSDavid du Colombier 	Dosdir *nd;
3117dd7cddfSDavid du Colombier 
3127dd7cddfSDavid du Colombier 	/*
3137dd7cddfSDavid du Colombier 	 * fill in the entry
3147dd7cddfSDavid du Colombier 	 */
3157dd7cddfSDavid du Colombier 	ndp->p = getsect(xf, ndp->addr);
3167dd7cddfSDavid du Colombier 	if(ndp->p == nil
3179a747e4fSDavid du Colombier 	|| longtype!=Short && putlongname(xf, ndp, name, sname) < 0){
3187dd7cddfSDavid du Colombier 		errno = Eio;
3197dd7cddfSDavid du Colombier 		return -1;
3207dd7cddfSDavid du Colombier 	}
3217dd7cddfSDavid du Colombier 
3227dd7cddfSDavid du Colombier 	ndp->d = (Dosdir *)&ndp->p->iobuf[ndp->offset];
3237dd7cddfSDavid du Colombier 	nd = ndp->d;
3247dd7cddfSDavid du Colombier 	memset(nd, 0, DOSDIRSIZE);
3257dd7cddfSDavid du Colombier 
3269a747e4fSDavid du Colombier 	if(longtype!=Short)
3277dd7cddfSDavid du Colombier 		name = sname;
3287dd7cddfSDavid du Colombier 	putname(name, nd);
3297dd7cddfSDavid du Colombier 
3307dd7cddfSDavid du Colombier 	nd->attr = nattr;
3317dd7cddfSDavid du Colombier 	puttime(nd, 0);
3327dd7cddfSDavid du Colombier 	putstart(xf, nd, start);
3337dd7cddfSDavid du Colombier 	nd->length[0] = length;
3347dd7cddfSDavid du Colombier 	nd->length[1] = length>>8;
3357dd7cddfSDavid du Colombier 	nd->length[2] = length>>16;
3367dd7cddfSDavid du Colombier 	nd->length[3] = length>>24;
3377dd7cddfSDavid du Colombier 
3387dd7cddfSDavid du Colombier 	ndp->p->flags |= BMOD;
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier 	return 0;
3417dd7cddfSDavid du Colombier }
3427dd7cddfSDavid du Colombier 
3433e12c5d1SDavid du Colombier void
rcreate(void)3443e12c5d1SDavid du Colombier rcreate(void)
3453e12c5d1SDavid du Colombier {
3463e12c5d1SDavid du Colombier 	Dosbpb *bp;
3473e12c5d1SDavid du Colombier 	Xfile *f;
3483e12c5d1SDavid du Colombier 	Dosptr *pdp, *ndp;
3493e12c5d1SDavid du Colombier 	Iosect *xp;
3507dd7cddfSDavid du Colombier 	Dosdir *pd, *xd;
3517dd7cddfSDavid du Colombier 	char sname[13];
3527dd7cddfSDavid du Colombier 	long start;
3539a747e4fSDavid du Colombier 	int longtype, attr, omode, nattr;
3543e12c5d1SDavid du Colombier 
3559a747e4fSDavid du Colombier 	f = xfile(req->fid, Asis);
3563e12c5d1SDavid du Colombier 	if(!f || (f->flags&Omodes) || getfile(f)<0){
3573e12c5d1SDavid du Colombier 		errno = Eio;
3583e12c5d1SDavid du Colombier 		return;
3593e12c5d1SDavid du Colombier 	}
3603e12c5d1SDavid du Colombier 	pdp = f->ptr;
3617dd7cddfSDavid du Colombier 	pd = pdp->d;
3627dd7cddfSDavid du Colombier 	/*
3637dd7cddfSDavid du Colombier 	 * perm check
3647dd7cddfSDavid du Colombier 	 */
3657dd7cddfSDavid du Colombier 	if(isroot(pdp->addr) && pd != nil)
3667dd7cddfSDavid du Colombier 		panic("root pd != nil");
3673e12c5d1SDavid du Colombier 	attr = pd ? pd->attr : DDIR;
3683e12c5d1SDavid du Colombier 	if(!(attr & DDIR) || (attr & DRONLY)){
3693e12c5d1SDavid du Colombier badperm:
3703e12c5d1SDavid du Colombier 		putfile(f);
3713e12c5d1SDavid du Colombier 		errno = Eperm;
3723e12c5d1SDavid du Colombier 		return;
3733e12c5d1SDavid du Colombier 	}
3747dd7cddfSDavid du Colombier 	omode = 0;
3759a747e4fSDavid du Colombier 	if(req->mode & ORCLOSE)
3763e12c5d1SDavid du Colombier 		omode |= Orclose;
3779a747e4fSDavid du Colombier 	switch(req->mode & 7){
3783e12c5d1SDavid du Colombier 	case OREAD:
3793e12c5d1SDavid du Colombier 	case OEXEC:
3803e12c5d1SDavid du Colombier 		omode |= Oread;
3813e12c5d1SDavid du Colombier 		break;
3823e12c5d1SDavid du Colombier 	case ORDWR:
3833e12c5d1SDavid du Colombier 		omode |= Oread;
3843e12c5d1SDavid du Colombier 		/* fall through */
3853e12c5d1SDavid du Colombier 	case OWRITE:
3863e12c5d1SDavid du Colombier 		omode |= Owrite;
3879a747e4fSDavid du Colombier 		if(req->perm & DMDIR)
3883e12c5d1SDavid du Colombier 			goto badperm;
3893e12c5d1SDavid du Colombier 		break;
3903e12c5d1SDavid du Colombier 	default:
3913e12c5d1SDavid du Colombier 		goto badperm;
3923e12c5d1SDavid du Colombier 	}
3937dd7cddfSDavid du Colombier 
3947dd7cddfSDavid du Colombier 	/*
3957dd7cddfSDavid du Colombier 	 * check the name, find the slot for the dentry,
3967dd7cddfSDavid du Colombier 	 * and find a good alias for a long name
3977dd7cddfSDavid du Colombier 	 */
3987dd7cddfSDavid du Colombier 	ndp = malloc(sizeof(Dosptr));
3997dd7cddfSDavid du Colombier 	if(ndp == nil){
4007dd7cddfSDavid du Colombier 		putfile(f);
4017dd7cddfSDavid du Colombier 		errno = Enomem;
4027dd7cddfSDavid du Colombier 		return;
4037dd7cddfSDavid du Colombier 	}
4049a747e4fSDavid du Colombier 	longtype = mk8dot3name(f, ndp, req->name, sname);
4059a747e4fSDavid du Colombier 	chat("rcreate %s longtype %d...\n", req->name, longtype);
4069a747e4fSDavid du Colombier 	if(longtype == Invalid){
4077dd7cddfSDavid du Colombier 		free(ndp);
4083e12c5d1SDavid du Colombier 		goto badperm;
4097dd7cddfSDavid du Colombier 	}
4107dd7cddfSDavid du Colombier 
4117dd7cddfSDavid du Colombier 	/*
4127dd7cddfSDavid du Colombier 	 * allocate first cluster, if making directory
4137dd7cddfSDavid du Colombier 	 */
4147dd7cddfSDavid du Colombier 	start = 0;
4157dd7cddfSDavid du Colombier 	bp = nil;
4169a747e4fSDavid du Colombier 	if(req->perm & DMDIR){
4173e12c5d1SDavid du Colombier 		bp = f->xf->ptr;
4187dd7cddfSDavid du Colombier 		mlock(bp);
4193e12c5d1SDavid du Colombier 		start = falloc(f->xf);
4207dd7cddfSDavid du Colombier 		unmlock(bp);
4213e12c5d1SDavid du Colombier 		if(start <= 0){
4223e12c5d1SDavid du Colombier 			free(ndp);
4233e12c5d1SDavid du Colombier 			putfile(f);
4243e12c5d1SDavid du Colombier 			errno = Eio;
4253e12c5d1SDavid du Colombier 			return;
4263e12c5d1SDavid du Colombier 		}
4277dd7cddfSDavid du Colombier 	}
4287dd7cddfSDavid du Colombier 
4293e12c5d1SDavid du Colombier 	/*
4307dd7cddfSDavid du Colombier 	 * make the entry
4313e12c5d1SDavid du Colombier 	 */
4327dd7cddfSDavid du Colombier 	nattr = 0;
4339a747e4fSDavid du Colombier 	if((req->perm & 0222) == 0)
4347dd7cddfSDavid du Colombier 		nattr |= DRONLY;
4359a747e4fSDavid du Colombier 	if(req->perm & DMDIR)
4367dd7cddfSDavid du Colombier 		nattr |= DDIR;
4377dd7cddfSDavid du Colombier 
4389a747e4fSDavid du Colombier 	if(mkdentry(f->xf, ndp, req->name, sname, longtype, nattr, start, 0) < 0){
4397dd7cddfSDavid du Colombier 		if(ndp->p != nil)
4407dd7cddfSDavid du Colombier 			putsect(ndp->p);
4417dd7cddfSDavid du Colombier 		free(ndp);
4427dd7cddfSDavid du Colombier 		if(start > 0)
4437dd7cddfSDavid du Colombier 			ffree(f->xf, start);
4447dd7cddfSDavid du Colombier 		putfile(f);
4457dd7cddfSDavid du Colombier 		return;
4467dd7cddfSDavid du Colombier 	}
4477dd7cddfSDavid du Colombier 
4487dd7cddfSDavid du Colombier 	if(pd != nil){
449219b2ee8SDavid du Colombier 		puttime(pd, 0);
4503e12c5d1SDavid du Colombier 		pdp->p->flags |= BMOD;
4513e12c5d1SDavid du Colombier 	}
4527dd7cddfSDavid du Colombier 
4537dd7cddfSDavid du Colombier 	/*
4547dd7cddfSDavid du Colombier 	 * fix up the fid
4557dd7cddfSDavid du Colombier 	 */
4563e12c5d1SDavid du Colombier 	f->ptr = ndp;
4579a747e4fSDavid du Colombier 	f->qid.type = QTFILE;
4587dd7cddfSDavid du Colombier 	f->qid.path = QIDPATH(ndp);
4597dd7cddfSDavid du Colombier 
4609a747e4fSDavid du Colombier //ZZZ set type for excl, append?
4619a747e4fSDavid du Colombier 	if(req->perm & DMDIR){
4629a747e4fSDavid du Colombier 		f->qid.type = QTDIR;
4637dd7cddfSDavid du Colombier 		xp = getsect(f->xf, clust2sect(bp, start));
4647dd7cddfSDavid du Colombier 		if(xp == nil){
4657dd7cddfSDavid du Colombier 			errno = Eio;
4663e12c5d1SDavid du Colombier 			goto badio;
4677dd7cddfSDavid du Colombier 		}
4683e12c5d1SDavid du Colombier 		xd = (Dosdir *)&xp->iobuf[0];
4697dd7cddfSDavid du Colombier 		memmove(xd, ndp->d, DOSDIRSIZE);
4703e12c5d1SDavid du Colombier 		memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
4713e12c5d1SDavid du Colombier 		xd->name[0] = '.';
4727dd7cddfSDavid du Colombier 		xd = (Dosdir *)&xp->iobuf[DOSDIRSIZE];
4733e12c5d1SDavid du Colombier 		if(pd)
4747dd7cddfSDavid du Colombier 			memmove(xd, pd, DOSDIRSIZE);
4753e12c5d1SDavid du Colombier 		else{
4767dd7cddfSDavid du Colombier 			memset(xd, 0, DOSDIRSIZE);
477219b2ee8SDavid du Colombier 			puttime(xd, 0);
4783e12c5d1SDavid du Colombier 			xd->attr = DDIR;
4793e12c5d1SDavid du Colombier 		}
4803e12c5d1SDavid du Colombier 		memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
4813e12c5d1SDavid du Colombier 		xd->name[0] = '.';
4823e12c5d1SDavid du Colombier 		xd->name[1] = '.';
4833e12c5d1SDavid du Colombier 		xp->flags |= BMOD;
4843e12c5d1SDavid du Colombier 		putsect(xp);
4853e12c5d1SDavid du Colombier 	}
4867dd7cddfSDavid du Colombier 
4873e12c5d1SDavid du Colombier 	f->flags |= omode;
4889a747e4fSDavid du Colombier 	rep->qid = f->qid;
4899a747e4fSDavid du Colombier 	rep->iounit = 0;
4907dd7cddfSDavid du Colombier 
4913e12c5d1SDavid du Colombier badio:
4923e12c5d1SDavid du Colombier 	putfile(f);
4933e12c5d1SDavid du Colombier 	putsect(pdp->p);
4943e12c5d1SDavid du Colombier 	free(pdp);
4953e12c5d1SDavid du Colombier }
4967dd7cddfSDavid du Colombier 
4973e12c5d1SDavid du Colombier void
rread(void)4983e12c5d1SDavid du Colombier rread(void)
4993e12c5d1SDavid du Colombier {
5007dd7cddfSDavid du Colombier 	Xfile *f;
5017dd7cddfSDavid du Colombier 	int r;
5023e12c5d1SDavid du Colombier 
5039a747e4fSDavid du Colombier 	if (!(f=xfile(req->fid, Asis)) || !(f->flags&Oread))
5043e12c5d1SDavid du Colombier 		goto error;
5059a747e4fSDavid du Colombier 	if(req->count > sizeof repdata)
5069a747e4fSDavid du Colombier 		req->count = sizeof repdata;
5079a747e4fSDavid du Colombier 	if(f->qid.type & QTDIR){
5083e12c5d1SDavid du Colombier 		if(getfile(f) < 0)
5093e12c5d1SDavid du Colombier 			goto error;
5109a747e4fSDavid du Colombier 		r = readdir(f, repdata, req->offset, req->count);
5113e12c5d1SDavid du Colombier 	}else{
5123e12c5d1SDavid du Colombier 		if(getfile(f) < 0)
5133e12c5d1SDavid du Colombier 			goto error;
5149a747e4fSDavid du Colombier 		r = readfile(f, repdata, req->offset, req->count);
5153e12c5d1SDavid du Colombier 	}
5163e12c5d1SDavid du Colombier 	putfile(f);
5173e12c5d1SDavid du Colombier 	if(r < 0){
5183e12c5d1SDavid du Colombier error:
5193e12c5d1SDavid du Colombier 		errno = Eio;
5203e12c5d1SDavid du Colombier 	}else{
5219a747e4fSDavid du Colombier 		rep->count = r;
5229a747e4fSDavid du Colombier 		rep->data = (char*)repdata;
5233e12c5d1SDavid du Colombier 	}
5243e12c5d1SDavid du Colombier }
5257dd7cddfSDavid du Colombier 
5263e12c5d1SDavid du Colombier void
rwrite(void)5273e12c5d1SDavid du Colombier rwrite(void)
5283e12c5d1SDavid du Colombier {
5297dd7cddfSDavid du Colombier 	Xfile *f;
5307dd7cddfSDavid du Colombier 	int r;
5313e12c5d1SDavid du Colombier 
5329a747e4fSDavid du Colombier 	if (!(f=xfile(req->fid, Asis)) || !(f->flags&Owrite))
5333e12c5d1SDavid du Colombier 		goto error;
5343e12c5d1SDavid du Colombier 	if(getfile(f) < 0)
5353e12c5d1SDavid du Colombier 		goto error;
5369a747e4fSDavid du Colombier 	r = writefile(f, req->data, req->offset, req->count);
5373e12c5d1SDavid du Colombier 	putfile(f);
5383e12c5d1SDavid du Colombier 	if(r < 0){
5393e12c5d1SDavid du Colombier error:
5403e12c5d1SDavid du Colombier 		errno = Eio;
5413e12c5d1SDavid du Colombier 	}else{
5429a747e4fSDavid du Colombier 		rep->count = r;
5433e12c5d1SDavid du Colombier 	}
5443e12c5d1SDavid du Colombier }
5457dd7cddfSDavid du Colombier 
5463e12c5d1SDavid du Colombier void
rclunk(void)5473e12c5d1SDavid du Colombier rclunk(void)
5483e12c5d1SDavid du Colombier {
5499a747e4fSDavid du Colombier 	xfile(req->fid, Clunk);
5503e12c5d1SDavid du Colombier 	sync();
5513e12c5d1SDavid du Colombier }
5527dd7cddfSDavid du Colombier 
5537dd7cddfSDavid du Colombier /*
5547dd7cddfSDavid du Colombier  * wipe out a dos directory entry
5557dd7cddfSDavid du Colombier  */
5567dd7cddfSDavid du Colombier static void
doremove(Xfs * xf,Dosptr * dp)5577dd7cddfSDavid du Colombier doremove(Xfs *xf, Dosptr *dp)
5587dd7cddfSDavid du Colombier {
5597dd7cddfSDavid du Colombier 	Iosect *p;
5607dd7cddfSDavid du Colombier 	int prevdo;
5617dd7cddfSDavid du Colombier 
5627dd7cddfSDavid du Colombier 	dp->p->iobuf[dp->offset] = DOSEMPTY;
5637dd7cddfSDavid du Colombier 	dp->p->flags |= BMOD;
56459cc4ca5SDavid du Colombier 	for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
5657dd7cddfSDavid du Colombier 		if(dp->p->iobuf[prevdo+11] != 0xf)
5667dd7cddfSDavid du Colombier 			break;
5677dd7cddfSDavid du Colombier 		dp->p->iobuf[prevdo] = DOSEMPTY;
5687dd7cddfSDavid du Colombier 	}
5697dd7cddfSDavid du Colombier 	if(prevdo < 0 && dp->prevaddr != -1){
5707dd7cddfSDavid du Colombier 		p = getsect(xf, dp->prevaddr);
57159cc4ca5SDavid du Colombier 		for(prevdo = ((Dosbpb*)xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
5727dd7cddfSDavid du Colombier 			if(p->iobuf[prevdo+11] != 0xf)
5737dd7cddfSDavid du Colombier 				break;
5747dd7cddfSDavid du Colombier 			p->iobuf[prevdo] = DOSEMPTY;
5757dd7cddfSDavid du Colombier 			p->flags |= BMOD;
5767dd7cddfSDavid du Colombier 		}
5777dd7cddfSDavid du Colombier 		putsect(p);
5787dd7cddfSDavid du Colombier 	}
5797dd7cddfSDavid du Colombier }
5807dd7cddfSDavid du Colombier 
5813e12c5d1SDavid du Colombier void
rremove(void)5823e12c5d1SDavid du Colombier rremove(void)
5833e12c5d1SDavid du Colombier {
5847dd7cddfSDavid du Colombier 	Xfile *f;
5853e12c5d1SDavid du Colombier 	Dosptr *dp;
5867dd7cddfSDavid du Colombier 	Iosect *parp;
5877dd7cddfSDavid du Colombier 	Dosdir *pard;
5883e12c5d1SDavid du Colombier 
5899a747e4fSDavid du Colombier 	f = xfile(req->fid, Asis);
5909a747e4fSDavid du Colombier 	parp = nil;
5919a747e4fSDavid du Colombier 	if(f == nil){
5923e12c5d1SDavid du Colombier 		errno = Eio;
5933e12c5d1SDavid du Colombier 		goto out;
5943e12c5d1SDavid du Colombier 	}
5953e12c5d1SDavid du Colombier 	dp = f->ptr;
5967dd7cddfSDavid du Colombier 	if(isroot(dp->addr)){
5973e12c5d1SDavid du Colombier 		errno = Eperm;
5983e12c5d1SDavid du Colombier 		goto out;
5993e12c5d1SDavid du Colombier 	}
6009a747e4fSDavid du Colombier 
6013e12c5d1SDavid du Colombier 	/*
6029a747e4fSDavid du Colombier 	 * can't remove if parent is read only,
6039a747e4fSDavid du Colombier 	 * it's a non-empty directory,
6049a747e4fSDavid du Colombier 	 * or it's a read only file in the root directory
6053e12c5d1SDavid du Colombier 	 */
6063e12c5d1SDavid du Colombier 	parp = getsect(f->xf, dp->paddr);
6079a747e4fSDavid du Colombier 	if(parp == nil
6089a747e4fSDavid du Colombier 	|| getfile(f) < 0){
6093e12c5d1SDavid du Colombier 		errno = Eio;
6103e12c5d1SDavid du Colombier 		goto out;
6113e12c5d1SDavid du Colombier 	}
6123e12c5d1SDavid du Colombier 	pard = (Dosdir *)&parp->iobuf[dp->poffset];
6139a747e4fSDavid du Colombier 	if(!isroot(dp->paddr) && (pard->attr & DRONLY)
6149a747e4fSDavid du Colombier 	|| (dp->d->attr & DDIR) && emptydir(f) < 0
6159a747e4fSDavid du Colombier 	|| isroot(dp->paddr) && (dp->d->attr&DRONLY)){
6163e12c5d1SDavid du Colombier 		errno = Eperm;
6173e12c5d1SDavid du Colombier 		goto out;
6183e12c5d1SDavid du Colombier 	}
6199a747e4fSDavid du Colombier 	if(truncfile(f, 0) < 0){
6203e12c5d1SDavid du Colombier 		errno = Eio;
6213e12c5d1SDavid du Colombier 		goto out;
6223e12c5d1SDavid du Colombier 	}
6237dd7cddfSDavid du Colombier 	doremove(f->xf, f->ptr);
6247dd7cddfSDavid du Colombier 	if(!isroot(dp->paddr)){
625219b2ee8SDavid du Colombier 		puttime(pard, 0);
6263e12c5d1SDavid du Colombier 		parp->flags |= BMOD;
6273e12c5d1SDavid du Colombier 	}
6283e12c5d1SDavid du Colombier out:
6299a747e4fSDavid du Colombier 	if(parp != nil)
6309a747e4fSDavid du Colombier 		putsect(parp);
6319a747e4fSDavid du Colombier 	if(f != nil)
6329a747e4fSDavid du Colombier 		putfile(f);
6339a747e4fSDavid du Colombier 	xfile(req->fid, Clunk);
6343e12c5d1SDavid du Colombier 	sync();
6353e12c5d1SDavid du Colombier }
6367dd7cddfSDavid du Colombier 
6377dd7cddfSDavid du Colombier static void
dostat(Xfile * f,Dir * d)6387dd7cddfSDavid du Colombier dostat(Xfile *f, Dir *d)
6397dd7cddfSDavid du Colombier {
6407dd7cddfSDavid du Colombier 	Dosptr *dp;
6417dd7cddfSDavid du Colombier 	Iosect *p;
6427dd7cddfSDavid du Colombier 	char *name, namebuf[DOSNAMELEN];
6437dd7cddfSDavid du Colombier 	int islong, sum, prevdo;
6447dd7cddfSDavid du Colombier 
6457dd7cddfSDavid du Colombier 	dp = f->ptr;
6467dd7cddfSDavid du Colombier 	if(isroot(dp->addr)){
6477dd7cddfSDavid du Colombier 		memset(d, 0, sizeof(Dir));
6489a747e4fSDavid du Colombier 		d->name = "/";
6499a747e4fSDavid du Colombier 		d->qid.type = QTDIR;
6509a747e4fSDavid du Colombier 		d->qid.path = f->xf->rootqid.path;
6519a747e4fSDavid du Colombier 		d->mode = DMDIR|0777;
6529a747e4fSDavid du Colombier 		d->uid = "bill";
6539a747e4fSDavid du Colombier 		d->muid = "bill";
6549a747e4fSDavid du Colombier 		d->gid = "trog";
6557dd7cddfSDavid du Colombier 	}else{
6567dd7cddfSDavid du Colombier 		/*
6577dd7cddfSDavid du Colombier 		 * assemble any long file name
6587dd7cddfSDavid du Colombier 		 */
6597dd7cddfSDavid du Colombier 		sum = aliassum(dp->d);
6607dd7cddfSDavid du Colombier 		islong = 0;
6617dd7cddfSDavid du Colombier 		name = namebuf;
66259cc4ca5SDavid du Colombier 		for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
6637dd7cddfSDavid du Colombier 			if(dp->p->iobuf[prevdo+11] != 0xf)
6647dd7cddfSDavid du Colombier 				break;
6657dd7cddfSDavid du Colombier 			name = getnamesect(namebuf, name, &dp->p->iobuf[prevdo], &islong, &sum, -1);
6667dd7cddfSDavid du Colombier 		}
6677dd7cddfSDavid du Colombier 		if(prevdo < 0 && dp->prevaddr != -1){
6687dd7cddfSDavid du Colombier 			p = getsect(f->xf, dp->prevaddr);
66959cc4ca5SDavid du Colombier 			for(prevdo = ((Dosbpb*)f->xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
6707dd7cddfSDavid du Colombier 				if(p->iobuf[prevdo+11] != 0xf)
6717dd7cddfSDavid du Colombier 					break;
6727dd7cddfSDavid du Colombier 				name = getnamesect(namebuf, name, &p->iobuf[prevdo], &islong, &sum, -1);
6737dd7cddfSDavid du Colombier 			}
6747dd7cddfSDavid du Colombier 			putsect(p);
6757dd7cddfSDavid du Colombier 		}
6767dd7cddfSDavid du Colombier 		getdir(f->xf, d, dp->d, dp->addr, dp->offset);
6777dd7cddfSDavid du Colombier 		if(islong && sum == -1 && nameok(namebuf))
6789a747e4fSDavid du Colombier 			strcpy(d->name, namebuf);
6797dd7cddfSDavid du Colombier 	}
6807dd7cddfSDavid du Colombier }
6817dd7cddfSDavid du Colombier 
6823e12c5d1SDavid du Colombier void
rstat(void)6833e12c5d1SDavid du Colombier rstat(void)
6843e12c5d1SDavid du Colombier {
6853e12c5d1SDavid du Colombier 	Dir dir;
6867dd7cddfSDavid du Colombier 	Xfile *f;
6873e12c5d1SDavid du Colombier 
6889a747e4fSDavid du Colombier 	f = xfile(req->fid, Asis);
6897dd7cddfSDavid du Colombier 	if(!f || getfile(f) < 0){
6903e12c5d1SDavid du Colombier 		errno = Eio;
6917dd7cddfSDavid du Colombier 		return;
6927dd7cddfSDavid du Colombier 	}
6937dd7cddfSDavid du Colombier 
6949a747e4fSDavid du Colombier 	dir.name = repdata;
6957dd7cddfSDavid du Colombier 	dostat(f, &dir);
6967dd7cddfSDavid du Colombier 
6979a747e4fSDavid du Colombier 	rep->nstat = convD2M(&dir, statbuf, sizeof statbuf);
6989a747e4fSDavid du Colombier 	rep->stat = statbuf;
6993e12c5d1SDavid du Colombier 	putfile(f);
7003e12c5d1SDavid du Colombier }
701219b2ee8SDavid du Colombier 
7023e12c5d1SDavid du Colombier void
rwstat(void)7033e12c5d1SDavid du Colombier rwstat(void)
7043e12c5d1SDavid du Colombier {
7057dd7cddfSDavid du Colombier 	Dir dir, wdir;
7067dd7cddfSDavid du Colombier 	Xfile *f, pf;
7077dd7cddfSDavid du Colombier 	Dosptr *dp, ndp, pdp;
7087dd7cddfSDavid du Colombier 	Iosect *parp;
7097dd7cddfSDavid du Colombier 	Dosdir *pard, *d, od;
7107dd7cddfSDavid du Colombier 	char sname[13];
7117dd7cddfSDavid du Colombier 	ulong oaddr, ooffset;
7127dd7cddfSDavid du Colombier 	long start, length;
7139a747e4fSDavid du Colombier 	int i, longtype, changes, attr;
7147dd7cddfSDavid du Colombier 
7159a747e4fSDavid du Colombier 	f = xfile(req->fid, Asis);
7167dd7cddfSDavid du Colombier 	if(!f || getfile(f) < 0){
7177dd7cddfSDavid du Colombier 		errno = Eio;
7187dd7cddfSDavid du Colombier 		return;
7197dd7cddfSDavid du Colombier 	}
7207dd7cddfSDavid du Colombier 	dp = f->ptr;
7217dd7cddfSDavid du Colombier 
7227dd7cddfSDavid du Colombier 	if(isroot(dp->addr)){
7233e12c5d1SDavid du Colombier 		errno = Eperm;
7247dd7cddfSDavid du Colombier 		goto out;
7257dd7cddfSDavid du Colombier 	}
7267dd7cddfSDavid du Colombier 
7277dd7cddfSDavid du Colombier 	changes = 0;
7289a747e4fSDavid du Colombier 	dir.name = repdata;
7297dd7cddfSDavid du Colombier 	dostat(f, &dir);
7309a747e4fSDavid du Colombier 	if(convM2D(req->stat, req->nstat, &wdir, (char*)statbuf) != req->nstat){
7319a747e4fSDavid du Colombier 		errno = Ebadstat;
7329a747e4fSDavid du Colombier 		goto out;
7339a747e4fSDavid du Colombier 	}
7349a747e4fSDavid du Colombier 
7359a747e4fSDavid du Colombier 	/*
7369a747e4fSDavid du Colombier 	 * To change length, must have write permission on file.
7379a747e4fSDavid du Colombier 	 * we only allow truncates for now.
7389a747e4fSDavid du Colombier 	 */
7399a747e4fSDavid du Colombier 	if(wdir.length!=~0 && wdir.length!=dir.length){
7409a747e4fSDavid du Colombier 		if(wdir.length > dir.length || !dir.mode & 0222){
7419a747e4fSDavid du Colombier 			errno = Eperm;
7429a747e4fSDavid du Colombier 			goto out;
7439a747e4fSDavid du Colombier 		}
7449a747e4fSDavid du Colombier 	}
7457dd7cddfSDavid du Colombier 
7467dd7cddfSDavid du Colombier 	/*
7477dd7cddfSDavid du Colombier 	 * no chown or chgrp
7487dd7cddfSDavid du Colombier 	 */
7499a747e4fSDavid du Colombier 	if(wdir.uid[0] != '\0' && strcmp(dir.uid, wdir.uid) != 0
7509a747e4fSDavid du Colombier 	|| wdir.gid[0] != '\0' && strcmp(dir.gid, wdir.gid) != 0){
7517dd7cddfSDavid du Colombier 		errno = Eperm;
7527dd7cddfSDavid du Colombier 		goto out;
7537dd7cddfSDavid du Colombier 	}
7547dd7cddfSDavid du Colombier 
7557dd7cddfSDavid du Colombier 	/*
7567dd7cddfSDavid du Colombier 	 * mode/mtime allowed
7577dd7cddfSDavid du Colombier 	 */
7589a747e4fSDavid du Colombier 	if(wdir.mtime != ~0 && dir.mtime != wdir.mtime)
7597dd7cddfSDavid du Colombier 		changes = 1;
7607dd7cddfSDavid du Colombier 
7617dd7cddfSDavid du Colombier 	/*
7629a747e4fSDavid du Colombier 	 * Setting DMAPPEND (make system file contiguous)
7639a747e4fSDavid du Colombier 	 * requires setting DMEXCL (system file).
7647dd7cddfSDavid du Colombier 	 */
7659a747e4fSDavid du Colombier 	if(wdir.mode != ~0){
7667dd7cddfSDavid du Colombier 		if((wdir.mode & 7) != ((wdir.mode >> 3) & 7)
7677dd7cddfSDavid du Colombier 		|| (wdir.mode & 7) != ((wdir.mode >> 6) & 7)){
7687dd7cddfSDavid du Colombier 			errno = Eperm;
7697dd7cddfSDavid du Colombier 			goto out;
7707dd7cddfSDavid du Colombier 		}
7719a747e4fSDavid du Colombier 		if((dir.mode^wdir.mode) & (DMEXCL|DMAPPEND|0777))
7729a747e4fSDavid du Colombier 			changes = 1;
7739a747e4fSDavid du Colombier 		if((dir.mode^wdir.mode) & DMAPPEND) {
7749a747e4fSDavid du Colombier 			if((wdir.mode & (DMEXCL|DMAPPEND)) == DMAPPEND) {
7759a747e4fSDavid du Colombier 				errno = Eperm;
7769a747e4fSDavid du Colombier 				goto out;
7779a747e4fSDavid du Colombier 			}
7789a747e4fSDavid du Colombier 			if((wdir.mode & DMAPPEND) && makecontig(f, 0) < 0) {
7799a747e4fSDavid du Colombier 				errno = Econtig;
7809a747e4fSDavid du Colombier 				goto out;
7819a747e4fSDavid du Colombier 			}
7829a747e4fSDavid du Colombier 		}
7839a747e4fSDavid du Colombier 	}
7849a747e4fSDavid du Colombier 
7857dd7cddfSDavid du Colombier 
7867dd7cddfSDavid du Colombier 	/*
7877dd7cddfSDavid du Colombier 	 * to rename:
7887dd7cddfSDavid du Colombier 	 *	1) make up a fake clone
7897dd7cddfSDavid du Colombier 	 *	2) walk to parent
7907dd7cddfSDavid du Colombier 	 *	3) remove the old entry
7917dd7cddfSDavid du Colombier 	 *	4) create entry with new name
7927dd7cddfSDavid du Colombier 	 *	5) write correct mode/mtime info
7937dd7cddfSDavid du Colombier 	 * we need to remove the old entry before creating the new one
7947dd7cddfSDavid du Colombier 	 * to avoid a lock loop.
7957dd7cddfSDavid du Colombier 	 */
7969a747e4fSDavid du Colombier 	if(wdir.name[0] != '\0' && strcmp(dir.name, wdir.name) != 0){
7979a747e4fSDavid du Colombier 		if(utflen(wdir.name) >= DOSNAMELEN){
7989a747e4fSDavid du Colombier 			errno = Etoolong;
7999a747e4fSDavid du Colombier 			goto out;
8009a747e4fSDavid du Colombier 		}
8019a747e4fSDavid du Colombier 
8027dd7cddfSDavid du Colombier 		/*
8037dd7cddfSDavid du Colombier 		 * grab parent directory of file to be changed and check for write perm
8047dd7cddfSDavid du Colombier 		 * rename also disallowed for read-only files in root directory
8057dd7cddfSDavid du Colombier 		 */
8067dd7cddfSDavid du Colombier 		parp = getsect(f->xf, dp->paddr);
8077dd7cddfSDavid du Colombier 		if(parp == nil){
8087dd7cddfSDavid du Colombier 			errno = Eio;
8097dd7cddfSDavid du Colombier 			goto out;
8107dd7cddfSDavid du Colombier 		}
8117dd7cddfSDavid du Colombier 		pard = (Dosdir *)&parp->iobuf[dp->poffset];
8127dd7cddfSDavid du Colombier 		if(!isroot(dp->paddr) && (pard->attr & DRONLY)
8137dd7cddfSDavid du Colombier 		|| isroot(dp->paddr) && (dp->d->attr&DRONLY)){
8147dd7cddfSDavid du Colombier 			putsect(parp);
8157dd7cddfSDavid du Colombier 			errno = Eperm;
8167dd7cddfSDavid du Colombier 			goto out;
8177dd7cddfSDavid du Colombier 		}
8187dd7cddfSDavid du Colombier 
8197dd7cddfSDavid du Colombier 		/*
8207dd7cddfSDavid du Colombier 		 * retrieve info from old entry
8217dd7cddfSDavid du Colombier 		 */
8227dd7cddfSDavid du Colombier 		oaddr = dp->addr;
8237dd7cddfSDavid du Colombier 		ooffset = dp->offset;
8247dd7cddfSDavid du Colombier 		d = dp->d;
8257dd7cddfSDavid du Colombier 		od = *d;
8267dd7cddfSDavid du Colombier 		start = getstart(f->xf, d);
8277dd7cddfSDavid du Colombier 		length = GLONG(d->length);
8287dd7cddfSDavid du Colombier 		attr = d->attr;
8297dd7cddfSDavid du Colombier 
8307dd7cddfSDavid du Colombier 		/*
8317dd7cddfSDavid du Colombier 		 * temporarily release file to allow other directory ops:
8327dd7cddfSDavid du Colombier 		 * walk to parent, validate new name
8337dd7cddfSDavid du Colombier 		 * then remove old entry
8347dd7cddfSDavid du Colombier 		 */
8357dd7cddfSDavid du Colombier 		putfile(f);
8367dd7cddfSDavid du Colombier 		pf = *f;
8377dd7cddfSDavid du Colombier 		memset(&pdp, 0, sizeof(Dosptr));
8387dd7cddfSDavid du Colombier 		pdp.prevaddr = -1;
8397dd7cddfSDavid du Colombier 		pdp.naddr = -1;
8407dd7cddfSDavid du Colombier 		pdp.addr = dp->paddr;
8417dd7cddfSDavid du Colombier 		pdp.offset = dp->poffset;
8427dd7cddfSDavid du Colombier 		pdp.p = parp;
8437dd7cddfSDavid du Colombier 		if(!isroot(pdp.addr))
8447dd7cddfSDavid du Colombier 			pdp.d = (Dosdir *)&parp->iobuf[pdp.offset];
8457dd7cddfSDavid du Colombier 		pf.ptr = &pdp;
8469a747e4fSDavid du Colombier 		longtype = mk8dot3name(&pf, &ndp, wdir.name, sname);
8479a747e4fSDavid du Colombier 		if(longtype==Invalid){
8487dd7cddfSDavid du Colombier 			putsect(parp);
8497dd7cddfSDavid du Colombier 			errno = Eperm;
8507dd7cddfSDavid du Colombier 			return;
8517dd7cddfSDavid du Colombier 		}
8527dd7cddfSDavid du Colombier 		if(getfile(f) < 0){
8537dd7cddfSDavid du Colombier 			putsect(parp);
8547dd7cddfSDavid du Colombier 			errno = Eio;
8557dd7cddfSDavid du Colombier 			return;
8567dd7cddfSDavid du Colombier 		}
8577dd7cddfSDavid du Colombier 		doremove(f->xf, dp);
8587dd7cddfSDavid du Colombier 		putfile(f);
8597dd7cddfSDavid du Colombier 
8607dd7cddfSDavid du Colombier 		/*
8617dd7cddfSDavid du Colombier 		 * search for dir entry again, since we may be able to use the old slot,
8627dd7cddfSDavid du Colombier 		 * and we need to set up the naddr field if a long name spans the block.
8637dd7cddfSDavid du Colombier 		 * create new entry.
8647dd7cddfSDavid du Colombier 		 */
8659a747e4fSDavid du Colombier 		if(searchdir(&pf, wdir.name, dp, 1, longtype) < 0
8669a747e4fSDavid du Colombier 		|| mkdentry(pf.xf, dp, wdir.name, sname, longtype, attr, start, length) < 0){
8677dd7cddfSDavid du Colombier 			putsect(parp);
8687dd7cddfSDavid du Colombier 			errno = Eio;
8697dd7cddfSDavid du Colombier 			goto out;
8707dd7cddfSDavid du Colombier 		}
8717dd7cddfSDavid du Colombier 
8727dd7cddfSDavid du Colombier 		/*
8737dd7cddfSDavid du Colombier 		 * copy invisible fields
8747dd7cddfSDavid du Colombier 		 */
8757dd7cddfSDavid du Colombier 		d = dp->d;
8767dd7cddfSDavid du Colombier 		for(i = 0; i < 2; i++)
8777dd7cddfSDavid du Colombier 			d->ctime[i] = od.ctime[i];
8787dd7cddfSDavid du Colombier 		for(i = 0; i < nelem(od.cdate); i++)
8797dd7cddfSDavid du Colombier 			d->cdate[i] = od.cdate[i];
8807dd7cddfSDavid du Colombier 		for(i = 0; i < nelem(od.adate); i++)
8817dd7cddfSDavid du Colombier 			d->adate[i] = od.adate[i];
8827dd7cddfSDavid du Colombier 
8837dd7cddfSDavid du Colombier 		putsect(parp);
8847dd7cddfSDavid du Colombier 
8857dd7cddfSDavid du Colombier 		/*
8867dd7cddfSDavid du Colombier 		 * relocate up other fids to the same file, if it moved
8877dd7cddfSDavid du Colombier 		 */
8889a747e4fSDavid du Colombier 		f->qid.path = QIDPATH(dp);
8897dd7cddfSDavid du Colombier 		if(oaddr != dp->addr || ooffset != dp->offset)
8907dd7cddfSDavid du Colombier 			dosptrreloc(f, dp, oaddr, ooffset);
8919a747e4fSDavid du Colombier 
8929a747e4fSDavid du Colombier 		/*
8939a747e4fSDavid du Colombier 		 * copy fields that are not supposed to change
8949a747e4fSDavid du Colombier 		 */
8959a747e4fSDavid du Colombier 		if(wdir.mtime == ~0)
8969a747e4fSDavid du Colombier 			wdir.mtime = dir.mtime;
8979a747e4fSDavid du Colombier 		if(wdir.mode == ~0)
8989a747e4fSDavid du Colombier 			wdir.mode = dir.mode;
8997dd7cddfSDavid du Colombier 		changes = 1;
9007dd7cddfSDavid du Colombier 	}
9017dd7cddfSDavid du Colombier 
9029a747e4fSDavid du Colombier 	/*
9039a747e4fSDavid du Colombier 	 * do the actual truncate
9049a747e4fSDavid du Colombier 	 */
9059a747e4fSDavid du Colombier 	if(wdir.length != ~0 && wdir.length != dir.length && truncfile(f, wdir.length) < 0)
9069a747e4fSDavid du Colombier 		errno = Eio;
9079a747e4fSDavid du Colombier 
9087dd7cddfSDavid du Colombier 	if(changes){
9097dd7cddfSDavid du Colombier 		putdir(dp->d, &wdir);
9107dd7cddfSDavid du Colombier 		dp->p->flags |= BMOD;
9117dd7cddfSDavid du Colombier 	}
9127dd7cddfSDavid du Colombier 
9137dd7cddfSDavid du Colombier out:
9147dd7cddfSDavid du Colombier 	putfile(f);
9157dd7cddfSDavid du Colombier 	sync();
9163e12c5d1SDavid du Colombier }
917