static Spfcall* npfs_open(Spfid *fid, u8 mode) { int err; Fid *f; Spqid qid; f = fid->aux; npfs_change_user(fid->user); if ((err = fidstat(f)) < 0) create_rerror(err); if (S_ISDIR(f->stat.st_mode)) { f->dir = opendir(f->path); if (!f->dir) create_rerror(errno); } else { f->fd = open(f->path, omode2uflags(mode)); if (f->fd < 0) create_rerror(errno); } err = fidstat(f); if (err < 0) create_rerror(err); f->omode = mode; ustat2qid(&f->stat, &qid); return sp_create_ropen(&qid, 0); }
static int npfs_walk(Spfid *fid, Spstr* wname, Spqid *wqid) { int n; Fid *f; struct stat st; char *path; f = fid->aux; npfs_change_user(fid->user); n = fidstat(f); if (n < 0) create_rerror(n); n = strlen(f->path); path = malloc(n + wname->len + 2); memcpy(path, f->path, n); path[n] = '/'; memcpy(path + n + 1, wname->str, wname->len); path[n + wname->len + 1] = '\0'; if (lstat(path, &st) < 0) { free(path); create_rerror(errno); return 0; } free(f->path); f->path = path; ustat2qid(&st, wqid); return 1; }
static Spfcall* ufs_read(Spfid *fid, u64 offset, u32 count, Spreq *req) { int n; Fid *f; Spfcall *ret; f = fid->aux; ret = sp_alloc_rread(count); if (f->dir) n = ufs_read_dir(fid, ret->data, offset, count, fid->conn->dotu); else { n = pread(f->fd, ret->data, count, offset); if (n < 0) create_rerror(errno); } if (sp_haserror()) { free(ret); ret = NULL; } else sp_set_rread_count(ret, n); return ret; }
static Spfcall* npfs_read(Spfid *fid, u64 offset, u32 count, Spreq *req) { int n; Fid *f; Spfcall *ret; f = fid->aux; ret = sp_alloc_rread(count); npfs_change_user(fid->user); if (f->dir) n = npfs_read_dir(f, ret->data, offset, count, fid->conn->dotu); else { if(mmapreads) { struct stat s; n = count; if(!f->aux) { fstat(f->fd, &s); f->aux=mmap(0, s.st_size, PROT_READ, MAP_SHARED, f->fd, 0); if(f->aux < 0) { create_rerror(errno); goto error; } } if(offset+count > s.st_size) n = s.st_size-offset; if(n>0) memcpy(ret->data, f->aux+offset, n); else n = 0; } else { n = pread(f->fd, ret->data, count, offset); if (n < 0) create_rerror(errno); } } error: if (sp_haserror()) { free(ret); ret = NULL; } else sp_set_rread_count(ret, n); return ret; }
static Spfcall* ufs_write(Spfid *fid, u64 offset, u32 count, u8 *data, Spreq *req) { int n; Fid *f; f = fid->aux; n = pwrite(f->fd, data, count, offset); if (n < 0) create_rerror(errno); return sp_create_rwrite(n); }
static Spfcall* npfs_remove(Spfid *fid) { Fid *f; Spfcall *ret; ret = NULL; f = fid->aux; npfs_change_user(fid->user); if (remove(f->path) < 0) { create_rerror(errno); goto out; } ret = sp_create_rremove(); out: // sp_fid_decref(fid); return ret; }
static Spfcall* ufs_stat(Spfid *fid) { int err; Fid *f; Spfcall *ret; Spwstat wstat; f = fid->aux; err = fidstat(f); if (err < 0) create_rerror(err); ustat2npwstat(f->path, &f->stat, &wstat, fid->conn->dotu, fid->conn->srv->upool); ret = sp_create_rstat(&wstat, fid->conn->dotu); free(wstat.extension); return ret; }
static Spfcall* npfs_attach(Spfid *nfid, Spfid *nafid, Spstr *uname, Spstr *aname, u32 n_uname) { int err; Spfcall* ret; Fid *fid; Spqid qid; char *user; user = NULL; ret = NULL; if (nafid != NULL) { sp_werror(Enoauth, EIO); goto done; } fid = npfs_fidalloc(); fid->omode = -1; npfs_change_user(nfid->user); fid->omode = -1; if (aname->len==0 || *aname->str!='/') fid->path = strdup("/"); else fid->path = sp_strdup(aname); nfid->aux = fid; err = fidstat(fid); if (err < 0) { create_rerror(err); goto done; } ustat2qid(&fid->stat, &qid); ret = sp_create_rattach(&qid); sp_fid_incref(nfid); done: return ret; }
static Spfcall* npfs_wstat(Spfid *fid, Spstat *stat) { int err; Fid *f; Spfcall *ret; uid_t uid; gid_t gid; char *npath, *p, *s; Spuser *user; Spgroup *group; struct utimbuf tb; ret = NULL; f = fid->aux; npfs_change_user(fid->user); err = fidstat(f); if (err < 0) { create_rerror(err); goto out; } if (fid->conn->dotu) { uid = stat->n_uid; gid = stat->n_gid; } else { uid = (uid_t) -1; gid = (gid_t) -1; } if (uid == -1 && stat->uid.len) { s = sp_strdup(&stat->uid); user = sp_uname2user(s); free(s); if (!user) { sp_werror(Eunknownuser, EIO); goto out; } uid = user->uid; } if (gid == -1 && stat->gid.len) { s = sp_strdup(&stat->gid); group = sp_gname2group(s); free(s); if (!group) { sp_werror(Eunknownuser, EIO); goto out; } gid = group->gid; } if (stat->mode != (u32)~0) { if (stat->mode&Dmdir && !S_ISDIR(f->stat.st_mode)) { sp_werror(Edirchange, EIO); goto out; } if (chmod(f->path, npstat2umode(stat, fid->conn->dotu)) < 0) { create_rerror(errno); goto out; } } if (stat->mtime != (u32)~0) { tb.actime = 0; tb.modtime = stat->mtime; if (utime(f->path, &tb) < 0) { create_rerror(errno); goto out; } } if (gid != -1) { if (chown(f->path, uid, gid) < 0) { create_rerror(errno); goto out; } } if (stat->name.len != 0) { p = strrchr(f->path, '/'); if (!p) p = f->path + strlen(f->path); npath = malloc(stat->name.len + (p - f->path) + 2); memcpy(npath, f->path, p - f->path); npath[p - f->path] = '/'; memcpy(npath + (p - f->path) + 1, stat->name.str, stat->name.len); npath[(p - f->path) + 1 + stat->name.len] = 0; if (strcmp(npath, f->path) != 0) { if (rename(f->path, npath) < 0) { create_rerror(errno); goto out; } free(f->path); f->path = npath; } } if (stat->length != ~0) { if (truncate(f->path, stat->length) < 0) { create_rerror(errno); goto out; } } ret = sp_create_rwstat(); out: return ret; }
static u32 npfs_read_dir(Fid *f, u8* buf, u64 offset, u32 count, int dotu) { int i, n, plen; char *dname, *path; struct dirent *dirent; struct stat st; Spwstat wstat; if (offset == 0) { rewinddir(f->dir); f->diroffset = 0; } plen = strlen(f->path); n = 0; dirent = NULL; dname = f->direntname; while (n < count) { if (!dname) { dirent = readdir(f->dir); if (!dirent) break; if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) continue; dname = dirent->d_name; } path = malloc(plen + strlen(dname) + 2); sprintf(path, "%s/%s", f->path, dname); if (lstat(path, &st) < 0) { free(path); create_rerror(errno); return 0; } ustat2npwstat(path, &st, &wstat, dotu); i = sp_serialize_stat(&wstat, buf + n, count - n - 1, dotu); free(wstat.extension); free(path); path = NULL; if (i==0) break; dname = NULL; n += i; } if (f->direntname) { free(f->direntname); f->direntname = NULL; } if (dirent) f->direntname = strdup(dirent->d_name); f->diroffset += n; return n; }
static Spfcall* npfs_create(Spfid *fid, Spstr *name, u32 perm, u8 mode, Spstr *extension) { int n, err, omode; Fid *f; Spfcall *ret; Spqid qid; char *npath; struct stat st; ret = NULL; omode = mode; f = fid->aux; if ((err = fidstat(f)) < 0) create_rerror(err); n = strlen(f->path); npath = malloc(n + name->len + 2); memmove(npath, f->path, n); npath[n] = '/'; memmove(npath + n + 1, name->str, name->len); npath[n + name->len + 1] = '\0'; if (lstat(npath, &st)==0 || errno!=ENOENT) { sp_werror(Eexist, EEXIST); goto out; } if (perm & Dmdir) { if (mkdir(npath, perm & 0777) < 0) { create_rerror(errno); goto out; } if (lstat(npath, &f->stat) < 0) { create_rerror(errno); rmdir(npath); goto out; } f->dir = opendir(npath); if (!f->dir) { create_rerror(errno); remove(npath); goto out; } } else if (perm & (Dmnamedpipe|Dmsymlink|Dmlink|Dmdevice)) { if (npfs_create_special(fid, npath, perm, extension) < 0) goto out; if (lstat(npath, &f->stat) < 0) { create_rerror(errno); remove(npath); goto out; } } else { f->fd = open(npath, O_CREAT|omode2uflags(mode), perm & 0777); if (f->fd < 0) { create_rerror(errno); goto out; } if (lstat(npath, &f->stat) < 0) { create_rerror(errno); remove(npath); goto out; } } free(f->path); f->path = npath; f->omode = omode; npath = NULL; ustat2qid(&f->stat, &qid); ret = sp_create_rcreate(&qid, 0); out: free(npath); return ret; }
static int npfs_create_special(Spfid *fid, char *path, u32 perm, Spstr *extension) { int nfid, err; int nmode, major, minor; char ctype; mode_t umode; Spfid *ofid; Fid *f, *of; char *ext; f = fid->aux; if (!perm&Dmnamedpipe && !extension->len) { sp_werror(Enoextension, EIO); return -1; } umode = np2umode(perm, extension, fid->conn->dotu); ext = sp_strdup(extension); if (perm & Dmsymlink) { if (symlink(ext, path) < 0) { err = errno; fprintf(stderr, "symlink %s %s %d\n", ext, path, err); create_rerror(err); goto error; } } else if (perm & Dmlink) { if (sscanf(ext, "%d", &nfid) == 0) { sp_werror(Eformat, EIO); goto error; } ofid = sp_fid_find(fid->conn, nfid); if (!ofid) { sp_werror(Eunknownfid, EIO); goto error; } of = ofid->aux; if (link(of->path, path) < 0) { create_rerror(errno); goto error; } } else if (perm & Dmdevice) { if (sscanf(ext, "%c %u %u", &ctype, &major, &minor) != 3) { sp_werror(Eformat, EIO); goto error; } nmode = 0; switch (ctype) { case 'c': nmode = S_IFCHR; break; case 'b': nmode = S_IFBLK; break; default: sp_werror(Eformat, EIO); goto error; } nmode |= perm & 0777; if (mknod(path, nmode, makedev(major, minor)) < 0) { create_rerror(errno); goto error; } } else if (perm & Dmnamedpipe) { if (mknod(path, S_IFIFO | (umode&0777), 0) < 0) { create_rerror(errno); goto error; } } f->omode = 0; if (!perm&Dmsymlink && chmod(path, umode)<0) { create_rerror(errno); goto error; } free(ext); return 0; error: free(ext); return -1; }