9 #define BADBNO ((u64int)~0ULL)
14 static int checkfsblk(Fsblk*);
15 static int checkcgblk(Cgblk*);
16 static Block *ffsblockread(Fsys*, u64int);
17 static int ffssync(Fsys*);
18 static void ffsclose(Fsys*);
20 static u64int ffsxfileblock(Fsys *fs, Nfs3Handle *h, u64int offset);
21 static Nfs3Status ffsroot(Fsys*, Nfs3Handle*);
22 static Nfs3Status ffsgetattr(Fsys*, SunAuthUnix *au, Nfs3Handle*, Nfs3Attr*);
23 static Nfs3Status ffslookup(Fsys*, SunAuthUnix *au, Nfs3Handle*, char*, Nfs3Handle*);
24 static Nfs3Status ffsreadfile(Fsys*, SunAuthUnix *au, Nfs3Handle*, u32int, u64int, uchar**, u32int*, u1int*);
25 static Nfs3Status ffsreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link);
26 static Nfs3Status ffsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int, u64int, uchar**, u32int*, u1int*);
27 static Nfs3Status ffsaccess(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr);
30 fsysopenffs(Disk *disk)
35 fsys = emalloc(sizeof(Fsys));
36 fs = emalloc(sizeof(Ffs));
40 fsys->_readblock = ffsblockread;
41 fsys->_sync = ffssync;
42 fsys->_root = ffsroot;
43 fsys->_getattr = ffsgetattr;
44 fsys->_access = ffsaccess;
45 fsys->_lookup = ffslookup;
46 fsys->_readfile = ffsreadfile;
47 fsys->_readlink = ffsreadlink;
48 fsys->_readdir = ffsreaddir;
49 fsys->_close = ffsclose;
50 fsys->fileblock = ffsxfileblock;
63 ffscylgrp(Ffs *fs, u32int i, Block **pb)
71 b = diskread(fs->disk, fs->blocksize, (u64int)fs->cg[i].cgblkno*fs->blocksize);
75 if(checkcgblk(cg) < 0){
76 fprint(2, "checkcgblk %d %lud: %r\n", i, (ulong)fs->cg[i].cgblkno);
88 int off[] = { SBOFF, SBOFF2, SBOFFPIGGY };
103 for(i=0; i<nelem(off); i++){
104 if((b = diskread(disk, SBSIZE, off[i])) == nil)
106 fsblk = (Fsblk*)b->data;
107 // fprint(2, "offset of magic: %ld\n", offsetof(Fsblk, magic));
108 if((fs->ufs = checkfsblk(fsblk)) > 0)
116 fs->blocksize = fsblk->blocksize;
117 fs->nblock = (fsblk->nfrag+fsblk->fragsperblock-1) / fsblk->fragsperblock;
118 fs->fragsize = fsblk->fragsize;
119 fs->fragspergroup = fsblk->fragspergroup;
120 fs->fragsperblock = fsblk->fragsperblock;
121 fs->inosperblock = fsblk->inosperblock;
122 fs->inospergroup = fsblk->inospergroup;
124 fs->nfrag = fsblk->nfrag;
125 fs->ndfrag = fsblk->ndfrag;
128 * fs->blockspergroup = (u64int)fsblk->_cylspergroup *
129 * fsblk->secspercyl * BYTESPERSEC / fsblk->blocksize;
130 * for UFS1, but this should work for both UFS1 and UFS2
132 fs->blockspergroup = (u64int)fsblk->fragspergroup / fsblk->fragsperblock;
133 fs->ncg = fsblk->ncg;
135 fsys->blocksize = fs->blocksize;
136 fsys->nblock = fs->nblock;
138 if(debug) fprint(2, "ffs %lld %d-byte blocks, %d cylinder groups\n",
139 fs->nblock, fs->blocksize, fs->ncg);
140 if(debug) fprint(2, "\tinospergroup %d perblock %d blockspergroup %lld\n",
141 fs->inospergroup, fs->inosperblock, fs->blockspergroup);
144 fs->cg = emalloc(fs->ncg*sizeof(Cylgrp));
145 for(i=0; i<fs->ncg; i++){
148 cg->bno = (u64int)fs->blockspergroup*i;
150 cg->bno = fs->blockspergroup*i + fsblk->_cgoffset * (i & ~fsblk->_cgmask);
151 cg->cgblkno = cg->bno + fsblk->cfragno/fs->fragsperblock;
152 cg->ibno = cg->bno + fsblk->ifragno/fs->fragsperblock;
153 cg->dbno = cg->bno + fsblk->dfragno/fs->fragsperblock;
156 if((cgb = diskread(disk, fs->blocksize, (u64int)cg->cgblkno*fs->blocksize)) == nil)
159 cgblk = (Cgblk*)cgb->data;
160 if(checkcgblk(cgblk) < 0){
164 if(cgblk->nfrag % fs->fragsperblock && i != fs->ncg-1){
165 werrstr("fractional number of blocks in non-last cylinder group %d", cgblk->nfrag);
169 /* cg->nfrag = cgblk->nfrag; */
170 /* cg->nblock = (cgblk->nfrag+fs->fragsperblock-1) / fs->fragsperblock; */
171 /* fprint(2, "cg #%d: cgblk %lud, %d blocks, %d inodes\n", cgblk->num, (ulong)cg->cgblkno, cg->nblock, cg->nino); */
195 checkfsblk(Fsblk *super)
197 // fprint(2, "ffs magic 0x%ux\n", super->magic);
198 if(super->magic == FSMAGIC){
199 super->time = super->_time;
200 super->nfrag = super->_nfrag;
201 super->ndfrag = super->_ndfrag;
202 super->flags = super->_flags;
205 if(super->magic == FSMAGIC2){
209 werrstr("bad super block");
214 checkcgblk(Cgblk *cg)
216 if(cg->magic != CGMAGIC){
217 werrstr("bad cylinder group block");
224 * Read block #bno from the disk, zeroing unused data.
225 * If there is no data whatsoever, it's okay to return nil.
229 ffsblockread(Fsys *fsys, u64int bno)
233 int frag, fsize, avail;
239 i = bno / fs->blockspergroup;
240 o = bno % fs->blockspergroup;
244 if((cgblk = ffscylgrp(fs, i, &b)) == nil)
247 fmap = (u8int*)cgblk+cgblk->fmapoff;
248 frag = fs->fragsperblock;
251 sysfatal("bad frag");
256 avail = (fmap[o>>1] >> ((o&1)*4)) & 0xF;
259 avail = (fmap[o>>2] >> ((o&3)*2)) & 0x3;
262 avail = (fmap[o>>3] >> (o&7)) & 0x1;
267 if(avail == ((1<<frag)-1))
272 if((b = diskread(fs->disk, fs->blocksize, bno*fs->blocksize)) == nil){
273 fprint(2, "diskread failed!!!\n");
277 fsize = fs->fragsize;
278 for(i=0; i<frag; i++)
280 memset(b->data + fsize*i, 0, fsize);
285 ffsdatablock(Ffs *fs, u64int bno, int size)
295 if(fsize < fs->fragsize)
296 fsize = fs->fragsize;
298 if(bno >= fs->nfrag){
299 fprint(2, "ffs: request for block %#lux; nfrag %#llux\n", (ulong)bno, fs->nfrag);
302 diskaddr = (u64int)bno*fs->fragsize;
303 b = diskread(fs->disk, fsize, diskaddr);
305 fprint(2, "ffs: disk i/o at %#llux for %#ux: %r\n", diskaddr, fsize);
309 fprint(2, "ffs: disk i/o at %#llux for %#ux got %#ux\n", diskaddr, fsize,
319 ifetch(Ffs *fs, u64int bno, u32int off)
325 b = ffsdatablock(fs, bno, fs->blocksize);
329 bno = ((u64int*)b->data)[off];
331 bno = ((u32int*)b->data)[off];
337 ffsfileblockno(Ffs *fs, Inode *ino, u64int bno)
342 if(debug) fprint(2, "ffsfileblock %lud: direct %#lux\n", (ulong)bno, (ulong)ino->db[bno]);
346 ppb = fs->blocksize/4;
348 if(bno < ppb) /* single indirect */
349 return ifetch(fs, ino->ib[0], bno);
353 return ifetch(fs, ifetch(fs, ino->ib[1], bno/ppb), bno%ppb);
356 if(bno/ppb/ppb/ppb == 0) /* bno < ppb*ppb*ppb w/o overflow */
357 return ifetch(fs, ifetch(fs, ifetch(fs, ino->ib[2], bno/ppb/ppb), (bno/ppb)%ppb), bno%ppb);
359 fprint(2, "ffsfileblock %llud: way too big\n", bno+NDADDR+ppb+ppb*ppb);
364 ffsfileblock(Ffs *fs, Inode *ino, u64int bno, int size)
368 b = ffsfileblockno(fs, ino, bno);
371 return ffsdatablock(fs, b, size);
375 * NFS handles are 4-byte inode number.
378 mkhandle(Nfs3Handle *h, u64int ino)
390 return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
393 static u64int lastiaddr; /* debugging */
396 inode1to2(Inode1 *i1, Inode *i2)
400 memset(i2, 0, sizeof *i2);
402 i2->nlink = i1->nlink;
404 i2->atime = i1->atime;
405 i2->atimensec = i1->atimensec;
406 i2->mtime = i1->mtime;
407 i2->mtimensec = i1->mtimensec;
408 i2->ctime = i1->ctime;
409 i2->ctimensec = i1->ctimensec;
410 for(i=0; i<NDADDR; i++)
411 i2->db[i] = i1->db[i];
412 for(i=0; i<NIADDR; i++)
413 i2->ib[i] = i1->ib[i];
414 i2->flags = i1->flags;
415 i2->nblock = i1->nblock;
422 handle2ino(Ffs *fs, Nfs3Handle *h, u32int *pinum, Inode *ino)
433 return Nfs3ErrBadHandle;
434 inum = byte2u32(h->h);
437 if(debug) print("inum %d...", (int)inum);
439 /* fetch inode from disk */
440 i = inum / fs->inospergroup;
441 ioff = inum % fs->inospergroup;
442 if(debug)print("cg %d off %d...", i, (int)ioff);
444 return Nfs3ErrBadHandle;
447 if(debug) print("cg->ibno %lld ufs %d...", cg->ibno, fs->ufs);
448 iaddr = (cg->ibno+ioff/fs->inosperblock)*(vlong)fs->blocksize;
449 ioff = ioff%fs->inosperblock;
450 if((b = diskread(fs->disk, fs->blocksize, iaddr)) == nil)
453 *ino = ((Inode*)b->data)[ioff];
454 lastiaddr = iaddr+ioff*sizeof(Inode);
456 ino1 = ((Inode1*)b->data)[ioff];
457 inode1to2(&ino1, ino);
458 lastiaddr = iaddr+ioff*sizeof(Inode1);
465 ffsroot(Fsys *fsys, Nfs3Handle *h)
473 ino2attr(Ffs *fs, Inode *ino, u32int inum, Nfs3Attr *attr)
478 switch(ino->mode&IFMT){
480 attr->type = Nfs3FileFifo;
483 attr->type = Nfs3FileChar;
486 attr->type = Nfs3FileDir;
489 attr->type = Nfs3FileBlock;
492 attr->type = Nfs3FileReg;
495 attr->type = Nfs3FileSymlink;
498 attr->type = Nfs3FileSocket;
502 return Nfs3ErrBadHandle;
505 attr->mode = ino->mode&07777;
506 attr->nlink = ino->nlink;
507 attr->uid = ino->uid;
508 attr->gid = ino->gid;
509 attr->size = ino->size;
510 attr->used = ino->nblock*fs->blocksize;
511 if(attr->type==Nfs3FileBlock || attr->type==Nfs3FileChar){
513 attr->major = (rdev>>8)&0xFF;
514 attr->minor = rdev & 0xFFFF00FF;
521 attr->atime.sec = ino->atime;
522 attr->atime.nsec = ino->atimensec;
523 attr->mtime.sec = ino->mtime;
524 attr->mtime.nsec = ino->mtimensec;
525 attr->ctime.sec = ino->ctime;
526 attr->ctime.nsec = ino->ctimensec;
531 ingroup(SunAuthUnix *au, uint gid)
535 for(i=0; i<au->ng; i++)
542 inoperm(Inode *ino, SunAuthUnix *au, int need)
549 have = ino->mode&0777;
550 if(ino->uid == au->uid)
552 else if(ino->gid == au->gid || ingroup(au, ino->gid))
555 if((have&need) != need)
556 return Nfs3ErrNotOwner; /* really EPERM */
561 ffsgetattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr)
569 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
572 USED(au); /* anyone can getattr */
574 return ino2attr(fs, &ino, inum, attr);
578 ffsaccess(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr)
587 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
590 have = ino.mode&0777;
591 if(ino.uid == au->uid)
593 else if(ino.gid == au->gid || ingroup(au, ino.gid))
597 if((want&Nfs3AccessRead) && (have&AREAD))
598 *got |= Nfs3AccessRead;
599 if((want&Nfs3AccessLookup) && (ino.mode&IFMT)==IFDIR && (have&AEXEC))
600 *got |= Nfs3AccessLookup;
601 if((want&Nfs3AccessExecute) && (ino.mode&IFMT)!=IFDIR && (have&AEXEC))
602 *got |= Nfs3AccessExecute;
604 return ino2attr(fs, &ino, inum, attr);
608 ffslookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh)
621 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
624 if((ino.mode&IFMT) != IFDIR)
625 return Nfs3ErrNotDir;
627 if((ok = inoperm(&ino, au, AEXEC)) != Nfs3Ok)
631 nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
632 for(i=0; i<nblock; i++){
634 want = ino.size % fs->blocksize;
636 want = fs->blocksize;
637 b = ffsfileblock(fs, &ino, i, want);
646 fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
652 fprint(2, "bad len %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
657 if(4+2+2+de->namlen > de->reclen){
659 fprint(2, "bad namelen %d at offset %d of %d\n", de->namlen, (int)(p-b->data), b->len);
662 if(de->namlen == len && memcmp(de->name, name, len) == 0){
663 mkhandle(nh, de->ino);
674 ffsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **pdata, u32int *pcount, u1int *peof)
679 uchar *data, *dp, *dep, *p, *ep, *ndp;
689 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
692 if((ino.mode&IFMT) != IFDIR)
693 return Nfs3ErrNotDir;
695 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
698 if(cookie >= ino.size){
711 nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
712 i = cookie/fs->blocksize;
713 off = cookie%fs->blocksize;
715 for(; i<nblock && !done; i++){
717 want = ino.size % fs->blocksize;
719 want = fs->blocksize;
720 b = ffsfileblock(fs, &ino, i, want);
725 memset(&e, 0, sizeof e);
729 if(debug) fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
734 if(debug) fprint(2, "reclen %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
738 if(debug) fprint(2, "zero inode\n");
741 if(4+2+2+de->namlen > de->reclen){
742 if(debug) fprint(2, "bad namlen %d reclen %d at offset %d of %d\n", de->namlen, de->reclen, (int)(p-b->data), b->len);
745 if(de->name[de->namlen] != 0){
746 if(debug) fprint(2, "bad name %d %.*s\n", de->namlen, de->namlen, de->name);
749 if(debug) print("%s/%d ", de->name, (int)de->ino);
750 if((uchar*)de - b->data < off)
754 e.namelen = de->namlen;
755 e.cookie = (u64int)i*fs->blocksize + (p - b->data);
756 if(nfs3entrypack(dp, dep, &ndp, &e) < 0){
774 ffsxfileblock(Fsys *fsys, Nfs3Handle *h, u64int offset)
782 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok){
786 if(offset == 1) /* clumsy hack for debugging */
788 if(offset >= ino.size){
789 werrstr("beyond end of file");
792 bno = offset/fs->blocksize;
793 bno = ffsfileblockno(fs, &ino, bno);
796 return bno*(u64int)fs->fragsize;
800 ffsreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
801 u64int offset, uchar **pdata, u32int *pcount, u1int *peof)
806 int off, want, fragcount;
811 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
814 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
817 if(offset >= ino.size){
823 if(offset+count > ino.size)
824 count = ino.size-offset;
825 if(offset/fs->blocksize != (offset+count-1)/fs->blocksize)
826 count = fs->blocksize - offset%fs->blocksize;
828 data = malloc(count);
832 want = offset%fs->blocksize+count;
833 if(want%fs->fragsize)
834 want += fs->fragsize - want%fs->fragsize;
836 b = ffsfileblock(fs, &ino, offset/fs->blocksize, want);
838 /* BUG: distinguish sparse file from I/O error */
839 memset(data, 0, count);
841 off = offset%fs->blocksize;
842 fragcount = count; /* need signed variable */
843 if(off+fragcount > b->len){
844 fragcount = b->len - off;
849 memmove(data, b->data+off, fragcount);
853 *peof = (offset+count == ino.size);
860 ffsreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link)
869 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
871 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
879 /* assumes symlink fits in one block */
880 b = ffsfileblock(fs, &ino, 0, len);
883 if(memchr(b->data, 0, len) != nil){
887 *link = malloc(len+1);
892 memmove(*link, b->data, len);
898 if(len > sizeof ino.db + sizeof ino.ib)
901 *link = malloc(len+1);
904 memmove(*link, ino.db, ino.size);