File system stuff.

This commit is contained in:
rsc 2003-12-06 18:08:52 +00:00
parent e97ceade5e
commit d3df308747
29 changed files with 3316 additions and 0 deletions

27
src/libfs/COPYRIGHT Normal file
View file

@ -0,0 +1,27 @@
This software was developed as part of a project at MIT:
/sys/src/libfs/* except dirread.c
/sys/include/fs.h
Copyright (c) 2003 Russ Cox,
Massachusetts Institute of Technology
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

26
src/libfs/close.c Normal file
View file

@ -0,0 +1,26 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#include "fsimpl.h"
static void
fidclunk(Fid *fid)
{
Fcall tx, rx;
tx.type = Tclunk;
tx.fid = fid->fid;
fsrpc(fid->fs, &tx, &rx, 0);
_fsputfid(fid);
}
void
fsclose(Fid *fid)
{
/* maybe someday there will be a ref count */
fidclunk(fid);
}

25
src/libfs/create.c Normal file
View file

@ -0,0 +1,25 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#include "fsimpl.h"
Fid*
fscreate(Fsys *fs, char *name, int mode, ulong perm)
{
Fid *fid;
Fcall tx, rx;
if((fid = fswalk(fs->root, name)) == nil)
return nil;
tx.type = Tcreate;
tx.fid = fid->fid;
tx.mode = mode;
tx.perm = perm;
if(fsrpc(fs, &tx, &rx, 0) < 0){
fsclose(fid);
return nil;
}
fid->mode = mode;
return fid;
}

100
src/libfs/dirread.c Normal file
View file

@ -0,0 +1,100 @@
/* Mostly copied from Plan 9's libc. */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
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;
}
long
fsdirread(Fid *fid, Dir **d)
{
uchar *buf;
long ts;
buf = malloc(DIRMAX);
if(buf == nil)
return -1;
ts = fsread(fid, buf, DIRMAX);
if(ts >= 0)
ts = dirpackage(buf, ts, d);
free(buf);
return ts;
}
long
fsdirreadall(Fid *fid, Dir **d)
{
uchar *buf, *nbuf;
long n, ts;
buf = nil;
ts = 0;
for(;;){
nbuf = realloc(buf, ts+DIRMAX);
if(nbuf == nil){
free(buf);
return -1;
}
buf = nbuf;
n = fsread(fid, buf+ts, DIRMAX);
if(n <= 0)
break;
ts += n;
}
if(ts >= 0)
ts = dirpackage(buf, ts, d);
free(buf);
if(ts == 0 && n < 0)
return -1;
return ts;
}

276
src/libfs/fs.c Normal file
View file

@ -0,0 +1,276 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#include "fsimpl.h"
static int _fssend(Mux*, void*);
static void *_fsrecv(Mux*);
static int _fsgettag(Mux*, void*);
static int _fssettag(Mux*, void*, uint);
enum
{
Fidchunk = 32
};
Fsys*
fsinit(int fd)
{
Fsys *fs;
fs = mallocz(sizeof(Fsys), 1);
if(fs == nil)
return nil;
fs->fd = fd;
fs->ref = 1;
fs->mux.aux = fs;
fs->mux.mintag = 0;
fs->mux.maxtag = 256;
fs->mux.send = _fssend;
fs->mux.recv = _fsrecv;
fs->mux.gettag = _fsgettag;
fs->mux.settag = _fssettag;
muxinit(&fs->mux);
return fs;
}
Fid*
fsroot(Fsys *fs)
{
/* N.B. no incref */
return fs->root;
}
Fsys*
fsmount(int fd)
{
int n;
char *user;
Fsys *fs;
fs = fsinit(fd);
if(fs == nil)
return nil;
strcpy(fs->version, "9P2000");
if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){
Error:
fsunmount(fs);
return nil;
}
fs->msize = n;
user = getuser();
if((fs->root = fsattach(fs, nil, getuser(), "")) == nil)
goto Error;
return fs;
}
void
fsunmount(Fsys *fs)
{
_fsdecref(fs);
}
void
_fsdecref(Fsys *fs)
{
Fid *f, *next;
qlock(&fs->lk);
if(--fs->ref == 0){
close(fs->fd);
for(f=fs->freefid; f; f=next){
next = f->next;
if(f->fid%Fidchunk == 0)
free(f);
}
free(fs);
}
qunlock(&fs->lk);
}
int
fsversion(Fsys *fs, int msize, char *version, int nversion)
{
void *freep;
Fcall tx, rx;
tx.type = Tversion;
tx.version = version;
tx.msize = msize;
if(fsrpc(fs, &tx, &rx, &freep) < 0)
return -1;
strecpy(version, version+nversion, rx.version);
free(freep);
return rx.msize;
}
Fid*
fsattach(Fsys *fs, Fid *afid, char *user, char *aname)
{
Fcall tx, rx;
Fid *fid;
if((fid = _fsgetfid(fs)) == nil)
return nil;
tx.type = Tattach;
tx.afid = afid ? afid->fid : NOFID;
tx.fid = fid->fid;
tx.uname = user;
tx.aname = aname;
if(fsrpc(fs, &tx, &rx, 0) < 0){
_fsputfid(fid);
return nil;
}
fid->qid = rx.qid;
return fid;
}
int
fsrpc(Fsys *fs, Fcall *tx, Fcall *rx, void **freep)
{
int n, nn;
void *tpkt, *rpkt;
n = sizeS2M(tx);
tpkt = malloc(n);
if(tpkt == nil)
return -1;
nn = convS2M(tx, tpkt, n);
if(nn != n){
free(tpkt);
werrstr("libfs: sizeS2M convS2M mismatch");
fprint(2, "%r\n");
return -1;
}
rpkt = muxrpc(&fs->mux, tpkt);
free(tpkt);
if(rpkt == nil)
return -1;
n = GBIT32((uchar*)rpkt);
nn = convM2S(rpkt, n, rx);
if(nn != n){
free(rpkt);
werrstr("libfs: convM2S packet size mismatch");
fprint(2, "%r\n");
return -1;
}
if(rx->type == Rerror){
werrstr("%s", rx->ename);
free(rpkt);
return -1;
}
if(rx->type != tx->type+1){
werrstr("packet type mismatch -- tx %d rx %d",
tx->type, rx->type);
free(rpkt);
return -1;
}
if(freep)
*freep = rpkt;
else
free(rpkt);
return 0;
}
Fid*
_fsgetfid(Fsys *fs)
{
int i;
Fid *f;
qlock(&fs->lk);
if(fs->freefid == nil){
f = malloc(sizeof(Fid)*Fidchunk);
if(f == nil){
qunlock(&fs->lk);
return nil;
}
for(i=0; i<Fidchunk; i++){
f[i].fid = fs->nextfid++;
f[i].next = &f[i+1];
f[i].fs = fs;
fs->ref++;
}
f[i-1].next = nil;
fs->freefid = f;
}
f = fs->freefid;
fs->freefid = f->next;
qunlock(&fs->lk);
return f;
}
void
_fsputfid(Fid *f)
{
Fsys *fs;
fs = f->fs;
qlock(&fs->lk);
f->next = fs->freefid;
fs->freefid = f;
qunlock(&fs->lk);
_fsdecref(fs);
}
static int
_fsgettag(Mux *mux, void *pkt)
{
return GBIT16((uchar*)pkt+5);
}
static int
_fssettag(Mux *mux, void *pkt, uint tag)
{
PBIT16((uchar*)pkt+5, tag);
return 0;
}
static int
_fssend(Mux *mux, void *pkt)
{
Fsys *fs;
fs = mux->aux;
return write(fs->fd, pkt, GBIT32((uchar*)pkt));
}
static void*
_fsrecv(Mux *mux)
{
uchar *pkt;
uchar buf[4];
int n;
Fsys *fs;
fs = mux->aux;
n = readn(fs->fd, buf, 4);
if(n != 4)
return nil;
n = GBIT32(buf);
pkt = malloc(n+4);
if(pkt == nil){
fprint(2, "libfs out of memory reading 9p packet; here comes trouble\n");
return nil;
}
PBIT32(buf, n);
if(readn(fs->fd, pkt+4, n-4) != n-4){
free(pkt);
return nil;
}
#if 0
if(pkt[4] == Ropenfd){
/* do unix socket crap */
sysfatal("no socket crap implemented");
}
#endif
return pkt;
}

41
src/libfs/fsimpl.h Normal file
View file

@ -0,0 +1,41 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
typedef struct Queue Queue;
Queue *_fsqalloc(void);
int _fsqsend(Queue*, void*);
void *_fsqrecv(Queue*);
void _fsqhangup(Queue*);
void *_fsnbqrecv(Queue*);
#include <mux.h>
struct Fsys
{
char version[20];
int msize;
QLock lk;
int fd;
int ref;
Mux mux;
Fid *root;
Queue *txq;
Queue *rxq;
Fid *freefid;
int nextfid;
};
struct Fid
{
int fid;
int mode;
Fid *next;
QLock lk;
Fsys *fs;
Qid qid;
vlong offset;
};
void _fsdecref(Fsys*);
void _fsputfid(Fid*);
Fid *_fsgetfid(Fsys*);

22
src/libfs/mkfile Normal file
View file

@ -0,0 +1,22 @@
PLAN9=../..
<$PLAN9/src/mkhdr
LIB=libfs.a
OFILES=\
close.$O\
create.$O\
dirread.$O\
fs.$O\
open.$O\
read.$O\
stat.$O\
walk.$O\
write.$O\
wstat.$O\
HFILES=\
$PLAN9/include/fs.h\
$PLAN9/include/mux.h\
<$PLAN9/src/mksyslib

24
src/libfs/open.c Normal file
View file

@ -0,0 +1,24 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#include "fsimpl.h"
Fid*
fsopen(Fsys *fs, char *name, int mode)
{
Fid *fid;
Fcall tx, rx;
if((fid = fswalk(fs->root, name)) == nil)
return nil;
tx.type = Topen;
tx.fid = fid->fid;
tx.mode = mode;
if(fsrpc(fs, &tx, &rx, 0) < 0){
fsclose(fid);
return nil;
}
fid->mode = mode;
return fid;
}

48
src/libfs/read.c Normal file
View file

@ -0,0 +1,48 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#include "fsimpl.h"
long
fspread(Fid *fid, void *buf, long n, vlong offset)
{
Fcall tx, rx;
void *freep;
tx.type = Tread;
if(offset == -1){
qlock(&fid->lk);
tx.offset = fid->offset;
qunlock(&fid->lk);
}else
tx.offset = offset;
tx.count = n;
fsrpc(fid->fs, &tx, &rx, &freep);
if(rx.type == Rerror){
werrstr("%s", rx.ename);
free(freep);
return -1;
}
if(rx.count){
memmove(buf, rx.data, rx.count);
if(offset == -1){
qlock(&fid->lk);
tx.offset += n;
qunlock(&fid->lk);
}
}
free(freep);
return rx.count;
}
long
fsread(Fid *fid, void *buf, long n)
{
return fspread(fid, buf, n, -1);
}

54
src/libfs/stat.c Normal file
View file

@ -0,0 +1,54 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#include "fsimpl.h"
Dir*
fsdirstat(Fsys *fs, char *name)
{
Dir *d;
Fid *fid;
if((fid = fswalk(fs->root, name)) == nil)
return nil;
d = fsdirfstat(fid);
fsclose(fid);
return d;
}
Dir*
fsdirfstat(Fid *fid)
{
Dir *d;
Fsys *fs;
Fcall tx, rx;
void *freep;
int n;
fs = fid->fs;
tx.type = Tstat;
tx.fid = fid->fid;
if(fsrpc(fs, &tx, &rx, &freep) < 0)
return nil;
d = malloc(sizeof(Dir)+rx.nstat);
if(d == nil){
free(freep);
return nil;
}
n = convM2D(rx.stat, rx.nstat, d, (char*)&d[1]);
free(freep);
if(n != rx.nstat){
free(d);
werrstr("rx.nstat and convM2D disagree about dir length");
return nil;
}
return d;
}

73
src/libfs/walk.c Normal file
View file

@ -0,0 +1,73 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#include "fsimpl.h"
Fid*
fswalk(Fid *fid, char *oname)
{
char *freep, *name;
int i, nwalk;
char *p;
Fid *wfid;
Fcall tx, rx;
freep = nil;
name = oname;
if(name){
freep = malloc(strlen(name)+1);
if(freep == nil)
return nil;
strcpy(freep, name);
name = freep;
}
if((wfid = _fsgetfid(fid->fs)) == nil){
free(freep);
return nil;
}
nwalk = 0;
do{
/* collect names */
for(i=0; name && *name && i < MAXWELEM; ){
p = name;
name = strchr(name, '/');
if(name)
*name++ = 0;
if(*p == 0)
continue;
tx.wname[i++] = p;
}
/* do a walk */
tx.type = Twalk;
tx.fid = nwalk ? wfid->fid : fid->fid;
tx.newfid = wfid->fid;
tx.nwname = i;
if(fsrpc(fid->fs, &tx, &rx, 0) < 0){
Error:
free(freep);
if(nwalk)
fsclose(wfid);
else
_fsputfid(wfid);
return nil;
}
if(rx.nwqid != tx.nwname){
/* XXX lame error */
werrstr("file '%s' not found", oname);
goto Error;
}
if(rx.nwqid == 0)
wfid->qid = fid->qid;
else
wfid->qid = rx.wqid[rx.nwqid-1];
nwalk++;
}while(name && *name);
return wfid;
}

46
src/libfs/write.c Normal file
View file

@ -0,0 +1,46 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#include "fsimpl.h"
long
fspwrite(Fid *fd, void *buf, long n, vlong offset)
{
Fcall tx, rx;
void *freep;
tx.type = Tread;
if(offset == -1){
qlock(&fd->lk);
tx.offset = fd->offset;
fd->offset += n;
qunlock(&fd->lk);
}else
tx.offset = offset;
tx.count = n;
tx.data = buf;
fsrpc(fd->fs, &tx, &rx, &freep);
if(rx.type == Rerror){
if(offset == -1){
qlock(&fd->lk);
fd->offset -= n;
qunlock(&fd->lk);
}
werrstr("%s", rx.ename);
free(freep);
return -1;
}
free(freep);
return rx.count;
}
long
fswrite(Fid *fd, void *buf, long n)
{
return fspwrite(fd, buf, n, -1);
}

49
src/libfs/wstat.c Normal file
View file

@ -0,0 +1,49 @@
/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <fs.h>
#include "fsimpl.h"
int
fsdirwstat(Fsys *fs, char *name, Dir *d)
{
int n;
Fid *fid;
if((fid = fswalk(fs->root, name)) == nil)
return -1;
n = fsdirfwstat(fid, d);
fsclose(fid);
return n;
}
int
fsdirfwstat(Fid *fid, Dir *d)
{
char *a;
int n, nn;
Fcall tx, rx;
n = sizeD2M(d);
a = malloc(n);
if(a == nil)
return -1;
nn = convD2M(d, a, n);
if(n != nn){
werrstr("convD2M and sizeD2M disagree");
free(a);
return -1;
}
tx.type = Twstat;
tx.fid = fid->fid;
tx.stat = a;
tx.nstat = n;
n = fsrpc(fid->fs, &tx, &rx, 0);
free(a);
return n;
}