summaryrefslogtreecommitdiff
path: root/sys/src/cmd/dossrv/xfile.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/dossrv/xfile.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/dossrv/xfile.c')
-rwxr-xr-xsys/src/cmd/dossrv/xfile.c255
1 files changed, 255 insertions, 0 deletions
diff --git a/sys/src/cmd/dossrv/xfile.c b/sys/src/cmd/dossrv/xfile.c
new file mode 100755
index 000000000..6dbfb40d4
--- /dev/null
+++ b/sys/src/cmd/dossrv/xfile.c
@@ -0,0 +1,255 @@
+#include <u.h>
+#include <libc.h>
+#include "iotrack.h"
+#include "dat.h"
+#include "fns.h"
+
+#define FIDMOD 127 /* prime */
+
+static Xfs *xhead;
+static Xfile *xfiles[FIDMOD], *freelist;
+static MLock xlock, xlocks[FIDMOD], freelock;
+
+static int
+okmode(int omode, int fmode)
+{
+ if(omode == OREAD)
+ return fmode & 4;
+ /* else ORDWR */
+ return (fmode & 6) == 6;
+}
+
+Xfs *
+getxfs(char *user, char *name)
+{
+ Xfs *xf, *fxf;
+ Dir *dir;
+ Qid dqid;
+ char *p, *q;
+ long offset;
+ int fd, omode;
+
+ USED(user);
+ if(name==nil || name[0]==0)
+ name = deffile;
+ if(name == nil){
+ errno = Enofilsys;
+ return 0;
+ }
+
+ /*
+ * If the name passed is of the form 'name:offset' then
+ * offset is used to prime xf->offset. This allows accessing
+ * a FAT-based filesystem anywhere within a partition.
+ * Typical use would be to mount a filesystem in the presence
+ * of a boot manager programme at the beginning of the disc.
+ */
+ offset = 0;
+ if(p = strrchr(name, ':')){
+ *p++ = 0;
+ offset = strtol(p, &q, 0);
+ chat("name %s, offset %ld\n", p, offset);
+ if(offset < 0 || p == q){
+ errno = Enofilsys;
+ return 0;
+ }
+ offset *= Sectorsize;
+ }
+
+ if(readonly)
+ omode = OREAD;
+ else
+ omode = ORDWR;
+ fd = open(name, omode);
+
+ if(fd < 0 && omode==ORDWR){
+ omode = OREAD;
+ fd = open(name, omode);
+ }
+
+ if(fd < 0){
+ chat("can't open %s: %r\n", name);
+ errno = Eerrstr;
+ return 0;
+ }
+ dir = dirfstat(fd);
+ if(dir == nil){
+ errno = Eio;
+ close(fd);
+ return 0;
+ }
+
+ dqid = dir->qid;
+ free(dir);
+ mlock(&xlock);
+ for(fxf=0,xf=xhead; xf; xf=xf->next){
+ if(xf->ref == 0){
+ if(fxf == 0)
+ fxf = xf;
+ continue;
+ }
+ if(!eqqid(xf->qid, dqid))
+ continue;
+ if(strcmp(xf->name, name) != 0 || xf->dev < 0)
+ continue;
+ if(devcheck(xf) < 0) /* look for media change */
+ continue;
+ if(offset && xf->offset != offset)
+ continue;
+ chat("incref \"%s\", dev=%d...", xf->name, xf->dev);
+ ++xf->ref;
+ unmlock(&xlock);
+ close(fd);
+ return xf;
+ }
+ if(fxf == nil){
+ fxf = malloc(sizeof(Xfs));
+ if(fxf == nil){
+ unmlock(&xlock);
+ close(fd);
+ errno = Enomem;
+ return nil;
+ }
+ fxf->next = xhead;
+ xhead = fxf;
+ }
+ chat("alloc \"%s\", dev=%d...", name, fd);
+ fxf->name = strdup(name);
+ fxf->ref = 1;
+ fxf->qid = dqid;
+ fxf->dev = fd;
+ fxf->fmt = 0;
+ fxf->offset = offset;
+ fxf->ptr = nil;
+ fxf->isfat32 = 0;
+ fxf->omode = omode;
+ unmlock(&xlock);
+ return fxf;
+}
+
+void
+refxfs(Xfs *xf, int delta)
+{
+ mlock(&xlock);
+ xf->ref += delta;
+ if(xf->ref == 0){
+ chat("free \"%s\", dev=%d...", xf->name, xf->dev);
+ free(xf->name);
+ free(xf->ptr);
+ purgebuf(xf);
+ if(xf->dev >= 0){
+ close(xf->dev);
+ xf->dev = -1;
+ }
+ }
+ unmlock(&xlock);
+}
+
+Xfile *
+xfile(int fid, int flag)
+{
+ Xfile **hp, *f, *pf;
+ int k;
+
+ k = ((ulong)fid) % FIDMOD;
+ hp = &xfiles[k];
+ mlock(&xlocks[k]);
+ pf = nil;
+ for(f=*hp; f; f=f->next){
+ if(f->fid == fid)
+ break;
+ pf = f;
+ }
+ if(f && pf){
+ pf->next = f->next;
+ f->next = *hp;
+ *hp = f;
+ }
+ switch(flag){
+ default:
+ panic("xfile");
+ case Asis:
+ unmlock(&xlocks[k]);
+ return (f && f->xf && f->xf->dev < 0) ? nil : f;
+ case Clean:
+ break;
+ case Clunk:
+ if(f){
+ *hp = f->next;
+ unmlock(&xlocks[k]);
+ clean(f);
+ mlock(&freelock);
+ f->next = freelist;
+ freelist = f;
+ unmlock(&freelock);
+ } else
+ unmlock(&xlocks[k]);
+ return nil;
+ }
+ unmlock(&xlocks[k]);
+ if(f)
+ return clean(f);
+ mlock(&freelock);
+ if(f = freelist){ /* assign = */
+ freelist = f->next;
+ unmlock(&freelock);
+ } else {
+ unmlock(&freelock);
+ f = malloc(sizeof(Xfile));
+ if(f == nil){
+ errno = Enomem;
+ return nil;
+ }
+ }
+ mlock(&xlocks[k]);
+ f->next = *hp;
+ *hp = f;
+ unmlock(&xlocks[k]);
+ f->fid = fid;
+ f->flags = 0;
+ f->qid = (Qid){0,0,0};
+ f->xf = nil;
+ f->ptr = nil;
+ return f;
+}
+
+Xfile *
+clean(Xfile *f)
+{
+ if(f->ptr){
+ free(f->ptr);
+ f->ptr = nil;
+ }
+ if(f->xf){
+ refxfs(f->xf, -1);
+ f->xf = nil;
+ }
+ f->flags = 0;
+ f->qid = (Qid){0,0,0};
+ return f;
+}
+
+/*
+ * the file at <addr, offset> has moved
+ * relocate the dos entries of all fids in the same file
+ */
+void
+dosptrreloc(Xfile *f, Dosptr *dp, ulong addr, ulong offset)
+{
+ int i;
+ Xfile *p;
+ Dosptr *xdp;
+
+ for(i=0; i < FIDMOD; i++){
+ for(p = xfiles[i]; p != nil; p = p->next){
+ xdp = p->ptr;
+ if(p != f && p->xf == f->xf
+ && xdp != nil && xdp->addr == addr && xdp->offset == offset){
+ memmove(xdp, dp, sizeof(Dosptr));
+ xdp->p = nil;
+ xdp->d = nil;
+ p->qid.path = QIDPATH(xdp);
+ }
+ }
+ }
+}