blob: 521296532119b5a16ff2511df26fcc9a97400320 [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 "ext2.h"
8
rsce77222a2006-05-04 18:02:13 +00009#define debug 0
rsc0c98da82005-07-13 03:48:35 +000010
11static int ext2sync(Fsys*);
12static void ext2close(Fsys*);
13static Block* ext2blockread(Fsys*, u64int);
14
15static Nfs3Status ext2root(Fsys*, Nfs3Handle*);
16static Nfs3Status ext2getattr(Fsys*, SunAuthUnix *au, Nfs3Handle*, Nfs3Attr*);
17static Nfs3Status ext2lookup(Fsys*, SunAuthUnix *au, Nfs3Handle*, char*, Nfs3Handle*);
18static Nfs3Status ext2readfile(Fsys*, SunAuthUnix *au, Nfs3Handle*, u32int, u64int, uchar**, u32int*, u1int*);
19static Nfs3Status ext2readlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link);
20static Nfs3Status ext2readdir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int, u64int, uchar**, u32int*, u1int*);
21static Nfs3Status ext2access(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr);
22
23Fsys*
24fsysopenext2(Disk *disk)
25{
26 Ext2 *fs;
27 Fsys *fsys;
28
29 fsys = emalloc(sizeof(Fsys));
30 fs = emalloc(sizeof(Ext2));
31 fs->disk = disk;
32 fsys->priv = fs;
33 fs->fsys = fsys;
34 fsys->type = "ext2";
35 fsys->_readblock = ext2blockread;
36 fsys->_sync = ext2sync;
37 fsys->_root = ext2root;
38 fsys->_getattr = ext2getattr;
39 fsys->_access = ext2access;
40 fsys->_lookup = ext2lookup;
41 fsys->_readfile = ext2readfile;
42 fsys->_readlink = ext2readlink;
43 fsys->_readdir = ext2readdir;
rsca51dffd2006-11-20 23:11:45 +000044 fsys->_close = ext2close;
rsc0c98da82005-07-13 03:48:35 +000045
46 if(ext2sync(fsys) < 0)
47 goto error;
48
49 return fsys;
50
51error:
52 ext2close(fsys);
53 return nil;
54}
55
56static void
57ext2close(Fsys *fsys)
58{
59 Ext2 *fs;
60
61 fs = fsys->priv;
62 free(fs);
63 free(fsys);
64}
65
66static Group*
67ext2group(Ext2 *fs, u32int i, Block **pb)
68{
69 Block *b;
70 u64int addr;
71 Group *g;
72
73 if(i >= fs->ngroup)
74 return nil;
75
76 addr = fs->groupaddr + i/fs->descperblock;
77 b = diskread(fs->disk, fs->blocksize, addr*fs->blocksize);
78 if(b == nil)
79 return nil;
80 g = (Group*)(b->data+i%fs->descperblock*GroupSize);
81 *pb = b;
82 return g;
83}
84
85static Block*
86ext2blockread(Fsys *fsys, u64int vbno)
87{
88 Block *bitb;
89 Group *g;
90 Block *gb;
91 uchar *bits;
rscc1a45922006-06-15 05:16:59 +000092 u32int bno, boff, bitblock;
93 u64int bitpos;
rsc0c98da82005-07-13 03:48:35 +000094 Ext2 *fs;
95
96 fs = fsys->priv;
97 if(vbno >= fs->nblock)
98 return nil;
99 bno = vbno;
100 if(bno != vbno)
101 return nil;
102
103/*
104 if(bno < fs->firstblock)
105 return diskread(fs->disk, fs->blocksize, (u64int)bno*fs->blocksize);
106*/
107 if(bno < fs->firstblock)
108 return nil;
109
110 bno -= fs->firstblock;
111 if((g = ext2group(fs, bno/fs->blockspergroup, &gb)) == nil){
112 if(debug)
113 fprint(2, "loading group: %r...");
114 return nil;
115 }
rsce77222a2006-05-04 18:02:13 +0000116/*
117 if(debug)
rscc1a45922006-06-15 05:16:59 +0000118 fprint(2, "ext2 group %d: bitblock=%ud inodebitblock=%ud inodeaddr=%ud freeblocks=%ud freeinodes=%ud useddirs=%ud\n",
119 (int)(bno/fs->blockspergroup),
120 g->bitblock,
121 g->inodebitblock,
122 g->inodeaddr,
123 g->freeblockscount,
124 g->freeinodescount,
125 g->useddirscount);
126 if(debug)
rsce77222a2006-05-04 18:02:13 +0000127 fprint(2, "group %d bitblock=%d...", bno/fs->blockspergroup, g->bitblock);
128*/
rscc1a45922006-06-15 05:16:59 +0000129 bitblock = g->bitblock;
130 bitpos = (u64int)bitblock*fs->blocksize;
rsc9bbcb802006-06-15 04:35:57 +0000131 blockput(gb);
rsc0c98da82005-07-13 03:48:35 +0000132
rsc9bbcb802006-06-15 04:35:57 +0000133 if((bitb = diskread(fs->disk, fs->blocksize, bitpos)) == nil){
rsc0c98da82005-07-13 03:48:35 +0000134 if(debug)
135 fprint(2, "loading bitblock: %r...");
rsc0c98da82005-07-13 03:48:35 +0000136 return nil;
137 }
138 bits = bitb->data;
139 boff = bno%fs->blockspergroup;
140 if((bits[boff>>3] & (1<<(boff&7))) == 0){
141 if(debug)
rscc1a45922006-06-15 05:16:59 +0000142 fprint(2, "block %d not allocated in group %d: bitblock %d/%lld bits[%d] = %#x\n",
143 boff, bno/fs->blockspergroup,
144 (int)bitblock,
145 bitpos,
146 boff>>3,
147 bits[boff>>3]);
rsc0c98da82005-07-13 03:48:35 +0000148 blockput(bitb);
rsc0c98da82005-07-13 03:48:35 +0000149 return nil;
150 }
rsc9bbcb802006-06-15 04:35:57 +0000151 blockput(bitb);
rsc0c98da82005-07-13 03:48:35 +0000152
153 bno += fs->firstblock;
154 return diskread(fs->disk, fs->blocksize, (u64int)bno*fs->blocksize);
155}
156
157static Block*
158ext2datablock(Ext2 *fs, u32int bno, int size)
159{
rsc3330e5b2005-10-29 17:41:35 +0000160 USED(size);
rsce77222a2006-05-04 18:02:13 +0000161 return ext2blockread(fs->fsys, bno);
rsc0c98da82005-07-13 03:48:35 +0000162}
163
164static Block*
165ext2fileblock(Ext2 *fs, Inode *ino, u32int bno, int size)
166{
167 int ppb;
168 Block *b;
169 u32int *a;
rscb1090492007-03-25 17:35:08 +0000170 u32int obno, pbno;
rsc0c98da82005-07-13 03:48:35 +0000171
172 obno = bno;
173 if(bno < NDIRBLOCKS){
174 if(debug)
175 fprint(2, "fileblock %d -> %d...",
176 bno, ino->block[bno]);
177 return ext2datablock(fs, ino->block[bno], size);
178 }
179 bno -= NDIRBLOCKS;
180 ppb = fs->blocksize/4;
181
182 /* one indirect */
183 if(bno < ppb){
184 b = ext2datablock(fs, ino->block[INDBLOCK], fs->blocksize);
185 if(b == nil)
186 return nil;
187 a = (u32int*)b->data;
rscb1090492007-03-25 17:35:08 +0000188 bno = a[bno];
rsc0c98da82005-07-13 03:48:35 +0000189 blockput(b);
190 return ext2datablock(fs, bno, size);
191 }
192 bno -= ppb;
193
194 /* one double indirect */
195 if(bno < ppb*ppb){
196 b = ext2datablock(fs, ino->block[DINDBLOCK], fs->blocksize);
197 if(b == nil)
198 return nil;
199 a = (u32int*)b->data;
rscb1090492007-03-25 17:35:08 +0000200 pbno = a[bno/ppb];
201 bno = bno%ppb;
rsc0c98da82005-07-13 03:48:35 +0000202 blockput(b);
rscb1090492007-03-25 17:35:08 +0000203 b = ext2datablock(fs, pbno, fs->blocksize);
rsc0c98da82005-07-13 03:48:35 +0000204 if(b == nil)
205 return nil;
206 a = (u32int*)b->data;
rscb1090492007-03-25 17:35:08 +0000207 bno = a[bno];
rsc0c98da82005-07-13 03:48:35 +0000208 blockput(b);
209 return ext2datablock(fs, bno, size);
210 }
211 bno -= ppb*ppb;
212
213 /* one triple indirect */
214 if(bno < ppb*ppb*ppb){
215 b = ext2datablock(fs, ino->block[TINDBLOCK], fs->blocksize);
216 if(b == nil)
217 return nil;
218 a = (u32int*)b->data;
rscb1090492007-03-25 17:35:08 +0000219 pbno = a[bno/(ppb*ppb)];
220 bno = bno%(ppb*ppb);
rsc0c98da82005-07-13 03:48:35 +0000221 blockput(b);
rscb1090492007-03-25 17:35:08 +0000222 b = ext2datablock(fs, pbno, fs->blocksize);
rsc0c98da82005-07-13 03:48:35 +0000223 if(b == nil)
224 return nil;
225 a = (u32int*)b->data;
rscb1090492007-03-25 17:35:08 +0000226 pbno = a[bno/ppb];
227 bno = bno%ppb;
rsc0c98da82005-07-13 03:48:35 +0000228 blockput(b);
rscb1090492007-03-25 17:35:08 +0000229 b = ext2datablock(fs, pbno, fs->blocksize);
rsc0c98da82005-07-13 03:48:35 +0000230 if(b == nil)
231 return nil;
232 a = (u32int*)b->data;
rscb1090492007-03-25 17:35:08 +0000233 bno = a[bno];
rsc0c98da82005-07-13 03:48:35 +0000234 blockput(b);
235 return ext2datablock(fs, bno, size);
236 }
237
rsc3330e5b2005-10-29 17:41:35 +0000238 fprint(2, "ext2fileblock %ud: too big\n", obno);
rsc0c98da82005-07-13 03:48:35 +0000239 return nil;
240}
241
242static int
243checksuper(Super *super)
244{
245 if(super->magic != SUPERMAGIC){
246 werrstr("bad magic 0x%ux wanted 0x%ux", super->magic, SUPERMAGIC);
247 return -1;
248 }
249 return 0;
250}
251
252static int
253ext2sync(Fsys *fsys)
254{
255 int i;
256 Group *g;
257 Block *b;
258 Super *super;
259 Ext2 *fs;
260 Disk *disk;
261
262 fs = fsys->priv;
263 disk = fs->disk;
264 if((b = diskread(disk, SBSIZE, SBOFF)) == nil)
265 goto error;
266 super = (Super*)b->data;
267 if(checksuper(super) < 0)
268 goto error;
269 fs->blocksize = MINBLOCKSIZE<<super->logblocksize;
270 fs->nblock = super->nblock;
271 fs->ngroup = (super->nblock+super->blockspergroup-1)
272 / super->blockspergroup;
273 fs->inospergroup = super->inospergroup;
274 fs->blockspergroup = super->blockspergroup;
275 fs->inosperblock = fs->blocksize / InodeSize;
276 if(fs->blocksize == SBOFF)
277 fs->groupaddr = 2;
278 else
279 fs->groupaddr = 1;
280 fs->descperblock = fs->blocksize / GroupSize;
281 fs->firstblock = super->firstdatablock;
282 blockput(b);
283
284 fsys->blocksize = fs->blocksize;
285 fsys->nblock = fs->nblock;
rsc27c1d3a2007-05-28 17:22:28 +0000286 if(debug) fprint(2, "ext2 %d %d-byte blocks, first data block %d, %d groups of %d\n",
rsc0c98da82005-07-13 03:48:35 +0000287 fs->nblock, fs->blocksize, fs->firstblock, fs->ngroup, fs->blockspergroup);
288
289 if(0){
290 for(i=0; i<fs->ngroup; i++)
291 if((g = ext2group(fs, i, &b)) != nil){
292 fprint(2, "grp %d: bitblock=%d\n", i, g->bitblock);
293 blockput(b);
294 }
295 }
296 return 0;
297
298error:
299 blockput(b);
300 return -1;
301}
302
303static void
304mkhandle(Nfs3Handle *h, u64int ino)
305{
306 h->h[0] = ino>>24;
307 h->h[1] = ino>>16;
308 h->h[2] = ino>>8;
309 h->h[3] = ino;
310 h->len = 4;
311}
312
313static u32int
314byte2u32(uchar *p)
315{
316 return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
317}
318
319static Nfs3Status
320handle2ino(Ext2 *fs, Nfs3Handle *h, u32int *pinum, Inode *ino)
321{
322 int i;
323 uint ioff;
324 u32int inum;
325 u32int addr;
326 Block *gb, *b;
327 Group *g;
328
329 if(h->len != 4)
330 return Nfs3ErrBadHandle;
331 inum = byte2u32(h->h);
332 if(pinum)
333 *pinum = inum;
334 i = (inum-1) / fs->inospergroup;
335 if(i >= fs->ngroup)
336 return Nfs3ErrBadHandle;
337 ioff = (inum-1) % fs->inospergroup;
338 if((g = ext2group(fs, i, &gb)) == nil)
339 return Nfs3ErrIo;
340 addr = g->inodeaddr + ioff/fs->inosperblock;
341 blockput(gb);
342 if((b = diskread(fs->disk, fs->blocksize, (u64int)addr*fs->blocksize)) == nil)
343 return Nfs3ErrIo;
344 *ino = ((Inode*)b->data)[ioff%fs->inosperblock];
345 blockput(b);
346 return Nfs3Ok;
347}
348
349static Nfs3Status
350ext2root(Fsys *fsys, Nfs3Handle *h)
351{
rsc3330e5b2005-10-29 17:41:35 +0000352 USED(fsys);
rsc0c98da82005-07-13 03:48:35 +0000353 mkhandle(h, ROOTINODE);
354 return Nfs3Ok;
355}
356
rscb1090492007-03-25 17:35:08 +0000357static u64int
358inosize(Inode* ino)
359{
360 u64int size;
361
362 size = ino->size;
363 if((ino->mode&IFMT)==IFREG)
364 size |= (u64int)ino->diracl << 32;
365 return size;
366}
367
rsc0c98da82005-07-13 03:48:35 +0000368static Nfs3Status
369ino2attr(Ext2 *fs, Inode *ino, u32int inum, Nfs3Attr *attr)
370{
371 u32int rdev;
372
373 attr->type = -1;
374 switch(ino->mode&IFMT){
375 case IFIFO:
376 attr->type = Nfs3FileFifo;
377 break;
378 case IFCHR:
379 attr->type = Nfs3FileChar;
380 break;
381 case IFDIR:
382 attr->type = Nfs3FileDir;
383 break;
384 case IFBLK:
385 attr->type = Nfs3FileBlock;
386 break;
387 case IFREG:
388 attr->type = Nfs3FileReg;
389 break;
390 case IFLNK:
391 attr->type = Nfs3FileSymlink;
392 break;
393 case IFSOCK:
394 attr->type = Nfs3FileSocket;
395 break;
396 case IFWHT:
397 default:
398 return Nfs3ErrBadHandle;
399 }
400
401 attr->mode = ino->mode&07777;
402 attr->nlink = ino->nlink;
403 attr->uid = ino->uid;
404 attr->gid = ino->gid;
rscb1090492007-03-25 17:35:08 +0000405 attr->size = inosize(ino);
406 attr->used = (u64int)ino->nblock*fs->blocksize;
rsc0c98da82005-07-13 03:48:35 +0000407 if(attr->type==Nfs3FileBlock || attr->type==Nfs3FileChar){
408 rdev = ino->block[0];
409 attr->major = (rdev>>8)&0xFF;
410 attr->minor = rdev & 0xFFFF00FF;
411 }else{
412 attr->major = 0;
413 attr->minor = 0;
414 }
415 attr->fsid = 0;
416 attr->fileid = inum;
417 attr->atime.sec = ino->atime;
418 attr->atime.nsec = 0;
419 attr->mtime.sec = ino->mtime;
420 attr->mtime.nsec = 0;
421 attr->ctime.sec = ino->ctime;
422 attr->ctime.nsec = 0;
423 return Nfs3Ok;
424}
425
426static int
427ingroup(SunAuthUnix *au, uint gid)
428{
429 int i;
430
431 for(i=0; i<au->ng; i++)
432 if(au->g[i] == gid)
433 return 1;
434 return 0;
435}
436
437static Nfs3Status
438inoperm(Inode *ino, SunAuthUnix *au, int need)
439{
440 int have;
441
442 if(allowall)
443 return Nfs3Ok;
444
445 have = ino->mode&0777;
446 if(ino->uid == au->uid)
447 have >>= 6;
448 else if(ino->gid == au->gid || ingroup(au, ino->gid))
449 have >>= 3;
450
451 if((have&need) != need)
452 return Nfs3ErrNotOwner; /* really EPERM */
453 return Nfs3Ok;
454}
455
456static Nfs3Status
457ext2getattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr)
458{
459 Inode ino;
460 u32int inum;
461 Ext2 *fs;
462 Nfs3Status ok;
463
464 fs = fsys->priv;
465 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
466 return ok;
467
468 USED(au); /* anyone can getattr */
469 return ino2attr(fs, &ino, inum, attr);
470}
471
472static Nfs3Status
473ext2access(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr)
474{
475 int have;
476 Inode ino;
477 u32int inum;
478 Ext2 *fs;
479 Nfs3Status ok;
480
481 fs = fsys->priv;
482 if((ok = handle2ino(fs, h, &inum, &ino)) != Nfs3Ok)
483 return ok;
484
485 have = ino.mode&0777;
486 if(ino.uid == au->uid)
487 have >>= 6;
488 else if(ino.gid == au->gid || ingroup(au, ino.gid))
489 have >>= 3;
490
491 *got = 0;
492 if((want&Nfs3AccessRead) && (have&AREAD))
493 *got |= Nfs3AccessRead;
494 if((want&Nfs3AccessLookup) && (ino.mode&IFMT)==IFDIR && (have&AEXEC))
495 *got |= Nfs3AccessLookup;
496 if((want&Nfs3AccessExecute) && (ino.mode&IFMT)!=IFDIR && (have&AEXEC))
497 *got |= Nfs3AccessExecute;
498
499 return ino2attr(fs, &ino, inum, attr);
500}
501
502static Nfs3Status
503ext2lookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh)
504{
505 u32int nblock;
506 u32int i;
507 uchar *p, *ep;
508 Dirent *de;
509 Inode ino;
510 Block *b;
511 Ext2 *fs;
512 Nfs3Status ok;
513 int len, want;
514
515 fs = fsys->priv;
516 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
517 return ok;
518
519 if((ino.mode&IFMT) != IFDIR)
520 return Nfs3ErrNotDir;
521
522 if((ok = inoperm(&ino, au, AEXEC)) != Nfs3Ok)
523 return ok;
524
525 len = strlen(name);
526 nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
527 if(debug) fprint(2, "%d blocks in dir...", nblock);
528 for(i=0; i<nblock; i++){
529 if(i==nblock-1)
530 want = ino.size % fs->blocksize;
531 else
532 want = fs->blocksize;
533 b = ext2fileblock(fs, &ino, i, want);
534 if(b == nil){
535 if(debug) fprint(2, "empty block...");
536 continue;
537 }
538 p = b->data;
539 ep = p+b->len;
540 while(p < ep){
541 de = (Dirent*)p;
542 if(de->reclen == 0){
543 if(debug)
544 fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
545 break;
546 }
547 p += de->reclen;
548 if(p > ep){
549 if(debug)
550 fprint(2, "bad len %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
551 break;
552 }
553 if(de->ino == 0)
554 continue;
555 if(4+2+2+de->namlen > de->reclen){
556 if(debug)
557 fprint(2, "bad namelen %d at offset %d of %d\n", de->namlen, (int)(p-b->data), b->len);
558 break;
559 }
560 if(de->namlen == len && memcmp(de->name, name, len) == 0){
561 mkhandle(nh, de->ino);
562 blockput(b);
563 return Nfs3Ok;
564 }
565 }
566 blockput(b);
567 }
568 return Nfs3ErrNoEnt;
569}
570
571static Nfs3Status
572ext2readdir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **pdata, u32int *pcount, u1int *peof)
573{
574 u32int nblock;
575 u32int i;
576 int off, done;
577 uchar *data, *dp, *dep, *p, *ep, *ndp;
578 Dirent *de;
579 Inode ino;
580 Block *b;
581 Ext2 *fs;
582 Nfs3Status ok;
583 Nfs3Entry e;
584 int want;
585
586 fs = fsys->priv;
587 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
588 return ok;
589
590 if((ino.mode&IFMT) != IFDIR)
591 return Nfs3ErrNotDir;
592
593 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
594 return ok;
595
596 if(cookie >= ino.size){
rsc63408c32007-06-08 14:29:39 +0000597 *peof = 1;
rsc0c98da82005-07-13 03:48:35 +0000598 *pcount = 0;
599 *pdata = 0;
600 return Nfs3Ok;
601 }
602
603 dp = malloc(count);
604 data = dp;
605 if(dp == nil)
606 return Nfs3ErrNoMem;
607 dep = dp+count;
608 *peof = 0;
609 nblock = (ino.size+fs->blocksize-1) / fs->blocksize;
610 i = cookie/fs->blocksize;
611 off = cookie%fs->blocksize;
612 done = 0;
613 for(; i<nblock && !done; i++){
614 if(i==nblock-1)
615 want = ino.size % fs->blocksize;
616 else
617 want = fs->blocksize;
618 b = ext2fileblock(fs, &ino, i, want);
619 if(b == nil)
620 continue;
621 p = b->data;
622 ep = p+b->len;
623 memset(&e, 0, sizeof e);
624 while(p < ep){
625 de = (Dirent*)p;
626 if(de->reclen == 0){
627 if(debug) fprint(2, "reclen 0 at offset %d of %d\n", (int)(p-b->data), b->len);
628 break;
629 }
630 p += de->reclen;
631 if(p > ep){
632 if(debug) fprint(2, "reclen %d at offset %d of %d\n", de->reclen, (int)(p-b->data), b->len);
633 break;
634 }
635 if(de->ino == 0){
636 if(debug) fprint(2, "zero inode\n");
637 continue;
638 }
639 if(4+2+2+de->namlen > de->reclen){
640 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);
641 break;
642 }
rsce77222a2006-05-04 18:02:13 +0000643 if(debug) print("%.*s/%d ", de->namlen, de->name, (int)de->ino);
rsc0c98da82005-07-13 03:48:35 +0000644 if((uchar*)de - b->data < off)
645 continue;
646 e.fileid = de->ino;
647 e.name = de->name;
rsce77222a2006-05-04 18:02:13 +0000648 e.namelen = de->namlen;
rsc0c98da82005-07-13 03:48:35 +0000649 e.cookie = (u64int)i*fs->blocksize + (p - b->data);
650 if(nfs3entrypack(dp, dep, &ndp, &e) < 0){
651 done = 1;
652 break;
653 }
654 dp = ndp;
655 }
656 off = 0;
657 blockput(b);
658 }
659 if(i==nblock)
660 *peof = 1;
661
662 *pcount = dp - data;
663 *pdata = data;
664 return Nfs3Ok;
665}
666
667static Nfs3Status
668ext2readfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
669 u64int offset, uchar **pdata, u32int *pcount, u1int *peof)
670{
671 uchar *data;
672 Block *b;
673 Ext2 *fs;
rscfa5af682006-06-15 05:52:24 +0000674 int skip1, tot, want, fragcount;
rsc0c98da82005-07-13 03:48:35 +0000675 Inode ino;
676 Nfs3Status ok;
rscb1090492007-03-25 17:35:08 +0000677 u64int size;
rsc0c98da82005-07-13 03:48:35 +0000678
679 fs = fsys->priv;
680 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
681 return ok;
682
683 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
684 return ok;
685
rscb1090492007-03-25 17:35:08 +0000686 size = inosize(&ino);
687 if(offset >= size){
rsc0c98da82005-07-13 03:48:35 +0000688 *pdata = 0;
689 *pcount = 0;
690 *peof = 1;
691 return Nfs3Ok;
692 }
rscb1090492007-03-25 17:35:08 +0000693 if(offset+count > size)
694 count = size-offset;
rsc0c98da82005-07-13 03:48:35 +0000695
696 data = malloc(count);
697 if(data == nil)
698 return Nfs3ErrNoMem;
rscfa5af682006-06-15 05:52:24 +0000699 memset(data, 0, count);
rsc0c98da82005-07-13 03:48:35 +0000700
rscfa5af682006-06-15 05:52:24 +0000701 skip1 = offset%fs->blocksize;
702 offset -= skip1;
703 want = skip1+count;
rsc0c98da82005-07-13 03:48:35 +0000704
rscfa5af682006-06-15 05:52:24 +0000705 /*
706 * have to read multiple blocks if we get asked for a big read.
707 * Linux NFS client assumes that if you ask for 8k and only get 4k
708 * back, the remaining 4k is zeros.
709 */
710 for(tot=0; tot<want; tot+=fragcount){
711 b = ext2fileblock(fs, &ino, (offset+tot)/fs->blocksize, fs->blocksize);
712 fragcount = fs->blocksize;
713 if(b == nil)
714 continue;
715 if(tot+fragcount > want)
716 fragcount = want - tot;
717 if(tot == 0)
718 memmove(data, b->data+skip1, fragcount-skip1);
719 else
720 memmove(data+tot-skip1, b->data, fragcount);
rsc0c98da82005-07-13 03:48:35 +0000721 blockput(b);
722 }
rscfa5af682006-06-15 05:52:24 +0000723 count = tot - skip1;
724
rscb1090492007-03-25 17:35:08 +0000725 *peof = (offset+count == size);
rsc0c98da82005-07-13 03:48:35 +0000726 *pcount = count;
727 *pdata = data;
728 return Nfs3Ok;
729}
730
731static Nfs3Status
732ext2readlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link)
733{
734 Ext2 *fs;
735 Nfs3Status ok;
736 int len;
737 Inode ino;
738 Block *b;
739
740 fs = fsys->priv;
741 if((ok = handle2ino(fs, h, nil, &ino)) != Nfs3Ok)
742 return ok;
743 if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
744 return ok;
745
746 if(ino.size > 1024)
747 return Nfs3ErrIo;
748 len = ino.size;
749
750 if(ino.nblock != 0){
751 /* BUG: assumes symlink fits in one block */
752 b = ext2fileblock(fs, &ino, 0, len);
753 if(b == nil)
754 return Nfs3ErrIo;
755 if(memchr(b->data, 0, len) != nil){
756 blockput(b);
757 return Nfs3ErrIo;
758 }
759 *link = malloc(len+1);
760 if(*link == 0){
761 blockput(b);
762 return Nfs3ErrNoMem;
763 }
764 memmove(*link, b->data, len);
765 (*link)[len] = 0;
766 blockput(b);
767 return Nfs3Ok;
768 }
769
770 if(len > sizeof ino.block)
771 return Nfs3ErrIo;
772
773 *link = malloc(len+1);
774 if(*link == 0)
775 return Nfs3ErrNoMem;
776 memmove(*link, ino.block, ino.size);
777 (*link)[len] = 0;
778 return Nfs3Ok;
779}
780