#include "u.h"#include <stdio.h> /* for remove, rename */#include <pwd.h>#include <grp.h> /* going to regret this - getgrgid is a stack smasher */#include <sys/socket.h>#include <sys/un.h> #if defined(__FreeBSD__)#include <sys/disk.h>#include <sys/disklabel.h>#include <sys/ioctl.h>#endif #if defined(__APPLE__)#include <sys/disk.h>#endif #if defined(__linux__)#include <linux/hdreg.h>#include <linux/fs.h>#include <sys/ioctl.h>#endif #include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "error.h" enum{ Trace = 0, FsChar = 'Z',}; extern char *canopen;extern Path *addelem(Path*, char*, Chan*);static char *uidtoname(int);static char *gidtoname(int);static int nametouid(char*);static int nametogid(char*); static vlong disksize(int, struct stat*); typedef struct UnixFd UnixFd;struct UnixFd{ int fd; int issocket; DIR* dir; vlong diroffset; QLock dirlock; struct dirent *nextde; Path *path;}; voidoserrstr(void){ if (errno == EINTR) kstrcpy(up->errstr, Eintr, ERRMAX); else kstrcpy(up->errstr, strerror(errno), ERRMAX);} voidoserror(void){ if (errno == EINTR) error(Eintr); else error(strerror(errno));} static Qidfsqid(struct stat *st){ Qid q; int dev; static int nqdev; static uchar *qdev; if(qdev == 0) qdev = smalloc(65536U); q.type = 0; if((st->st_mode&S_IFMT) == S_IFDIR) q.type = QTDIR; dev = st->st_dev & 0xFFFFUL; if(qdev[dev] == 0) qdev[dev] = ++nqdev; q.path = (vlong)qdev[dev]<<48; q.path ^= st->st_ino; q.vers = st->st_mtime; return q;} static Chan*fsattach(char *spec){ struct stat st; Chan *c; UnixFd *ufd; int dev; dev = 1; if(spec && spec[0]){ snprint(up->genbuf, sizeof up->genbuf, "no file system #%C%s", FsChar, spec); error(up->genbuf); } if(stat("/", &st) < 0) oserror(); c = devattach(FsChar, 0); ufd = mallocz(sizeof(UnixFd), 1); ufd->path = newpath("/"); ufd->fd = -1; c->aux = ufd; c->dev = dev; c->qid = fsqid(&st); if(Trace) print("fsattach /\n"); return c;} static Chan*fsclone(Chan *c, Chan *nc){ UnixFd *ufd; ufd = mallocz(sizeof(UnixFd), 1); *ufd = *(UnixFd*)c->aux; if(ufd->path) incref(&ufd->path->ref); ufd->fd = -1; nc->aux = ufd; return nc;} static char*lastelem(char *s){ char *t; if(s[0] == '/' && s[1] == 0) return s; t = strrchr(s, '/'); if(t == nil) return s; return t+1;} static char*fspath(Chan *c, char *suffix){ char *s, *t; int len; UnixFd *ufd; ufd = c->aux; s = ufd->path->s; len = strlen(s)+1; if(suffix) len += 1+strlen(suffix); t = smalloc(len); strcpy(t, s); if(suffix){ if(s[strlen(s)-1] != '/') strcat(t, "/"); strcat(t, suffix); } return t;} static intfswalk1(Chan *c, char *name){ struct stat st; char *path; UnixFd *ufd; ufd = c->aux; if(strcmp(name, "..") == 0 && strcmp(ufd->path->s, "/") == 0) return 0; path = fspath(c, name); if(stat(path, &st) < 0){ if(Trace) print("fswalk1 %s (%s)\n", path, strerror(errno)); free(path); return -1; } if(Trace) print("fswalk1 %s\n", path); free(path); c->qid = fsqid(&st); return 0;} static voidreplacepath(Chan *c, Path *p){ UnixFd *ufd; ufd = c->aux; incref(&p->ref); pathclose(ufd->path); ufd->path = p;} static Walkqid*fswalk(Chan *c, Chan *nc, char **name, int nname){ int i; Path *path; Walkqid *wq; UnixFd *ufd; if(nc != nil) panic("fswalk: nc != nil"); wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); nc = devclone(c); fsclone(c, nc); ufd = c->aux; path = ufd->path; incref(&path->ref); wq->clone = nc; for(i=0; i<nname; i++){ ufd = nc->aux; replacepath(nc, path); if(fswalk1(nc, name[i]) < 0){ if(i == 0){ pathclose(path); cclose(nc); free(wq); error(Enonexist); } break; } path = addelem(path, name[i], nil); wq->qid[i] = nc->qid; } replacepath(nc, path); pathclose(path); if(i != nname){ cclose(nc); wq->clone = nil; } wq->nqid = i; return wq;} static intfsdirstat(char *path, int dev, Dir *d){ int fd; struct stat st; if(stat(path, &st) < 0 && lstat(path, &st) < 0) return -1; d->name = lastelem(path); d->uid = uidtoname(st.st_uid); d->gid = gidtoname(st.st_gid); d->muid = ""; d->qid = fsqid(&st); d->mode = (d->qid.type<<24) | (st.st_mode&0777); d->atime = st.st_atime; d->mtime = st.st_mtime; d->length = st.st_size; if(S_ISBLK(st.st_mode) && (fd = open(path, O_RDONLY)) >= 0){ d->length = disksize(fd, &st); close(fd); } // devmnt leaves 1-9 unused so that we can steal them. // it is easier for all involved if #Z shows M as the file type instead of Z. // dev is c->dev, either 1 (#Z) or 2 (#Zplan9). d->type = 'M'; d->dev = dev; return 0;} static intfsstat(Chan *c, uchar *buf, int n){ Dir d; char *path; UnixFd *ufd; ufd = c->aux; if(Trace) print("fsstat %s\n", ufd->path->s); if(n < BIT16SZ) error(Eshortstat); path = fspath(c, nil); if(fsdirstat(path, c->dev, &d) < 0){ free(path); oserror(); } if(strcmp(ufd->path->s, "/") == 0) d.name = "/"; n = convD2M(&d, buf, n); free(path); return n;} static intopensocket(UnixFd *ufd, char *path){ int fd; struct stat st; struct sockaddr_un su; if(stat(path, &st) < 0) return -1; if(!S_ISSOCK(st.st_mode)) return -1; memset(&su, 0, sizeof su); su.sun_family = AF_UNIX; if(strlen(path)+1 > sizeof su.sun_path){ errno = ENAMETOOLONG; return -1; } strcpy(su.sun_path, path); if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) return -1; if(connect(fd, (struct sockaddr*)&su, sizeof su) < 0){ close(fd); return -1; } ufd->fd = fd; ufd->issocket = 1; return 0;} static Chan*fsopen(Chan *c, int mode){ char *path; int m; UnixFd *ufd; ufd = c->aux; if(Trace) print("fsopen %s %#x\n", ufd->path->s, mode); /* protect files whose path does not begin with allowed */ if(strncmp(ufd->path->s, canopen, strlen(canopen)) != 0) error(Eperm); if(mode & ~(OTRUNC|ORCLOSE|3)) error(Ebadarg); if((c->qid.type & QTDIR) && mode != OREAD) error(Eperm); if((c->qid.type&QTDIR) && mode != OREAD) error(Eperm); c->mode = openmode(mode); path = fspath(c, nil); if(c->qid.type & QTDIR){ ufd->dir = opendir(path); if(ufd->dir == nil){ free(path); oserror(); } ufd->diroffset = 0; ufd->nextde = nil; }else{ m = mode & 3; if(m == OEXEC) m = OREAD; if(mode & OTRUNC) m |= O_TRUNC; if((ufd->fd = open(path, m)) < 0 && opensocket(ufd, path) < 0){ free(path); oserror(); } } free(path); c->flag |= COPEN; return c;} static voidfscreate(Chan *c, char *name, int mode, ulong perm){ char *path, *path0; int fd, mm; UnixFd *ufd; struct stat st; ufd = c->aux; if(Trace) print("fscreate %s %#x %#o\n", ufd->path->s, mode, perm); if(!(c->qid.type & QTDIR)) error(Enotdir); if(mode & ~(OTRUNC|ORCLOSE|3)) error(Ebadarg); if(perm & ~(DMDIR|0777)) error(Ebadarg); path0 = fspath(c, nil); path = fspath(c, name); if(waserror()){ free(path); free(path0); nexterror(); } if(stat(path0, &st) < 0) oserror(); if(perm & DMDIR){ if(mode != OREAD) error(Eperm); /* have to do the minimum 0400 so we can open it */ if(mkdir(path, (0400 | perm) & 0777) < 0) oserror(); if((fd = open(path, 0)) < 0) oserror(); fchown(fd, -1, st.st_gid); if(fstat(fd, &st) < 0){ close(fd); oserror(); } if((ufd->dir = opendir(path)) == nil) { /* arguably we should set the mode here too * but it's hard to see that this case * will ever happen */ close(fd); oserror(); } // Be like Plan 9 file servers: inherit mode bits // and group from parent. fchmod(fd, perm & st.st_mode & 0777); close(fd); ufd->diroffset = 0; ufd->nextde = nil; }else{ mm = mode & 3; if(mode & OTRUNC) mm |= O_TRUNC; if((fd = open(path, mm|O_CREAT|O_EXCL, 0666)) < 0) oserror(); // Be like Plan 9 file servers: inherit mode bits // and group from parent. fchmod(fd, perm & st.st_mode & 0777); fchown(fd, -1, st.st_gid); if(fstat(fd, &st) < 0){ close(fd); oserror(); } ufd->fd = fd; } free(path); free(path0); poperror(); ufd->path = addelem(ufd->path, name, nil); c->qid = fsqid(&st); c->offset = 0; c->flag |= COPEN; c->mode = openmode(mode);} static voidfsclose(Chan *c){ UnixFd *ufd; char *path; ufd = c->aux; if(Trace) print("fsclose %s\n", ufd->path->s); if(c->flag & COPEN) { if(c->flag & CRCLOSE) { path = fspath(c, nil); unlink(path); free(path); } if(c->qid.type & QTDIR)Lines 1–500 of 942. Load more
#include "u.h" #include <stdio.h> /* for remove, rename */ #include <pwd.h> #include <grp.h> /* going to regret this - getgrgid is a stack smasher */ #include <sys/socket.h> #include <sys/un.h> #if defined(__FreeBSD__) #include <sys/disk.h> #include <sys/disklabel.h> #include <sys/ioctl.h> #endif #if defined(__APPLE__) #include <sys/disk.h> #endif #if defined(__linux__) #include <linux/hdreg.h> #include <linux/fs.h> #include <sys/ioctl.h> #endif #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "error.h" enum { Trace = 0, FsChar = 'Z', }; extern char *canopen; extern Path *addelem(Path*, char*, Chan*); static char *uidtoname(int); static char *gidtoname(int); static int nametouid(char*); static int nametogid(char*); static vlong disksize(int, struct stat*); typedef struct UnixFd UnixFd; struct UnixFd { int fd; int issocket; DIR* dir; vlong diroffset; QLock dirlock; struct dirent *nextde; Path *path; }; void oserrstr(void) { if (errno == EINTR) kstrcpy(up->errstr, Eintr, ERRMAX); else kstrcpy(up->errstr, strerror(errno), ERRMAX); } void oserror(void) { if (errno == EINTR) error(Eintr); else error(strerror(errno)); } static Qid fsqid(struct stat *st) { Qid q; int dev; static int nqdev; static uchar *qdev; if(qdev == 0) qdev = smalloc(65536U); q.type = 0; if((st->st_mode&S_IFMT) == S_IFDIR) q.type = QTDIR; dev = st->st_dev & 0xFFFFUL; if(qdev[dev] == 0) qdev[dev] = ++nqdev; q.path = (vlong)qdev[dev]<<48; q.path ^= st->st_ino; q.vers = st->st_mtime; return q; } static Chan* fsattach(char *spec) { struct stat st; Chan *c; UnixFd *ufd; int dev; dev = 1; if(spec && spec[0]){ snprint(up->genbuf, sizeof up->genbuf, "no file system #%C%s", FsChar, spec); error(up->genbuf); } if(stat("/", &st) < 0) oserror(); c = devattach(FsChar, 0); ufd = mallocz(sizeof(UnixFd), 1); ufd->path = newpath("/"); ufd->fd = -1; c->aux = ufd; c->dev = dev; c->qid = fsqid(&st); if(Trace) print("fsattach /\n"); return c; } static Chan* fsclone(Chan *c, Chan *nc) { UnixFd *ufd; ufd = mallocz(sizeof(UnixFd), 1); *ufd = *(UnixFd*)c->aux; if(ufd->path) incref(&ufd->path->ref); ufd->fd = -1; nc->aux = ufd; return nc; } static char* lastelem(char *s) { char *t; if(s[0] == '/' && s[1] == 0) return s; t = strrchr(s, '/'); if(t == nil) return s; return t+1; } static char* fspath(Chan *c, char *suffix) { char *s, *t; int len; UnixFd *ufd; ufd = c->aux; s = ufd->path->s; len = strlen(s)+1; if(suffix) len += 1+strlen(suffix); t = smalloc(len); strcpy(t, s); if(suffix){ if(s[strlen(s)-1] != '/') strcat(t, "/"); strcat(t, suffix); } return t; } static int fswalk1(Chan *c, char *name) { struct stat st; char *path; UnixFd *ufd; ufd = c->aux; if(strcmp(name, "..") == 0 && strcmp(ufd->path->s, "/") == 0) return 0; path = fspath(c, name); if(stat(path, &st) < 0){ if(Trace) print("fswalk1 %s (%s)\n", path, strerror(errno)); free(path); return -1; } if(Trace) print("fswalk1 %s\n", path); free(path); c->qid = fsqid(&st); return 0; } static void replacepath(Chan *c, Path *p) { UnixFd *ufd; ufd = c->aux; incref(&p->ref); pathclose(ufd->path); ufd->path = p; } static Walkqid* fswalk(Chan *c, Chan *nc, char **name, int nname) { int i; Path *path; Walkqid *wq; UnixFd *ufd; if(nc != nil) panic("fswalk: nc != nil"); wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); nc = devclone(c); fsclone(c, nc); ufd = c->aux; path = ufd->path; incref(&path->ref); wq->clone = nc; for(i=0; i<nname; i++){ ufd = nc->aux; replacepath(nc, path); if(fswalk1(nc, name[i]) < 0){ if(i == 0){ pathclose(path); cclose(nc); free(wq); error(Enonexist); } break; } path = addelem(path, name[i], nil); wq->qid[i] = nc->qid; } replacepath(nc, path); pathclose(path); if(i != nname){ cclose(nc); wq->clone = nil; } wq->nqid = i; return wq; } static int fsdirstat(char *path, int dev, Dir *d) { int fd; struct stat st; if(stat(path, &st) < 0 && lstat(path, &st) < 0) return -1; d->name = lastelem(path); d->uid = uidtoname(st.st_uid); d->gid = gidtoname(st.st_gid); d->muid = ""; d->qid = fsqid(&st); d->mode = (d->qid.type<<24) | (st.st_mode&0777); d->atime = st.st_atime; d->mtime = st.st_mtime; d->length = st.st_size; if(S_ISBLK(st.st_mode) && (fd = open(path, O_RDONLY)) >= 0){ d->length = disksize(fd, &st); close(fd); } // devmnt leaves 1-9 unused so that we can steal them. // it is easier for all involved if #Z shows M as the file type instead of Z. // dev is c->dev, either 1 (#Z) or 2 (#Zplan9). d->type = 'M'; d->dev = dev; return 0; } static int fsstat(Chan *c, uchar *buf, int n) { Dir d; char *path; UnixFd *ufd; ufd = c->aux; if(Trace) print("fsstat %s\n", ufd->path->s); if(n < BIT16SZ) error(Eshortstat); path = fspath(c, nil); if(fsdirstat(path, c->dev, &d) < 0){ free(path); oserror(); } if(strcmp(ufd->path->s, "/") == 0) d.name = "/"; n = convD2M(&d, buf, n); free(path); return n; } static int opensocket(UnixFd *ufd, char *path) { int fd; struct stat st; struct sockaddr_un su; if(stat(path, &st) < 0) return -1; if(!S_ISSOCK(st.st_mode)) return -1; memset(&su, 0, sizeof su); su.sun_family = AF_UNIX; if(strlen(path)+1 > sizeof su.sun_path){ errno = ENAMETOOLONG; return -1; } strcpy(su.sun_path, path); if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) return -1; if(connect(fd, (struct sockaddr*)&su, sizeof su) < 0){ close(fd); return -1; } ufd->fd = fd; ufd->issocket = 1; return 0; } static Chan* fsopen(Chan *c, int mode) { char *path; int m; UnixFd *ufd; ufd = c->aux; if(Trace) print("fsopen %s %#x\n", ufd->path->s, mode); /* protect files whose path does not begin with allowed */ if(strncmp(ufd->path->s, canopen, strlen(canopen)) != 0) error(Eperm); if(mode & ~(OTRUNC|ORCLOSE|3)) error(Ebadarg); if((c->qid.type & QTDIR) && mode != OREAD) error(Eperm); if((c->qid.type&QTDIR) && mode != OREAD) error(Eperm); c->mode = openmode(mode); path = fspath(c, nil); if(c->qid.type & QTDIR){ ufd->dir = opendir(path); if(ufd->dir == nil){ free(path); oserror(); } ufd->diroffset = 0; ufd->nextde = nil; }else{ m = mode & 3; if(m == OEXEC) m = OREAD; if(mode & OTRUNC) m |= O_TRUNC; if((ufd->fd = open(path, m)) < 0 && opensocket(ufd, path) < 0){ free(path); oserror(); } } free(path); c->flag |= COPEN; return c; } static void fscreate(Chan *c, char *name, int mode, ulong perm) { char *path, *path0; int fd, mm; UnixFd *ufd; struct stat st; ufd = c->aux; if(Trace) print("fscreate %s %#x %#o\n", ufd->path->s, mode, perm); if(!(c->qid.type & QTDIR)) error(Enotdir); if(mode & ~(OTRUNC|ORCLOSE|3)) error(Ebadarg); if(perm & ~(DMDIR|0777)) error(Ebadarg); path0 = fspath(c, nil); path = fspath(c, name); if(waserror()){ free(path); free(path0); nexterror(); } if(stat(path0, &st) < 0) oserror(); if(perm & DMDIR){ if(mode != OREAD) error(Eperm); /* have to do the minimum 0400 so we can open it */ if(mkdir(path, (0400 | perm) & 0777) < 0) oserror(); if((fd = open(path, 0)) < 0) oserror(); fchown(fd, -1, st.st_gid); if(fstat(fd, &st) < 0){ close(fd); oserror(); } if((ufd->dir = opendir(path)) == nil) { /* arguably we should set the mode here too * but it's hard to see that this case * will ever happen */ close(fd); oserror(); } // Be like Plan 9 file servers: inherit mode bits // and group from parent. fchmod(fd, perm & st.st_mode & 0777); close(fd); ufd->diroffset = 0; ufd->nextde = nil; }else{ mm = mode & 3; if(mode & OTRUNC) mm |= O_TRUNC; if((fd = open(path, mm|O_CREAT|O_EXCL, 0666)) < 0) oserror(); // Be like Plan 9 file servers: inherit mode bits // and group from parent. fchmod(fd, perm & st.st_mode & 0777); fchown(fd, -1, st.st_gid); if(fstat(fd, &st) < 0){ close(fd); oserror(); } ufd->fd = fd; } free(path); free(path0); poperror(); ufd->path = addelem(ufd->path, name, nil); c->qid = fsqid(&st); c->offset = 0; c->flag |= COPEN; c->mode = openmode(mode); } static void fsclose(Chan *c) { UnixFd *ufd; char *path; ufd = c->aux; if(Trace) print("fsclose %s\n", ufd->path->s); if(c->flag & COPEN) { if(c->flag & CRCLOSE) { path = fspath(c, nil); unlink(path); free(path); } if(c->qid.type & QTDIR)