xref: /plan9/sys/src/cmd/unix/drawterm/kern/devfs-posix.c (revision 58da3067adcdccaaa043d0bfde28ba83b7ced07d)
196cbc34fSDavid du Colombier #include	"u.h"
28ccd4a63SDavid du Colombier #include	<sys/types.h>
38ccd4a63SDavid du Colombier #include	<sys/stat.h>
48ccd4a63SDavid du Colombier #include	<dirent.h>
58ccd4a63SDavid du Colombier #include	<fcntl.h>
68ccd4a63SDavid du Colombier #include	<errno.h>
78ccd4a63SDavid du Colombier #include	<stdio.h> /* for remove, rename */
88ccd4a63SDavid du Colombier #include	<limits.h>
98ccd4a63SDavid du Colombier 
108ccd4a63SDavid du Colombier #ifndef NAME_MAX
118ccd4a63SDavid du Colombier #	define NAME_MAX 256
128ccd4a63SDavid du Colombier #endif
138ccd4a63SDavid du Colombier #include	"lib.h"
148ccd4a63SDavid du Colombier #include	"dat.h"
158ccd4a63SDavid du Colombier #include	"fns.h"
168ccd4a63SDavid du Colombier #include	"error.h"
178ccd4a63SDavid du Colombier 
188ccd4a63SDavid du Colombier 
198ccd4a63SDavid du Colombier typedef	struct Ufsinfo	Ufsinfo;
208ccd4a63SDavid du Colombier 
218ccd4a63SDavid du Colombier enum
228ccd4a63SDavid du Colombier {
238ccd4a63SDavid du Colombier 	NUID	= 256,
248ccd4a63SDavid du Colombier 	NGID	= 256,
258ccd4a63SDavid du Colombier 	MAXPATH	= 1024,
268ccd4a63SDavid du Colombier 	MAXCOMP	= 128
278ccd4a63SDavid du Colombier };
288ccd4a63SDavid du Colombier 
298ccd4a63SDavid du Colombier struct Ufsinfo
308ccd4a63SDavid du Colombier {
318ccd4a63SDavid du Colombier 	int	mode;
328ccd4a63SDavid du Colombier 	int	fd;
338ccd4a63SDavid du Colombier 	int	uid;
348ccd4a63SDavid du Colombier 	int	gid;
358ccd4a63SDavid du Colombier 	DIR*	dir;
3696cbc34fSDavid du Colombier 	vlong	offset;
378ccd4a63SDavid du Colombier 	QLock	oq;
388ccd4a63SDavid du Colombier 	char nextname[NAME_MAX];
398ccd4a63SDavid du Colombier };
408ccd4a63SDavid du Colombier 
418ccd4a63SDavid du Colombier char	*base = "/";
428ccd4a63SDavid du Colombier 
438ccd4a63SDavid du Colombier static	Qid	fsqid(char*, struct stat *);
448ccd4a63SDavid du Colombier static	void	fspath(Chan*, char*, char*);
458ccd4a63SDavid du Colombier static	ulong	fsdirread(Chan*, uchar*, int, ulong);
468ccd4a63SDavid du Colombier static	int	fsomode(int);
478ccd4a63SDavid du Colombier 
488ccd4a63SDavid du Colombier /* clumsy hack, but not worse than the Path stuff in the last one */
498ccd4a63SDavid du Colombier static char*
uc2name(Chan * c)508ccd4a63SDavid du Colombier uc2name(Chan *c)
518ccd4a63SDavid du Colombier {
528ccd4a63SDavid du Colombier 	char *s;
538ccd4a63SDavid du Colombier 
548ccd4a63SDavid du Colombier 	if(c->name == nil)
558ccd4a63SDavid du Colombier 		return "/";
568ccd4a63SDavid du Colombier 	s = c2name(c);
578ccd4a63SDavid du Colombier 	if(s[0]=='#' && s[1]=='U')
588ccd4a63SDavid du Colombier 		return s+2;
598ccd4a63SDavid du Colombier 	return s;
608ccd4a63SDavid du Colombier }
618ccd4a63SDavid du Colombier 
628ccd4a63SDavid du Colombier static char*
lastelem(Chan * c)638ccd4a63SDavid du Colombier lastelem(Chan *c)
648ccd4a63SDavid du Colombier {
658ccd4a63SDavid du Colombier 	char *s, *t;
668ccd4a63SDavid du Colombier 
678ccd4a63SDavid du Colombier 	s = uc2name(c);
688ccd4a63SDavid du Colombier 	if((t = strrchr(s, '/')) == nil)
698ccd4a63SDavid du Colombier 		return s;
708ccd4a63SDavid du Colombier 	if(t[1] == 0)
718ccd4a63SDavid du Colombier 		return t;
728ccd4a63SDavid du Colombier 	return t+1;
738ccd4a63SDavid du Colombier }
748ccd4a63SDavid du Colombier 
758ccd4a63SDavid du Colombier static Chan*
fsattach(char * spec)768ccd4a63SDavid du Colombier fsattach(char *spec)
778ccd4a63SDavid du Colombier {
788ccd4a63SDavid du Colombier 	Chan *c;
798ccd4a63SDavid du Colombier 	struct stat stbuf;
808ccd4a63SDavid du Colombier 	static int devno;
818ccd4a63SDavid du Colombier 	Ufsinfo *uif;
828ccd4a63SDavid du Colombier 
838ccd4a63SDavid du Colombier 	if(stat(base, &stbuf) < 0)
848ccd4a63SDavid du Colombier 		error(strerror(errno));
858ccd4a63SDavid du Colombier 
868ccd4a63SDavid du Colombier 	c = devattach('U', spec);
878ccd4a63SDavid du Colombier 
888ccd4a63SDavid du Colombier 	uif = mallocz(sizeof(Ufsinfo), 1);
898ccd4a63SDavid du Colombier 	uif->mode = stbuf.st_mode;
908ccd4a63SDavid du Colombier 	uif->uid = stbuf.st_uid;
918ccd4a63SDavid du Colombier 	uif->gid = stbuf.st_gid;
928ccd4a63SDavid du Colombier 
938ccd4a63SDavid du Colombier 	c->aux = uif;
948ccd4a63SDavid du Colombier 	c->dev = devno++;
958ccd4a63SDavid du Colombier 	c->qid.type = QTDIR;
968ccd4a63SDavid du Colombier /*print("fsattach %s\n", c2name(c));*/
978ccd4a63SDavid du Colombier 
988ccd4a63SDavid du Colombier 	return c;
998ccd4a63SDavid du Colombier }
1008ccd4a63SDavid du Colombier 
1018ccd4a63SDavid du Colombier static Chan*
fsclone(Chan * c,Chan * nc)1028ccd4a63SDavid du Colombier fsclone(Chan *c, Chan *nc)
1038ccd4a63SDavid du Colombier {
1048ccd4a63SDavid du Colombier 	Ufsinfo *uif;
1058ccd4a63SDavid du Colombier 
1068ccd4a63SDavid du Colombier 	uif = mallocz(sizeof(Ufsinfo), 1);
1078ccd4a63SDavid du Colombier 	*uif = *(Ufsinfo*)c->aux;
1088ccd4a63SDavid du Colombier 	nc->aux = uif;
1098ccd4a63SDavid du Colombier 
1108ccd4a63SDavid du Colombier 	return nc;
1118ccd4a63SDavid du Colombier }
1128ccd4a63SDavid du Colombier 
1138ccd4a63SDavid du Colombier static int
fswalk1(Chan * c,char * name)1148ccd4a63SDavid du Colombier fswalk1(Chan *c, char *name)
1158ccd4a63SDavid du Colombier {
1168ccd4a63SDavid du Colombier 	struct stat stbuf;
1178ccd4a63SDavid du Colombier 	char path[MAXPATH];
1188ccd4a63SDavid du Colombier 	Ufsinfo *uif;
1198ccd4a63SDavid du Colombier 
1208ccd4a63SDavid du Colombier 	fspath(c, name, path);
1218ccd4a63SDavid du Colombier 
1228ccd4a63SDavid du Colombier 	/*print("** fs walk '%s' -> %s\n", path, name);  */
1238ccd4a63SDavid du Colombier 
1248ccd4a63SDavid du Colombier 	if(stat(path, &stbuf) < 0)
1258ccd4a63SDavid du Colombier 		return 0;
1268ccd4a63SDavid du Colombier 
1278ccd4a63SDavid du Colombier 	uif = c->aux;
1288ccd4a63SDavid du Colombier 
1298ccd4a63SDavid du Colombier 	uif->mode = stbuf.st_mode;
1308ccd4a63SDavid du Colombier 	uif->uid = stbuf.st_uid;
1318ccd4a63SDavid du Colombier 	uif->gid = stbuf.st_gid;
1328ccd4a63SDavid du Colombier 
1338ccd4a63SDavid du Colombier 	c->qid = fsqid(path, &stbuf);
1348ccd4a63SDavid du Colombier 
1358ccd4a63SDavid du Colombier 	return 1;
1368ccd4a63SDavid du Colombier }
1378ccd4a63SDavid du Colombier 
1388ccd4a63SDavid du Colombier extern Cname* addelem(Cname*, char*);
1398ccd4a63SDavid du Colombier 
1408ccd4a63SDavid du Colombier static Walkqid*
fswalk(Chan * c,Chan * nc,char ** name,int nname)1418ccd4a63SDavid du Colombier fswalk(Chan *c, Chan *nc, char **name, int nname)
1428ccd4a63SDavid du Colombier {
1438ccd4a63SDavid du Colombier 	int i;
1448ccd4a63SDavid du Colombier 	Cname *cname;
1458ccd4a63SDavid du Colombier 	Walkqid *wq;
1468ccd4a63SDavid du Colombier 
1478ccd4a63SDavid du Colombier 	if(nc != nil)
1488ccd4a63SDavid du Colombier 		panic("fswalk: nc != nil");
1498ccd4a63SDavid du Colombier 	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
1508ccd4a63SDavid du Colombier 	nc = devclone(c);
1518ccd4a63SDavid du Colombier 	cname = c->name;
1528ccd4a63SDavid du Colombier 	incref(&cname->ref);
1538ccd4a63SDavid du Colombier 
1548ccd4a63SDavid du Colombier 	fsclone(c, nc);
1558ccd4a63SDavid du Colombier 	wq->clone = nc;
1568ccd4a63SDavid du Colombier 	for(i=0; i<nname; i++){
1578ccd4a63SDavid du Colombier 		nc->name = cname;
1588ccd4a63SDavid du Colombier 		if(fswalk1(nc, name[i]) == 0)
1598ccd4a63SDavid du Colombier 			break;
1608ccd4a63SDavid du Colombier 		cname = addelem(cname, name[i]);
1618ccd4a63SDavid du Colombier 		wq->qid[i] = nc->qid;
1628ccd4a63SDavid du Colombier 	}
16396cbc34fSDavid du Colombier 	nc->name = cname;
1648ccd4a63SDavid du Colombier 	if(i != nname){
1658ccd4a63SDavid du Colombier 		cclose(nc);
1668ccd4a63SDavid du Colombier 		wq->clone = nil;
1678ccd4a63SDavid du Colombier 	}
1688ccd4a63SDavid du Colombier 	wq->nqid = i;
1698ccd4a63SDavid du Colombier 	return wq;
1708ccd4a63SDavid du Colombier }
1718ccd4a63SDavid du Colombier 
1728ccd4a63SDavid du Colombier static int
fsstat(Chan * c,uchar * buf,int n)1738ccd4a63SDavid du Colombier fsstat(Chan *c, uchar *buf, int n)
1748ccd4a63SDavid du Colombier {
1758ccd4a63SDavid du Colombier 	Dir d;
1768ccd4a63SDavid du Colombier 	struct stat stbuf;
1778ccd4a63SDavid du Colombier 	char path[MAXPATH];
1788ccd4a63SDavid du Colombier 
1798ccd4a63SDavid du Colombier 	if(n < BIT16SZ)
1808ccd4a63SDavid du Colombier 		error(Eshortstat);
1818ccd4a63SDavid du Colombier 
1828ccd4a63SDavid du Colombier 	fspath(c, 0, path);
1838ccd4a63SDavid du Colombier 	if(stat(path, &stbuf) < 0)
1848ccd4a63SDavid du Colombier 		error(strerror(errno));
1858ccd4a63SDavid du Colombier 
1868ccd4a63SDavid du Colombier 	d.name = lastelem(c);
1878ccd4a63SDavid du Colombier 	d.uid = "unknown";
1888ccd4a63SDavid du Colombier 	d.gid = "unknown";
1898ccd4a63SDavid du Colombier 	d.muid = "unknown";
1908ccd4a63SDavid du Colombier 	d.qid = c->qid;
1918ccd4a63SDavid du Colombier 	d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777);
1928ccd4a63SDavid du Colombier 	d.atime = stbuf.st_atime;
1938ccd4a63SDavid du Colombier 	d.mtime = stbuf.st_mtime;
1948ccd4a63SDavid du Colombier 	d.length = stbuf.st_size;
1958ccd4a63SDavid du Colombier 	d.type = 'U';
1968ccd4a63SDavid du Colombier 	d.dev = c->dev;
1978ccd4a63SDavid du Colombier 	return convD2M(&d, buf, n);
1988ccd4a63SDavid du Colombier }
1998ccd4a63SDavid du Colombier 
2008ccd4a63SDavid du Colombier static Chan*
fsopen(Chan * c,int mode)2018ccd4a63SDavid du Colombier fsopen(Chan *c, int mode)
2028ccd4a63SDavid du Colombier {
2038ccd4a63SDavid du Colombier 	char path[MAXPATH];
2048ccd4a63SDavid du Colombier 	int m, isdir;
2058ccd4a63SDavid du Colombier 	Ufsinfo *uif;
2068ccd4a63SDavid du Colombier 
2078ccd4a63SDavid du Colombier /*print("fsopen %s\n", c2name(c));*/
2088ccd4a63SDavid du Colombier 	m = mode & (OTRUNC|3);
2098ccd4a63SDavid du Colombier 	switch(m) {
2108ccd4a63SDavid du Colombier 	case 0:
2118ccd4a63SDavid du Colombier 		break;
2128ccd4a63SDavid du Colombier 	case 1:
2138ccd4a63SDavid du Colombier 	case 1|16:
2148ccd4a63SDavid du Colombier 		break;
2158ccd4a63SDavid du Colombier 	case 2:
2168ccd4a63SDavid du Colombier 	case 0|16:
2178ccd4a63SDavid du Colombier 	case 2|16:
2188ccd4a63SDavid du Colombier 		break;
2198ccd4a63SDavid du Colombier 	case 3:
2208ccd4a63SDavid du Colombier 		break;
2218ccd4a63SDavid du Colombier 	default:
2228ccd4a63SDavid du Colombier 		error(Ebadarg);
2238ccd4a63SDavid du Colombier 	}
2248ccd4a63SDavid du Colombier 
2258ccd4a63SDavid du Colombier 	isdir = c->qid.type & QTDIR;
2268ccd4a63SDavid du Colombier 
2278ccd4a63SDavid du Colombier 	if(isdir && mode != OREAD)
2288ccd4a63SDavid du Colombier 		error(Eperm);
2298ccd4a63SDavid du Colombier 
2308ccd4a63SDavid du Colombier 	m = fsomode(m & 3);
2318ccd4a63SDavid du Colombier 	c->mode = openmode(mode);
2328ccd4a63SDavid du Colombier 
2338ccd4a63SDavid du Colombier 	uif = c->aux;
2348ccd4a63SDavid du Colombier 
2358ccd4a63SDavid du Colombier 	fspath(c, 0, path);
2368ccd4a63SDavid du Colombier 	if(isdir) {
2378ccd4a63SDavid du Colombier 		uif->dir = opendir(path);
2388ccd4a63SDavid du Colombier 		if(uif->dir == 0)
2398ccd4a63SDavid du Colombier 			error(strerror(errno));
2408ccd4a63SDavid du Colombier 	}
2418ccd4a63SDavid du Colombier 	else {
2428ccd4a63SDavid du Colombier 		if(mode & OTRUNC)
2438ccd4a63SDavid du Colombier 			m |= O_TRUNC;
2448ccd4a63SDavid du Colombier 		uif->fd = open(path, m, 0666);
2458ccd4a63SDavid du Colombier 
2468ccd4a63SDavid du Colombier 		if(uif->fd < 0)
2478ccd4a63SDavid du Colombier 			error(strerror(errno));
2488ccd4a63SDavid du Colombier 	}
2498ccd4a63SDavid du Colombier 	uif->offset = 0;
2508ccd4a63SDavid du Colombier 
2518ccd4a63SDavid du Colombier 	c->offset = 0;
2528ccd4a63SDavid du Colombier 	c->flag |= COPEN;
2538ccd4a63SDavid du Colombier 	return c;
2548ccd4a63SDavid du Colombier }
2558ccd4a63SDavid du Colombier 
2568ccd4a63SDavid du Colombier static void
fscreate(Chan * c,char * name,int mode,ulong perm)2578ccd4a63SDavid du Colombier fscreate(Chan *c, char *name, int mode, ulong perm)
2588ccd4a63SDavid du Colombier {
2598ccd4a63SDavid du Colombier 	int fd, m;
2608ccd4a63SDavid du Colombier 	char path[MAXPATH];
2618ccd4a63SDavid du Colombier 	struct stat stbuf;
2628ccd4a63SDavid du Colombier 	Ufsinfo *uif;
2638ccd4a63SDavid du Colombier 
2648ccd4a63SDavid du Colombier 	m = fsomode(mode&3);
2658ccd4a63SDavid du Colombier 
2668ccd4a63SDavid du Colombier 	fspath(c, name, path);
2678ccd4a63SDavid du Colombier 
2688ccd4a63SDavid du Colombier 	uif = c->aux;
2698ccd4a63SDavid du Colombier 
2708ccd4a63SDavid du Colombier 	if(perm & DMDIR) {
2718ccd4a63SDavid du Colombier 		if(m)
2728ccd4a63SDavid du Colombier 			error(Eperm);
2738ccd4a63SDavid du Colombier 
2748ccd4a63SDavid du Colombier 		if(mkdir(path, perm & 0777) < 0)
2758ccd4a63SDavid du Colombier 			error(strerror(errno));
2768ccd4a63SDavid du Colombier 
2778ccd4a63SDavid du Colombier 		fd = open(path, 0);
2788ccd4a63SDavid du Colombier 		if(fd >= 0) {
2798ccd4a63SDavid du Colombier 			chmod(path, perm & 0777);
2808ccd4a63SDavid du Colombier 			chown(path, uif->uid, uif->uid);
2818ccd4a63SDavid du Colombier 		}
2828ccd4a63SDavid du Colombier 		close(fd);
2838ccd4a63SDavid du Colombier 
2848ccd4a63SDavid du Colombier 		uif->dir = opendir(path);
2858ccd4a63SDavid du Colombier 		if(uif->dir == 0)
2868ccd4a63SDavid du Colombier 			error(strerror(errno));
2878ccd4a63SDavid du Colombier 	}
2888ccd4a63SDavid du Colombier 	else {
2898ccd4a63SDavid du Colombier 		fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666);
2908ccd4a63SDavid du Colombier 		if(fd >= 0) {
2918ccd4a63SDavid du Colombier 			if(m != 1) {
2928ccd4a63SDavid du Colombier 				close(fd);
2938ccd4a63SDavid du Colombier 				fd = open(path, m);
2948ccd4a63SDavid du Colombier 			}
2958ccd4a63SDavid du Colombier 			chmod(path, perm & 0777);
2968ccd4a63SDavid du Colombier 			chown(path, uif->uid, uif->gid);
2978ccd4a63SDavid du Colombier 		}
2988ccd4a63SDavid du Colombier 		if(fd < 0)
2998ccd4a63SDavid du Colombier 			error(strerror(errno));
3008ccd4a63SDavid du Colombier 		uif->fd = fd;
3018ccd4a63SDavid du Colombier 	}
3028ccd4a63SDavid du Colombier 
3038ccd4a63SDavid du Colombier 	if(stat(path, &stbuf) < 0)
3048ccd4a63SDavid du Colombier 		error(strerror(errno));
3058ccd4a63SDavid du Colombier 	c->qid = fsqid(path, &stbuf);
3068ccd4a63SDavid du Colombier 	c->offset = 0;
3078ccd4a63SDavid du Colombier 	c->flag |= COPEN;
3088ccd4a63SDavid du Colombier 	c->mode = openmode(mode);
3098ccd4a63SDavid du Colombier }
3108ccd4a63SDavid du Colombier 
3118ccd4a63SDavid du Colombier static void
fsclose(Chan * c)3128ccd4a63SDavid du Colombier fsclose(Chan *c)
3138ccd4a63SDavid du Colombier {
3148ccd4a63SDavid du Colombier 	Ufsinfo *uif;
3158ccd4a63SDavid du Colombier 
3168ccd4a63SDavid du Colombier 	uif = c->aux;
3178ccd4a63SDavid du Colombier 
3188ccd4a63SDavid du Colombier 	if(c->flag & COPEN) {
3198ccd4a63SDavid du Colombier 		if(c->qid.type & QTDIR)
3208ccd4a63SDavid du Colombier 			closedir(uif->dir);
3218ccd4a63SDavid du Colombier 		else
3228ccd4a63SDavid du Colombier 			close(uif->fd);
3238ccd4a63SDavid du Colombier 	}
3248ccd4a63SDavid du Colombier 
3258ccd4a63SDavid du Colombier 	free(uif);
3268ccd4a63SDavid du Colombier }
3278ccd4a63SDavid du Colombier 
3288ccd4a63SDavid du Colombier static long
fsread(Chan * c,void * va,long n,vlong offset)3298ccd4a63SDavid du Colombier fsread(Chan *c, void *va, long n, vlong offset)
3308ccd4a63SDavid du Colombier {
3318ccd4a63SDavid du Colombier 	int fd, r;
3328ccd4a63SDavid du Colombier 	Ufsinfo *uif;
3338ccd4a63SDavid du Colombier 
3348ccd4a63SDavid du Colombier /*print("fsread %s\n", c2name(c));*/
3358ccd4a63SDavid du Colombier 	if(c->qid.type & QTDIR)
3368ccd4a63SDavid du Colombier 		return fsdirread(c, va, n, offset);
3378ccd4a63SDavid du Colombier 
3388ccd4a63SDavid du Colombier 	uif = c->aux;
3398ccd4a63SDavid du Colombier 	qlock(&uif->oq);
3408ccd4a63SDavid du Colombier 	if(waserror()) {
3418ccd4a63SDavid du Colombier 		qunlock(&uif->oq);
3428ccd4a63SDavid du Colombier 		nexterror();
3438ccd4a63SDavid du Colombier 	}
3448ccd4a63SDavid du Colombier 	fd = uif->fd;
3458ccd4a63SDavid du Colombier 	if(uif->offset != offset) {
3468ccd4a63SDavid du Colombier 		r = lseek(fd, offset, 0);
3478ccd4a63SDavid du Colombier 		if(r < 0)
3488ccd4a63SDavid du Colombier 			error(strerror(errno));
3498ccd4a63SDavid du Colombier 		uif->offset = offset;
3508ccd4a63SDavid du Colombier 	}
3518ccd4a63SDavid du Colombier 
3528ccd4a63SDavid du Colombier 	n = read(fd, va, n);
3538ccd4a63SDavid du Colombier 	if(n < 0)
3548ccd4a63SDavid du Colombier 		error(strerror(errno));
3558ccd4a63SDavid du Colombier 
3568ccd4a63SDavid du Colombier 	uif->offset += n;
3578ccd4a63SDavid du Colombier 	qunlock(&uif->oq);
3588ccd4a63SDavid du Colombier 	poperror();
3598ccd4a63SDavid du Colombier 
3608ccd4a63SDavid du Colombier 	return n;
3618ccd4a63SDavid du Colombier }
3628ccd4a63SDavid du Colombier 
3638ccd4a63SDavid du Colombier static long
fswrite(Chan * c,void * va,long n,vlong offset)3648ccd4a63SDavid du Colombier fswrite(Chan *c, void *va, long n, vlong offset)
3658ccd4a63SDavid du Colombier {
3668ccd4a63SDavid du Colombier 	int fd, r;
3678ccd4a63SDavid du Colombier 	Ufsinfo *uif;
3688ccd4a63SDavid du Colombier 
3698ccd4a63SDavid du Colombier 	uif = c->aux;
3708ccd4a63SDavid du Colombier 
3718ccd4a63SDavid du Colombier 	qlock(&uif->oq);
3728ccd4a63SDavid du Colombier 	if(waserror()) {
3738ccd4a63SDavid du Colombier 		qunlock(&uif->oq);
3748ccd4a63SDavid du Colombier 		nexterror();
3758ccd4a63SDavid du Colombier 	}
3768ccd4a63SDavid du Colombier 	fd = uif->fd;
3778ccd4a63SDavid du Colombier 	if(uif->offset != offset) {
3788ccd4a63SDavid du Colombier 		r = lseek(fd, offset, 0);
3798ccd4a63SDavid du Colombier 		if(r < 0)
3808ccd4a63SDavid du Colombier 			error(strerror(errno));
3818ccd4a63SDavid du Colombier 		uif->offset = offset;
3828ccd4a63SDavid du Colombier 	}
3838ccd4a63SDavid du Colombier 
3848ccd4a63SDavid du Colombier 	n = write(fd, va, n);
3858ccd4a63SDavid du Colombier 	if(n < 0)
3868ccd4a63SDavid du Colombier 		error(strerror(errno));
3878ccd4a63SDavid du Colombier 
3888ccd4a63SDavid du Colombier 	uif->offset += n;
3898ccd4a63SDavid du Colombier 	qunlock(&uif->oq);
3908ccd4a63SDavid du Colombier 	poperror();
3918ccd4a63SDavid du Colombier 
3928ccd4a63SDavid du Colombier 	return n;
3938ccd4a63SDavid du Colombier }
3948ccd4a63SDavid du Colombier 
3958ccd4a63SDavid du Colombier static void
fsremove(Chan * c)3968ccd4a63SDavid du Colombier fsremove(Chan *c)
3978ccd4a63SDavid du Colombier {
3988ccd4a63SDavid du Colombier 	int n;
3998ccd4a63SDavid du Colombier 	char path[MAXPATH];
4008ccd4a63SDavid du Colombier 
4018ccd4a63SDavid du Colombier 	fspath(c, 0, path);
4028ccd4a63SDavid du Colombier 	if(c->qid.type & QTDIR)
4038ccd4a63SDavid du Colombier 		n = rmdir(path);
4048ccd4a63SDavid du Colombier 	else
4058ccd4a63SDavid du Colombier 		n = remove(path);
4068ccd4a63SDavid du Colombier 	if(n < 0)
4078ccd4a63SDavid du Colombier 		error(strerror(errno));
4088ccd4a63SDavid du Colombier }
4098ccd4a63SDavid du Colombier 
4108ccd4a63SDavid du Colombier int
fswstat(Chan * c,uchar * buf,int n)4118ccd4a63SDavid du Colombier fswstat(Chan *c, uchar *buf, int n)
4128ccd4a63SDavid du Colombier {
4138ccd4a63SDavid du Colombier 	Dir d;
4148ccd4a63SDavid du Colombier 	struct stat stbuf;
4158ccd4a63SDavid du Colombier 	char old[MAXPATH], new[MAXPATH];
4168ccd4a63SDavid du Colombier 	char strs[MAXPATH*3], *p;
4178ccd4a63SDavid du Colombier 	Ufsinfo *uif;
4188ccd4a63SDavid du Colombier 
4198ccd4a63SDavid du Colombier 	if(convM2D(buf, n, &d, strs) != n)
4208ccd4a63SDavid du Colombier 		error(Ebadstat);
4218ccd4a63SDavid du Colombier 
4228ccd4a63SDavid du Colombier 	fspath(c, 0, old);
4238ccd4a63SDavid du Colombier 	if(stat(old, &stbuf) < 0)
4248ccd4a63SDavid du Colombier 		error(strerror(errno));
4258ccd4a63SDavid du Colombier 
4268ccd4a63SDavid du Colombier 	uif = c->aux;
4278ccd4a63SDavid du Colombier 
428*58da3067SDavid du Colombier 	fspath(c, 0, old);
429*58da3067SDavid du Colombier 	if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) {
430*58da3067SDavid du Colombier 		if(chmod(old, d.mode&0777) < 0)
431*58da3067SDavid du Colombier 			error(strerror(errno));
432*58da3067SDavid du Colombier 		uif->mode &= ~0777;
433*58da3067SDavid du Colombier 		uif->mode |= d.mode&0777;
434*58da3067SDavid du Colombier 	}
435*58da3067SDavid du Colombier 
4368ccd4a63SDavid du Colombier 	if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) {
4378ccd4a63SDavid du Colombier 		fspath(c, 0, old);
4388ccd4a63SDavid du Colombier 		strcpy(new, old);
4398ccd4a63SDavid du Colombier 		p = strrchr(new, '/');
4408ccd4a63SDavid du Colombier 		strcpy(p+1, d.name);
4418ccd4a63SDavid du Colombier 		if(rename(old, new) < 0)
4428ccd4a63SDavid du Colombier 			error(strerror(errno));
4438ccd4a63SDavid du Colombier 	}
4448ccd4a63SDavid du Colombier 
4458ccd4a63SDavid du Colombier /*
4468ccd4a63SDavid du Colombier 	p = name2pass(gid, d.gid);
4478ccd4a63SDavid du Colombier 	if(p == 0)
4488ccd4a63SDavid du Colombier 		error(Eunknown);
4498ccd4a63SDavid du Colombier 
4508ccd4a63SDavid du Colombier 	if(p->id != stbuf.st_gid) {
4518ccd4a63SDavid du Colombier 		if(chown(old, stbuf.st_uid, p->id) < 0)
4528ccd4a63SDavid du Colombier 			error(strerror(errno));
4538ccd4a63SDavid du Colombier 
4548ccd4a63SDavid du Colombier 		uif->gid = p->id;
4558ccd4a63SDavid du Colombier 	}
4568ccd4a63SDavid du Colombier */
4578ccd4a63SDavid du Colombier 	return n;
4588ccd4a63SDavid du Colombier }
4598ccd4a63SDavid du Colombier 
4608ccd4a63SDavid du Colombier static Qid
fsqid(char * p,struct stat * st)4618ccd4a63SDavid du Colombier fsqid(char *p, struct stat *st)
4628ccd4a63SDavid du Colombier {
4638ccd4a63SDavid du Colombier 	Qid q;
4648ccd4a63SDavid du Colombier 	int dev;
4658ccd4a63SDavid du Colombier 	ulong h;
4668ccd4a63SDavid du Colombier 	static int nqdev;
4678ccd4a63SDavid du Colombier 	static uchar *qdev;
4688ccd4a63SDavid du Colombier 
4698ccd4a63SDavid du Colombier 	if(qdev == 0)
4708ccd4a63SDavid du Colombier 		qdev = mallocz(65536U, 1);
4718ccd4a63SDavid du Colombier 
4728ccd4a63SDavid du Colombier 	q.type = 0;
4738ccd4a63SDavid du Colombier 	if((st->st_mode&S_IFMT) ==  S_IFDIR)
4748ccd4a63SDavid du Colombier 		q.type = QTDIR;
4758ccd4a63SDavid du Colombier 
4768ccd4a63SDavid du Colombier 	dev = st->st_dev & 0xFFFFUL;
4778ccd4a63SDavid du Colombier 	if(qdev[dev] == 0)
4788ccd4a63SDavid du Colombier 		qdev[dev] = ++nqdev;
4798ccd4a63SDavid du Colombier 
4808ccd4a63SDavid du Colombier 	h = 0;
4818ccd4a63SDavid du Colombier 	while(*p != '\0')
4828ccd4a63SDavid du Colombier 		h += *p++ * 13;
4838ccd4a63SDavid du Colombier 
4848ccd4a63SDavid du Colombier 	q.path = (vlong)qdev[dev]<<32;
4858ccd4a63SDavid du Colombier 	q.path |= h;
4868ccd4a63SDavid du Colombier 	q.vers = st->st_mtime;
4878ccd4a63SDavid du Colombier 
4888ccd4a63SDavid du Colombier 	return q;
4898ccd4a63SDavid du Colombier }
4908ccd4a63SDavid du Colombier 
4918ccd4a63SDavid du Colombier static void
fspath(Chan * c,char * ext,char * path)4928ccd4a63SDavid du Colombier fspath(Chan *c, char *ext, char *path)
4938ccd4a63SDavid du Colombier {
4948ccd4a63SDavid du Colombier 	strcpy(path, base);
4958ccd4a63SDavid du Colombier 	strcat(path, "/");
4968ccd4a63SDavid du Colombier 	strcat(path, uc2name(c));
4978ccd4a63SDavid du Colombier 	if(ext){
4988ccd4a63SDavid du Colombier 		strcat(path, "/");
4998ccd4a63SDavid du Colombier 		strcat(path, ext);
5008ccd4a63SDavid du Colombier 	}
5018ccd4a63SDavid du Colombier 	cleanname(path);
5028ccd4a63SDavid du Colombier }
5038ccd4a63SDavid du Colombier 
5048ccd4a63SDavid du Colombier static int
isdots(char * name)5058ccd4a63SDavid du Colombier isdots(char *name)
5068ccd4a63SDavid du Colombier {
5078ccd4a63SDavid du Colombier 	if(name[0] != '.')
5088ccd4a63SDavid du Colombier 		return 0;
5098ccd4a63SDavid du Colombier 	if(name[1] == '\0')
5108ccd4a63SDavid du Colombier 		return 1;
5118ccd4a63SDavid du Colombier 	if(name[1] != '.')
5128ccd4a63SDavid du Colombier 		return 0;
5138ccd4a63SDavid du Colombier 	if(name[2] == '\0')
5148ccd4a63SDavid du Colombier 		return 1;
5158ccd4a63SDavid du Colombier 	return 0;
5168ccd4a63SDavid du Colombier }
5178ccd4a63SDavid du Colombier 
5188ccd4a63SDavid du Colombier static int
p9readdir(char * name,Ufsinfo * uif)5198ccd4a63SDavid du Colombier p9readdir(char *name, Ufsinfo *uif)
5208ccd4a63SDavid du Colombier {
5218ccd4a63SDavid du Colombier 	struct dirent *de;
5228ccd4a63SDavid du Colombier 
5238ccd4a63SDavid du Colombier 	if(uif->nextname[0]){
5248ccd4a63SDavid du Colombier 		strcpy(name, uif->nextname);
5258ccd4a63SDavid du Colombier 		uif->nextname[0] = 0;
5268ccd4a63SDavid du Colombier 		return 1;
5278ccd4a63SDavid du Colombier 	}
5288ccd4a63SDavid du Colombier 
5298ccd4a63SDavid du Colombier 	de = readdir(uif->dir);
5308ccd4a63SDavid du Colombier 	if(de == NULL)
5318ccd4a63SDavid du Colombier 		return 0;
5328ccd4a63SDavid du Colombier 
5338ccd4a63SDavid du Colombier 	strcpy(name, de->d_name);
5348ccd4a63SDavid du Colombier 	return 1;
5358ccd4a63SDavid du Colombier }
5368ccd4a63SDavid du Colombier 
5378ccd4a63SDavid du Colombier static ulong
fsdirread(Chan * c,uchar * va,int count,ulong offset)5388ccd4a63SDavid du Colombier fsdirread(Chan *c, uchar *va, int count, ulong offset)
5398ccd4a63SDavid du Colombier {
5408ccd4a63SDavid du Colombier 	int i;
5418ccd4a63SDavid du Colombier 	Dir d;
5428ccd4a63SDavid du Colombier 	long n;
5438ccd4a63SDavid du Colombier 	char de[NAME_MAX];
5448ccd4a63SDavid du Colombier 	struct stat stbuf;
5458ccd4a63SDavid du Colombier 	char path[MAXPATH], dirpath[MAXPATH];
5468ccd4a63SDavid du Colombier 	Ufsinfo *uif;
5478ccd4a63SDavid du Colombier 
5488ccd4a63SDavid du Colombier /*print("fsdirread %s\n", c2name(c));*/
5498ccd4a63SDavid du Colombier 	i = 0;
5508ccd4a63SDavid du Colombier 	uif = c->aux;
5518ccd4a63SDavid du Colombier 
5528ccd4a63SDavid du Colombier 	errno = 0;
5538ccd4a63SDavid du Colombier 	if(uif->offset != offset) {
5548ccd4a63SDavid du Colombier 		if(offset != 0)
5558ccd4a63SDavid du Colombier 			error("bad offset in fsdirread");
5568ccd4a63SDavid du Colombier 		uif->offset = offset;  /* sync offset */
5578ccd4a63SDavid du Colombier 		uif->nextname[0] = 0;
5588ccd4a63SDavid du Colombier 		rewinddir(uif->dir);
5598ccd4a63SDavid du Colombier 	}
5608ccd4a63SDavid du Colombier 
5618ccd4a63SDavid du Colombier 	fspath(c, 0, dirpath);
5628ccd4a63SDavid du Colombier 
5638ccd4a63SDavid du Colombier 	while(i+BIT16SZ < count) {
5648ccd4a63SDavid du Colombier 		if(!p9readdir(de, uif))
5658ccd4a63SDavid du Colombier 			break;
5668ccd4a63SDavid du Colombier 
5678ccd4a63SDavid du Colombier 		if(de[0]==0 || isdots(de))
5688ccd4a63SDavid du Colombier 			continue;
5698ccd4a63SDavid du Colombier 
5708ccd4a63SDavid du Colombier 		d.name = de;
5718ccd4a63SDavid du Colombier 		sprint(path, "%s/%s", dirpath, de);
5728ccd4a63SDavid du Colombier 		memset(&stbuf, 0, sizeof stbuf);
5738ccd4a63SDavid du Colombier 
5748ccd4a63SDavid du Colombier 		if(stat(path, &stbuf) < 0) {
5758ccd4a63SDavid du Colombier 			/* fprint(2, "dir: bad path %s\n", path); */
5768ccd4a63SDavid du Colombier 			/* but continue... probably a bad symlink */
5778ccd4a63SDavid du Colombier 		}
5788ccd4a63SDavid du Colombier 
5798ccd4a63SDavid du Colombier 		d.uid = "unknown";
5808ccd4a63SDavid du Colombier 		d.gid = "unknown";
5818ccd4a63SDavid du Colombier 		d.muid = "unknown";
5828ccd4a63SDavid du Colombier 		d.qid = fsqid(path, &stbuf);
5838ccd4a63SDavid du Colombier 		d.mode = (d.qid.type<<24)|(stbuf.st_mode&0777);
5848ccd4a63SDavid du Colombier 		d.atime = stbuf.st_atime;
5858ccd4a63SDavid du Colombier 		d.mtime = stbuf.st_mtime;
5868ccd4a63SDavid du Colombier 		d.length = stbuf.st_size;
5878ccd4a63SDavid du Colombier 		d.type = 'U';
5888ccd4a63SDavid du Colombier 		d.dev = c->dev;
5898ccd4a63SDavid du Colombier 		n = convD2M(&d, (uchar*)va+i, count-i);
5908ccd4a63SDavid du Colombier 		if(n == BIT16SZ){
5918ccd4a63SDavid du Colombier 			strcpy(uif->nextname, de);
5928ccd4a63SDavid du Colombier 			break;
5938ccd4a63SDavid du Colombier 		}
5948ccd4a63SDavid du Colombier 		i += n;
5958ccd4a63SDavid du Colombier 	}
5968ccd4a63SDavid du Colombier /*print("got %d\n", i);*/
5978ccd4a63SDavid du Colombier 	uif->offset += i;
5988ccd4a63SDavid du Colombier 	return i;
5998ccd4a63SDavid du Colombier }
6008ccd4a63SDavid du Colombier 
6018ccd4a63SDavid du Colombier static int
fsomode(int m)6028ccd4a63SDavid du Colombier fsomode(int m)
6038ccd4a63SDavid du Colombier {
6048ccd4a63SDavid du Colombier 	switch(m) {
6058ccd4a63SDavid du Colombier 	case 0:			/* OREAD */
6068ccd4a63SDavid du Colombier 	case 3:			/* OEXEC */
6078ccd4a63SDavid du Colombier 		return 0;
6088ccd4a63SDavid du Colombier 	case 1:			/* OWRITE */
6098ccd4a63SDavid du Colombier 		return 1;
6108ccd4a63SDavid du Colombier 	case 2:			/* ORDWR */
6118ccd4a63SDavid du Colombier 		return 2;
6128ccd4a63SDavid du Colombier 	}
6138ccd4a63SDavid du Colombier 	error(Ebadarg);
6148ccd4a63SDavid du Colombier 	return 0;
6158ccd4a63SDavid du Colombier }
6168ccd4a63SDavid du Colombier 
6178ccd4a63SDavid du Colombier Dev fsdevtab = {
6188ccd4a63SDavid du Colombier 	'U',
6198ccd4a63SDavid du Colombier 	"fs",
6208ccd4a63SDavid du Colombier 
6218ccd4a63SDavid du Colombier 	devreset,
6228ccd4a63SDavid du Colombier 	devinit,
6238ccd4a63SDavid du Colombier 	devshutdown,
6248ccd4a63SDavid du Colombier 	fsattach,
6258ccd4a63SDavid du Colombier 	fswalk,
6268ccd4a63SDavid du Colombier 	fsstat,
6278ccd4a63SDavid du Colombier 	fsopen,
6288ccd4a63SDavid du Colombier 	fscreate,
6298ccd4a63SDavid du Colombier 	fsclose,
6308ccd4a63SDavid du Colombier 	fsread,
6318ccd4a63SDavid du Colombier 	devbread,
6328ccd4a63SDavid du Colombier 	fswrite,
6338ccd4a63SDavid du Colombier 	devbwrite,
6348ccd4a63SDavid du Colombier 	fsremove,
6358ccd4a63SDavid du Colombier 	fswstat,
6368ccd4a63SDavid du Colombier };
637