static long dsoconcatread(MyFiles *f, void *a, long n, vlong offset){ int nfiles = f->nfiles; long leido = 0, aux_leido; vlong newoff = offset; Dir* fs; int tamb = 1024; int i = 0, j; long toread; uchar* buffer = (uchar*)malloc(sizeof(uchar)*tamb); // Posicionamos el offset Chan* file = f->files[i]; if (offset >= f->size) return 0; if ((offset + n) > f->size) n = f->size - offset; if (n == 0) return 0; fs = &(f->info[i]); devtab[file->type]->stat(file,buffer,tamb); convM2D(buffer, tamb, fs, 0); for(; (newoff > fs->length) && (i < nfiles);){ newoff -= fs->length; file = f->files[++i]; devtab[file->type]->stat(file,buffer,tamb); convM2D(buffer, tamb, fs, 0); } // Vamos leyendo hasta terminar if(i < nfiles){ toread = fs->length - newoff; leido += devtab[file->type]->read(file, a, toread, newoff); a = (char*)a + leido; for(j = i+1; (leido < n) && (j < nfiles); j++){ file = f->files[j]; fs = &(f->info[j]); devtab[file->type]->stat(file,buffer,tamb); convM2D(buffer, tamb, fs, 0); if((leido + fs->length) < n) toread = fs->length; else toread = n-leido; aux_leido = devtab[file->type]->read(file, a, toread, 0); a = (char*)a + aux_leido; leido += aux_leido; } } return leido; }
void setswapchan(Chan *c) { uchar dirbuf[sizeof(Dir)+100]; Dir d; int n; if(swapimage.c) { if(swapalloc.free != conf.nswap){ cclose(c); error(Einuse); } cclose(swapimage.c); } /* * if this isn't a file, set the swap space * to be at most the size of the partition */ if(devtab[c->type]->dc != L'M'){ n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf); if(n <= 0){ cclose(c); error("stat failed in setswapchan"); } convM2D(dirbuf, n, &d, nil); if(d.length < conf.nswap*BY2PG){ conf.nswap = d.length/BY2PG; swapalloc.top = &swapalloc.swmap[conf.nswap]; swapalloc.free = conf.nswap; } } swapimage.c = c; }
static int sdwstat(Chan* c, uchar* dp, int n) { Dir *d; SDpart *pp; SDperm *perm; SDunit *unit; SDev *sdev; if(c->qid.type & QTDIR) error(Eperm); sdev = sdgetdev(DEV(c->qid)); if(sdev == nil) error(Enonexist); unit = sdev->unit[UNIT(c->qid)]; qlock(&unit->ctl); d = nil; if(waserror()){ free(d); qunlock(&unit->ctl); decref(&sdev->r); nexterror(); } switch(TYPE(c->qid)){ default: error(Eperm); case Qctl: perm = &unit->ctlperm; break; case Qraw: perm = &unit->rawperm; break; case Qpart: pp = &unit->part[PART(c->qid)]; if(unit->vers+pp->vers != c->qid.vers) error(Enonexist); perm = &pp->SDperm; break; } if(strcmp(up->env->user, perm->user) && !iseve()) error(Eperm); d = smalloc(sizeof(Dir)+n); n = convM2D(dp, n, &d[0], (char*)&d[1]); if(n == 0) error(Eshortstat); if(!emptystr(d[0].uid)) kstrdup(&perm->user, d[0].uid); if(d[0].mode != ~0UL) perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777); free(d); qunlock(&unit->ctl); decref(&sdev->r); poperror(); return n; }
static int progwstat(Chan *c, uchar *db, int n) { Dir d; Prog *p; char *u; Osenv *o; if(c->qid.type&QTDIR) error(Eperm); acquire(); p = progpid(PID(c->qid)); if(p == nil) { release(); error(Ethread); } u = up->env->user; o = p->osenv; if(strcmp(u, o->user) != 0 && strcmp(u, eve) != 0) { release(); error(Eperm); } n = convM2D(db, n, &d, nil); if(n == 0){ release(); error(Eshortstat); } if(d.mode != ~0UL) o->pgrp->progmode = d.mode&0777; release(); return n; }
static long dsopartwrite(MyFiles *f, void *a, long n, vlong offset){ Chan* file = f->files[0]; int tamb = 1024; Dir* fs; int r; uchar* buffer = (uchar*)malloc(sizeof(uchar)*tamb); if (offset >= f->size) return 0; if ((offset + n) > f->size) n = f->size - offset; if (n == 0) return 0; r = devtab[file->type]->write(file, a, n, (offset + f->offset)); fs = &(f->info[0]); devtab[file->type]->stat(file,buffer,tamb); convM2D(buffer, tamb, fs, 0); f->mdate[0] = fs->mtime; return r; }
static int segmentwstat(Chan *c, uchar *dp, int n) { Globalseg *g; Dir *d; if(c->qid.type == QTDIR) error(Eperm); g = getgseg(c); if(waserror()){ putgseg(g); nexterror(); } if(strcmp(g->uid, up->user) && !iseve()) error(Eperm); d = smalloc(sizeof(Dir)+n); n = convM2D(dp, n, &d[0], (char*)&d[1]); g->perm = d->mode & 0777; putgseg(g); poperror(); free(d); return n; }
static int ipwstat(Chan *c, uchar *dp, int n) { Dir d; Conv *cv; Fs *f; Proto *p; f = ipfs[c->dev]; switch(TYPE(c->qid)) { default: error(Eperm); break; case Qctl: case Qdata: break; } n = convM2D(dp, n, &d, nil); if(n > 0){ p = f->p[PROTO(c->qid)]; cv = p->conv[CONV(c->qid)]; if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0) error(Eperm); if(d.uid[0]) kstrdup(&cv->owner, d.uid); cv->perm = d.mode & 0777; } return n; }
int32_t netifwstat(Netif *nif, Chan *c, uint8_t *db, int32_t n) { Proc *up = externup(); Dir *dir; Netfile *f; int l; f = nif->f[NETID(c->qid.path)]; if(f == 0) error(Enonexist); if(netown(f, up->user, OWRITE) < 0) error(Eperm); dir = smalloc(sizeof(Dir)+n); l = convM2D(db, n, &dir[0], (char*)&dir[1]); if(l == 0){ free(dir); error(Eshortstat); } if(!emptystr(dir[0].uid)) strncpy(f->owner, dir[0].uid, KNAMELEN); if(dir[0].mode != (uint32_t)~0UL) f->mode = dir[0].mode; free(dir); return l; }
static int pipewstat(struct chan *c, uint8_t *dp, int n) { ERRSTACK(2); struct dir *d; Pipe *p; int d1; if (c->qid.type & QTDIR) error(EPERM, ERROR_FIXME); p = c->aux; if (strcmp(current->user, p->user) != 0) error(EPERM, ERROR_FIXME); d = kzmalloc(sizeof(*d) + n, 0); if (waserror()) { kfree(d); nexterror(); } n = convM2D(dp, n, d, (char *)&d[1]); if (n == 0) error(ENODATA, ERROR_FIXME); d1 = NETTYPE(c->qid.path) == Qdata1; if (!emptystr(d->name)) { validwstatname(d->name); if (strlen(d->name) >= KNAMELEN) error(ENAMETOOLONG, ERROR_FIXME); if (strncmp(p->pipedir[1 + !d1].name, d->name, KNAMELEN) == 0) error(EEXIST, ERROR_FIXME); strncpy(p->pipedir[1 + d1].name, d->name, KNAMELEN); } if (d->mode != ~0UL) p->pipedir[d1 + 1].perm = d->mode & 0777; poperror(); kfree(d); return n; }
/* must call with c qlocked */ static void identify(Ctlr *c, SDunit *u) { int n; uvlong s, osectors; uchar buf[sizeof(Dir) + 100]; Dir dir; if(waserror()){ iprint("sdloop: identify: %s\n", up->errstr); nexterror(); } osectors = c->sectors; n = devtab[c->c->type]->stat(c->c, buf, sizeof buf); if(convM2D(buf, n, &dir, nil) == 0) error("internal error: stat error in seek"); s = dir.length / c->sectsize; poperror(); memset(u->inquiry, 0, sizeof u->inquiry); u->inquiry[2] = 2; u->inquiry[3] = 2; u->inquiry[4] = sizeof u->inquiry - 4; memmove(u->inquiry+8, c->path, 40); if(osectors == 0 || osectors != s){ c->sectors = s; c->drivechange = 1; c->vers++; } }
long sys_stat(uint32 *arg) { Chan *c; uint l; uchar buf[128]; /* old DIRLEN plus a little should be plenty */ char strs[128], *name, *elem; Dir d; char old[] = "old stat system call - recompile"; uchar *p; p = uvalidaddr(arg[1], 116, 1); name = uvalidaddr(arg[0], 1, 0); c = namec(name, Aaccess, 0, 0); if(waserror()){ cclose(c); nexterror(); } l = devtab[c->type]->stat(c, buf, sizeof buf); /* buf contains a new stat buf; convert to old. yuck. */ if(l <= BIT16SZ) /* buffer too small; time to face reality */ error(old); elem = pathlast(c->path); if(elem) l = dirsetname(elem, strlen(elem), buf, l, sizeof buf); l = convM2D(buf, l, &d, strs); if(l == 0) error(old); packoldstat(p, &d); poperror(); cclose(c); return 0; }
Dir* dirfstat(int fd) { Dir *d; uint8_t *buf; int n, nd, i; nd = DIRSIZE; for(i=0; i<2; i++){ /* should work by the second try */ d = malloc(sizeof(Dir) + BIT16SZ + nd); if(d == nil) return nil; buf = (uint8_t*)&d[1]; n = fstat(fd, buf, BIT16SZ+nd); if(n < BIT16SZ){ free(d); return nil; } nd = GBIT16(buf); /* upper bound on size of Dir + strings */ if(nd <= n){ convM2D(buf, n, d, (char*)&d[1]); return d; } /* else sizeof(Dir)+BIT16SZ+nd is plenty */ free(d); } return nil; }
/* * Cannot error. * Check that unit is online. * If media changed, return 2. * If ready, return 1. * If not ready, return 0. */ static int looponline(SDunit *unit) { uchar buf[sizeof(Dir)+100]; Chan *c; SDev *sdev; Ctlr *ctlr; Dir dir; long n; if(waserror()) return 0; sdev = unit->dev; ctlr = sdev->ctlr; c = ctlr->c; n = devtab[c->type]->stat(c, buf, sizeof buf); if(convM2D(buf, n, &dir, nil) == 0) error("internal error: stat error in looponline"); if(ctlr->qidpath != dir.qid.path){ unit->sectors = dir.length/512; unit->secsize = 512; ctlr->qidpath = dir.qid.path; poperror(); return 2; } poperror(); return 1; }
long sys_fstat(ulong *arg) { Chan *c; char *name; uint l; uchar buf[128]; /* old DIRLEN plus a little should be plenty */ char strs[128]; Dir d; char old[] = "old fstat system call - recompile"; validaddr(arg[1], 116, 1); c = fdtochan(arg[0], -1, 0, 1); if(waserror()){ cclose(c); nexterror(); } l = devtab[c->type]->stat(c, buf, sizeof buf); /* buf contains a new stat buf; convert to old. yuck. */ if(l <= BIT16SZ) /* buffer too small; time to face reality */ error(old); name = pathlast(c->path); if(name) l = dirsetname(name, strlen(name), buf, l, sizeof buf); l = convM2D(buf, l, &d, strs); if(l == 0) error(old); packoldstat((uchar*)arg[1], &d); poperror(); cclose(c); return 0; }
__private_extern__ int stat_9p(mount_9p *nmp, fid_9p fid, dir_9p **dpp) { Fcall tx, rx; Dir *dp; void *p; int e, n; TRACE(); p = NULL; dp = NULL; tx.type = Tstat; tx.fid = fid; if ((e=rpc_9p(nmp, &tx, &rx, &p))) return e; n = GBIT16((uint8_t*)p); dp = malloc_9p(sizeof(Dir) + BIT16SZ + n); if (dp == NULL) { e = ENOMEM; goto error; } if(convM2D(rx.stat, rx.nstat, dp, (char*)&dp[1], ISSET(nmp->flags, F_DOTU)) != rx.nstat) { DEBUG("convM2D"); e = EBADRPC; goto error; } error: free_9p(p); *dpp = dp; return e; }
static int rootwstat(struct chan *c, uint8_t *m_buf, int m_buf_sz) { struct dirtab *file = &roottab[c->qid.path]; struct dir *dir; int m_sz; /* TODO: some security check, Eperm on error */ /* common trick in wstats. we want the dir and any strings in the M. the * strings are smaller than entire M (strings plus other M). the strings * will be placed right after the dir (dir[1]) */ dir = kzmalloc(sizeof(struct dir) + m_buf_sz, KMALLOC_WAIT); m_sz = convM2D(m_buf, m_buf_sz, &dir[0], (char*)&dir[1]); if (!m_sz) { kfree(dir); error(ENODATA, ERROR_FIXME); } /* TODO: handle more things than just the mode */ if (!emptystr(dir->name)) printk("[%s] attempted rename of %s to %s\n", __FUNCTION__, file->name, dir->name); /* strncpy for this btw */ if (dir->mode != ~0UL) file->perm = dir->mode | (file->qid.type == QTDIR ? DMDIR : 0); kfree(dir); return m_sz; }
static long segmentwstat(Chan *c, uchar *dp, long n) { Globalseg *g; Dir *d; if(c->qid.type == QTDIR) error(Eperm); g = getgseg(c); if(waserror()){ putgseg(g); nexterror(); } if(strcmp(g->uid, up->user)!=0 && !iseve()) error(Eperm); d = smalloc(sizeof(Dir)+n); if(waserror()){ free(d); nexterror(); } n = convM2D(dp, n, &d[0], (char*)&d[1]); if(!emptystr(d->uid) && strcmp(d->uid, g->uid) != 0) kstrdup(&g->uid, d->uid); if(d->mode != ~0UL) g->perm = d->mode & 0777; poperror(); free(d); poperror(); putgseg(g); return n; }
int netifwstat(struct ether *nif, struct chan *c, uint8_t * db, int n) { struct dir *dir; struct netfile *f; int m; f = nif->f[NETID(c->qid.path)]; if (f == 0) { set_errno(ENOENT); error(Enonexist); } if (netown(f, current->user, OWRITE) < 0) error(Eperm); dir = kzmalloc(sizeof(struct dir) + n, 0); m = convM2D(db, n, &dir[0], (char *)&dir[1]); if (m == 0) { kfree(dir); error(Eshortstat); } if (!emptystr(dir[0].uid)) strncpy(f->owner, dir[0].uid, KNAMELEN); if (dir[0].mode != ~0UL) f->mode = dir[0].mode; kfree(dir); return m; }
static void rread(Fcall* f) { ulong n, rn, nn, delta; Dir d; Fid* fp; if (!isfdir(f, &fp)) return; if (f->count == 0) goto done; cleannames(); for (n = nn = 0; n < f->count; n += rn){ rn = convM2D((uchar*)f->data + n, f->count - n, &d, statbuf); if (rn <= BIT16SZ) break; d.name = importname(d.name); //dprint("⇒ %D\n", &d); nn += convD2M(&d, (uchar*)dirbuf + nn, sizeof(dirbuf) - nn); } delta = nn - n; setaux(fp, getaux(fp) + delta); f->count = nn; f->data = dirbuf; done: closefid(fp); }
static int pipewstat(Chan *c, uchar *dp, int n) { Dir *d; Pipe *p; int d1; if (c->qid.type&QTDIR) error(Eperm); p = c->aux; if(strcmp(up->env->user, p->user) != 0) error(Eperm); d = smalloc(sizeof(*d)+n); if(waserror()){ free(d); nexterror(); } n = convM2D(dp, n, d, (char*)&d[1]); if(n == 0) error(Eshortstat); d1 = NETTYPE(c->qid.path) == Qdata1; if(!emptystr(d->name)){ validwstatname(d->name); if(strlen(d->name) >= KNAMELEN) error(Efilename); if(strcmp(p->pipedir[1+!d1].name, d->name) == 0) error(Eexist); kstrcpy(p->pipedir[1+d1].name, d->name, KNAMELEN); } if(d->mode != ~0U) p->pipedir[d1 + 1].perm = d->mode & 0777; poperror(); free(d); return n; }
static int pipewstat(Chan* c, uchar* db, int n) { int m; Dir *dir; Pipe *p; p = c->aux; if(strcmp(up->user, eve) != 0) error(Eperm); if(NETTYPE(c->qid.path) == Qdir) error(Eisdir); dir = smalloc(sizeof(Dir)+n); if(waserror()){ free(dir); nexterror(); } m = convM2D(db, n, &dir[0], (char*)&dir[1]); if(m == 0) error(Eshortstat); if(!emptystr(dir[0].uid)) error("can't change owner"); if(dir[0].mode != ~0UL) p->perm = dir[0].mode; poperror(); free(dir); return m; }
static int cmdwstat(Chan *c, uchar *dp, int n) { Dir *d; Conv *cv; switch(TYPE(c->qid)){ default: error(Eperm); case Qctl: case Qdata: case Qstderr: d = malloc(sizeof(*d)+n); if(d == nil) error(Enomem); if(waserror()){ free(d); nexterror(); } n = convM2D(dp, n, d, (char*)&d[1]); if(n == 0) error(Eshortstat); cv = cmd.conv[CONV(c->qid)]; if(!iseve() && strcmp(up->env->user, cv->owner) != 0) error(Eperm); if(!emptystr(d->uid)) kstrdup(&cv->owner, d->uid); if(d->mode != ~0UL) cv->perm = d->mode & 0777; poperror(); free(d); break; } return n; }
static vlong _sysseek(int fd, vlong off, int whence) { Chan *c; uchar buf[sizeof(Dir)+100]; Dir dir; int n; c = fdtochan(fd, -1, 1, 1); if(waserror()){ cclose(c); nexterror(); } if(devtab[c->type]->dc == '|') error(Eisstream); switch(whence){ case 0: if((c->qid.type & QTDIR) && off != 0) error(Eisdir); if(off < 0) error(Enegoff); c->offset = off; break; case 1: if(c->qid.type & QTDIR) error(Eisdir); lock(&c->ref.lk); /* lock for read/write update */ off = off + c->offset; if(off < 0) error(Enegoff); c->offset = off; unlock(&c->ref.lk); break; case 2: if(c->qid.type & QTDIR) error(Eisdir); n = devtab[c->type]->stat(c, buf, sizeof buf); if(convM2D(buf, n, &dir, nil) == 0) error("internal error: stat error in seek"); off = dir.length + off; if(off < 0) error(Enegoff); c->offset = off; break; default: error(Ebadarg); } c->uri = 0; c->dri = 0; cclose(c); poperror(); return off; }
void settime(int islocal, int afd, char *rp) { int n, f; Dir dir[2]; char timebuf[64]; static int timeset; if(timeset) return; print("time..."); if(islocal){ /* * set the time from the real time clock */ f = open("#r/rtc", ORDWR); if(f >= 0){ if((n = read(f, timebuf, sizeof(timebuf)-1)) > 0){ timebuf[n] = '\0'; timeset = 1; } close(f); }else do{ strcpy(timebuf, "yymmddhhmm[ss]"); outin("\ndate/time ", timebuf, sizeof(timebuf)); }while((timeset=lusertime(timebuf)) <= 0); } if(timeset == 0){ /* * set the time from the access time of the root */ f = open(timeserver, ORDWR); if(f < 0) return; if(mount(f, afd, "/tmp", MREPL, rp) < 0){ warning("settime mount"); close(f); return; } close(f); if(stat("/tmp", statbuf, sizeof statbuf) < 0) fatal("stat"); convM2D(statbuf, sizeof statbuf, &dir[0], (char*)&dir[1]); sprint(timebuf, "%ld", dir[0].atime); unmount(0, "/tmp"); } f = open("#c/time", OWRITE); if(write(f, timebuf, strlen(timebuf)) < 0) warning("can't set #c/time"); close(f); print("\n"); }
static int64_t sseek(int fd, int64_t offset, int whence) { Proc *up = externup(); Chan *c; uint8_t buf[sizeof(Dir)+100]; Dir dir; int n; c = fdtochan(fd, -1, 1, 1); if(waserror()){ cclose(c); nexterror(); } if(c->dev->dc == '|') error(Eisstream); switch(whence){ case 0: if((c->qid.type & QTDIR) && offset != 0LL) error(Eisdir); c->offset = offset; break; case 1: if(c->qid.type & QTDIR) error(Eisdir); lock(&c->r.l); /* lock for read/write update */ offset += c->offset; c->offset = offset; unlock(&c->r.l); break; case 2: if(c->qid.type & QTDIR) error(Eisdir); n = c->dev->stat(c, buf, sizeof buf); if(convM2D(buf, n, &dir, nil) == 0) error("internal error: stat error in seek"); offset += dir.length; c->offset = offset; break; default: error(Ebadarg); } c->uri = 0; c->dri = 0; cclose(c); poperror(); return offset; }
static int dirpackage(uint8_t *buf, int ts, Dir **d, uint32_t *nd, int dotu) { char *s; int ss, i, n, nn; uint m; *d = nil; *nd = 0; if(ts <= 0) return 0; /* * first find number of all stats, check they look like stats, & size all associated strings */ ss = 0; n = 0; for(i = 0; i < ts; i += m){ m = BIT16SZ + GBIT16(&buf[i]); if(statcheck(&buf[i], m, dotu) < 0) break; ss += m; n++; } if(i != ts) { DEBUG("statcheck"); return EBADRPC; } *d = malloc_9p(n * sizeof(Dir) + ss); if (*d == NULL) return ENOMEM; /* * then convert all buffers */ s = (char*)*d + n * sizeof(Dir); nn = 0; for(i = 0; i < ts; i += m){ m = BIT16SZ + GBIT16(&buf[i]); if(nn >= n || convM2D(&buf[i], m, *d + nn, s, dotu) != m){ free_9p(*d); *d = nil; DEBUG("convM2D"); return EBADRPC; } nn++; s += m; } *nd = nn; return 0; }
static void rstat(Fcall* f) { Dir d; cleannames(); convM2D(f->stat, f->nstat, &d, statbuf); d.name = importname(d.name); f->nstat = convD2M(&d, (uchar*)dirbuf, sizeof(dirbuf)); f->stat = (uchar*)dirbuf; if (statcheck(f->stat, f->nstat) < 0) dprint("stat fails\n"); }
static void twstat(Fcall* f) { Dir d; cleannames(); if (convM2D(f->stat, f->nstat, &d, statbuf) <= BIT16SZ) return; d.name = exportname(d.name); f->nstat = convD2M(&d, (uchar*)dirbuf, sizeof(dirbuf)); f->stat = (uchar*)dirbuf; if (statcheck(f->stat, f->nstat) < 0) dprint("stat fails\n"); }
static long dirpackage(uchar *buf, long ts, Dir **d) { char *s; long ss, i, n, nn, m; *d = nil; if(ts <= 0) return 0; /* * first find number of all stats, check they look like stats, & size all associated strings */ ss = 0; n = 0; for(i = 0; i < ts; i += m){ m = BIT16SZ + GBIT16(&buf[i]); if(statcheck(&buf[i], m) < 0) break; ss += m; n++; } if(i != ts) return -1; *d = malloc(n * sizeof(Dir) + ss); if(*d == nil) return -1; /* * then convert all buffers */ s = (char*)*d + n * sizeof(Dir); nn = 0; for(i = 0; i < ts; i += m){ m = BIT16SZ + GBIT16((uchar*)&buf[i]); if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){ free(*d); *d = nil; return -1; } nn++; s += m; } return nn; }
int eiawstat(Chan *c, uchar *dp, int n) { Dir d; int i; if(strcmp(up->env->user, eve) != 0) error(Eperm); if(c->qid.type & QTDIR) error(Eperm); n = convM2D(dp, n, &d, nil); i = Nqid*NETID(c->qid.path)+NETTYPE(c->qid.path)-Ndataqid; eiadir[i+1].perm = d.mode&0666; return n; }