blob: 7864c7193c7fee4dc83506381ac31be041bfae6d [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;
rsc9f4a65a2005-07-28 05:16:42 +000049 fsys->fileblock = ffsxfileblock;
rsc0c98da82005-07-13 03:48:35 +000050
51 if(ffssync(fsys) < 0)
52 goto error;
53
54 return fsys;
55
56error:
57 ffsclose(fsys);
58 return nil;
59}
60
61static Cgblk*
rsce060bc52005-08-11 16:45:39 +000062ffscylgrp(Ffs *fs, u32int i, Block **pb)
rsc0c98da82005-07-13 03:48:35 +000063{
64 Block *b;
65 Cgblk *cg;
66
67 if(i >= fs->ncg)
68 return nil;
69
70 b = diskread(fs->disk, fs->blocksize, (u64int)fs->cg[i].cgblkno*fs->blocksize);
71 if(b == nil)
72 return nil;
73 cg = (Cgblk*)b->data;
74 if(checkcgblk(cg) < 0){
75fprint(2, "checkcgblk %d %lud: %r\n", i, (ulong)fs->cg[i].cgblkno);
76 blockput(b);
77 return nil;
78 }
79 *pb = b;
80 return cg;
81}
82
83static int
84ffssync(Fsys *fsys)
85{
86 int i;
rsce060bc52005-08-11 16:45:39 +000087 int off[] = { SBOFF, SBOFF2, SBOFFPIGGY };
rsc0c98da82005-07-13 03:48:35 +000088 Block *b, *cgb;
89 Cgblk *cgblk;
90 Cylgrp *cg;
91 Disk *disk;
92 Ffs *fs;
93 Fsblk *fsblk;
94
95 fs = fsys->priv;
96 disk = fs->disk;
97
98 /*
99 * Read super block.
100 */
rsc9614b462005-10-29 17:41:45 +0000101 b = nil;
rsce060bc52005-08-11 16:45:39 +0000102 for(i=0; i<nelem(off); i++){
103 if((b = diskread(disk, SBSIZE, off[i])) == nil)
104 goto error;
105 fsblk = (Fsblk*)b->data;
rsc6802a892006-04-28 03:08:00 +0000106 // fprint(2, "offset of magic: %ld\n", offsetof(Fsblk, magic));
rsce060bc52005-08-11 16:45:39 +0000107 if((fs->ufs = checkfsblk(fsblk)) > 0)
108 goto okay;
109 blockput(b);
rsc5e084a42006-04-28 03:06:40 +0000110 b = nil;
rsce060bc52005-08-11 16:45:39 +0000111 }
112 goto error;
rsc0c98da82005-07-13 03:48:35 +0000113
rsce060bc52005-08-11 16:45:39 +0000114okay:
rsc0c98da82005-07-13 03:48:35 +0000115 fs->blocksize = fsblk->blocksize;
116 fs->nblock = (fsblk->nfrag+fsblk->fragsperblock-1) / fsblk->fragsperblock;
117 fs->fragsize = fsblk->fragsize;
118 fs->fragspergroup = fsblk->fragspergroup;
119 fs->fragsperblock = fsblk->fragsperblock;
120 fs->inosperblock = fsblk->inosperblock;
121 fs->inospergroup = fsblk->inospergroup;
122
123 fs->nfrag = fsblk->nfrag;
124 fs->ndfrag = fsblk->ndfrag;
rsce060bc52005-08-11 16:45:39 +0000125 /*
126 * used to use
127 * fs->blockspergroup = (u64int)fsblk->_cylspergroup *
128 * fsblk->secspercyl * BYTESPERSEC / fsblk->blocksize;
129 * for UFS1, but this should work for both UFS1 and UFS2
130 */
131 fs->blockspergroup = (u64int)fsblk->fragspergroup / fsblk->fragsperblock;
rsc0c98da82005-07-13 03:48:35 +0000132 fs->ncg = fsblk->ncg;
133
134 fsys->blocksize = fs->blocksize;
135 fsys->nblock = fs->nblock;
136
rsce060bc52005-08-11 16:45:39 +0000137 if(debug) fprint(2, "ffs %lld %d-byte blocks, %d cylinder groups\n",
rsc0c98da82005-07-13 03:48:35 +0000138 fs->nblock, fs->blocksize, fs->ncg);
rsce060bc52005-08-11 16:45:39 +0000139 if(debug) fprint(2, "\tinospergroup %d perblock %d blockspergroup %lld\n",
140 fs->inospergroup, fs->inosperblock, fs->blockspergroup);
rsc0c98da82005-07-13 03:48:35 +0000141
142 if(fs->cg == nil)
143 fs->cg = emalloc(fs->ncg*sizeof(Cylgrp));
144 for(i=0; i<fs->ncg; i++){
145 cg = &fs->cg[i];
rsce060bc52005-08-11 16:45:39 +0000146 if(fs->ufs == 2)
147 cg->bno = (u64int)fs->blockspergroup*i;
148 else
149 cg->bno = fs->blockspergroup*i + fsblk->_cgoffset * (i & ~fsblk->_cgmask);
rsc0c98da82005-07-13 03:48:35 +0000150 cg->cgblkno = cg->bno + fsblk->cfragno/fs->fragsperblock;
151 cg->ibno = cg->bno + fsblk->ifragno/fs->fragsperblock;
152 cg->dbno = cg->bno + fsblk->dfragno/fs->fragsperblock;
153
154 if(checkcg){
155 if((cgb = diskread(disk, fs->blocksize, (u64int)cg->cgblkno*fs->blocksize)) == nil)
156 goto error;
157
158 cgblk = (Cgblk*)cgb->data;
159 if(checkcgblk(cgblk) < 0){
160 blockput(cgb);
161 goto error;
162 }
163 if(cgblk->nfrag % fs->fragsperblock && i != fs->ncg-1){
164 werrstr("fractional number of blocks in non-last cylinder group %d", cgblk->nfrag);
165 blockput(cgb);
166 goto error;
167 }
rsccbeb0b22006-04-01 19:24:03 +0000168 /* cg->nfrag = cgblk->nfrag; */
169 /* cg->nblock = (cgblk->nfrag+fs->fragsperblock-1) / fs->fragsperblock; */
170 /* 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 +0000171 }
172 }
173 blockput(b);
174 return 0;
175
176error:
177 blockput(b);
178 return -1;
179}
180
181static void
182ffsclose(Fsys *fsys)
183{
184 Ffs *fs;
185
186 fs = fsys->priv;
187 if(fs->cg)
188 free(fs->cg);
189 free(fs);
190 free(fsys);
191}
192
193static int
194checkfsblk(Fsblk *super)
195{
rsc6802a892006-04-28 03:08:00 +0000196// fprint(2, "ffs magic 0x%ux\n", super->magic);
rsce060bc52005-08-11 16:45:39 +0000197 if(super->magic == FSMAGIC){
198 super->time = super->_time;
199 super->nfrag = super->_nfrag;
200 super->ndfrag = super->_ndfrag;
201 super->flags = super->_flags;
202 return 1;
203 }
204 if(super->magic == FSMAGIC2){
205 return 2;
rsc0c98da82005-07-13 03:48:35 +0000206 }
207
rsce060bc52005-08-11 16:45:39 +0000208 werrstr("bad super block");
209 return -1;
rsc0c98da82005-07-13 03:48:35 +0000210}
211
212static int
213checkcgblk(Cgblk *cg)
214{
215 if(cg->magic != CGMAGIC){
216 werrstr("bad cylinder group block");
217 return -1;
218 }
219 return 0;
220}
221
222/*
223 * Read block #bno from the disk, zeroing unused data.
224 * If there is no data whatsoever, it's okay to return nil.
225 */
226int nskipx;
227static Block*
228ffsblockread(Fsys *fsys, u64int bno)
229{
rsce060bc52005-08-11 16:45:39 +0000230 int i, o;
rsc0c98da82005-07-13 03:48:35 +0000231 u8int *fmap;
232 int frag, fsize, avail;
233 Block *b;
rsc0c98da82005-07-13 03:48:35 +0000234 Cgblk *cgblk;
235 Ffs *fs;
236
237 fs = fsys->priv;
238 i = bno / fs->blockspergroup;
239 o = bno % fs->blockspergroup;
240 if(i >= fs->ncg)
241 return nil;
rsc0c98da82005-07-13 03:48:35 +0000242
243 if((cgblk = ffscylgrp(fs, i, &b)) == nil)
244 return nil;
245
246 fmap = (u8int*)cgblk+cgblk->fmapoff;
247 frag = fs->fragsperblock;
248 switch(frag){
249 default:
250 sysfatal("bad frag");
251 case 8:
252 avail = fmap[o];
253 break;
254 case 4:
255 avail = (fmap[o>>1] >> ((o&1)*4)) & 0xF;
256 break;
257 case 2:
258 avail = (fmap[o>>2] >> ((o&3)*2)) & 0x3;
259 break;
260 case 1:
261 avail = (fmap[o>>3] >> (o&7)) & 0x1;
262 break;
263 }
264 blockput(b);
265
266 if(avail == ((1<<frag)-1))
267{
268nskipx++;
269 return nil;
270}
271 if((b = diskread(fs->disk, fs->blocksize, bno*fs->blocksize)) == nil){
272 fprint(2, "diskread failed!!!\n");
273 return nil;
274 }
275
276 fsize = fs->fragsize;
277 for(i=0; i<frag; i++)
278 if(avail & (1<<i))
279 memset(b->data + fsize*i, 0, fsize);
280 return b;
281}
282
283static Block*
rsce060bc52005-08-11 16:45:39 +0000284ffsdatablock(Ffs *fs, u64int bno, int size)
rsc0c98da82005-07-13 03:48:35 +0000285{
286 int fsize;
287 u64int diskaddr;
288 Block *b;
289
290 if(bno == 0)
291 return nil;
292
293 fsize = size;
294 if(fsize < fs->fragsize)
295 fsize = fs->fragsize;
296
297 if(bno >= fs->nfrag){
rsc9614b462005-10-29 17:41:45 +0000298 fprint(2, "ffs: request for block %#lux; nfrag %#llux\n", (ulong)bno, fs->nfrag);
rsc0c98da82005-07-13 03:48:35 +0000299 return nil;
300 }
301 diskaddr = (u64int)bno*fs->fragsize;
302 b = diskread(fs->disk, fsize, diskaddr);
303 if(b == nil){
304 fprint(2, "ffs: disk i/o at %#llux for %#ux: %r\n", diskaddr, fsize);
305 return nil;
306 }
307 if(b->len < fsize){
308 fprint(2, "ffs: disk i/o at %#llux for %#ux got %#ux\n", diskaddr, fsize,
309 b->len);
310 blockput(b);
311 return nil;
312 }
313
314 return b;
315}
316
rsce060bc52005-08-11 16:45:39 +0000317static u64int
318ifetch(Ffs *fs, u64int bno, u32int off)
rsc9f4a65a2005-07-28 05:16:42 +0000319{
rsc9f4a65a2005-07-28 05:16:42 +0000320 Block *b;
321
rsce060bc52005-08-11 16:45:39 +0000322 if(bno == BADBNO)
323 return BADBNO;
rsc9f4a65a2005-07-28 05:16:42 +0000324 b = ffsdatablock(fs, bno, fs->blocksize);
325 if(b == nil)
rsce060bc52005-08-11 16:45:39 +0000326 return BADBNO;
327 if(fs->ufs == 2)
328 bno = ((u64int*)b->data)[off];
329 else
330 bno = ((u32int*)b->data)[off];
rsc9f4a65a2005-07-28 05:16:42 +0000331 blockput(b);
332 return bno;
333}
334
rsce060bc52005-08-11 16:45:39 +0000335static u64int
336ffsfileblockno(Ffs *fs, Inode *ino, u64int bno)
rsc0c98da82005-07-13 03:48:35 +0000337{
338 int ppb;
rsc0c98da82005-07-13 03:48:35 +0000339
340 if(bno < NDADDR){
341 if(debug) fprint(2, "ffsfileblock %lud: direct %#lux\n", (ulong)bno, (ulong)ino->db[bno]);
rsc9f4a65a2005-07-28 05:16:42 +0000342 return ino->db[bno];
rsc0c98da82005-07-13 03:48:35 +0000343 }
344 bno -= NDADDR;
345 ppb = fs->blocksize/4;
346
rsc9f4a65a2005-07-28 05:16:42 +0000347 if(bno < ppb) /* single indirect */
348 return ifetch(fs, ino->ib[0], bno);
349 bno -= ppb;
rsc0c98da82005-07-13 03:48:35 +0000350
rsc9f4a65a2005-07-28 05:16:42 +0000351 if(bno < ppb*ppb)
352 return ifetch(fs, ifetch(fs, ino->ib[1], bno/ppb), bno%ppb);
353 bno -= ppb*ppb;
354
355 if(bno/ppb/ppb/ppb == 0) /* bno < ppb*ppb*ppb w/o overflow */
356 return ifetch(fs, ifetch(fs, ifetch(fs, ino->ib[2], bno/ppb/ppb), (bno/ppb)%ppb), bno%ppb);
rsc9f4a65a2005-07-28 05:16:42 +0000357
rsce060bc52005-08-11 16:45:39 +0000358 fprint(2, "ffsfileblock %llud: way too big\n", bno+NDADDR+ppb+ppb*ppb);
359 return BADBNO;
rsc9f4a65a2005-07-28 05:16:42 +0000360}
361
362static Block*
rsce060bc52005-08-11 16:45:39 +0000363ffsfileblock(Ffs *fs, Inode *ino, u64int bno, int size)
rsc9f4a65a2005-07-28 05:16:42 +0000364{
rsce060bc52005-08-11 16:45:39 +0000365 u64int b;
rsc9f4a65a2005-07-28 05:16:42 +0000366
367 b = ffsfileblockno(fs, ino, bno);
368 if(b == ~0)
369 return nil;
370 return ffsdatablock(fs, b, size);
rsc0c98da82005-07-13 03:48:35 +0000371}
372
373/*
374 * NFS handles are 4-byte inode number.
375 */
376static void
377mkhandle(Nfs3Handle *h, u64int ino)
378{
379 h->h[0] = ino >> 24;
380 h->h[1] = ino >> 16;
381 h->h[2] = ino >> 8;
382 h->h[3] = ino;
383 h->len = 4;
384}
385
386static u32int
387byte2u32(uchar *p)
388{
389 return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
390}
391
rsce060bc52005-08-11 16:45:39 +0000392static u64int lastiaddr; /* debugging */
393
394static void
395inode1to2(Inode1 *i1, Inode *i2)
396{
397 int i;
398
399 memset(i2, 0, sizeof *i2);
400 i2->mode = i1->mode;
401 i2->nlink = i1->nlink;
402 i2->size = i1->size;
403 i2->atime = i1->atime;
404 i2->atimensec = i1->atimensec;
405 i2->mtime = i1->mtime;
406 i2->mtimensec = i1->mtimensec;
407 i2->ctime = i1->ctime;
408 i2->ctimensec = i1->ctimensec;
409 for(i=0; i<NDADDR; i++)
410 i2->db[i] = i1->db[i];
411 for(i=0; i<NIADDR; i++)
412 i2->ib[i] = i1->ib[i];
413 i2->flags = i1->flags;
414 i2->nblock = i1->nblock;
415 i2->gen = i1->gen;
416 i2->uid = i1->uid;
417 i2->gid = i1->gid;
418}
rsc9f4a65a2005-07-28 05:16:42 +0000419
rsc0c98da82005-07-13 03:48:35 +0000420static Nfs3Status
421handle2ino(Ffs *fs, Nfs3Handle *h, u32int *pinum, Inode *ino)
422{
423 int i;
424 u32int ioff;
425 u32int inum;
rsce060bc52005-08-11 16:45:39 +0000426 u64int iaddr;
rsc0c98da82005-07-13 03:48:35 +0000427 Block *b;
428 Cylgrp *cg;
rsce060bc52005-08-11 16:45:39 +0000429 Inode1 ino1;
rsc0c98da82005-07-13 03:48:35 +0000430
431 if(h->len != 4)
432 return Nfs3ErrBadHandle;
433 inum = byte2u32(h->h);
434 if(pinum)
435 *pinum = inum;
436 if(debug) print("inum %d...", (int)inum);
437
438 /* fetch inode from disk */
439 i = inum / fs->inospergroup;
440 ioff = inum % fs->inospergroup;
441 if(debug)print("cg %d off %d...", i, (int)ioff);
442 if(i >= fs->ncg)
443 return Nfs3ErrBadHandle;
444 cg = &fs->cg[i];
rsc0c98da82005-07-13 03:48:35 +0000445
rsce060bc52005-08-11 16:45:39 +0000446 if(debug) print("cg->ibno %lld ufs %d...", cg->ibno, fs->ufs);
447 iaddr = (cg->ibno+ioff/fs->inosperblock)*(vlong)fs->blocksize;
448 ioff = ioff%fs->inosperblock;
449 if((b = diskread(fs->disk, fs->blocksize, iaddr)) == nil)
rsc0c98da82005-07-13 03:48:35 +0000450 return Nfs3ErrIo;
rsce060bc52005-08-11 16:45:39 +0000451 if(fs->ufs == 2){
452 *ino = ((Inode*)b->data)[ioff];
453 lastiaddr = iaddr+ioff*sizeof(Inode);
454 }else{
455 ino1 = ((Inode1*)b->data)[ioff];
456 inode1to2(&ino1, ino);
457 lastiaddr = iaddr+ioff*sizeof(Inode1);
458 }
rsc0c98da82005-07-13 03:48:35 +0000459 blockput(b);
rsc0c98da82005-07-13 03:48:35 +0000460 return Nfs3Ok;
461}
462
463static Nfs3Status
464ffsroot(Fsys *fsys, Nfs3Handle *h)
465{
466 USED(fsys);
467 mkhandle(h, 2);
468 return Nfs3Ok;
469}
470
471static Nfs3Status
472ino2attr(Ffs *fs, Inode *ino, u32int inum, Nfs3Attr *attr)
473{
474 u32int rdev;
475
476 attr->type = -1;
477 switch(ino->mode&IFMT){
478 case IFIFO:
479 attr->type = Nfs3FileFifo;
480 break;
481 case IFCHR:
482 attr->type = Nfs3FileChar;
483 break;
484 case IFDIR:
485 attr->type = Nfs3FileDir;
486 break;
487 case IFBLK:
488 attr->type = Nfs3FileBlock;
489 break;
490 case IFREG:
491 attr->type = Nfs3FileReg;
492 break;
493 case IFLNK:
494 attr->type = Nfs3FileSymlink;
495 break;
496 case IFSOCK:
497 attr->type = Nfs3FileSocket;
498 break;
499 case IFWHT:
500 default:
501 return Nfs3ErrBadHandle;
502 }
503
504 attr->mode = ino->mode&07777;
505 attr->nlink = ino->nlink;
506 attr->uid = ino->uid;
507 attr->gid = ino->gid;
508 attr->size = ino->size;
509 attr->used = ino->nblock*fs->blocksize;
510 if(attr->type==Nfs3FileBlock || attr->type==Nfs3FileChar){
511 rdev = ino->db[0];
512 attr->major = (rdev>>8)&0xFF;
513 attr->minor = rdev & 0xFFFF00FF;
514 }else{
515 attr->major = 0;
516 attr->minor = 0;
517 }
518 attr->fsid = 0;
519 attr->fileid = inum;
520 attr->atime.sec = ino->atime;
521 attr->atime.nsec = ino->atimensec;
522 attr->mtime.sec = ino->mtime;
523 attr->mtime.nsec = ino->mtimensec;
524 attr->ctime.sec = ino->ctime;
525 attr->ctime.nsec = ino->ctimensec;
526 return Nfs3Ok;
527}
528
529static int
530ingroup(SunAuthUnix *au, uint gid)
531{
532 int i;
533
534 for(i=0; i<au->ng; i++)
535 if(au->g[i] == gid)
536 return 1;
537 return 0;
538}
539
540static Nfs3Status
541inoperm(Inode *ino, SunAuthUnix *au, int need)
542{
543 int have;
544
rsc9f4a65a2005-07-28 05:16:42 +0000545 if(au == nil)
546 return Nfs3Ok;
547
rsc0c98da82005-07-13 03:48:35 +0000548 have = ino->mode&0777;
549 if(ino->uid == au->uid)
550 have >>= 6;
551 else if(ino->gid == au->gid || ingroup(au, ino->gid))
552 have >>= 3;
553
554 if((have&need) != need)
555 return Nfs3ErrNotOwner; /* really EPERM */
556 return Nfs3Ok;
557}
558
559static Nfs3Status
560ffsgetattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr)
561{
562 Inode ino;
563 u32int inum;
564 Ffs *fs;
565 Nfs3Status ok;
566
567 fs = fsys->priv;
568 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
569 return ok;
570
571 USED(au); /* anyone can getattr */
572
573 return ino2attr(fs, &ino, inum, attr);
574}
575
576static Nfs3Status
577ffsaccess(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr)
578{
579 int have;
580 Inode ino;
581 u32int inum;
582 Ffs *fs;
583 Nfs3Status ok;
584
585 fs = fsys->priv;
586 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
587 return ok;
588
589 have = ino.mode&0777;
590 if(ino.uid == au->uid)
591 have >>= 6;
592 else if(ino.gid == au->gid || ingroup(au, ino.gid))
593 have >>= 3;
594
595 *got = 0;
596 if((want&Nfs3AccessRead) && (have&AREAD))
597 *got |= Nfs3AccessRead;
598 if((want&Nfs3AccessLookup) && (ino.mode&IFMT)==IFDIR && (have&AEXEC))
599 *got |= Nfs3AccessLookup;
600 if((want&Nfs3AccessExecute) && (ino.mode&IFMT)!=IFDIR && (have&AEXEC))
601 *got |= Nfs3AccessExecute;
602
603 return ino2attr(fs, &ino, inum, attr);
604}
605
606static Nfs3Status
607ffslookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh)
608{
609 u32int nblock;
610 u32int i;
611 uchar *p, *ep;
612 Dirent *de;
613 Inode ino;
614 Block *b;
615 Ffs *fs;
616 Nfs3Status ok;
617 int len, want;
618
619 fs = fsys->priv;
620 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
621 return ok;
622
623 if((ino.mode&IFMT) != IFDIR)
624 return Nfs3ErrNotDir;
625
626 if((ok = inoperm(&ino, au, AEXEC)) != Nfs3Ok)
627 return ok;
628
629 len = strlen(name);
630 nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
631 for(i=0; i<nblock; i++){
632 if(i==nblock-1)
633 want = ino.size % fs->blocksize;
634 else
635 want = fs->blocksize;
636 b = ffsfileblock(fs, &ino, i, want);
637 if(b == nil)
638 continue;
639 p = b->data;
640 ep = p+b->len;
641 while(p < ep){
642 de = (Dirent*)p;
643 if(de->reclen == 0){
644 if(debug)
645 fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
646 break;
647 }
648 p += de->reclen;
649 if(p > ep){
650 if(debug)
651 fprint(2, "bad len %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
652 break;
653 }
654 if(de->ino == 0)
655 continue;
656 if(4+2+2+de->namlen > de->reclen){
657 if(debug)
658 fprint(2, "bad namelen %d at offset %d of %d\n", de->namlen, (int)(p-b->data), b->len);
659 break;
660 }
661 if(de->namlen == len && memcmp(de->name, name, len) == 0){
662 mkhandle(nh, de->ino);
663 blockput(b);
664 return Nfs3Ok;
665 }
666 }
667 blockput(b);
668 }
669 return Nfs3ErrNoEnt;
670}
671
672static Nfs3Status
673ffsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **pdata, u32int *pcount, u1int *peof)
674{
675 u32int nblock;
676 u32int i;
677 int off, done;
678 uchar *data, *dp, *dep, *p, *ep, *ndp;
679 Dirent *de;
680 Inode ino;
681 Block *b;
682 Ffs *fs;
683 Nfs3Status ok;
684 Nfs3Entry e;
685 int want;
686
687 fs = fsys->priv;
688 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
689 return ok;
690
691 if((ino.mode&IFMT) != IFDIR)
692 return Nfs3ErrNotDir;
693
694 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
695 return ok;
696
697 if(cookie >= ino.size){
698 *pcount = 0;
699 *pdata = 0;
700 return Nfs3Ok;
701 }
702
703 dp = malloc(count);
704 data = dp;
705 if(dp == nil)
706 return Nfs3ErrNoMem;
707 dep = dp+count;
708 *peof = 0;
709 nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
710 i = cookie/fs->blocksize;
711 off = cookie%fs->blocksize;
712 done = 0;
713 for(; i<nblock && !done; i++){
714 if(i==nblock-1)
715 want = ino.size % fs->blocksize;
716 else
717 want = fs->blocksize;
718 b = ffsfileblock(fs, &ino, i, want);
719 if(b == nil)
720 continue;
721 p = b->data;
722 ep = p+b->len;
723 memset(&e, 0, sizeof e);
724 while(p < ep){
725 de = (Dirent*)p;
726 if(de->reclen == 0){
727 if(debug) fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
728 break;
729 }
730 p += de->reclen;
731 if(p > ep){
732 if(debug) fprint(2, "reclen %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
733 break;
734 }
735 if(de->ino == 0){
736 if(debug) fprint(2, "zero inode\n");
737 continue;
738 }
739 if(4+2+2+de->namlen > de->reclen){
740 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);
741 break;
742 }
743 if(de->name[de->namlen] != 0){
744 if(debug) fprint(2, "bad name %d %.*s\n", de->namlen, de->namlen, de->name);
745 continue;
746 }
747 if(debug) print("%s/%d ", de->name, (int)de->ino);
748 if((uchar*)de - b->data < off)
749 continue;
750 e.fileid = de->ino;
751 e.name = de->name;
rsc4e81d4f2006-05-09 18:35:24 +0000752 e.namelen = de->namlen;
rsc0c98da82005-07-13 03:48:35 +0000753 e.cookie = (u64int)i*fs->blocksize + (p - b->data);
754 if(nfs3entrypack(dp, dep, &ndp, &e) < 0){
755 done = 1;
756 break;
757 }
758 dp = ndp;
759 }
760 off = 0;
761 blockput(b);
762 }
763 if(i==nblock)
764 *peof = 1;
765
766 *pcount = dp - data;
767 *pdata = data;
768 return Nfs3Ok;
769}
770
rsc9f4a65a2005-07-28 05:16:42 +0000771static u64int
772ffsxfileblock(Fsys *fsys, Nfs3Handle *h, u64int offset)
773{
rsce060bc52005-08-11 16:45:39 +0000774 u64int bno;
rsc9f4a65a2005-07-28 05:16:42 +0000775 Inode ino;
776 Nfs3Status ok;
777 Ffs *fs;
778
779 fs = fsys->priv;
780 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok){
781 nfs3errstr(ok);
782 return 0;
783 }
rsce060bc52005-08-11 16:45:39 +0000784 if(offset == 1) /* clumsy hack for debugging */
785 return lastiaddr;
rsc9f4a65a2005-07-28 05:16:42 +0000786 if(offset >= ino.size){
787 werrstr("beyond end of file");
788 return 0;
789 }
790 bno = offset/fs->blocksize;
791 bno = ffsfileblockno(fs, &ino, bno);
792 if(bno == ~0)
793 return 0;
794 return bno*(u64int)fs->fragsize;
795}
796
rsc0c98da82005-07-13 03:48:35 +0000797static Nfs3Status
798ffsreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
799 u64int offset, uchar **pdata, u32int *pcount, u1int *peof)
800{
801 uchar *data;
802 Block *b;
803 Ffs *fs;
804 int off, want, fragcount;
805 Inode ino;
806 Nfs3Status ok;
807
808 fs = fsys->priv;
809 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
810 return ok;
811
812 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
813 return ok;
814
815 if(offset >= ino.size){
816 *pdata = 0;
817 *pcount = 0;
818 *peof = 1;
819 return Nfs3Ok;
820 }
821 if(offset+count > ino.size)
822 count = ino.size-offset;
823 if(offset/fs->blocksize != (offset+count-1)/fs->blocksize)
824 count = fs->blocksize - offset%fs->blocksize;
825
826 data = malloc(count);
827 if(data == nil)
828 return Nfs3ErrNoMem;
829
830 want = offset%fs->blocksize+count;
831 if(want%fs->fragsize)
832 want += fs->fragsize - want%fs->fragsize;
833
834 b = ffsfileblock(fs, &ino, offset/fs->blocksize, want);
835 if(b == nil){
836 /* BUG: distinguish sparse file from I/O error */
837 memset(data, 0, count);
838 }else{
839 off = offset%fs->blocksize;
840 fragcount = count; /* need signed variable */
841 if(off+fragcount > b->len){
842 fragcount = b->len - off;
843 if(fragcount < 0)
844 fragcount = 0;
845 }
846 if(fragcount > 0)
847 memmove(data, b->data+off, fragcount);
848 count = fragcount;
849 blockput(b);
850 }
851 *peof = (offset+count == ino.size);
852 *pcount = count;
853 *pdata = data;
854 return Nfs3Ok;
855}
856
857static Nfs3Status
858ffsreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link)
859{
860 Ffs *fs;
861 Nfs3Status ok;
862 int len;
863 Inode ino;
864 Block *b;
865
866 fs = fsys->priv;
867 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
868 return ok;
869 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
870 return ok;
871
872 if(ino.size > 1024)
873 return Nfs3ErrIo;
874 len = ino.size;
875
876 if(ino.nblock != 0){
rsce060bc52005-08-11 16:45:39 +0000877 /* assumes symlink fits in one block */
rsc0c98da82005-07-13 03:48:35 +0000878 b = ffsfileblock(fs, &ino, 0, len);
879 if(b == nil)
880 return Nfs3ErrIo;
881 if(memchr(b->data, 0, len) != nil){
882 blockput(b);
883 return Nfs3ErrIo;
884 }
885 *link = malloc(len+1);
886 if(*link == 0){
887 blockput(b);
888 return Nfs3ErrNoMem;
889 }
890 memmove(*link, b->data, len);
891 (*link)[len] = 0;
892 blockput(b);
893 return Nfs3Ok;
894 }
895
896 if(len > sizeof ino.db + sizeof ino.ib)
897 return Nfs3ErrIo;
898
899 *link = malloc(len+1);
900 if(*link == 0)
901 return Nfs3ErrNoMem;
902 memmove(*link, ino.db, ino.size);
903 (*link)[len] = 0;
904 return Nfs3Ok;
905}