137da2899SCharles.Forsyth /*
237da2899SCharles.Forsyth * Unix file system interface
337da2899SCharles.Forsyth */
437da2899SCharles.Forsyth #define _LARGEFILE64_SOURCE 1
537da2899SCharles.Forsyth #define _FILE_OFFSET_BITS 64
637da2899SCharles.Forsyth #include "dat.h"
737da2899SCharles.Forsyth #include "fns.h"
837da2899SCharles.Forsyth #include "error.h"
937da2899SCharles.Forsyth
1037da2899SCharles.Forsyth #include <sys/types.h>
1137da2899SCharles.Forsyth #include <sys/stat.h>
12*3f109ae8SYaroslav Kolomiiets #include <fcntl.h>
1335a6f3e1Sforsyth #include <sys/socket.h>
1435a6f3e1Sforsyth #include <sys/un.h>
1537da2899SCharles.Forsyth #include <utime.h>
1637da2899SCharles.Forsyth #include <dirent.h>
1737da2899SCharles.Forsyth #include <stdio.h>
1837da2899SCharles.Forsyth #define __EXTENSIONS__
1937da2899SCharles.Forsyth #undef getwd
2037da2899SCharles.Forsyth #include <unistd.h>
2137da2899SCharles.Forsyth #include <pwd.h>
2237da2899SCharles.Forsyth #include <grp.h>
2337da2899SCharles.Forsyth
2437da2899SCharles.Forsyth typedef struct Fsinfo Fsinfo;
2537da2899SCharles.Forsyth struct Fsinfo
2637da2899SCharles.Forsyth {
2737da2899SCharles.Forsyth int uid;
2837da2899SCharles.Forsyth int gid;
2937da2899SCharles.Forsyth int mode; /* Unix mode */
3037da2899SCharles.Forsyth DIR* dir; /* open directory */
3137da2899SCharles.Forsyth struct dirent* de; /* directory reading */
3237da2899SCharles.Forsyth int fd; /* open files */
3337da2899SCharles.Forsyth ulong offset; /* offset when reading directory */
3423babd45SCharles.Forsyth int eod; /* end of directory */
3535a6f3e1Sforsyth int issocket;
3637da2899SCharles.Forsyth QLock oq; /* mutex for offset */
3737da2899SCharles.Forsyth char* spec;
3837da2899SCharles.Forsyth Cname* name; /* Unix's name for file */
3937da2899SCharles.Forsyth Qid rootqid; /* Plan 9's qid for Inferno's root */
4037da2899SCharles.Forsyth };
4137da2899SCharles.Forsyth
4237da2899SCharles.Forsyth #define FS(c) ((Fsinfo*)(c)->aux)
4337da2899SCharles.Forsyth
4437da2899SCharles.Forsyth enum
4537da2899SCharles.Forsyth {
4637da2899SCharles.Forsyth IDSHIFT = 8,
4737da2899SCharles.Forsyth NID = 1 << IDSHIFT,
4837da2899SCharles.Forsyth IDMASK = NID - 1,
4937da2899SCharles.Forsyth MAXPATH = 1024 /* TO DO: eliminate this */
5037da2899SCharles.Forsyth };
5137da2899SCharles.Forsyth
52184c64d4SCharles.Forsyth typedef struct User User;
53184c64d4SCharles.Forsyth struct User
5437da2899SCharles.Forsyth {
55184c64d4SCharles.Forsyth int id; /* might be user or group ID */
56184c64d4SCharles.Forsyth int gid; /* if it's a user not a group, the group ID (only for setid) */
5737da2899SCharles.Forsyth char* name;
58184c64d4SCharles.Forsyth int nmem;
59184c64d4SCharles.Forsyth int* mem; /* member array, if nmem != 0 */
60184c64d4SCharles.Forsyth User* next;
6137da2899SCharles.Forsyth };
6237da2899SCharles.Forsyth
6337da2899SCharles.Forsyth char rootdir[MAXROOT] = ROOT;
6437da2899SCharles.Forsyth
65184c64d4SCharles.Forsyth static User* uidmap[NID];
66184c64d4SCharles.Forsyth static User* gidmap[NID];
67184c64d4SCharles.Forsyth static QLock idl;
68184c64d4SCharles.Forsyth static User* name2user(User**, char*, User* (*get)(char*));
69184c64d4SCharles.Forsyth static User* id2user(User**, int, User* (*get)(int));
70184c64d4SCharles.Forsyth static User* newuid(int);
71184c64d4SCharles.Forsyth static User* newgid(int);
72184c64d4SCharles.Forsyth static User* newuname(char*);
73184c64d4SCharles.Forsyth static User* newgname(char*);
7437da2899SCharles.Forsyth
7537da2899SCharles.Forsyth static Qid fsqid(struct stat *);
7637da2899SCharles.Forsyth static void fspath(Cname*, char*, char*);
7748cb024aSforsyth static int fsdirconv(Chan*, char*, char*, struct stat*, uchar*, int, int);
7837da2899SCharles.Forsyth static Cname* fswalkpath(Cname*, char*, int);
7937da2899SCharles.Forsyth static char* fslastelem(Cname*);
8037da2899SCharles.Forsyth static int ingroup(int id, int gid);
8137da2899SCharles.Forsyth static void fsperm(Chan*, int);
8237da2899SCharles.Forsyth static long fsdirread(Chan*, uchar*, int, vlong);
8337da2899SCharles.Forsyth static int fsomode(int);
8437da2899SCharles.Forsyth static void fsremove(Chan*);
8548cb024aSforsyth static vlong osdisksize(int); /* defined by including file */
8637da2899SCharles.Forsyth
8737da2899SCharles.Forsyth /*
8835a6f3e1Sforsyth * make invalid symbolic links visible; less confusing, and at least you can then delete them.
8937da2899SCharles.Forsyth */
9037da2899SCharles.Forsyth static int
xstat(char * f,struct stat * sb)9137da2899SCharles.Forsyth xstat(char *f, struct stat *sb)
9237da2899SCharles.Forsyth {
9337da2899SCharles.Forsyth if(stat(f, sb) >= 0)
9437da2899SCharles.Forsyth return 0;
95184c64d4SCharles.Forsyth /* could possibly generate ->name as rob once suggested */
9637da2899SCharles.Forsyth return lstat(f, sb);
9737da2899SCharles.Forsyth }
9837da2899SCharles.Forsyth
9937da2899SCharles.Forsyth static void
fsfree(Chan * c)10037da2899SCharles.Forsyth fsfree(Chan *c)
10137da2899SCharles.Forsyth {
10237da2899SCharles.Forsyth cnameclose(FS(c)->name);
10337da2899SCharles.Forsyth free(FS(c));
10437da2899SCharles.Forsyth }
10537da2899SCharles.Forsyth
10637da2899SCharles.Forsyth Chan*
fsattach(char * spec)10737da2899SCharles.Forsyth fsattach(char *spec)
10837da2899SCharles.Forsyth {
10937da2899SCharles.Forsyth Chan *c;
11035a6f3e1Sforsyth struct stat st;
11137da2899SCharles.Forsyth static int devno;
11237da2899SCharles.Forsyth static Lock l;
11337da2899SCharles.Forsyth
11437da2899SCharles.Forsyth if(!emptystr(spec) && strcmp(spec, "*") != 0)
11537da2899SCharles.Forsyth error(Ebadspec);
11635a6f3e1Sforsyth if(stat(rootdir, &st) < 0)
11737da2899SCharles.Forsyth oserror();
11835a6f3e1Sforsyth if(!S_ISDIR(st.st_mode))
11935a6f3e1Sforsyth error(Enotdir);
12037da2899SCharles.Forsyth
12137da2899SCharles.Forsyth c = devattach('U', spec);
12235a6f3e1Sforsyth c->qid = fsqid(&st);
12337da2899SCharles.Forsyth c->aux = smalloc(sizeof(Fsinfo));
12437da2899SCharles.Forsyth FS(c)->dir = nil;
12537da2899SCharles.Forsyth FS(c)->de = nil;
12637da2899SCharles.Forsyth FS(c)->fd = -1;
12735a6f3e1Sforsyth FS(c)->issocket = 0;
12835a6f3e1Sforsyth FS(c)->gid = st.st_gid;
12935a6f3e1Sforsyth FS(c)->uid = st.st_uid;
13035a6f3e1Sforsyth FS(c)->mode = st.st_mode;
13137da2899SCharles.Forsyth lock(&l);
13237da2899SCharles.Forsyth c->dev = devno++;
13337da2899SCharles.Forsyth unlock(&l);
13437da2899SCharles.Forsyth if(!emptystr(spec)){
13537da2899SCharles.Forsyth FS(c)->spec = "/";
13637da2899SCharles.Forsyth FS(c)->name = newcname(FS(c)->spec);
13737da2899SCharles.Forsyth }else
13837da2899SCharles.Forsyth FS(c)->name = newcname(rootdir);
13937da2899SCharles.Forsyth FS(c)->rootqid = c->qid;
14037da2899SCharles.Forsyth
14137da2899SCharles.Forsyth return c;
14237da2899SCharles.Forsyth }
14337da2899SCharles.Forsyth
14437da2899SCharles.Forsyth Walkqid*
fswalk(Chan * c,Chan * nc,char ** name,int nname)14537da2899SCharles.Forsyth fswalk(Chan *c, Chan *nc, char **name, int nname)
14637da2899SCharles.Forsyth {
14737da2899SCharles.Forsyth int j;
14837da2899SCharles.Forsyth volatile int alloc;
14937da2899SCharles.Forsyth Walkqid *wq;
15035a6f3e1Sforsyth struct stat st;
15137da2899SCharles.Forsyth char *n;
15237da2899SCharles.Forsyth Cname *next;
15337da2899SCharles.Forsyth Cname *volatile current;
15437da2899SCharles.Forsyth Qid rootqid;
15537da2899SCharles.Forsyth
15637da2899SCharles.Forsyth if(nname > 0)
15737da2899SCharles.Forsyth isdir(c);
15837da2899SCharles.Forsyth
15937da2899SCharles.Forsyth alloc = 0;
16037da2899SCharles.Forsyth current = nil;
16137da2899SCharles.Forsyth wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
16237da2899SCharles.Forsyth if(waserror()){
16337da2899SCharles.Forsyth if(alloc && wq->clone != nil)
16437da2899SCharles.Forsyth cclose(wq->clone);
16537da2899SCharles.Forsyth cnameclose(current);
16637da2899SCharles.Forsyth free(wq);
16737da2899SCharles.Forsyth return nil;
16837da2899SCharles.Forsyth }
16937da2899SCharles.Forsyth if(nc == nil){
17037da2899SCharles.Forsyth nc = devclone(c);
17137da2899SCharles.Forsyth nc->type = 0;
17237da2899SCharles.Forsyth alloc = 1;
17337da2899SCharles.Forsyth }
17437da2899SCharles.Forsyth wq->clone = nc;
17537da2899SCharles.Forsyth rootqid = FS(c)->rootqid;
17637da2899SCharles.Forsyth current = FS(c)->name;
17737da2899SCharles.Forsyth if(current != nil)
17837da2899SCharles.Forsyth incref(¤t->r);
17937da2899SCharles.Forsyth for(j = 0; j < nname; j++){
18037da2899SCharles.Forsyth if(!(nc->qid.type&QTDIR)){
18137da2899SCharles.Forsyth if(j==0)
18237da2899SCharles.Forsyth error(Enotdir);
18337da2899SCharles.Forsyth break;
18437da2899SCharles.Forsyth }
18537da2899SCharles.Forsyth n = name[j];
18637da2899SCharles.Forsyth if(strcmp(n, ".") != 0 && !(isdotdot(n) && nc->qid.path == rootqid.path)){
18737da2899SCharles.Forsyth next = current;
18837da2899SCharles.Forsyth incref(&next->r);
18937da2899SCharles.Forsyth next = addelem(current, n);
19037da2899SCharles.Forsyth //print("** ufs walk '%s' -> %s [%s]\n", current->s, n, next->s);
19135a6f3e1Sforsyth if(xstat(next->s, &st) < 0){
19237da2899SCharles.Forsyth cnameclose(next);
19337da2899SCharles.Forsyth if(j == 0)
19437da2899SCharles.Forsyth error(Enonexist);
19537da2899SCharles.Forsyth strcpy(up->env->errstr, Enonexist);
19637da2899SCharles.Forsyth break;
19737da2899SCharles.Forsyth }
19835a6f3e1Sforsyth nc->qid = fsqid(&st);
19937da2899SCharles.Forsyth cnameclose(current);
20037da2899SCharles.Forsyth current = next;
20137da2899SCharles.Forsyth }
20237da2899SCharles.Forsyth wq->qid[wq->nqid++] = nc->qid;
20337da2899SCharles.Forsyth }
20437da2899SCharles.Forsyth poperror();
20537da2899SCharles.Forsyth if(wq->nqid < nname){
20637da2899SCharles.Forsyth cnameclose(current);
20737da2899SCharles.Forsyth if(alloc)
20837da2899SCharles.Forsyth cclose(wq->clone);
20937da2899SCharles.Forsyth wq->clone = nil;
21037da2899SCharles.Forsyth }else if(wq->clone){
21137da2899SCharles.Forsyth nc->aux = smalloc(sizeof(Fsinfo));
21237da2899SCharles.Forsyth nc->type = c->type;
21335a6f3e1Sforsyth if(nname > 0) {
21435a6f3e1Sforsyth FS(nc)->gid = st.st_gid;
21535a6f3e1Sforsyth FS(nc)->uid = st.st_uid;
21635a6f3e1Sforsyth FS(nc)->mode = st.st_mode;
21735a6f3e1Sforsyth FS(nc)->issocket = S_ISSOCK(st.st_mode);
21837da2899SCharles.Forsyth } else {
21937da2899SCharles.Forsyth FS(nc)->gid = FS(c)->gid;
22037da2899SCharles.Forsyth FS(nc)->uid = FS(c)->uid;
22137da2899SCharles.Forsyth FS(nc)->mode = FS(c)->mode;
22235a6f3e1Sforsyth FS(nc)->issocket = FS(c)->issocket;
22337da2899SCharles.Forsyth }
22437da2899SCharles.Forsyth FS(nc)->name = current;
22537da2899SCharles.Forsyth FS(nc)->spec = FS(c)->spec;
22637da2899SCharles.Forsyth FS(nc)->rootqid = rootqid;
22737da2899SCharles.Forsyth FS(nc)->fd = -1;
22837da2899SCharles.Forsyth FS(nc)->dir = nil;
22937da2899SCharles.Forsyth FS(nc)->de = nil;
23037da2899SCharles.Forsyth }
23137da2899SCharles.Forsyth return wq;
23237da2899SCharles.Forsyth }
23337da2899SCharles.Forsyth
23437da2899SCharles.Forsyth static int
fsstat(Chan * c,uchar * dp,int n)23537da2899SCharles.Forsyth fsstat(Chan *c, uchar *dp, int n)
23637da2899SCharles.Forsyth {
23735a6f3e1Sforsyth struct stat st;
23837da2899SCharles.Forsyth char *p;
23937da2899SCharles.Forsyth
24048cb024aSforsyth if(FS(c)->fd >= 0){
24148cb024aSforsyth if(fstat(FS(c)->fd, &st) < 0)
24248cb024aSforsyth oserror();
24348cb024aSforsyth }else{
24435a6f3e1Sforsyth if(xstat(FS(c)->name->s, &st) < 0)
24537da2899SCharles.Forsyth oserror();
24648cb024aSforsyth }
24737da2899SCharles.Forsyth p = fslastelem(FS(c)->name);
24837da2899SCharles.Forsyth if(*p == 0)
24937da2899SCharles.Forsyth p = "/";
250184c64d4SCharles.Forsyth qlock(&idl);
25148cb024aSforsyth n = fsdirconv(c, FS(c)->name->s, p, &st, dp, n, 0);
252184c64d4SCharles.Forsyth qunlock(&idl);
25337da2899SCharles.Forsyth return n;
25437da2899SCharles.Forsyth }
25537da2899SCharles.Forsyth
25635a6f3e1Sforsyth static int
opensocket(char * path)25735a6f3e1Sforsyth opensocket(char *path)
25835a6f3e1Sforsyth {
25935a6f3e1Sforsyth int fd;
26035a6f3e1Sforsyth struct sockaddr_un su;
26135a6f3e1Sforsyth
26235a6f3e1Sforsyth memset(&su, 0, sizeof su);
26335a6f3e1Sforsyth su.sun_family = AF_UNIX;
26435a6f3e1Sforsyth if(strlen(path)+1 > sizeof su.sun_path)
26535a6f3e1Sforsyth error("unix socket name too long");
26635a6f3e1Sforsyth strcpy(su.sun_path, path);
26735a6f3e1Sforsyth if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
26835a6f3e1Sforsyth return -1;
26935a6f3e1Sforsyth if(connect(fd, (struct sockaddr*)&su, sizeof su) >= 0)
27035a6f3e1Sforsyth return fd;
27135a6f3e1Sforsyth close(fd);
27248cb024aSforsyth if((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
27348cb024aSforsyth return -1;
27448cb024aSforsyth if(connect(fd, (struct sockaddr*)&su, sizeof su) >= 0)
27548cb024aSforsyth return fd;
27648cb024aSforsyth close(fd);
27735a6f3e1Sforsyth return -1;
27835a6f3e1Sforsyth }
27935a6f3e1Sforsyth
28037da2899SCharles.Forsyth static Chan*
fsopen(Chan * c,int mode)28137da2899SCharles.Forsyth fsopen(Chan *c, int mode)
28237da2899SCharles.Forsyth {
28337da2899SCharles.Forsyth int m, isdir;
28437da2899SCharles.Forsyth
28537da2899SCharles.Forsyth m = mode & (OTRUNC|3);
28637da2899SCharles.Forsyth switch(m) {
28737da2899SCharles.Forsyth case 0:
28837da2899SCharles.Forsyth fsperm(c, 4);
28937da2899SCharles.Forsyth break;
29037da2899SCharles.Forsyth case 1:
29137da2899SCharles.Forsyth case 1|16:
29237da2899SCharles.Forsyth fsperm(c, 2);
29337da2899SCharles.Forsyth break;
29437da2899SCharles.Forsyth case 2:
29537da2899SCharles.Forsyth case 0|16:
29637da2899SCharles.Forsyth case 2|16:
29737da2899SCharles.Forsyth fsperm(c, 4);
29837da2899SCharles.Forsyth fsperm(c, 2);
29937da2899SCharles.Forsyth break;
30037da2899SCharles.Forsyth case 3:
30137da2899SCharles.Forsyth fsperm(c, 1);
30237da2899SCharles.Forsyth break;
30337da2899SCharles.Forsyth default:
30437da2899SCharles.Forsyth error(Ebadarg);
30537da2899SCharles.Forsyth }
30637da2899SCharles.Forsyth
30737da2899SCharles.Forsyth isdir = c->qid.type & QTDIR;
30837da2899SCharles.Forsyth
30937da2899SCharles.Forsyth if(isdir && mode != OREAD)
31037da2899SCharles.Forsyth error(Eperm);
31137da2899SCharles.Forsyth
31237da2899SCharles.Forsyth m = fsomode(m & 3);
31337da2899SCharles.Forsyth c->mode = openmode(mode);
31437da2899SCharles.Forsyth
31537da2899SCharles.Forsyth if(isdir) {
31637da2899SCharles.Forsyth FS(c)->dir = opendir(FS(c)->name->s);
31735a6f3e1Sforsyth if(FS(c)->dir == nil)
31837da2899SCharles.Forsyth oserror();
31923babd45SCharles.Forsyth FS(c)->eod = 0;
32037da2899SCharles.Forsyth }
32137da2899SCharles.Forsyth else {
32235a6f3e1Sforsyth if(!FS(c)->issocket){
32337da2899SCharles.Forsyth if(mode & OTRUNC)
32437da2899SCharles.Forsyth m |= O_TRUNC;
32537da2899SCharles.Forsyth FS(c)->fd = open(FS(c)->name->s, m, 0666);
32635a6f3e1Sforsyth }else
32735a6f3e1Sforsyth FS(c)->fd = opensocket(FS(c)->name->s);
32837da2899SCharles.Forsyth if(FS(c)->fd < 0)
32937da2899SCharles.Forsyth oserror();
33037da2899SCharles.Forsyth }
33137da2899SCharles.Forsyth
33237da2899SCharles.Forsyth c->offset = 0;
33337da2899SCharles.Forsyth FS(c)->offset = 0;
33437da2899SCharles.Forsyth c->flag |= COPEN;
33537da2899SCharles.Forsyth return c;
33637da2899SCharles.Forsyth }
33737da2899SCharles.Forsyth
33837da2899SCharles.Forsyth static void
fscreate(Chan * c,char * name,int mode,ulong perm)33937da2899SCharles.Forsyth fscreate(Chan *c, char *name, int mode, ulong perm)
34037da2899SCharles.Forsyth {
34137da2899SCharles.Forsyth int fd, m, o;
34235a6f3e1Sforsyth struct stat st;
34337da2899SCharles.Forsyth Cname *n;
34437da2899SCharles.Forsyth
34537da2899SCharles.Forsyth fsperm(c, 2);
34637da2899SCharles.Forsyth
34737da2899SCharles.Forsyth m = fsomode(mode&3);
34837da2899SCharles.Forsyth openmode(mode); /* get the errors out of the way */
34937da2899SCharles.Forsyth
35037da2899SCharles.Forsyth if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
35137da2899SCharles.Forsyth error(Efilename);
35237da2899SCharles.Forsyth n = fswalkpath(FS(c)->name, name, 1);
35337da2899SCharles.Forsyth if(waserror()){
35437da2899SCharles.Forsyth cnameclose(n);
35537da2899SCharles.Forsyth nexterror();
35637da2899SCharles.Forsyth }
35737da2899SCharles.Forsyth if(perm & DMDIR) {
35837da2899SCharles.Forsyth if(m)
35937da2899SCharles.Forsyth error(Eperm);
36037da2899SCharles.Forsyth
36137da2899SCharles.Forsyth perm &= ~0777 | (FS(c)->mode & 0777);
36237da2899SCharles.Forsyth if(mkdir(n->s, perm) < 0)
36337da2899SCharles.Forsyth oserror();
36437da2899SCharles.Forsyth
36537da2899SCharles.Forsyth fd = open(n->s, 0);
36637da2899SCharles.Forsyth if(fd < 0)
36737da2899SCharles.Forsyth oserror();
36837da2899SCharles.Forsyth fchmod(fd, perm);
36937da2899SCharles.Forsyth fchown(fd, up->env->uid, FS(c)->gid);
37035a6f3e1Sforsyth if(fstat(fd, &st) <0){
37137da2899SCharles.Forsyth close(fd);
37237da2899SCharles.Forsyth oserror();
37337da2899SCharles.Forsyth }
37437da2899SCharles.Forsyth close(fd);
37537da2899SCharles.Forsyth FS(c)->dir = opendir(n->s);
37637da2899SCharles.Forsyth if(FS(c)->dir == nil)
37737da2899SCharles.Forsyth oserror();
37823babd45SCharles.Forsyth FS(c)->eod = 0;
37937da2899SCharles.Forsyth } else {
38037da2899SCharles.Forsyth o = (O_CREAT | O_EXCL) | (mode&3);
38137da2899SCharles.Forsyth if(mode & OTRUNC)
38237da2899SCharles.Forsyth o |= O_TRUNC;
38337da2899SCharles.Forsyth perm &= ~0666 | (FS(c)->mode & 0666);
38437da2899SCharles.Forsyth fd = open(n->s, o, perm);
38537da2899SCharles.Forsyth if(fd < 0)
38637da2899SCharles.Forsyth oserror();
38737da2899SCharles.Forsyth fchmod(fd, perm);
38837da2899SCharles.Forsyth fchown(fd, up->env->uid, FS(c)->gid);
38935a6f3e1Sforsyth if(fstat(fd, &st) < 0){
39037da2899SCharles.Forsyth close(fd);
39137da2899SCharles.Forsyth oserror();
39237da2899SCharles.Forsyth }
39337da2899SCharles.Forsyth FS(c)->fd = fd;
39437da2899SCharles.Forsyth }
39537da2899SCharles.Forsyth cnameclose(FS(c)->name);
39637da2899SCharles.Forsyth FS(c)->name = n;
39737da2899SCharles.Forsyth poperror();
39837da2899SCharles.Forsyth
39935a6f3e1Sforsyth c->qid = fsqid(&st);
40035a6f3e1Sforsyth FS(c)->gid = st.st_gid;
40135a6f3e1Sforsyth FS(c)->uid = st.st_uid;
40235a6f3e1Sforsyth FS(c)->mode = st.st_mode;
40337da2899SCharles.Forsyth c->mode = openmode(mode);
40437da2899SCharles.Forsyth c->offset = 0;
40537da2899SCharles.Forsyth FS(c)->offset = 0;
40635a6f3e1Sforsyth FS(c)->issocket = 0;
40737da2899SCharles.Forsyth c->flag |= COPEN;
40837da2899SCharles.Forsyth }
40937da2899SCharles.Forsyth
41037da2899SCharles.Forsyth static void
fsclose(Chan * c)41137da2899SCharles.Forsyth fsclose(Chan *c)
41237da2899SCharles.Forsyth {
41337da2899SCharles.Forsyth if((c->flag & COPEN) != 0){
41437da2899SCharles.Forsyth if(c->qid.type & QTDIR)
41537da2899SCharles.Forsyth closedir(FS(c)->dir);
41637da2899SCharles.Forsyth else
41737da2899SCharles.Forsyth close(FS(c)->fd);
41837da2899SCharles.Forsyth }
41937da2899SCharles.Forsyth if(c->flag & CRCLOSE) {
42037da2899SCharles.Forsyth if(!waserror()) {
42137da2899SCharles.Forsyth fsremove(c);
42237da2899SCharles.Forsyth poperror();
42337da2899SCharles.Forsyth }
42437da2899SCharles.Forsyth return;
42537da2899SCharles.Forsyth }
42637da2899SCharles.Forsyth fsfree(c);
42737da2899SCharles.Forsyth }
42837da2899SCharles.Forsyth
42937da2899SCharles.Forsyth static long
fsread(Chan * c,void * va,long n,vlong offset)43037da2899SCharles.Forsyth fsread(Chan *c, void *va, long n, vlong offset)
43137da2899SCharles.Forsyth {
43237da2899SCharles.Forsyth long r;
43337da2899SCharles.Forsyth
43437da2899SCharles.Forsyth if(c->qid.type & QTDIR){
43537da2899SCharles.Forsyth qlock(&FS(c)->oq);
43637da2899SCharles.Forsyth if(waserror()) {
43737da2899SCharles.Forsyth qunlock(&FS(c)->oq);
43837da2899SCharles.Forsyth nexterror();
43937da2899SCharles.Forsyth }
44037da2899SCharles.Forsyth r = fsdirread(c, va, n, offset);
44137da2899SCharles.Forsyth poperror();
44237da2899SCharles.Forsyth qunlock(&FS(c)->oq);
44337da2899SCharles.Forsyth }else{
44435a6f3e1Sforsyth if(!FS(c)->issocket){
44537da2899SCharles.Forsyth r = pread(FS(c)->fd, va, n, offset);
446b18a52b7SCharles.Forsyth if(r >= 0)
447b18a52b7SCharles.Forsyth return r;
44835a6f3e1Sforsyth if(errno != ESPIPE && errno != EPIPE)
44937da2899SCharles.Forsyth oserror();
45037da2899SCharles.Forsyth }
45135a6f3e1Sforsyth r = read(FS(c)->fd, va, n);
45235a6f3e1Sforsyth if(r < 0)
45335a6f3e1Sforsyth oserror();
45437da2899SCharles.Forsyth }
45537da2899SCharles.Forsyth return r;
45637da2899SCharles.Forsyth }
45737da2899SCharles.Forsyth
45837da2899SCharles.Forsyth static long
fswrite(Chan * c,void * va,long n,vlong offset)45937da2899SCharles.Forsyth fswrite(Chan *c, void *va, long n, vlong offset)
46037da2899SCharles.Forsyth {
46137da2899SCharles.Forsyth long r;
46237da2899SCharles.Forsyth
46335a6f3e1Sforsyth if(!FS(c)->issocket){
46437da2899SCharles.Forsyth r = pwrite(FS(c)->fd, va, n, offset);
46535a6f3e1Sforsyth if(r >= 0)
46635a6f3e1Sforsyth return r;
46735a6f3e1Sforsyth if(errno != ESPIPE && errno != EPIPE)
46835a6f3e1Sforsyth oserror();
46935a6f3e1Sforsyth }
47037da2899SCharles.Forsyth r = write(FS(c)->fd, va, n);
47137da2899SCharles.Forsyth if(r < 0)
47237da2899SCharles.Forsyth oserror();
47337da2899SCharles.Forsyth return r;
47437da2899SCharles.Forsyth }
47537da2899SCharles.Forsyth
47637da2899SCharles.Forsyth static void
fswchk(Cname * c)47737da2899SCharles.Forsyth fswchk(Cname *c)
47837da2899SCharles.Forsyth {
47935a6f3e1Sforsyth struct stat st;
48037da2899SCharles.Forsyth
48135a6f3e1Sforsyth if(stat(c->s, &st) < 0)
48237da2899SCharles.Forsyth oserror();
48337da2899SCharles.Forsyth
48435a6f3e1Sforsyth if(st.st_uid == up->env->uid)
48535a6f3e1Sforsyth st.st_mode >>= 6;
48635a6f3e1Sforsyth else if(st.st_gid == up->env->gid || ingroup(up->env->uid, st.st_gid))
48735a6f3e1Sforsyth st.st_mode >>= 3;
48837da2899SCharles.Forsyth
48935a6f3e1Sforsyth if(st.st_mode & S_IWOTH)
49037da2899SCharles.Forsyth return;
49137da2899SCharles.Forsyth
49237da2899SCharles.Forsyth error(Eperm);
49337da2899SCharles.Forsyth }
49437da2899SCharles.Forsyth
49537da2899SCharles.Forsyth static void
fsremove(Chan * c)49637da2899SCharles.Forsyth fsremove(Chan *c)
49737da2899SCharles.Forsyth {
49837da2899SCharles.Forsyth int n;
49935a6f3e1Sforsyth Cname *volatile dir;
50037da2899SCharles.Forsyth
50137da2899SCharles.Forsyth if(waserror()){
50237da2899SCharles.Forsyth fsfree(c);
50337da2899SCharles.Forsyth nexterror();
50437da2899SCharles.Forsyth }
50535a6f3e1Sforsyth dir = fswalkpath(FS(c)->name, "..", 1);
50635a6f3e1Sforsyth if(waserror()){
50735a6f3e1Sforsyth cnameclose(dir);
50835a6f3e1Sforsyth nexterror();
50935a6f3e1Sforsyth }
51035a6f3e1Sforsyth fswchk(dir);
51135a6f3e1Sforsyth cnameclose(dir);
51235a6f3e1Sforsyth poperror();
51337da2899SCharles.Forsyth if(c->qid.type & QTDIR)
51437da2899SCharles.Forsyth n = rmdir(FS(c)->name->s);
51537da2899SCharles.Forsyth else
51637da2899SCharles.Forsyth n = remove(FS(c)->name->s);
51737da2899SCharles.Forsyth if(n < 0)
51837da2899SCharles.Forsyth oserror();
51937da2899SCharles.Forsyth poperror();
52037da2899SCharles.Forsyth fsfree(c);
52137da2899SCharles.Forsyth }
52237da2899SCharles.Forsyth
52337da2899SCharles.Forsyth static int
fswstat(Chan * c,uchar * buf,int nb)52437da2899SCharles.Forsyth fswstat(Chan *c, uchar *buf, int nb)
52537da2899SCharles.Forsyth {
52637da2899SCharles.Forsyth Dir *d;
527184c64d4SCharles.Forsyth User *p;
52835a6f3e1Sforsyth Cname *volatile ph;
52935a6f3e1Sforsyth struct stat st;
53037da2899SCharles.Forsyth struct utimbuf utbuf;
53137da2899SCharles.Forsyth int tsync;
53237da2899SCharles.Forsyth
53337da2899SCharles.Forsyth if(FS(c)->fd >= 0){
53435a6f3e1Sforsyth if(fstat(FS(c)->fd, &st) < 0)
53537da2899SCharles.Forsyth oserror();
53637da2899SCharles.Forsyth }else{
53735a6f3e1Sforsyth if(stat(FS(c)->name->s, &st) < 0)
53837da2899SCharles.Forsyth oserror();
53937da2899SCharles.Forsyth }
54037da2899SCharles.Forsyth d = malloc(sizeof(*d)+nb);
54137da2899SCharles.Forsyth if(d == nil)
54237da2899SCharles.Forsyth error(Enomem);
54337da2899SCharles.Forsyth if(waserror()){
54437da2899SCharles.Forsyth free(d);
54537da2899SCharles.Forsyth nexterror();
54637da2899SCharles.Forsyth }
54737da2899SCharles.Forsyth tsync = 1;
54837da2899SCharles.Forsyth nb = convM2D(buf, nb, d, (char*)&d[1]);
54937da2899SCharles.Forsyth if(nb == 0)
55037da2899SCharles.Forsyth error(Eshortstat);
55137da2899SCharles.Forsyth if(!emptystr(d->name) && strcmp(d->name, fslastelem(FS(c)->name)) != 0) {
55237da2899SCharles.Forsyth tsync = 0;
55337da2899SCharles.Forsyth validname(d->name, 0);
55435a6f3e1Sforsyth ph = fswalkpath(FS(c)->name, "..", 1);
55537da2899SCharles.Forsyth if(waserror()){
55635a6f3e1Sforsyth cnameclose(ph);
55737da2899SCharles.Forsyth nexterror();
55837da2899SCharles.Forsyth }
55935a6f3e1Sforsyth fswchk(ph);
56035a6f3e1Sforsyth ph = fswalkpath(ph, d->name, 0);
56135a6f3e1Sforsyth if(rename(FS(c)->name->s, ph->s) < 0)
56237da2899SCharles.Forsyth oserror();
56337da2899SCharles.Forsyth cnameclose(FS(c)->name);
56437da2899SCharles.Forsyth poperror();
56535a6f3e1Sforsyth FS(c)->name = ph;
56637da2899SCharles.Forsyth }
56737da2899SCharles.Forsyth
56835a6f3e1Sforsyth if(d->mode != ~0 && (d->mode&0777) != (st.st_mode&0777)) {
56937da2899SCharles.Forsyth tsync = 0;
57035a6f3e1Sforsyth if(up->env->uid != st.st_uid)
57137da2899SCharles.Forsyth error(Eowner);
57237da2899SCharles.Forsyth if(FS(c)->fd >= 0){
57337da2899SCharles.Forsyth if(fchmod(FS(c)->fd, d->mode&0777) < 0)
57437da2899SCharles.Forsyth oserror();
57537da2899SCharles.Forsyth }else{
57637da2899SCharles.Forsyth if(chmod(FS(c)->name->s, d->mode&0777) < 0)
57737da2899SCharles.Forsyth oserror();
57837da2899SCharles.Forsyth }
57937da2899SCharles.Forsyth FS(c)->mode &= ~0777;
58037da2899SCharles.Forsyth FS(c)->mode |= d->mode&0777;
58137da2899SCharles.Forsyth }
58237da2899SCharles.Forsyth
58335a6f3e1Sforsyth if(d->atime != ~0 && d->atime != st.st_atime ||
58435a6f3e1Sforsyth d->mtime != ~0 && d->mtime != st.st_mtime) {
58537da2899SCharles.Forsyth tsync = 0;
58635a6f3e1Sforsyth if(up->env->uid != st.st_uid)
58737da2899SCharles.Forsyth error(Eowner);
58837da2899SCharles.Forsyth if(d->mtime != ~0)
58937da2899SCharles.Forsyth utbuf.modtime = d->mtime;
59037da2899SCharles.Forsyth else
59135a6f3e1Sforsyth utbuf.modtime = st.st_mtime;
59237da2899SCharles.Forsyth if(d->atime != ~0)
59337da2899SCharles.Forsyth utbuf.actime = d->atime;
59437da2899SCharles.Forsyth else
59535a6f3e1Sforsyth utbuf.actime = st.st_atime;
59637da2899SCharles.Forsyth if(utime(FS(c)->name->s, &utbuf) < 0) /* TO DO: futimes isn't portable */
59737da2899SCharles.Forsyth oserror();
59837da2899SCharles.Forsyth }
59937da2899SCharles.Forsyth
60037da2899SCharles.Forsyth if(*d->gid){
60137da2899SCharles.Forsyth tsync = 0;
602184c64d4SCharles.Forsyth qlock(&idl);
60337da2899SCharles.Forsyth if(waserror()){
604184c64d4SCharles.Forsyth qunlock(&idl);
60537da2899SCharles.Forsyth nexterror();
60637da2899SCharles.Forsyth }
607184c64d4SCharles.Forsyth p = name2user(gidmap, d->gid, newgname);
60837da2899SCharles.Forsyth if(p == 0)
60937da2899SCharles.Forsyth error(Eunknown);
61035a6f3e1Sforsyth if(p->id != st.st_gid) {
61135a6f3e1Sforsyth if(up->env->uid != st.st_uid)
61237da2899SCharles.Forsyth error(Eowner);
61337da2899SCharles.Forsyth if(FS(c)->fd >= 0){
61435a6f3e1Sforsyth if(fchown(FS(c)->fd, st.st_uid, p->id) < 0)
61537da2899SCharles.Forsyth oserror();
61637da2899SCharles.Forsyth }else{
61735a6f3e1Sforsyth if(chown(FS(c)->name->s, st.st_uid, p->id) < 0)
61837da2899SCharles.Forsyth oserror();
61937da2899SCharles.Forsyth }
62037da2899SCharles.Forsyth FS(c)->gid = p->id;
62137da2899SCharles.Forsyth }
62237da2899SCharles.Forsyth poperror();
623184c64d4SCharles.Forsyth qunlock(&idl);
62437da2899SCharles.Forsyth }
62537da2899SCharles.Forsyth
62637da2899SCharles.Forsyth if(d->length != ~(uvlong)0){
62737da2899SCharles.Forsyth tsync = 0;
62837da2899SCharles.Forsyth if(FS(c)->fd >= 0){
62937da2899SCharles.Forsyth fsperm(c, 2);
63037da2899SCharles.Forsyth if(ftruncate(FS(c)->fd, d->length) < 0)
63137da2899SCharles.Forsyth oserror();
63237da2899SCharles.Forsyth }else{
63337da2899SCharles.Forsyth fswchk(FS(c)->name);
63437da2899SCharles.Forsyth if(truncate(FS(c)->name->s, d->length) < 0)
63537da2899SCharles.Forsyth oserror();
63637da2899SCharles.Forsyth }
63737da2899SCharles.Forsyth }
63837da2899SCharles.Forsyth
63937da2899SCharles.Forsyth poperror();
64037da2899SCharles.Forsyth free(d);
64137da2899SCharles.Forsyth if(tsync && FS(c)->fd >= 0 && fsync(FS(c)->fd) < 0)
64237da2899SCharles.Forsyth oserror();
64337da2899SCharles.Forsyth return nb;
64437da2899SCharles.Forsyth }
64537da2899SCharles.Forsyth
64637da2899SCharles.Forsyth static Qid
fsqid(struct stat * st)64737da2899SCharles.Forsyth fsqid(struct stat *st)
64837da2899SCharles.Forsyth {
64937da2899SCharles.Forsyth Qid q;
650c594916bSforsyth u16int dev;
65137da2899SCharles.Forsyth
65237da2899SCharles.Forsyth q.type = QTFILE;
65337da2899SCharles.Forsyth if(S_ISDIR(st->st_mode))
65437da2899SCharles.Forsyth q.type = QTDIR;
65537da2899SCharles.Forsyth
656c594916bSforsyth dev = (u16int)st->st_dev;
657c594916bSforsyth if(dev & 0x8000){
6582aba3aa7SCharles Forsyth static int aware = 1;
659c594916bSforsyth if(aware==0){
660c594916bSforsyth aware = 1;
661c594916bSforsyth fprint(2, "fs: fsqid: top-bit dev: %#4.4ux\n", dev);
66237da2899SCharles.Forsyth }
663c594916bSforsyth dev ^= 0x8080;
66437da2899SCharles.Forsyth }
66537da2899SCharles.Forsyth
666c594916bSforsyth q.path = (uvlong)dev<<48;
667c594916bSforsyth q.path ^= st->st_ino;
66837da2899SCharles.Forsyth q.vers = st->st_mtime;
66937da2899SCharles.Forsyth
67037da2899SCharles.Forsyth return q;
67137da2899SCharles.Forsyth }
67237da2899SCharles.Forsyth
67337da2899SCharles.Forsyth static void
fspath(Cname * c,char * name,char * path)67437da2899SCharles.Forsyth fspath(Cname *c, char *name, char *path)
67537da2899SCharles.Forsyth {
67637da2899SCharles.Forsyth int n;
67737da2899SCharles.Forsyth
67837da2899SCharles.Forsyth if(c->len+strlen(name) >= MAXPATH)
67937da2899SCharles.Forsyth panic("fspath: name too long");
68037da2899SCharles.Forsyth memmove(path, c->s, c->len);
68137da2899SCharles.Forsyth n = c->len;
68237da2899SCharles.Forsyth if(path[n-1] != '/')
68337da2899SCharles.Forsyth path[n++] = '/';
68437da2899SCharles.Forsyth strcpy(path+n, name);
68537da2899SCharles.Forsyth if(isdotdot(name))
68637da2899SCharles.Forsyth cleanname(path);
68737da2899SCharles.Forsyth /*print("->%s\n", path);*/
68837da2899SCharles.Forsyth }
68937da2899SCharles.Forsyth
69037da2899SCharles.Forsyth static Cname *
fswalkpath(Cname * c,char * name,int dup)69137da2899SCharles.Forsyth fswalkpath(Cname *c, char *name, int dup)
69237da2899SCharles.Forsyth {
69337da2899SCharles.Forsyth if(dup)
69437da2899SCharles.Forsyth c = newcname(c->s);
69537da2899SCharles.Forsyth c = addelem(c, name);
69637da2899SCharles.Forsyth if(isdotdot(name))
69737da2899SCharles.Forsyth cleancname(c);
69837da2899SCharles.Forsyth return c;
69937da2899SCharles.Forsyth }
70037da2899SCharles.Forsyth
70137da2899SCharles.Forsyth static char *
fslastelem(Cname * c)70237da2899SCharles.Forsyth fslastelem(Cname *c)
70337da2899SCharles.Forsyth {
70437da2899SCharles.Forsyth char *p;
70537da2899SCharles.Forsyth
70637da2899SCharles.Forsyth p = c->s + c->len;
70737da2899SCharles.Forsyth while(p > c->s && p[-1] != '/')
70837da2899SCharles.Forsyth p--;
70937da2899SCharles.Forsyth return p;
71037da2899SCharles.Forsyth }
71137da2899SCharles.Forsyth
71237da2899SCharles.Forsyth static void
fsperm(Chan * c,int mask)71337da2899SCharles.Forsyth fsperm(Chan *c, int mask)
71437da2899SCharles.Forsyth {
71537da2899SCharles.Forsyth int m;
71637da2899SCharles.Forsyth
71737da2899SCharles.Forsyth m = FS(c)->mode;
71837da2899SCharles.Forsyth /*
71937da2899SCharles.Forsyth print("fsperm: %o %o uuid %d ugid %d cuid %d cgid %d\n",
72037da2899SCharles.Forsyth m, mask, up->env->uid, up->env->gid, FS(c)->uid, FS(c)->gid);
72137da2899SCharles.Forsyth */
72237da2899SCharles.Forsyth if(FS(c)->uid == up->env->uid)
72337da2899SCharles.Forsyth m >>= 6;
72435a6f3e1Sforsyth else if(FS(c)->gid == up->env->gid || ingroup(up->env->uid, FS(c)->gid))
72537da2899SCharles.Forsyth m >>= 3;
72637da2899SCharles.Forsyth
72737da2899SCharles.Forsyth m &= mask;
72837da2899SCharles.Forsyth if(m == 0)
72937da2899SCharles.Forsyth error(Eperm);
73037da2899SCharles.Forsyth }
73137da2899SCharles.Forsyth
73237da2899SCharles.Forsyth static int
isdots(char * name)73337da2899SCharles.Forsyth isdots(char *name)
73437da2899SCharles.Forsyth {
73537da2899SCharles.Forsyth return name[0] == '.' && (name[1] == '\0' || name[1] == '.' && name[2] == '\0');
73637da2899SCharles.Forsyth }
73737da2899SCharles.Forsyth
73837da2899SCharles.Forsyth static int
fsdirconv(Chan * c,char * path,char * name,struct stat * s,uchar * va,int nb,int indir)73948cb024aSforsyth fsdirconv(Chan *c, char *path, char *name, struct stat *s, uchar *va, int nb, int indir)
74037da2899SCharles.Forsyth {
74137da2899SCharles.Forsyth Dir d;
742184c64d4SCharles.Forsyth char uidbuf[NUMSIZE], gidbuf[NUMSIZE];
743184c64d4SCharles.Forsyth User *u;
74448cb024aSforsyth int fd;
74537da2899SCharles.Forsyth
74637da2899SCharles.Forsyth memset(&d, 0, sizeof(d));
74737da2899SCharles.Forsyth d.name = name;
748184c64d4SCharles.Forsyth u = id2user(uidmap, s->st_uid, newuid);
749184c64d4SCharles.Forsyth if(u == nil){
750184c64d4SCharles.Forsyth snprint(uidbuf, sizeof(uidbuf), "#%lud", (long)s->st_uid);
751184c64d4SCharles.Forsyth d.uid = uidbuf;
752184c64d4SCharles.Forsyth }else
753184c64d4SCharles.Forsyth d.uid = u->name;
754184c64d4SCharles.Forsyth u = id2user(gidmap, s->st_gid, newgid);
755184c64d4SCharles.Forsyth if(u == nil){
756184c64d4SCharles.Forsyth snprint(gidbuf, sizeof(gidbuf), "#%lud", (long)s->st_gid);
757184c64d4SCharles.Forsyth d.gid = gidbuf;
758184c64d4SCharles.Forsyth }else
759184c64d4SCharles.Forsyth d.gid = u->name;
76037da2899SCharles.Forsyth d.muid = "";
76137da2899SCharles.Forsyth d.qid = fsqid(s);
76237da2899SCharles.Forsyth d.mode = (d.qid.type<<24)|(s->st_mode&0777);
76337da2899SCharles.Forsyth d.atime = s->st_atime;
76437da2899SCharles.Forsyth d.mtime = s->st_mtime;
76537da2899SCharles.Forsyth d.length = s->st_size;
76637da2899SCharles.Forsyth if(d.mode&DMDIR)
76737da2899SCharles.Forsyth d.length = 0;
76848cb024aSforsyth else if(S_ISBLK(s->st_mode) && s->st_size == 0){
76948cb024aSforsyth fd = open(path, O_RDONLY);
77048cb024aSforsyth if(fd >= 0){
77148cb024aSforsyth d.length = osdisksize(fd);
77248cb024aSforsyth close(fd);
77348cb024aSforsyth }
77448cb024aSforsyth }
77537da2899SCharles.Forsyth d.type = 'U';
77637da2899SCharles.Forsyth d.dev = c->dev;
77737da2899SCharles.Forsyth if(indir && sizeD2M(&d) > nb)
77837da2899SCharles.Forsyth return -1; /* directory reader needs to know it didn't fit */
77937da2899SCharles.Forsyth return convD2M(&d, va, nb);
78037da2899SCharles.Forsyth }
78137da2899SCharles.Forsyth
78237da2899SCharles.Forsyth static long
fsdirread(Chan * c,uchar * va,int count,vlong offset)78337da2899SCharles.Forsyth fsdirread(Chan *c, uchar *va, int count, vlong offset)
78437da2899SCharles.Forsyth {
78537da2899SCharles.Forsyth int i;
78637da2899SCharles.Forsyth long n, r;
78735a6f3e1Sforsyth struct stat st;
78837da2899SCharles.Forsyth char path[MAXPATH], *ep;
78937da2899SCharles.Forsyth struct dirent *de;
790aee7f58dSforsyth static uchar slop[8192];
79137da2899SCharles.Forsyth
79237da2899SCharles.Forsyth i = 0;
79337da2899SCharles.Forsyth fspath(FS(c)->name, "", path);
79437da2899SCharles.Forsyth ep = path+strlen(path);
79537da2899SCharles.Forsyth if(FS(c)->offset != offset) {
79637da2899SCharles.Forsyth seekdir(FS(c)->dir, 0);
79737da2899SCharles.Forsyth FS(c)->de = nil;
79823babd45SCharles.Forsyth FS(c)->eod = 0;
79937da2899SCharles.Forsyth for(n=0; n<offset; ) {
80037da2899SCharles.Forsyth de = readdir(FS(c)->dir);
80137da2899SCharles.Forsyth if(de == 0) {
80237da2899SCharles.Forsyth /* EOF, so stash offset and return 0 */
80337da2899SCharles.Forsyth FS(c)->offset = n;
80423babd45SCharles.Forsyth FS(c)->eod = 1;
80537da2899SCharles.Forsyth return 0;
80637da2899SCharles.Forsyth }
80737da2899SCharles.Forsyth if(de->d_ino==0 || de->d_name[0]==0 || isdots(de->d_name))
80837da2899SCharles.Forsyth continue;
80937da2899SCharles.Forsyth strecpy(ep, path+sizeof(path), de->d_name);
81035a6f3e1Sforsyth if(xstat(path, &st) < 0) {
81137da2899SCharles.Forsyth fprint(2, "dir: bad path %s\n", path);
81237da2899SCharles.Forsyth continue;
81337da2899SCharles.Forsyth }
814184c64d4SCharles.Forsyth qlock(&idl);
8151d6f6b43Sforsyth if(waserror()){
8161d6f6b43Sforsyth qunlock(&idl);
8171d6f6b43Sforsyth nexterror();
8181d6f6b43Sforsyth }
81948cb024aSforsyth r = fsdirconv(c, path, de->d_name, &st, slop, sizeof(slop), 1);
8201d6f6b43Sforsyth poperror();
821184c64d4SCharles.Forsyth qunlock(&idl);
82237da2899SCharles.Forsyth if(r <= 0) {
82337da2899SCharles.Forsyth FS(c)->offset = n;
82437da2899SCharles.Forsyth return 0;
82537da2899SCharles.Forsyth }
82637da2899SCharles.Forsyth n += r;
82737da2899SCharles.Forsyth }
82837da2899SCharles.Forsyth FS(c)->offset = offset;
82937da2899SCharles.Forsyth }
83037da2899SCharles.Forsyth
83123babd45SCharles.Forsyth if(FS(c)->eod)
83223babd45SCharles.Forsyth return 0;
83323babd45SCharles.Forsyth
83437da2899SCharles.Forsyth /*
83537da2899SCharles.Forsyth * Take idl on behalf of id2name. Stalling attach, which is a
83637da2899SCharles.Forsyth * rare operation, until the readdir completes is probably
83737da2899SCharles.Forsyth * preferable to adding lock round-trips.
83837da2899SCharles.Forsyth */
839184c64d4SCharles.Forsyth qlock(&idl);
84037da2899SCharles.Forsyth while(i < count){
84137da2899SCharles.Forsyth de = FS(c)->de;
84237da2899SCharles.Forsyth FS(c)->de = nil;
84337da2899SCharles.Forsyth if(de == nil)
84437da2899SCharles.Forsyth de = readdir(FS(c)->dir);
84523babd45SCharles.Forsyth if(de == nil){
84623babd45SCharles.Forsyth FS(c)->eod = 1;
84737da2899SCharles.Forsyth break;
84823babd45SCharles.Forsyth }
84937da2899SCharles.Forsyth
85037da2899SCharles.Forsyth if(de->d_ino==0 || de->d_name[0]==0 || isdots(de->d_name))
85137da2899SCharles.Forsyth continue;
85237da2899SCharles.Forsyth
85337da2899SCharles.Forsyth strecpy(ep, path+sizeof(path), de->d_name);
85435a6f3e1Sforsyth if(xstat(path, &st) < 0) {
85537da2899SCharles.Forsyth fprint(2, "dir: bad path %s\n", path);
85637da2899SCharles.Forsyth continue;
85737da2899SCharles.Forsyth }
85848cb024aSforsyth r = fsdirconv(c, path, de->d_name, &st, va+i, count-i, 1);
85937da2899SCharles.Forsyth if(r <= 0){
86037da2899SCharles.Forsyth FS(c)->de = de;
86137da2899SCharles.Forsyth break;
86237da2899SCharles.Forsyth }
86337da2899SCharles.Forsyth i += r;
86437da2899SCharles.Forsyth FS(c)->offset += r;
86537da2899SCharles.Forsyth }
866184c64d4SCharles.Forsyth qunlock(&idl);
86737da2899SCharles.Forsyth return i;
86837da2899SCharles.Forsyth }
86937da2899SCharles.Forsyth
87037da2899SCharles.Forsyth static int
fsomode(int m)87137da2899SCharles.Forsyth fsomode(int m)
87237da2899SCharles.Forsyth {
87337da2899SCharles.Forsyth if(m < 0 || m > 3)
87437da2899SCharles.Forsyth error(Ebadarg);
87537da2899SCharles.Forsyth return m == 3? 0: m;
87637da2899SCharles.Forsyth }
87737da2899SCharles.Forsyth
87837da2899SCharles.Forsyth void
setid(char * name,int owner)87937da2899SCharles.Forsyth setid(char *name, int owner)
88037da2899SCharles.Forsyth {
881184c64d4SCharles.Forsyth User *u;
88237da2899SCharles.Forsyth
88337da2899SCharles.Forsyth if(owner && !iseve())
88437da2899SCharles.Forsyth return;
88537da2899SCharles.Forsyth kstrdup(&up->env->user, name);
88637da2899SCharles.Forsyth
887184c64d4SCharles.Forsyth qlock(&idl);
888184c64d4SCharles.Forsyth u = name2user(uidmap, name, newuname);
889184c64d4SCharles.Forsyth if(u == nil){
890184c64d4SCharles.Forsyth qunlock(&idl);
89137da2899SCharles.Forsyth up->env->uid = -1;
89237da2899SCharles.Forsyth up->env->gid = -1;
89337da2899SCharles.Forsyth return;
89437da2899SCharles.Forsyth }
89537da2899SCharles.Forsyth
896184c64d4SCharles.Forsyth up->env->uid = u->id;
897184c64d4SCharles.Forsyth up->env->gid = u->gid;
898184c64d4SCharles.Forsyth qunlock(&idl);
899184c64d4SCharles.Forsyth }
900184c64d4SCharles.Forsyth
901184c64d4SCharles.Forsyth static User**
hashuser(User ** tab,int id)902184c64d4SCharles.Forsyth hashuser(User** tab, int id)
903184c64d4SCharles.Forsyth {
904184c64d4SCharles.Forsyth int i;
905184c64d4SCharles.Forsyth
906184c64d4SCharles.Forsyth i = (id>>IDSHIFT) ^ id;
907184c64d4SCharles.Forsyth return &tab[i & IDMASK];
908184c64d4SCharles.Forsyth }
909184c64d4SCharles.Forsyth
910184c64d4SCharles.Forsyth /*
911184c64d4SCharles.Forsyth * the caller of the following functions must hold QLock idl.
912184c64d4SCharles.Forsyth */
913184c64d4SCharles.Forsyth
914184c64d4SCharles.Forsyth /*
915184c64d4SCharles.Forsyth * we could keep separate maps of user and group names to Users to
916184c64d4SCharles.Forsyth * speed this up, but the reverse lookup currently isn't common (ie, change group by wstat and setid)
917184c64d4SCharles.Forsyth */
918184c64d4SCharles.Forsyth static User*
name2user(User ** tab,char * name,User * (* get)(char *))919184c64d4SCharles.Forsyth name2user(User **tab, char *name, User* (*get)(char*))
920184c64d4SCharles.Forsyth {
921184c64d4SCharles.Forsyth int i;
922184c64d4SCharles.Forsyth User *u, **h;
923184c64d4SCharles.Forsyth static User *prevu;
924184c64d4SCharles.Forsyth static User **prevtab;
925184c64d4SCharles.Forsyth
926184c64d4SCharles.Forsyth if(prevu != nil && prevtab == tab && strcmp(name, prevu->name) == 0)
927184c64d4SCharles.Forsyth return prevu; /* it's often the one we've just seen */
928184c64d4SCharles.Forsyth
929184c64d4SCharles.Forsyth for(i=0; i<NID; i++)
930184c64d4SCharles.Forsyth for(u = tab[i]; u != nil; u = u->next)
931184c64d4SCharles.Forsyth if(strcmp(name, u->name) == 0) {
932184c64d4SCharles.Forsyth prevtab = tab;
933184c64d4SCharles.Forsyth prevu = u;
934184c64d4SCharles.Forsyth return u;
935184c64d4SCharles.Forsyth }
936184c64d4SCharles.Forsyth
937184c64d4SCharles.Forsyth u = get(name);
938184c64d4SCharles.Forsyth if(u == nil)
939184c64d4SCharles.Forsyth return nil;
940184c64d4SCharles.Forsyth h = hashuser(tab, u->id);
941184c64d4SCharles.Forsyth u->next = *h;
942184c64d4SCharles.Forsyth *h = u;
943184c64d4SCharles.Forsyth prevtab = tab;
944184c64d4SCharles.Forsyth prevu = u;
945184c64d4SCharles.Forsyth return u;
946184c64d4SCharles.Forsyth }
947184c64d4SCharles.Forsyth
948184c64d4SCharles.Forsyth static void
freeuser(User * u)949184c64d4SCharles.Forsyth freeuser(User *u)
950184c64d4SCharles.Forsyth {
951184c64d4SCharles.Forsyth if(u != nil){
952184c64d4SCharles.Forsyth free(u->name);
953184c64d4SCharles.Forsyth free(u->mem);
954184c64d4SCharles.Forsyth free(u);
955184c64d4SCharles.Forsyth }
956184c64d4SCharles.Forsyth }
957184c64d4SCharles.Forsyth
958184c64d4SCharles.Forsyth static User*
newuser(int id,int gid,char * name,int nmem)959184c64d4SCharles.Forsyth newuser(int id, int gid, char *name, int nmem)
960184c64d4SCharles.Forsyth {
961184c64d4SCharles.Forsyth User *u;
962184c64d4SCharles.Forsyth
963184c64d4SCharles.Forsyth u = malloc(sizeof(*u));
964184c64d4SCharles.Forsyth if(u == nil)
965184c64d4SCharles.Forsyth return nil;
966184c64d4SCharles.Forsyth u->name = strdup(name);
967184c64d4SCharles.Forsyth if(u->name == nil){
968184c64d4SCharles.Forsyth free(u);
969184c64d4SCharles.Forsyth return nil;
970184c64d4SCharles.Forsyth }
971184c64d4SCharles.Forsyth u->nmem = nmem;
972184c64d4SCharles.Forsyth if(nmem){
973184c64d4SCharles.Forsyth u->mem = malloc(nmem*sizeof(*u->mem));
974184c64d4SCharles.Forsyth if(u->mem == nil){
975184c64d4SCharles.Forsyth free(u->name);
976184c64d4SCharles.Forsyth free(u);
977184c64d4SCharles.Forsyth return nil;
978184c64d4SCharles.Forsyth }
979184c64d4SCharles.Forsyth }else
980184c64d4SCharles.Forsyth u->mem = nil;
981184c64d4SCharles.Forsyth u->id = id;
982184c64d4SCharles.Forsyth u->gid = gid;
983184c64d4SCharles.Forsyth u->next = nil;
984184c64d4SCharles.Forsyth return u;
985184c64d4SCharles.Forsyth }
986184c64d4SCharles.Forsyth
987184c64d4SCharles.Forsyth static User*
newuname(char * name)988184c64d4SCharles.Forsyth newuname(char *name)
989184c64d4SCharles.Forsyth {
990184c64d4SCharles.Forsyth struct passwd *p;
991184c64d4SCharles.Forsyth
992184c64d4SCharles.Forsyth p = getpwnam(name);
993184c64d4SCharles.Forsyth if(p == nil)
994184c64d4SCharles.Forsyth return nil;
995184c64d4SCharles.Forsyth return newuser(p->pw_uid, p->pw_gid, name, 0);
996184c64d4SCharles.Forsyth }
997184c64d4SCharles.Forsyth
998184c64d4SCharles.Forsyth static User*
newuid(int id)999184c64d4SCharles.Forsyth newuid(int id)
1000184c64d4SCharles.Forsyth {
1001184c64d4SCharles.Forsyth struct passwd *p;
1002184c64d4SCharles.Forsyth
1003184c64d4SCharles.Forsyth p = getpwuid(id);
1004184c64d4SCharles.Forsyth if(p == nil)
1005184c64d4SCharles.Forsyth return nil;
1006184c64d4SCharles.Forsyth return newuser(p->pw_uid, p->pw_gid, p->pw_name, 0);
1007184c64d4SCharles.Forsyth }
1008184c64d4SCharles.Forsyth
1009184c64d4SCharles.Forsyth static User*
newgroup(struct group * g)1010184c64d4SCharles.Forsyth newgroup(struct group *g)
1011184c64d4SCharles.Forsyth {
1012184c64d4SCharles.Forsyth User *u, *gm;
1013184c64d4SCharles.Forsyth int n, o;
1014184c64d4SCharles.Forsyth
1015184c64d4SCharles.Forsyth if(g == nil)
1016184c64d4SCharles.Forsyth return nil;
1017184c64d4SCharles.Forsyth for(n=0; g->gr_mem[n] != nil; n++)
1018184c64d4SCharles.Forsyth ;
1019184c64d4SCharles.Forsyth u = newuser(g->gr_gid, g->gr_gid, g->gr_name, n);
1020184c64d4SCharles.Forsyth if(u == nil)
1021184c64d4SCharles.Forsyth return nil;
1022184c64d4SCharles.Forsyth o = 0;
1023184c64d4SCharles.Forsyth for(n=0; g->gr_mem[n] != nil; n++){
1024184c64d4SCharles.Forsyth gm = name2user(uidmap, g->gr_mem[n], newuname);
1025184c64d4SCharles.Forsyth if(gm != nil)
1026184c64d4SCharles.Forsyth u->mem[o++] = gm->id;
1027184c64d4SCharles.Forsyth /* ignore names that don't map to IDs */
1028184c64d4SCharles.Forsyth }
1029184c64d4SCharles.Forsyth u->nmem = o;
1030184c64d4SCharles.Forsyth return u;
1031184c64d4SCharles.Forsyth }
1032184c64d4SCharles.Forsyth
1033184c64d4SCharles.Forsyth static User*
newgid(int id)1034184c64d4SCharles.Forsyth newgid(int id)
1035184c64d4SCharles.Forsyth {
1036184c64d4SCharles.Forsyth return newgroup(getgrgid(id));
1037184c64d4SCharles.Forsyth }
1038184c64d4SCharles.Forsyth
1039184c64d4SCharles.Forsyth static User*
newgname(char * name)1040184c64d4SCharles.Forsyth newgname(char *name)
1041184c64d4SCharles.Forsyth {
1042184c64d4SCharles.Forsyth return newgroup(getgrnam(name));
1043184c64d4SCharles.Forsyth }
1044184c64d4SCharles.Forsyth
1045184c64d4SCharles.Forsyth static User*
id2user(User ** tab,int id,User * (* get)(int))1046184c64d4SCharles.Forsyth id2user(User **tab, int id, User* (*get)(int))
1047184c64d4SCharles.Forsyth {
1048184c64d4SCharles.Forsyth User *u, **h;
1049184c64d4SCharles.Forsyth
1050184c64d4SCharles.Forsyth h = hashuser(tab, id);
1051184c64d4SCharles.Forsyth for(u = *h; u != nil; u = u->next)
1052184c64d4SCharles.Forsyth if(u->id == id)
1053184c64d4SCharles.Forsyth return u;
1054184c64d4SCharles.Forsyth u = get(id);
1055184c64d4SCharles.Forsyth if(u == nil)
1056184c64d4SCharles.Forsyth return nil;
1057184c64d4SCharles.Forsyth u->next = *h;
1058184c64d4SCharles.Forsyth *h = u;
1059184c64d4SCharles.Forsyth return u;
1060184c64d4SCharles.Forsyth }
1061184c64d4SCharles.Forsyth
1062184c64d4SCharles.Forsyth static int
ingroup(int id,int gid)1063184c64d4SCharles.Forsyth ingroup(int id, int gid)
1064184c64d4SCharles.Forsyth {
1065184c64d4SCharles.Forsyth int i;
1066184c64d4SCharles.Forsyth User *g;
1067184c64d4SCharles.Forsyth
1068184c64d4SCharles.Forsyth g = id2user(gidmap, gid, newgid);
1069184c64d4SCharles.Forsyth if(g == nil || g->mem == nil)
1070184c64d4SCharles.Forsyth return 0;
1071184c64d4SCharles.Forsyth for(i = 0; i < g->nmem; i++)
1072184c64d4SCharles.Forsyth if(g->mem[i] == id)
1073184c64d4SCharles.Forsyth return 1;
1074184c64d4SCharles.Forsyth return 0;
107537da2899SCharles.Forsyth }
107637da2899SCharles.Forsyth
107737da2899SCharles.Forsyth Dev fsdevtab = {
107837da2899SCharles.Forsyth 'U',
107937da2899SCharles.Forsyth "fs",
108037da2899SCharles.Forsyth
108137da2899SCharles.Forsyth devinit,
108237da2899SCharles.Forsyth fsattach,
108337da2899SCharles.Forsyth fswalk,
108437da2899SCharles.Forsyth fsstat,
108537da2899SCharles.Forsyth fsopen,
108637da2899SCharles.Forsyth fscreate,
108737da2899SCharles.Forsyth fsclose,
108837da2899SCharles.Forsyth fsread,
108937da2899SCharles.Forsyth devbread,
109037da2899SCharles.Forsyth fswrite,
109137da2899SCharles.Forsyth devbwrite,
109237da2899SCharles.Forsyth fsremove,
109337da2899SCharles.Forsyth fswstat
109437da2899SCharles.Forsyth };
1095