#define _DEFAULT_SOURCE#define _FILE_OFFSET_BITS 64#include <dirent.h>#include <errno.h>#include <fcntl.h>#include <grp.h>#include <inttypes.h>#include <pwd.h>#include <signal.h>#include <stdarg.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/select.h>#include <sys/stat.h>#include <sys/time.h>#include <unistd.h>#include "c9.h"#include "parg.h" #define max(a,b) ((a)>(b)?(a):(b))#define used(x) ((void)(x))#define nelem(x) (int)(sizeof(x)/sizeof((x)[0])) uint32_t crc32(const void *data, int len); enum{ Canrd = 1<<0, Canwr = 1<<1,}; typedef struct{ char *path; /* full path */ char *name; /* base name */ DIR *dir; /* set when it's an opened directory */ uint64_t diroffset; /* to read dirs correctly */ C9qid qid; C9fid fid; C9mode mode; /* mode in which the file was opened */ uint32_t iounit; int fd; /* set when it's an opened file */}Fid; typedef struct{ C9tag tag;}Tag; typedef struct{ char *name; uint32_t id;}Id; static char *t2s[] = { [Tversion-Tversion] = "Tversion", [Tauth-Tversion] = "Tauth", [Tattach-Tversion] = "Tattach", [Tflush-Tversion] = "Tflush", [Twalk-Tversion] = "Twalk", [Topen-Tversion] = "Topen", [Tcreate-Tversion] = "Tcreate", [Tread-Tversion] = "Tread", [Twrite-Tversion] = "Twrite", [Tclunk-Tversion] = "Tclunk", [Tremove-Tversion] = "Tremove", [Tstat-Tversion] = "Tstat", [Twstat-Tversion] = "Twstat",}; static char *modes[] = { "read", "write", "rdwr", "exec",}; static char *Enoauth = "authentication not required";static char *Eunknownfid = "unknown fid";static char *Enowstat = "wstat prohibited";static char *Eperm = "permission denied";static char *Enowrite = "write prohibited";static char *Enomem = "out of memory";static char *Edupfid = "duplicate fid";static char *Ewalknodir = "walk in non-directory";static char *Enotfound = "file not found";static char *Eduptag = "duplicate tag";static char *Ebotch = "9P protocol botch";static char *Enocreate = "create prohibited";static char *Eisdir = "is a directory";static char *Ebadoffset = "bad offset"; static int in, out, eof;static C9ctx ctx;static int debug;static Fid **fids;static int numfids;static Tag **tags;static int numtags;static char *rootpath;static size_t rootlen;static C9qid walkqids[C9maxpathel];static uint8_t *rdbuf;static uint8_t *wrbuf;static uint32_t wroff, wrend, wrbufsz;static Id *uids, *gids;static int numuids, numgids; __attribute__ ((format (printf, 1, 2)))static voidtrace(const char *fmt, ...){ va_list ap; if (debug == 0) return; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap);} static intcanrw(int rdonly, int block){ struct timeval t; fd_set r, w, e; int n, fl; FD_ZERO(&r); FD_SET(in, &r); FD_ZERO(&w); if (rdonly == 0) FD_SET(out, &w); FD_ZERO(&e); FD_SET(in, &e); FD_SET(out, &e); memset(&t, 0, sizeof(t)); t.tv_usec = 1000; for (;;) { errno = 0; if ((n = select(max(in, out) + 1, &r, &w, &e, block ? NULL : &t)) < 0 || FD_ISSET(in, &e) || FD_ISSET(out, &e)) { if (errno == EINTR) continue; return -1; } break; } fl = 0; if (FD_ISSET(in, &r)) fl |= Canrd; if (FD_ISSET(out, &w)) fl |= Canwr; return fl;} static intwrsend(void){ uint32_t n; int w; if (wrend == 0) return 0; for (n = 0; n < wrend; n += w) { errno = 0; if ((w = write(out, wrbuf+n, wrend-n)) <= 0) { if (errno == EINTR) continue; if (errno != EPIPE) /* remote end closed */ perror("write"); return -1; } } if (debug >= 2) trace("<- %d bytes, %d left\n", wrend, wroff-wrend); memmove(wrbuf, wrbuf+wrend, wroff-wrend); wroff = wroff - wrend; return 0;} static inthastag(C9tag tag){ int i; for (i = 0; i < numtags; i++) { if (tags[i] != NULL && tags[i]->tag == tag) return 1; } return 0;} static intstatpath(char *path, struct stat *st, char **err){ if (stat(path, st) == 0) return 0; if (errno == EACCES) *err = Eperm; else if (errno == ENOMEM) *err = Enomem; else if (errno == ENOTDIR) *err = Ewalknodir; else if (errno == ENOENT) *err = Enotfound; else *err = strerror(errno); return -1;} static voidstat2qid(struct stat *st, C9qid *qid, uint32_t *iounit){ int fmt; qid->path = st->st_ino; qid->version = crc32(&st->st_ctim, sizeof(st->st_ctime)); qid->type = C9qtfile; fmt = st->st_mode & S_IFMT; if (fmt == S_IFDIR) qid->type |= C9qtdir; if ((st->st_mode & 0222) != 0 && (fmt == S_IFCHR || fmt == S_IFCHR || fmt == S_IFSOCK || fmt == S_IFIFO)) qid->type |= C9qtappend; if (iounit != NULL) *iounit = st->st_blksize;} static Fid *newfid(C9fid fid, char *path, char **err){ Fid *f, **newfids; struct stat st; int i; for (i = 0; i < numfids; i++) { if (fids[i] != NULL && fids[i]->fid == fid) { *err = Edupfid; return NULL; } } if (statpath(path, &st, err) != 0) return NULL; if ((f = calloc(1, sizeof(*f))) == NULL) { *err = Enomem; return NULL; } f->fd = -1; f->path = strdup(path); f->name = strrchr(f->path, '/'); if (f->name == NULL) f->name = f->path; else f->name++; for (i = 0; i < numfids; i++) { if (fids[i] == NULL) { fids[i] = f; break; } } if (i >= numfids) { if ((newfids = realloc(fids, (numfids+1)*sizeof(*fids))) == NULL) { *err = Enomem; return NULL; } fids = newfids; fids[numfids++] = f; } f->fid = fid; stat2qid(&st, &f->qid, &f->iounit); return f;} static Fid *findfid(C9fid fid, char **err){ int i; for (i = 0; i < numfids; i++) { if (fids[i] != NULL && fids[i]->fid == fid) { return fids[i]; } } *err = Eunknownfid; return NULL;} static intdelfid(C9fid fid, char **err){ Fid *f; int i; for (i = 0; i < numfids; i++) { f = fids[i]; if (f != NULL && f->fid == fid) { if (f->dir != NULL) closedir(f->dir); else if (f->fd >= 0) close(f->fd); free(f->path); free(f); fids[i] = NULL; return 0; } } *err = Eunknownfid; return -1;} static inthasperm(struct stat *st, C9mode mode, char **err){ int m, stm, fmt; m = mode & 0xf; stm = st->st_mode & 0777; *err = Eperm; if (((stm & 0111) == 0 || (stm & 0444) == 0) && m == C9exec) /* executing needs rx */ return 0; if ((stm & 0222) == 0 && (m == C9write || m == C9rdwr)) /* writing needs w */ return 0; if ((stm & 0444) == 0 && m != C9write) /* reading needs r */ return 0; fmt = st->st_mode & S_IFMT; if (fmt == S_IFDIR && ((stm & 0111) == 0 || (stm & 0444) == 0)) /* dirs need rx */ return 0; *err = NULL; return 1;} static Fid *walk(C9fid fid, C9fid nfid, char *el[], C9qid *qids[], char **err){ Fid *f; char *path, *real, *p; struct stat st; int i, plen, ellen; if ((f = findfid(fid, err)) == NULL) return NULL; if (el[0] == NULL) { /* nwname = 0 */ qids[0] = NULL; if (fid == nfid) return f; return newfid(nfid, f->path, err); } if ((f->qid.type & C9qtdir) == 0) { /* has to be a dir */ *err = Ewalknodir; return NULL; } p = strdup(f->path); f = NULL; for (i = 0; el[i] != NULL; i++) { plen = strlen(p); ellen = strlen(el[i]); path = malloc(plen + 1 + ellen + 1); memmove(path, p, plen); path[plen] = '/'; memmove(path+plen+1, el[i], ellen); path[plen+1+ellen] = 0; if ((real = realpath(path, NULL)) == NULL) break; free(path); if (strlen(real) < rootlen) { /* don't escape root */ free(real); real = strdup(rootpath); } free(p); p = real; if (statpath(p, &st, err) != 0) break; if (el[i+1] != NULL && !hasperm(&st, C9read, err)) break; qids[i] = &walkqids[i]; stat2qid(&st, qids[i], NULL); } qids[i] = NULL; if (el[i] == NULL) { /* could walk all the way */ f = newfid(nfid, p, err); if (f != NULL && f->name[0] == '/' && f->name[1] == 0) /* root */ f->name = "/"; } else if (i != 0) { /* didn't fail on the first one */ *err = NULL; } free(p); return f;} static intopenfid(Fid *f, C9mode mode, char **err){ struct stat st; int omode; if ((f->qid.type & C9qtdir) != 0) { if ((f->dir = opendir(f->path)) == NULL) { *err = strerror(errno); return -1; } f->fd = dirfd(f->dir); } else { omode = O_RDONLY; if ((f->qid.type & C9qtappend) != 0) omode |= O_APPEND; f->fd = open(f->path, omode); } if (f->fd < 0 || fstat(f->fd, &st) != 0 || !hasperm(&st, mode, err)) { if (*err == NULL) *err = strerror(errno); if (f->dir != NULL) closedir(f->dir); else if (f->fd >= 0) close(f->fd); f->dir = NULL; f->fd = -1; return -1; } stat2qid(&st, &f->qid, &f->iounit); f->mode = mode; return 0;} static char *uid2str(uid_t uid, char **err){ struct passwd *p; Id *newuids; int i; for (i = 0; i < numuids; i++) { if (uids[i].id == uid) return uids[i].name; } if ((p = getpwuid(uid)) == NULL) { *err = strerror(errno); return NULL; } if ((newuids = realloc(uids, sizeof(*uids)*(numuids+1))) == NULL) { *err = Enomem; return NULL; } uids = newuids; uids[numuids].id = uid; uids[numuids].name = strdup(p->pw_name); return uids[numuids++].name;} static char *gid2str(gid_t gid, char **err){ struct group *g; Id *newgids; int i; for (i = 0; i < numgids; i++) { if (gids[i].id == gid) return gids[i].name; } if ((g = getgrgid(gid)) == NULL) { *err = strerror(errno); return NULL; } if ((newgids = realloc(gids, sizeof(*gids)*(numgids+1))) == NULL) { *err = Enomem; return NULL; } gids = newgids;Lines 1–500 of 1000. Load more
#define _DEFAULT_SOURCE #define _FILE_OFFSET_BITS 64 #include <dirent.h> #include <errno.h> #include <fcntl.h> #include <grp.h> #include <inttypes.h> #include <pwd.h> #include <signal.h> #include <stdarg.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/select.h> #include <sys/stat.h> #include <sys/time.h> #include <unistd.h> #include "c9.h" #include "parg.h" #define max(a,b) ((a)>(b)?(a):(b)) #define used(x) ((void)(x)) #define nelem(x) (int)(sizeof(x)/sizeof((x)[0])) uint32_t crc32(const void *data, int len); enum { Canrd = 1<<0, Canwr = 1<<1, }; typedef struct { char *path; /* full path */ char *name; /* base name */ DIR *dir; /* set when it's an opened directory */ uint64_t diroffset; /* to read dirs correctly */ C9qid qid; C9fid fid; C9mode mode; /* mode in which the file was opened */ uint32_t iounit; int fd; /* set when it's an opened file */ }Fid; typedef struct { C9tag tag; }Tag; typedef struct { char *name; uint32_t id; }Id; static char *t2s[] = { [Tversion-Tversion] = "Tversion", [Tauth-Tversion] = "Tauth", [Tattach-Tversion] = "Tattach", [Tflush-Tversion] = "Tflush", [Twalk-Tversion] = "Twalk", [Topen-Tversion] = "Topen", [Tcreate-Tversion] = "Tcreate", [Tread-Tversion] = "Tread", [Twrite-Tversion] = "Twrite", [Tclunk-Tversion] = "Tclunk", [Tremove-Tversion] = "Tremove", [Tstat-Tversion] = "Tstat", [Twstat-Tversion] = "Twstat", }; static char *modes[] = { "read", "write", "rdwr", "exec", }; static char *Enoauth = "authentication not required"; static char *Eunknownfid = "unknown fid"; static char *Enowstat = "wstat prohibited"; static char *Eperm = "permission denied"; static char *Enowrite = "write prohibited"; static char *Enomem = "out of memory"; static char *Edupfid = "duplicate fid"; static char *Ewalknodir = "walk in non-directory"; static char *Enotfound = "file not found"; static char *Eduptag = "duplicate tag"; static char *Ebotch = "9P protocol botch"; static char *Enocreate = "create prohibited"; static char *Eisdir = "is a directory"; static char *Ebadoffset = "bad offset"; static int in, out, eof; static C9ctx ctx; static int debug; static Fid **fids; static int numfids; static Tag **tags; static int numtags; static char *rootpath; static size_t rootlen; static C9qid walkqids[C9maxpathel]; static uint8_t *rdbuf; static uint8_t *wrbuf; static uint32_t wroff, wrend, wrbufsz; static Id *uids, *gids; static int numuids, numgids; __attribute__ ((format (printf, 1, 2))) static void trace(const char *fmt, ...) { va_list ap; if (debug == 0) return; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } static int canrw(int rdonly, int block) { struct timeval t; fd_set r, w, e; int n, fl; FD_ZERO(&r); FD_SET(in, &r); FD_ZERO(&w); if (rdonly == 0) FD_SET(out, &w); FD_ZERO(&e); FD_SET(in, &e); FD_SET(out, &e); memset(&t, 0, sizeof(t)); t.tv_usec = 1000; for (;;) { errno = 0; if ((n = select(max(in, out) + 1, &r, &w, &e, block ? NULL : &t)) < 0 || FD_ISSET(in, &e) || FD_ISSET(out, &e)) { if (errno == EINTR) continue; return -1; } break; } fl = 0; if (FD_ISSET(in, &r)) fl |= Canrd; if (FD_ISSET(out, &w)) fl |= Canwr; return fl; } static int wrsend(void) { uint32_t n; int w; if (wrend == 0) return 0; for (n = 0; n < wrend; n += w) { errno = 0; if ((w = write(out, wrbuf+n, wrend-n)) <= 0) { if (errno == EINTR) continue; if (errno != EPIPE) /* remote end closed */ perror("write"); return -1; } } if (debug >= 2) trace("<- %d bytes, %d left\n", wrend, wroff-wrend); memmove(wrbuf, wrbuf+wrend, wroff-wrend); wroff = wroff - wrend; return 0; } static int hastag(C9tag tag) { int i; for (i = 0; i < numtags; i++) { if (tags[i] != NULL && tags[i]->tag == tag) return 1; } return 0; } static int statpath(char *path, struct stat *st, char **err) { if (stat(path, st) == 0) return 0; if (errno == EACCES) *err = Eperm; else if (errno == ENOMEM) *err = Enomem; else if (errno == ENOTDIR) *err = Ewalknodir; else if (errno == ENOENT) *err = Enotfound; else *err = strerror(errno); return -1; } static void stat2qid(struct stat *st, C9qid *qid, uint32_t *iounit) { int fmt; qid->path = st->st_ino; qid->version = crc32(&st->st_ctim, sizeof(st->st_ctime)); qid->type = C9qtfile; fmt = st->st_mode & S_IFMT; if (fmt == S_IFDIR) qid->type |= C9qtdir; if ((st->st_mode & 0222) != 0 && (fmt == S_IFCHR || fmt == S_IFCHR || fmt == S_IFSOCK || fmt == S_IFIFO)) qid->type |= C9qtappend; if (iounit != NULL) *iounit = st->st_blksize; } static Fid * newfid(C9fid fid, char *path, char **err) { Fid *f, **newfids; struct stat st; int i; for (i = 0; i < numfids; i++) { if (fids[i] != NULL && fids[i]->fid == fid) { *err = Edupfid; return NULL; } } if (statpath(path, &st, err) != 0) return NULL; if ((f = calloc(1, sizeof(*f))) == NULL) { *err = Enomem; return NULL; } f->fd = -1; f->path = strdup(path); f->name = strrchr(f->path, '/'); if (f->name == NULL) f->name = f->path; else f->name++; for (i = 0; i < numfids; i++) { if (fids[i] == NULL) { fids[i] = f; break; } } if (i >= numfids) { if ((newfids = realloc(fids, (numfids+1)*sizeof(*fids))) == NULL) { *err = Enomem; return NULL; } fids = newfids; fids[numfids++] = f; } f->fid = fid; stat2qid(&st, &f->qid, &f->iounit); return f; } static Fid * findfid(C9fid fid, char **err) { int i; for (i = 0; i < numfids; i++) { if (fids[i] != NULL && fids[i]->fid == fid) { return fids[i]; } } *err = Eunknownfid; return NULL; } static int delfid(C9fid fid, char **err) { Fid *f; int i; for (i = 0; i < numfids; i++) { f = fids[i]; if (f != NULL && f->fid == fid) { if (f->dir != NULL) closedir(f->dir); else if (f->fd >= 0) close(f->fd); free(f->path); free(f); fids[i] = NULL; return 0; } } *err = Eunknownfid; return -1; } static int hasperm(struct stat *st, C9mode mode, char **err) { int m, stm, fmt; m = mode & 0xf; stm = st->st_mode & 0777; *err = Eperm; if (((stm & 0111) == 0 || (stm & 0444) == 0) && m == C9exec) /* executing needs rx */ return 0; if ((stm & 0222) == 0 && (m == C9write || m == C9rdwr)) /* writing needs w */ return 0; if ((stm & 0444) == 0 && m != C9write) /* reading needs r */ return 0; fmt = st->st_mode & S_IFMT; if (fmt == S_IFDIR && ((stm & 0111) == 0 || (stm & 0444) == 0)) /* dirs need rx */ return 0; *err = NULL; return 1; } static Fid * walk(C9fid fid, C9fid nfid, char *el[], C9qid *qids[], char **err) { Fid *f; char *path, *real, *p; struct stat st; int i, plen, ellen; if ((f = findfid(fid, err)) == NULL) return NULL; if (el[0] == NULL) { /* nwname = 0 */ qids[0] = NULL; if (fid == nfid) return f; return newfid(nfid, f->path, err); } if ((f->qid.type & C9qtdir) == 0) { /* has to be a dir */ *err = Ewalknodir; return NULL; } p = strdup(f->path); f = NULL; for (i = 0; el[i] != NULL; i++) { plen = strlen(p); ellen = strlen(el[i]); path = malloc(plen + 1 + ellen + 1); memmove(path, p, plen); path[plen] = '/'; memmove(path+plen+1, el[i], ellen); path[plen+1+ellen] = 0; if ((real = realpath(path, NULL)) == NULL) break; free(path); if (strlen(real) < rootlen) { /* don't escape root */ free(real); real = strdup(rootpath); } free(p); p = real; if (statpath(p, &st, err) != 0) break; if (el[i+1] != NULL && !hasperm(&st, C9read, err)) break; qids[i] = &walkqids[i]; stat2qid(&st, qids[i], NULL); } qids[i] = NULL; if (el[i] == NULL) { /* could walk all the way */ f = newfid(nfid, p, err); if (f != NULL && f->name[0] == '/' && f->name[1] == 0) /* root */ f->name = "/"; } else if (i != 0) { /* didn't fail on the first one */ *err = NULL; } free(p); return f; } static int openfid(Fid *f, C9mode mode, char **err) { struct stat st; int omode; if ((f->qid.type & C9qtdir) != 0) { if ((f->dir = opendir(f->path)) == NULL) { *err = strerror(errno); return -1; } f->fd = dirfd(f->dir); } else { omode = O_RDONLY; if ((f->qid.type & C9qtappend) != 0) omode |= O_APPEND; f->fd = open(f->path, omode); } if (f->fd < 0 || fstat(f->fd, &st) != 0 || !hasperm(&st, mode, err)) { if (*err == NULL) *err = strerror(errno); if (f->dir != NULL) closedir(f->dir); else if (f->fd >= 0) close(f->fd); f->dir = NULL; f->fd = -1; return -1; } stat2qid(&st, &f->qid, &f->iounit); f->mode = mode; return 0; } static char * uid2str(uid_t uid, char **err) { struct passwd *p; Id *newuids; int i; for (i = 0; i < numuids; i++) { if (uids[i].id == uid) return uids[i].name; } if ((p = getpwuid(uid)) == NULL) { *err = strerror(errno); return NULL; } if ((newuids = realloc(uids, sizeof(*uids)*(numuids+1))) == NULL) { *err = Enomem; return NULL; } uids = newuids; uids[numuids].id = uid; uids[numuids].name = strdup(p->pw_name); return uids[numuids++].name; } static char * gid2str(gid_t gid, char **err) { struct group *g; Id *newgids; int i; for (i = 0; i < numgids; i++) { if (gids[i].id == gid) return gids[i].name; } if ((g = getgrgid(gid)) == NULL) { *err = strerror(errno); return NULL; } if ((newgids = realloc(gids, sizeof(*gids)*(numgids+1))) == NULL) { *err = Enomem; return NULL; } gids = newgids;