blob: 9607cfbebb91c1a8f782a264f2d0b7b7d6d6601b [file] [log] [blame]
rsc0c98da82005-07-13 03:48:35 +00001#include <u.h>
2#include <libc.h>
3#include <thread.h>
4#include <sunrpc.h>
5#include <nfs3.h>
6#include <diskfs.h>
7#include "ffs.h"
8
rsce060bc52005-08-11 16:45:39 +00009#define BADBNO ((u64int)~0ULL)
10
rsc0c98da82005-07-13 03:48:35 +000011#define checkcg 0
12#define debug 0
13
14static int checkfsblk(Fsblk*);
15static int checkcgblk(Cgblk*);
16static Block *ffsblockread(Fsys*, u64int);
17static int ffssync(Fsys*);
18static void ffsclose(Fsys*);
19
rsc9f4a65a2005-07-28 05:16:42 +000020static u64int ffsxfileblock(Fsys *fs, Nfs3Handle *h, u64int offset);
rsc0c98da82005-07-13 03:48:35 +000021static Nfs3Status ffsroot(Fsys*, Nfs3Handle*);
22static Nfs3Status ffsgetattr(Fsys*, SunAuthUnix *au, Nfs3Handle*, Nfs3Attr*);
23static Nfs3Status ffslookup(Fsys*, SunAuthUnix *au, Nfs3Handle*, char*, Nfs3Handle*);
24static Nfs3Status ffsreadfile(Fsys*, SunAuthUnix *au, Nfs3Handle*, u32int, u64int, uchar**, u32int*, u1int*);
25static Nfs3Status ffsreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link);
26static Nfs3Status ffsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int, u64int, uchar**, u32int*, u1int*);
27static Nfs3Status ffsaccess(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr);
28
29Fsys*
30fsysopenffs(Disk *disk)
31{
32 Ffs *fs;
33 Fsys *fsys;
34
35 fsys = emalloc(sizeof(Fsys));
36 fs = emalloc(sizeof(Ffs));
37 fs->disk = disk;
38 fsys->priv = fs;
39 fsys->type = "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;
rsc6fc7da32006-10-19 21:58:59 +000049 fsys->_close = ffsclose;
rsc9f4a65a2005-07-28 05:16:42 +000050 fsys->fileblock = ffsxfileblock;
rsc0c98da82005-07-13 03:48:35 +000051
52 if(ffssync(fsys) < 0)
53 goto error;
54
55 return fsys;
56
57error:
58 ffsclose(fsys);
59 return nil;
60}
61
62static Cgblk*
rsce060bc52005-08-11 16:45:39 +000063ffscylgrp(Ffs *fs, u32int i, Block **pb)
rsc0c98da82005-07-13 03:48:35 +000064{
65 Block *b;
66 Cgblk *cg;
67
68 if(i >= fs->ncg)
69 return nil;
70
71 b = diskread(fs->disk, fs->blocksize, (u64int)fs->cg[i].cgblkno*fs->blocksize);
72 if(b == nil)
73 return nil;
74 cg = (Cgblk*)b->data;
75 if(checkcgblk(cg) < 0){
76fprint(2, "checkcgblk %d %lud: %r\n", i, (ulong)fs->cg[i].cgblkno);
77 blockput(b);
78 return nil;
79 }
80 *pb = b;
81 return cg;
82}
83
84static int
85ffssync(Fsys *fsys)
86{
87 int i;
rsce060bc52005-08-11 16:45:39 +000088 int off[] = { SBOFF, SBOFF2, SBOFFPIGGY };
rsc0c98da82005-07-13 03:48:35 +000089 Block *b, *cgb;
90 Cgblk *cgblk;
91 Cylgrp *cg;
92 Disk *disk;
93 Ffs *fs;
94 Fsblk *fsblk;
95
96 fs = fsys->priv;
97 disk = fs->disk;
98
99 /*
100 * Read super block.
101 */
rsc9614b462005-10-29 17:41:45 +0000102 b = nil;
rsce060bc52005-08-11 16:45:39 +0000103 for(i=0; i<nelem(off); i++){
104 if((b = diskread(disk, SBSIZE, off[i])) == nil)
105 goto error;
106 fsblk = (Fsblk*)b->data;
rsc6802a892006-04-28 03:08:00 +0000107 // fprint(2, "offset of magic: %ld\n", offsetof(Fsblk, magic));
rsce060bc52005-08-11 16:45:39 +0000108 if((fs->ufs = checkfsblk(fsblk)) > 0)
109 goto okay;
110 blockput(b);
rsc5e084a42006-04-28 03:06:40 +0000111 b = nil;
rsce060bc52005-08-11 16:45:39 +0000112 }
113 goto error;
rsc0c98da82005-07-13 03:48:35 +0000114
rsce060bc52005-08-11 16:45:39 +0000115okay:
rsc0c98da82005-07-13 03:48:35 +0000116 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;
123
124 fs->nfrag = fsblk->nfrag;
125 fs->ndfrag = fsblk->ndfrag;
rsce060bc52005-08-11 16:45:39 +0000126 /*
127 * used to use
128 * fs->blockspergroup = (u64int)fsblk->_cylspergroup *
129 * fsblk->secspercyl * BYTESPERSEC / fsblk->blocksize;
130 * for UFS1, but this should work for both UFS1 and UFS2
131 */
132 fs->blockspergroup = (u64int)fsblk->fragspergroup / fsblk->fragsperblock;
rsc0c98da82005-07-13 03:48:35 +0000133 fs->ncg = fsblk->ncg;
134
135 fsys->blocksize = fs->blocksize;
136 fsys->nblock = fs->nblock;
137
rsce060bc52005-08-11 16:45:39 +0000138 if(debug) fprint(2, "ffs %lld %d-byte blocks, %d cylinder groups\n",
rsc0c98da82005-07-13 03:48:35 +0000139 fs->nblock, fs->blocksize, fs->ncg);
rsce060bc52005-08-11 16:45:39 +0000140 if(debug) fprint(2, "\tinospergroup %d perblock %d blockspergroup %lld\n",
141 fs->inospergroup, fs->inosperblock, fs->blockspergroup);
rsc0c98da82005-07-13 03:48:35 +0000142
143 if(fs->cg == nil)
144 fs->cg = emalloc(fs->ncg*sizeof(Cylgrp));
145 for(i=0; i<fs->ncg; i++){
146 cg = &fs->cg[i];
rsce060bc52005-08-11 16:45:39 +0000147 if(fs->ufs == 2)
148 cg->bno = (u64int)fs->blockspergroup*i;
149 else
150 cg->bno = fs->blockspergroup*i + fsblk->_cgoffset * (i & ~fsblk->_cgmask);
rsc0c98da82005-07-13 03:48:35 +0000151 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;
154
155 if(checkcg){
156 if((cgb = diskread(disk, fs->blocksize, (u64int)cg->cgblkno*fs->blocksize)) == nil)
157 goto error;
158
159 cgblk = (Cgblk*)cgb->data;
160 if(checkcgblk(cgblk) < 0){
161 blockput(cgb);
162 goto error;
163 }
164 if(cgblk->nfrag % fs->fragsperblock && i != fs->ncg-1){
165 werrstr("fractional number of blocks in non-last cylinder group %d", cgblk->nfrag);
166 blockput(cgb);
167 goto error;
168 }
rsccbeb0b22006-04-01 19:24:03 +0000169 /* 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); */
rsc0c98da82005-07-13 03:48:35 +0000172 }
173 }
174 blockput(b);
175 return 0;
176
177error:
178 blockput(b);
179 return -1;
180}
181
182static void
183ffsclose(Fsys *fsys)
184{
185 Ffs *fs;
186
187 fs = fsys->priv;
188 if(fs->cg)
189 free(fs->cg);
190 free(fs);
191 free(fsys);
192}
193
194static int
195checkfsblk(Fsblk *super)
196{
rsc6802a892006-04-28 03:08:00 +0000197// fprint(2, "ffs magic 0x%ux\n", super->magic);
rsce060bc52005-08-11 16:45:39 +0000198 if(super->magic == FSMAGIC){
199 super->time = super->_time;
200 super->nfrag = super->_nfrag;
201 super->ndfrag = super->_ndfrag;
202 super->flags = super->_flags;
203 return 1;
204 }
205 if(super->magic == FSMAGIC2){
206 return 2;
rsc0c98da82005-07-13 03:48:35 +0000207 }
208
rsce060bc52005-08-11 16:45:39 +0000209 werrstr("bad super block");
210 return -1;
rsc0c98da82005-07-13 03:48:35 +0000211}
212
213static int
214checkcgblk(Cgblk *cg)
215{
216 if(cg->magic != CGMAGIC){
217 werrstr("bad cylinder group block");
218 return -1;
219 }
220 return 0;
221}
222
223/*
224 * Read block #bno from the disk, zeroing unused data.
225 * If there is no data whatsoever, it's okay to return nil.
226 */
227int nskipx;
228static Block*
229ffsblockread(Fsys *fsys, u64int bno)
230{
rsce060bc52005-08-11 16:45:39 +0000231 int i, o;
rsc0c98da82005-07-13 03:48:35 +0000232 u8int *fmap;
233 int frag, fsize, avail;
234 Block *b;
rsc0c98da82005-07-13 03:48:35 +0000235 Cgblk *cgblk;
236 Ffs *fs;
237
238 fs = fsys->priv;
239 i = bno / fs->blockspergroup;
240 o = bno % fs->blockspergroup;
241 if(i >= fs->ncg)
242 return nil;
rsc0c98da82005-07-13 03:48:35 +0000243
244 if((cgblk = ffscylgrp(fs, i, &b)) == nil)
245 return nil;
246
247 fmap = (u8int*)cgblk+cgblk->fmapoff;
248 frag = fs->fragsperblock;
249 switch(frag){
250 default:
251 sysfatal("bad frag");
252 case 8:
253 avail = fmap[o];
254 break;
255 case 4:
256 avail = (fmap[o>>1] >> ((o&1)*4)) & 0xF;
257 break;
258 case 2:
259 avail = (fmap[o>>2] >> ((o&3)*2)) & 0x3;
260 break;
261 case 1:
262 avail = (fmap[o>>3] >> (o&7)) & 0x1;
263 break;
264 }
265 blockput(b);
266
267 if(avail == ((1<<frag)-1))
268{
269nskipx++;
270 return nil;
271}
272 if((b = diskread(fs->disk, fs->blocksize, bno*fs->blocksize)) == nil){
273 fprint(2, "diskread failed!!!\n");
274 return nil;
275 }
276
277 fsize = fs->fragsize;
278 for(i=0; i<frag; i++)
279 if(avail & (1<<i))
280 memset(b->data + fsize*i, 0, fsize);
281 return b;
282}
283
284static Block*
rsce060bc52005-08-11 16:45:39 +0000285ffsdatablock(Ffs *fs, u64int bno, int size)
rsc0c98da82005-07-13 03:48:35 +0000286{
287 int fsize;
288 u64int diskaddr;
289 Block *b;
290
291 if(bno == 0)
292 return nil;
293
294 fsize = size;
295 if(fsize < fs->fragsize)
296 fsize = fs->fragsize;
297
298 if(bno >= fs->nfrag){
rsc9614b462005-10-29 17:41:45 +0000299 fprint(2, "ffs: request for block %#lux; nfrag %#llux\n", (ulong)bno, fs->nfrag);
rsc0c98da82005-07-13 03:48:35 +0000300 return nil;
301 }
302 diskaddr = (u64int)bno*fs->fragsize;
303 b = diskread(fs->disk, fsize, diskaddr);
304 if(b == nil){
305 fprint(2, "ffs: disk i/o at %#llux for %#ux: %r\n", diskaddr, fsize);
306 return nil;
307 }
308 if(b->len < fsize){
309 fprint(2, "ffs: disk i/o at %#llux for %#ux got %#ux\n", diskaddr, fsize,
310 b->len);
311 blockput(b);
312 return nil;
313 }
314
315 return b;
316}
317
rsce060bc52005-08-11 16:45:39 +0000318static u64int
319ifetch(Ffs *fs, u64int bno, u32int off)
rsc9f4a65a2005-07-28 05:16:42 +0000320{
rsc9f4a65a2005-07-28 05:16:42 +0000321 Block *b;
322
rsce060bc52005-08-11 16:45:39 +0000323 if(bno == BADBNO)
324 return BADBNO;
rsc9f4a65a2005-07-28 05:16:42 +0000325 b = ffsdatablock(fs, bno, fs->blocksize);
326 if(b == nil)
rsce060bc52005-08-11 16:45:39 +0000327 return BADBNO;
328 if(fs->ufs == 2)
329 bno = ((u64int*)b->data)[off];
330 else
331 bno = ((u32int*)b->data)[off];
rsc9f4a65a2005-07-28 05:16:42 +0000332 blockput(b);
333 return bno;
334}
335
rsce060bc52005-08-11 16:45:39 +0000336static u64int
337ffsfileblockno(Ffs *fs, Inode *ino, u64int bno)
rsc0c98da82005-07-13 03:48:35 +0000338{
339 int ppb;
rsc0c98da82005-07-13 03:48:35 +0000340
341 if(bno < NDADDR){
342 if(debug) fprint(2, "ffsfileblock %lud: direct %#lux\n", (ulong)bno, (ulong)ino->db[bno]);
rsc9f4a65a2005-07-28 05:16:42 +0000343 return ino->db[bno];
rsc0c98da82005-07-13 03:48:35 +0000344 }
345 bno -= NDADDR;
346 ppb = fs->blocksize/4;
347
rsc9f4a65a2005-07-28 05:16:42 +0000348 if(bno < ppb) /* single indirect */
349 return ifetch(fs, ino->ib[0], bno);
350 bno -= ppb;
rsc0c98da82005-07-13 03:48:35 +0000351
rsc9f4a65a2005-07-28 05:16:42 +0000352 if(bno < ppb*ppb)
353 return ifetch(fs, ifetch(fs, ino->ib[1], bno/ppb), bno%ppb);
354 bno -= ppb*ppb;
355
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);
rsc9f4a65a2005-07-28 05:16:42 +0000358
rsce060bc52005-08-11 16:45:39 +0000359 fprint(2, "ffsfileblock %llud: way too big\n", bno+NDADDR+ppb+ppb*ppb);
360 return BADBNO;
rsc9f4a65a2005-07-28 05:16:42 +0000361}
362
363static Block*
rsce060bc52005-08-11 16:45:39 +0000364ffsfileblock(Ffs *fs, Inode *ino, u64int bno, int size)
rsc9f4a65a2005-07-28 05:16:42 +0000365{
rsce060bc52005-08-11 16:45:39 +0000366 u64int b;
rsc9f4a65a2005-07-28 05:16:42 +0000367
368 b = ffsfileblockno(fs, ino, bno);
369 if(b == ~0)
370 return nil;
371 return ffsdatablock(fs, b, size);
rsc0c98da82005-07-13 03:48:35 +0000372}
373
374/*
375 * NFS handles are 4-byte inode number.
376 */
377static void
378mkhandle(Nfs3Handle *h, u64int ino)
379{
380 h->h[0] = ino >> 24;
381 h->h[1] = ino >> 16;
382 h->h[2] = ino >> 8;
383 h->h[3] = ino;
384 h->len = 4;
385}
386
387static u32int
388byte2u32(uchar *p)
389{
390 return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
391}
392
rsce060bc52005-08-11 16:45:39 +0000393static u64int lastiaddr; /* debugging */
394
395static void
396inode1to2(Inode1 *i1, Inode *i2)
397{
398 int i;
399
400 memset(i2, 0, sizeof *i2);
401 i2->mode = i1->mode;
402 i2->nlink = i1->nlink;
403 i2->size = i1->size;
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;
416 i2->gen = i1->gen;
417 i2->uid = i1->uid;
418 i2->gid = i1->gid;
419}
rsc9f4a65a2005-07-28 05:16:42 +0000420
rsc0c98da82005-07-13 03:48:35 +0000421static Nfs3Status
422handle2ino(Ffs *fs, Nfs3Handle *h, u32int *pinum, Inode *ino)
423{
424 int i;
425 u32int ioff;
426 u32int inum;
rsce060bc52005-08-11 16:45:39 +0000427 u64int iaddr;
rsc0c98da82005-07-13 03:48:35 +0000428 Block *b;
429 Cylgrp *cg;
rsce060bc52005-08-11 16:45:39 +0000430 Inode1 ino1;
rsc0c98da82005-07-13 03:48:35 +0000431
432 if(h->len != 4)
433 return Nfs3ErrBadHandle;
434 inum = byte2u32(h->h);
435 if(pinum)
436 *pinum = inum;
437 if(debug) print("inum %d...", (int)inum);
438
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);
443 if(i >= fs->ncg)
444 return Nfs3ErrBadHandle;
445 cg = &fs->cg[i];
rsc0c98da82005-07-13 03:48:35 +0000446
rsce060bc52005-08-11 16:45:39 +0000447 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)
rsc0c98da82005-07-13 03:48:35 +0000451 return Nfs3ErrIo;
rsce060bc52005-08-11 16:45:39 +0000452 if(fs->ufs == 2){
453 *ino = ((Inode*)b->data)[ioff];
454 lastiaddr = iaddr+ioff*sizeof(Inode);
455 }else{
456 ino1 = ((Inode1*)b->data)[ioff];
457 inode1to2(&ino1, ino);
458 lastiaddr = iaddr+ioff*sizeof(Inode1);
459 }
rsc0c98da82005-07-13 03:48:35 +0000460 blockput(b);
rsc0c98da82005-07-13 03:48:35 +0000461 return Nfs3Ok;
462}
463
464static Nfs3Status
465ffsroot(Fsys *fsys, Nfs3Handle *h)
466{
467 USED(fsys);
468 mkhandle(h, 2);
469 return Nfs3Ok;
470}
471
472static Nfs3Status
473ino2attr(Ffs *fs, Inode *ino, u32int inum, Nfs3Attr *attr)
474{
475 u32int rdev;
476
477 attr->type = -1;
478 switch(ino->mode&IFMT){
479 case IFIFO:
480 attr->type = Nfs3FileFifo;
481 break;
482 case IFCHR:
483 attr->type = Nfs3FileChar;
484 break;
485 case IFDIR:
486 attr->type = Nfs3FileDir;
487 break;
488 case IFBLK:
489 attr->type = Nfs3FileBlock;
490 break;
491 case IFREG:
492 attr->type = Nfs3FileReg;
493 break;
494 case IFLNK:
495 attr->type = Nfs3FileSymlink;
496 break;
497 case IFSOCK:
498 attr->type = Nfs3FileSocket;
499 break;
500 case IFWHT:
501 default:
502 return Nfs3ErrBadHandle;
503 }
504
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){
512 rdev = ino->db[0];
513 attr->major = (rdev>>8)&0xFF;
514 attr->minor = rdev & 0xFFFF00FF;
515 }else{
516 attr->major = 0;
517 attr->minor = 0;
518 }
519 attr->fsid = 0;
520 attr->fileid = inum;
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;
527 return Nfs3Ok;
528}
529
530static int
531ingroup(SunAuthUnix *au, uint gid)
532{
533 int i;
534
535 for(i=0; i<au->ng; i++)
536 if(au->g[i] == gid)
537 return 1;
538 return 0;
539}
540
541static Nfs3Status
542inoperm(Inode *ino, SunAuthUnix *au, int need)
543{
544 int have;
545
rsc9f4a65a2005-07-28 05:16:42 +0000546 if(au == nil)
547 return Nfs3Ok;
548
rsc0c98da82005-07-13 03:48:35 +0000549 have = ino->mode&0777;
550 if(ino->uid == au->uid)
551 have >>= 6;
552 else if(ino->gid == au->gid || ingroup(au, ino->gid))
553 have >>= 3;
554
555 if((have&need) != need)
556 return Nfs3ErrNotOwner; /* really EPERM */
557 return Nfs3Ok;
558}
559
560static Nfs3Status
561ffsgetattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr)
562{
563 Inode ino;
564 u32int inum;
565 Ffs *fs;
566 Nfs3Status ok;
567
568 fs = fsys->priv;
569 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
570 return ok;
571
572 USED(au); /* anyone can getattr */
573
574 return ino2attr(fs, &ino, inum, attr);
575}
576
577static Nfs3Status
578ffsaccess(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr)
579{
580 int have;
581 Inode ino;
582 u32int inum;
583 Ffs *fs;
584 Nfs3Status ok;
585
586 fs = fsys->priv;
587 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
588 return ok;
589
590 have = ino.mode&0777;
591 if(ino.uid == au->uid)
592 have >>= 6;
593 else if(ino.gid == au->gid || ingroup(au, ino.gid))
594 have >>= 3;
595
596 *got = 0;
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;
603
604 return ino2attr(fs, &ino, inum, attr);
605}
606
607static Nfs3Status
608ffslookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh)
609{
610 u32int nblock;
611 u32int i;
612 uchar *p, *ep;
613 Dirent *de;
614 Inode ino;
615 Block *b;
616 Ffs *fs;
617 Nfs3Status ok;
618 int len, want;
619
620 fs = fsys->priv;
621 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
622 return ok;
623
624 if((ino.mode&IFMT) != IFDIR)
625 return Nfs3ErrNotDir;
626
627 if((ok = inoperm(&ino, au, AEXEC)) != Nfs3Ok)
628 return ok;
629
630 len = strlen(name);
631 nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
632 for(i=0; i<nblock; i++){
633 if(i==nblock-1)
634 want = ino.size % fs->blocksize;
635 else
636 want = fs->blocksize;
637 b = ffsfileblock(fs, &ino, i, want);
638 if(b == nil)
639 continue;
640 p = b->data;
641 ep = p+b->len;
642 while(p < ep){
643 de = (Dirent*)p;
644 if(de->reclen == 0){
645 if(debug)
646 fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
647 break;
648 }
649 p += de->reclen;
650 if(p > ep){
651 if(debug)
652 fprint(2, "bad len %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
653 break;
654 }
655 if(de->ino == 0)
656 continue;
657 if(4+2+2+de->namlen > de->reclen){
658 if(debug)
659 fprint(2, "bad namelen %d at offset %d of %d\n", de->namlen, (int)(p-b->data), b->len);
660 break;
661 }
662 if(de->namlen == len && memcmp(de->name, name, len) == 0){
663 mkhandle(nh, de->ino);
664 blockput(b);
665 return Nfs3Ok;
666 }
667 }
668 blockput(b);
669 }
670 return Nfs3ErrNoEnt;
671}
672
673static Nfs3Status
674ffsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **pdata, u32int *pcount, u1int *peof)
675{
676 u32int nblock;
677 u32int i;
678 int off, done;
679 uchar *data, *dp, *dep, *p, *ep, *ndp;
680 Dirent *de;
681 Inode ino;
682 Block *b;
683 Ffs *fs;
684 Nfs3Status ok;
685 Nfs3Entry e;
686 int want;
687
688 fs = fsys->priv;
689 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
690 return ok;
691
692 if((ino.mode&IFMT) != IFDIR)
693 return Nfs3ErrNotDir;
694
695 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
696 return ok;
697
698 if(cookie >= ino.size){
699 *pcount = 0;
700 *pdata = 0;
701 return Nfs3Ok;
702 }
703
704 dp = malloc(count);
705 data = dp;
706 if(dp == nil)
707 return Nfs3ErrNoMem;
708 dep = dp+count;
709 *peof = 0;
710 nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
711 i = cookie/fs->blocksize;
712 off = cookie%fs->blocksize;
713 done = 0;
714 for(; i<nblock && !done; i++){
715 if(i==nblock-1)
716 want = ino.size % fs->blocksize;
717 else
718 want = fs->blocksize;
719 b = ffsfileblock(fs, &ino, i, want);
720 if(b == nil)
721 continue;
722 p = b->data;
723 ep = p+b->len;
724 memset(&e, 0, sizeof e);
725 while(p < ep){
726 de = (Dirent*)p;
727 if(de->reclen == 0){
728 if(debug) fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
729 break;
730 }
731 p += de->reclen;
732 if(p > ep){
733 if(debug) fprint(2, "reclen %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
734 break;
735 }
736 if(de->ino == 0){
737 if(debug) fprint(2, "zero inode\n");
738 continue;
739 }
740 if(4+2+2+de->namlen > de->reclen){
741 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);
742 break;
743 }
744 if(de->name[de->namlen] != 0){
745 if(debug) fprint(2, "bad name %d %.*s\n", de->namlen, de->namlen, de->name);
746 continue;
747 }
748 if(debug) print("%s/%d ", de->name, (int)de->ino);
749 if((uchar*)de - b->data < off)
750 continue;
751 e.fileid = de->ino;
752 e.name = de->name;
rsc4e81d4f2006-05-09 18:35:24 +0000753 e.namelen = de->namlen;
rsc0c98da82005-07-13 03:48:35 +0000754 e.cookie = (u64int)i*fs->blocksize + (p - b->data);
755 if(nfs3entrypack(dp, dep, &ndp, &e) < 0){
756 done = 1;
757 break;
758 }
759 dp = ndp;
760 }
761 off = 0;
762 blockput(b);
763 }
764 if(i==nblock)
765 *peof = 1;
766
767 *pcount = dp - data;
768 *pdata = data;
769 return Nfs3Ok;
770}
771
rsc9f4a65a2005-07-28 05:16:42 +0000772static u64int
773ffsxfileblock(Fsys *fsys, Nfs3Handle *h, u64int offset)
774{
rsce060bc52005-08-11 16:45:39 +0000775 u64int bno;
rsc9f4a65a2005-07-28 05:16:42 +0000776 Inode ino;
777 Nfs3Status ok;
778 Ffs *fs;
779
780 fs = fsys->priv;
781 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok){
782 nfs3errstr(ok);
783 return 0;
784 }
rsce060bc52005-08-11 16:45:39 +0000785 if(offset == 1) /* clumsy hack for debugging */
786 return lastiaddr;
rsc9f4a65a2005-07-28 05:16:42 +0000787 if(offset >= ino.size){
788 werrstr("beyond end of file");
789 return 0;
790 }
791 bno = offset/fs->blocksize;
792 bno = ffsfileblockno(fs, &ino, bno);
793 if(bno == ~0)
794 return 0;
795 return bno*(u64int)fs->fragsize;
796}
797
rsc0c98da82005-07-13 03:48:35 +0000798static Nfs3Status
799ffsreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
800 u64int offset, uchar **pdata, u32int *pcount, u1int *peof)
801{
802 uchar *data;
803 Block *b;
804 Ffs *fs;
805 int off, want, fragcount;
806 Inode ino;
807 Nfs3Status ok;
808
809 fs = fsys->priv;
810 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
811 return ok;
812
813 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
814 return ok;
815
816 if(offset >= ino.size){
817 *pdata = 0;
818 *pcount = 0;
819 *peof = 1;
820 return Nfs3Ok;
821 }
822 if(offset+count > ino.size)
823 count = ino.size-offset;
824 if(offset/fs->blocksize != (offset+count-1)/fs->blocksize)
825 count = fs->blocksize - offset%fs->blocksize;
826
827 data = malloc(count);
828 if(data == nil)
829 return Nfs3ErrNoMem;
830
831 want = offset%fs->blocksize+count;
832 if(want%fs->fragsize)
833 want += fs->fragsize - want%fs->fragsize;
834
835 b = ffsfileblock(fs, &ino, offset/fs->blocksize, want);
836 if(b == nil){
837 /* BUG: distinguish sparse file from I/O error */
838 memset(data, 0, count);
839 }else{
840 off = offset%fs->blocksize;
841 fragcount = count; /* need signed variable */
842 if(off+fragcount > b->len){
843 fragcount = b->len - off;
844 if(fragcount < 0)
845 fragcount = 0;
846 }
847 if(fragcount > 0)
848 memmove(data, b->data+off, fragcount);
849 count = fragcount;
850 blockput(b);
851 }
852 *peof = (offset+count == ino.size);
853 *pcount = count;
854 *pdata = data;
855 return Nfs3Ok;
856}
857
858static Nfs3Status
859ffsreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link)
860{
861 Ffs *fs;
862 Nfs3Status ok;
863 int len;
864 Inode ino;
865 Block *b;
866
867 fs = fsys->priv;
868 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
869 return ok;
870 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
871 return ok;
872
873 if(ino.size > 1024)
874 return Nfs3ErrIo;
875 len = ino.size;
876
877 if(ino.nblock != 0){
rsce060bc52005-08-11 16:45:39 +0000878 /* assumes symlink fits in one block */
rsc0c98da82005-07-13 03:48:35 +0000879 b = ffsfileblock(fs, &ino, 0, len);
880 if(b == nil)
881 return Nfs3ErrIo;
882 if(memchr(b->data, 0, len) != nil){
883 blockput(b);
884 return Nfs3ErrIo;
885 }
886 *link = malloc(len+1);
887 if(*link == 0){
888 blockput(b);
889 return Nfs3ErrNoMem;
890 }
891 memmove(*link, b->data, len);
892 (*link)[len] = 0;
893 blockput(b);
894 return Nfs3Ok;
895 }
896
897 if(len > sizeof ino.db + sizeof ino.ib)
898 return Nfs3ErrIo;
899
900 *link = malloc(len+1);
901 if(*link == 0)
902 return Nfs3ErrNoMem;
903 memmove(*link, ino.db, ino.size);
904 (*link)[len] = 0;
905 return Nfs3Ok;
906}