## diffname bitsy/devsac.c 2000/1015
## diff -e /dev/null /n/emeliedump/2000/1015/sys/src/9/bitsy/devsac.c
0a
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"
enum
{
OPERM = 0x3, /* mask of all permission types in open mode */
Nram = 512,
CacheSize = 20,
OffsetSize = 4, /* size in bytes of an offset */
};
typedef struct SacPath SacPath;
typedef struct Sac Sac;
typedef struct SacHeader SacHeader;
typedef struct SacDir SacDir;
typedef struct Cache Cache;
enum {
Magic = 0x5acf5,
};
struct SacDir
{
char name[NAMELEN];
char uid[NAMELEN];
char gid[NAMELEN];
uchar qid[4];
uchar mode[4];
uchar atime[4];
uchar mtime[4];
uchar length[8];
uchar blocks[8];
};
struct SacHeader
{
uchar magic[4];
uchar length[8];
uchar blocksize[4];
uchar md5[16];
};
struct Sac
{
SacDir;
SacPath *path;
};
struct SacPath
{
Ref;
SacPath *up;
long blocks;
int entry;
int nentry;
};
struct Cache
{
long block;
ulong age;
uchar *data;
};
enum
{
Pexec = 1,
Pwrite = 2,
Pread = 4,
Pother = 1,
Pgroup = 8,
Powner = 64,
};
static char *sacfs = "fs.sac";
static uchar *data;
static int blocksize;
static Sac root;
static Cache cache[CacheSize];
static ulong cacheage;
static void sacdir(Chan *, SacDir*, char*);
static ulong getl(void *p);
static Sac *saccpy(Sac *s);
static Sac *saclookup(Sac *s, char *name);
static int sacdirread(Chan *, char *p, long off, long cnt);
static void loadblock(void *buf, uchar *offset, int blocksize);
static void sacfree(Sac*);
static void
sacinit(void)
{
SacHeader *hdr;
uchar *p;
char *s;
int i;
print("sacinit\n");
s = getconf("flash");
if(s == nil) {
print("devsac: no flash file system\n");
return;
}
p = (uchar*)strtoul(s, 0, 0);
if(p == 0) {
print("devsac: bad address for flash file system\n");
return;
}
data = tarlookup(p, sacfs, &i);
if(data == 0) {
print("devsac: could not find file: %s\n", sacfs);
return;
}
hdr = (SacHeader*)data;
if(getl(hdr->magic) != Magic) {
print("devsac: bad magic\n");
return;
}
blocksize = getl(hdr->blocksize);
root.SacDir = *(SacDir*)(data + sizeof(SacHeader));
p = malloc(CacheSize*blocksize);
if(p == nil)
error("allocating cache");
for(i=0; i<CacheSize; i++) {
cache[i].data = p;
p += blocksize;
}
}
static Chan*
sacattach(char* spec)
{
Chan *c;
int dev;
dev = atoi(spec);
if(dev != 0)
error("bad specification");
// check if init found sac file system in memory
if(blocksize == 0)
error("devsac: bad magic");
c = devattach('C', spec);
c->qid = (Qid){getl(root.qid), 0};
c->dev = dev;
c->aux = saccpy(&root);
return c;
}
static Chan*
sacclone(Chan *c, Chan *nc)
{
nc = devclone(c, nc);
nc->aux = saccpy(c->aux);
return nc;
}
static int
sacwalk(Chan *c, char *name)
{
Sac *sac;
//print("walk %s\n", name);
isdir(c);
if(name[0]=='.' && name[1]==0)
return 1;
if(name[0]=='.' && name[1]=='.' && name[2]==0)
return 1;
sac = c->aux;
sac = saclookup(sac, name);
if(sac == nil) {
strncpy(up->error, Enonexist, NAMELEN);
return 0;
}
c->aux = sac;
c->qid = (Qid){getl(sac->qid), 0};
return 1;
}
static Chan*
sacopen(Chan *c, int omode)
{
ulong t, mode;
Sac *sac;
static int access[] = { 0400, 0200, 0600, 0100 };
sac = c->aux;
mode = getl(sac->mode);
if(strcmp(up->user, sac->uid) == 0)
mode = mode;
else if(strcmp(up->user, sac->gid) == 0)
mode = mode<<3;
else
mode = mode<<6;
t = access[omode&3];
if((t & mode) != t)
error(Eperm);
c->offset = 0;
c->mode = openmode(omode);
c->flag |= COPEN;
return c;
}
static long
sacread(Chan *c, void *a, long n, vlong voff)
{
Sac *sac;
char *buf, *buf2;
int nn, cnt, i, j;
uchar *blocks;
long length;
long off = voff;
buf = a;
cnt = n;
if(c->qid.path & CHDIR){
cnt = (cnt/DIRLEN)*DIRLEN;
if(off%DIRLEN)
error("i/o error");
return sacdirread(c, buf, off, cnt);
}
sac = c->aux;
length = getl(sac->length);
if(off >= length)
return 0;
if(cnt > length-off)
cnt = length-off;
if(cnt == 0)
return 0;
n = cnt;
blocks = data + getl(sac->blocks);
buf2 = malloc(blocksize);
while(cnt > 0) {
i = off/blocksize;
nn = blocksize;
if(nn > length-i*blocksize)
nn = length-i*blocksize;
loadblock(buf2, blocks+i*OffsetSize, nn);
j = off-i*blocksize;
nn -= j;
if(nn > cnt)
nn = cnt;
memmove(buf, buf2+j, nn);
cnt -= nn;
off += nn;
buf += nn;
}
free(buf2);
return n;
}
static long
sacwrite(Chan *, void *, long, vlong)
{
error(Eperm);
return 0;
}
static void
sacclose(Chan* c)
{
Sac *sac = c->aux;
c->aux = nil;
sacfree(sac);
}
static void
sacstat(Chan *c, char *db)
{
sacdir(c, c->aux, db);
}
static Sac*
saccpy(Sac *s)
{
Sac *ss;
ss = malloc(sizeof(Sac));
*ss = *s;
if(ss->path)
incref(ss->path);
return ss;
}
static SacPath *
sacpathalloc(SacPath *p, long blocks, int entry, int nentry)
{
SacPath *pp = malloc(sizeof(SacPath));
pp->ref = 1;
pp->blocks = blocks;
pp->entry = entry;
pp->nentry = nentry;
pp->up = p;
return pp;
}
static void
sacpathfree(SacPath *p)
{
if(p == nil)
return;
if(decref(p) > 0)
return;
sacpathfree(p->up);
free(p);
}
static void
sacfree(Sac *s)
{
sacpathfree(s->path);
free(s);
}
static void
sacdir(Chan *c, SacDir *s, char *buf)
{
Dir dir;
memmove(dir.name, s->name, NAMELEN);
dir.qid = (Qid){getl(s->qid), 0};
dir.mode = getl(s->mode);
dir.length = getl(s->length);
if(dir.mode &CHDIR)
dir.length *= DIRLEN;
memmove(dir.uid, s->uid, NAMELEN);
memmove(dir.gid, s->gid, NAMELEN);
dir.atime = getl(s->atime);
dir.mtime = getl(s->mtime);
dir.type = devtab[c->type]->dc;
dir.dev = c->dev;
convD2M(&dir, buf);
}
static void
loadblock(void *buf, uchar *offset, int blocksize)
{
long block, n;
ulong age;
int i, j;
block = getl(offset);
if(block < 0) {
block = -block;
cacheage++;
// age has wraped
if(cacheage == 0) {
for(i=0; i<CacheSize; i++)
cache[i].age = 0;
}
j = 0;
age = cache[0].age;
for(i=0; i<CacheSize; i++) {
if(cache[i].age < age) {
age = cache[i].age;
j = i;
}
if(cache[i].block != block)
continue;
memmove(buf, cache[i].data, blocksize);
cache[i].age = cacheage;
return;
}
n = getl(offset+OffsetSize);
if(n < 0)
n = -n;
n -= block;
if(unsac(buf, data+block, blocksize, n)<0)
panic("unsac failed!");
memmove(cache[j].data, buf, blocksize);
cache[j].age = cacheage;
cache[j].block = block;
} else {
memmove(buf, data+block, blocksize);
}
}
static Sac*
sacparent(Sac *s)
{
uchar *blocks;
SacDir *buf;
int per, i, n;
SacPath *p;
p = s->path;
if(p == nil || p->up == nil) {
sacpathfree(p);
*s = root;
return s;
}
p = p->up;
blocks = data + p->blocks;
per = blocksize/sizeof(SacDir);
i = p->entry/per;
n = per;
if(n > p->nentry-i*per)
n = p->nentry-i*per;
buf = malloc(per*sizeof(SacDir));
loadblock(buf, blocks + i*OffsetSize, n*sizeof(SacDir));
s->SacDir = buf[p->entry-i*per];
free(buf);
incref(p);
sacpathfree(s->path);
s->path = p;
return s;
}
static int
sacdirread(Chan *c, char *p, long off, long cnt)
{
uchar *blocks;
SacDir *buf;
int iblock, per, i, j, n, ndir;
Sac *s;
s = c->aux;
blocks = data + getl(s->blocks);
per = blocksize/sizeof(SacDir);
ndir = getl(s->length);
off /= DIRLEN;
cnt /= DIRLEN;
if(off >= ndir)
return 0;
if(cnt > ndir-off)
cnt = ndir-off;
iblock = -1;
buf = malloc(per*sizeof(SacDir));
for(i=off; i<off+cnt; i++) {
j = i/per;
if(j != iblock) {
n = per;
if(n > ndir-j*per)
n = ndir-j*per;
loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir));
iblock = j;
}
j *= per;
sacdir(c, buf+i-j, p);
p += DIRLEN;
}
free(buf);
return cnt*DIRLEN;
}
static Sac*
saclookup(Sac *s, char *name)
{
int ndir;
int i, j, k, n, per;
uchar *blocks;
SacDir *buf;
int iblock;
SacDir *sd;
if(strcmp(name, "..") == 0)
return sacparent(s);
blocks = data + getl(s->blocks);
per = blocksize/sizeof(SacDir);
ndir = getl(s->length);
buf = malloc(per*sizeof(SacDir));
iblock = -1;
// linear search
for(i=0; i<ndir; i++) {
j = i/per;
if(j != iblock) {
n = per;
if(n > ndir-j*per)
n = ndir-j*per;
loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir));
iblock = j;
}
j *= per;
sd = buf+i-j;
k = strcmp(name, sd->name);
if(k == 0) {
s->path = sacpathalloc(s->path, getl(s->blocks), i, ndir);
s->SacDir = *sd;
free(buf);
return s;
}
}
free(buf);
return 0;
}
static ulong
getl(void *p)
{
uchar *a = p;
return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
}
Dev sacdevtab = {
'C',
"sac",
devreset,
sacinit,
sacattach,
sacclone,
sacwalk,
sacstat,
sacopen,
devcreate,
sacclose,
sacread,
devbread,
sacwrite,
devbwrite,
devremove,
devwstat,
};
.
## diffname bitsy/devsac.c 2000/1016
## diff -e /n/emeliedump/2000/1015/sys/src/9/bitsy/devsac.c /n/emeliedump/2000/1016/sys/src/9/bitsy/devsac.c
123c
print("devsac: bad magic\n");
.
104,115c
p = (uchar*)Flash_tar+4;
.
101d
## diffname bitsy/devsac.c 2000/1208
## diff -e /n/emeliedump/2000/1016/sys/src/9/bitsy/devsac.c /n/emeliedump/2000/1208/sys/src/9/bitsy/devsac.c
164,165d
## diffname bitsy/devsac.c 2001/0529
## diff -e /n/emeliedump/2000/1208/sys/src/9/bitsy/devsac.c /n/emeliedump/2001/0529/sys/src/9/bitsy/devsac.c
140c
path = getl(root.qid);
if(path & CHDIR)
c->qid.type = QTDIR;
else
c->qid.type = QTFILE;
c->qid.path = path & ~CHDIR;
c->qid.vers = 0;
.
129a
int opath;
.
29,31c
char name[KNAMELEN];
char uid[KNAMELEN];
char gid[KNAMELEN];
.
## diffname bitsy/devsac.c 2001/0531
## diff -e /n/emeliedump/2001/0529/sys/src/9/bitsy/devsac.c /n/emeliedump/2001/0531/sys/src/9/bitsy/devsac.c
177,178c
if(nc == nil){
nc = devclone(c);
nc->type = 0; /* device doesn't know about this channel yet */
alloc = 1;
}
wq->clone = nc;
for(j=0; j<nname; j++){
isdir(nc);
if(name[0]=='.' && name[1]==0)
return 1;
sac = nc->aux;
sac = saclookup(sac, name);
if(sac == nil) {
strncpy(up->error, Enonexist, NAMELEN);
return 0;
}
nc->aux = sac;
pathtoqid(getl(sac->qid), &nc->qid);
}
.
168,175c
alloc = 0;
wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
if(waserror()){
if(alloc && wq->clone!=nil)
cclose(wq->clone);
free(wq);
return nil;
.
166c
if(nname > 0)
isdir(c);
.
164a
int i, j, alloc;
Walkqid *wq;
char *n;
Dir dir;
.
161,162c
static Walkqid*
sacwalk(Chan *c, Chan *nc, char **name, int nname)
.
142,147c
pathtoqid(path, &c->qid;
.
96a
pathtoqid(ulong path, Qid *q)
{
if(path & CHDIR)
q->type = QTDIR;
else
q->type = QTFILE;
q->path = path & ~(CHDIR|CHAPPEND|CHEXCL|CHMOUNT);
q->vers = 0;
}
static void
.
29,31c
char name[NAMELEN];
char uid[NAMELEN];
char gid[NAMELEN];
.
8a
/*
* definitions from the old 9P. we need these because sac files
* are encoded using the old definitions.
*/
#define NAMELEN 28
#define CHDIR 0x80000000 /* mode bit for directories */
#define CHAPPEND 0x40000000 /* mode bit for append only files */
#define CHEXCL 0x20000000 /* mode bit for exclusive use files */
#define CHMOUNT 0x10000000 /* mode bit for mounted channel */
#define CHREAD 0x4 /* mode bit for read permission */
#define CHWRITE 0x2 /* mode bit for write permission */
#define CHEXEC 0x1 /* mode bit for execute permission */
.
## diffname bitsy/devsac.c 2001/0601
## diff -e /n/emeliedump/2001/0531/sys/src/9/bitsy/devsac.c /n/emeliedump/2001/0601/sys/src/9/bitsy/devsac.c
554d
494c
return sofar;
.
489,491c
n = sacdir(c, buf+i, p, cnt - sofar);
if(n == 0)
break;
if(off > 0)
off -= n;
else {
p += n;
sofar += n;
}
.
487d
472,482c
buf = malloc(blocksize);
sofar = 0;
for(j = 0; j < ndir; j++) {
i = j%per;
if(i == 0) {
.
465c
int per, i, j, n, ndir;
long sofar;
.
461c
sacdirread(Chan *c, uchar *p, long off, long cnt)
.
459a
/* n**2 alg to read a directory */
.
381c
return convD2M(&dir, db, n);
.
373,376d
369,371c
dir.name = s->name;
dir.uid = s->uid;
dir.gid = s->gid;
dir.muid = s->uid;
pathtoqid(getl(s->qid), &dir.qid);
omodetomode(getl(s->mode), &dir.mode);
.
364,365c
static int
sacdir(Chan *c, SacDir *s, uchar *db, int n)
.
318c
n = sacdir(c, c->aux, db, n);
if(n == 0)
error(Ebadarg);
return n;
.
314,316c
static int
sacstat(Chan *c, uchar *db, int n)
.
263,268c
if(c->qid.type & QTDIR)
return sacdirread(c, a, off, cnt);
.
222c
poperror();
if(wq->nqid < nname){
if(alloc)
cclose(wq->clone);
wq->clone = nil;
}
return wq;
.
217c
break;
.
215a
if(j == 0)
error(Enonexist);
.
214c
sac = saclookup(sac, n);
.
210,212c
n = name[j];
if(strcmp(n, ".") == 0){
wq->qid[wq->nqid++] = nc->qid;
continue;
}
.
203d
188d
185c
int j, alloc;
.
173,180d
166,167c
pathtoqid(getl(root.qid), &c->qid);
.
155d
121a
omodetomode(ulong om, ulong *m)
{
ulong nm;
nm = om & ~(CHDIR|CHAPPEND|CHEXCL|CHMOUNT);
if(om & CHDIR)
nm |= DMDIR;
*m = nm;
}
static void
.
105,108c
static Sac *saclookup(Sac *s, char *name);
static int sacdirread(Chan *, uchar *p, long off, long cnt);
static void loadblock(void *buf, uchar *offset, int blocksize);
static void sacfree(Sac*);
.
102c
static int sacdir(Chan *, SacDir*, uchar*, int);
.
## diffname bitsy/devsac.c 2001/0605
## diff -e /n/emeliedump/2001/0601/sys/src/9/bitsy/devsac.c /n/emeliedump/2001/0605/sys/src/9/bitsy/devsac.c
538c
s->path = sacpathalloc(s->path, getl(s->blocks), i, ndir);
.
314a
.
223a
wq->qid[wq->nqid++] = nc->qid;
.
222d
202a
nc->aux = saccpy(c->aux);
.
## diffname bitsy/devsac.c 2001/0616
## diff -e /n/emeliedump/2001/0605/sys/src/9/bitsy/devsac.c /n/emeliedump/2001/0616/sys/src/9/bitsy/devsac.c
227a
// listprint(name, wq->nqid, j);
.
181a
static void listprint(char **name, int nname, int j)
{
int i;
print("%d ", j);
for(i = 0; i< nname; i++)
print("%s/", name[i]);
print("\n");
}
.
142,143c
p = (uchar*)Flash_tar;
data = tarlookup(p, sacfs, &i);
if(data == 0) {
print("devsac: could not find file: %s\n", sacfs);
return;
}
.
## diffname bitsy/devsac.c 2001/0617
## diff -e /n/emeliedump/2001/0616/sys/src/9/bitsy/devsac.c /n/emeliedump/2001/0617/sys/src/9/bitsy/devsac.c
234c
strncpy(up->error, Enonexist, ERRMAX);
.
## diffname bitsy/devsac.c 2001/0809
## diff -e /n/emeliedump/2001/0617/sys/src/9/bitsy/devsac.c /n/emeliedump/2001/0809/sys/src/9/bitsy/devsac.c
142c
p = (uchar*)Flash_tar+4;
.
139c
p = (uchar*)Flash_tar;
.
## diffname bitsy/devsac.c 2001/0924
## diff -e /n/emeliedump/2001/0809/sys/src/9/bitsy/devsac.c /n/emeliedump/2001/0924/sys/src/9/bitsy/devsac.c
234c
kstrcpy(up->errstr, Enonexist, ERRMAX);
.
## diffname bitsy/devsac.c 2002/0109
## diff -e /n/emeliedump/2001/0924/sys/src/9/bitsy/devsac.c /n/emeliedump/2002/0109/sys/src/9/bitsy/devsac.c
578a
devshutdown,
.
## diffname bitsy/devsac.c 2002/0413 # deleted
## diff -e /n/emeliedump/2002/0109/sys/src/9/bitsy/devsac.c /n/emeliedump/2002/0413/sys/src/9/bitsy/devsac.c
1,592d
|