1 /*
2 * ext2subs.c version 0.20
3 *
4 * Some strategic functions come from linux/fs/ext2
5 * kernel sources written by Remy Card.
6 *
7 */
8
9 #include <u.h>
10 #include <libc.h>
11 #include <bio.h>
12 #include <fcall.h>
13 #include <thread.h>
14 #include <9p.h>
15 #include "dat.h"
16 #include "fns.h"
17
18 #define putext2(e) putbuf((e).buf)
19 #define dirtyext2(e) dirtybuf((e).buf)
20
21 static Intmap *uidmap, *gidmap;
22
23 static int
getnum(char * s,int * n)24 getnum(char *s, int *n)
25 {
26 char *r;
27
28 *n = strtol(s, &r, 10);
29 return (r != s);
30 }
31
32 static Intmap*
idfile(char * f)33 idfile(char *f)
34 {
35 Biobuf *bin;
36 Intmap *map;
37 char *fields[3];
38 char *s;
39 int nf, id;
40
41 map = allocmap(0);
42 bin = Bopen(f, OREAD);
43 if (bin == 0)
44 return 0;
45 while ((s = Brdline(bin, '\n')) != 0) {
46 s[Blinelen(bin)-1] = '\0';
47 nf = getfields(s, fields, 3, 0, ":");
48 if (nf == 3 && getnum(fields[2], &id))
49 insertkey(map, id, strdup(fields[0]));
50 }
51 Bterm(bin);
52 return map;
53 }
54
55 void
uidfile(char * f)56 uidfile(char *f)
57 {
58 uidmap = idfile(f);
59 }
60
61 void
gidfile(char * f)62 gidfile(char *f)
63 {
64 gidmap = idfile(f);
65 }
66
67 static char*
mapuid(int id)68 mapuid(int id)
69 {
70 static char s[12];
71 char *p;
72
73 if (uidmap && (p = lookupkey(uidmap, id)) != 0)
74 return p;
75 sprint(s, "%d", id);
76 return s;
77 }
78
79 static char*
mapgid(int id)80 mapgid(int id)
81 {
82 static char s[12];
83 char *p;
84
85 if (gidmap && (p = lookupkey(gidmap, id)) != 0)
86 return p;
87 sprint(s, "%d", id);
88 return s;
89 }
90
91 int
ext2fs(Xfs * xf)92 ext2fs(Xfs *xf)
93 {
94 SuperBlock superblock;
95
96 /* get the super block */
97 seek(xf->dev, OFFSET_SUPER_BLOCK, 0);
98 if( sizeof(SuperBlock) !=
99 read(xf->dev, &superblock, sizeof(SuperBlock)) ){
100 chat("can't read super block %r...", xf->dev);
101 errno = Eformat;
102 return -1;
103 }
104 if( superblock.s_magic != EXT2_SUPER_MAGIC ){
105 chat("Bad super block...");
106 errno = Eformat;
107 return -1;
108 }
109 if( !(superblock.s_state & EXT2_VALID_FS) ){
110 chat("fs not checked...");
111 errno = Enotclean;
112 return -1;
113 }
114
115 xf->block_size = EXT2_MIN_BLOCK_SIZE << superblock.s_log_block_size;
116 xf->desc_per_block = xf->block_size / sizeof (GroupDesc);
117 xf->inodes_per_group = superblock.s_inodes_per_group;
118 xf->inodes_per_block = xf->block_size / sizeof (Inode);
119 xf->addr_per_block = xf->block_size / sizeof (uint);
120 xf->blocks_per_group = superblock.s_blocks_per_group;
121
122 if( xf->block_size == OFFSET_SUPER_BLOCK )
123 xf->superaddr = 1, xf->superoff = 0, xf->grpaddr = 2;
124 else if( xf->block_size == 2*OFFSET_SUPER_BLOCK ||
125 xf->block_size == 4*OFFSET_SUPER_BLOCK )
126 xf->superaddr = 0, xf->superoff = OFFSET_SUPER_BLOCK, xf->grpaddr = 1;
127 else {
128 chat(" blocks of %d bytes are not supported...", xf->block_size);
129 errno = Eformat;
130 return -1;
131 }
132
133 chat("good super block...");
134
135 xf->ngroups = (superblock.s_blocks_count -
136 superblock.s_first_data_block +
137 superblock.s_blocks_per_group -1) /
138 superblock.s_blocks_per_group;
139
140 superblock.s_state &= ~EXT2_VALID_FS;
141 superblock.s_mnt_count++;
142 seek(xf->dev, OFFSET_SUPER_BLOCK, 0);
143 if( !rdonly && sizeof(SuperBlock) !=
144 write(xf->dev, &superblock, sizeof(SuperBlock)) ){
145 chat("can't write super block...");
146 errno = Eio;
147 return -1;
148 }
149
150 return 0;
151 }
152 Ext2
getext2(Xfs * xf,char type,int n)153 getext2(Xfs *xf, char type, int n)
154 {
155 Iobuf *bd;
156 Ext2 e;
157
158 switch(type){
159 case EXT2_SUPER:
160 e.buf = getbuf(xf, xf->superaddr);
161 if( !e.buf ) goto error;
162 e.u.sb = (SuperBlock *)(e.buf->iobuf + xf->superoff);
163 e.type = EXT2_SUPER;
164 break;
165 case EXT2_DESC:
166 e.buf = getbuf(xf, DESC_ADDR(xf, n));
167 if( !e.buf ) goto error;
168 e.u.gd = DESC_OFFSET(xf, e.buf->iobuf, n);
169 e.type = EXT2_DESC;
170 break;
171 case EXT2_BBLOCK:
172 bd = getbuf(xf, DESC_ADDR(xf, n));
173 if( !bd ) goto error;
174 e.buf = getbuf(xf, DESC_OFFSET(xf, bd->iobuf, n)->bg_block_bitmap);
175 if( !e.buf ){
176 putbuf(bd);
177 goto error;
178 }
179 putbuf(bd);
180 e.u.bmp = (char *)e.buf->iobuf;
181 e.type = EXT2_BBLOCK;
182 break;
183 case EXT2_BINODE:
184 bd = getbuf(xf, DESC_ADDR(xf, n));
185 if( !bd ) goto error;
186 e.buf = getbuf(xf, DESC_OFFSET(xf, bd->iobuf, n)->bg_inode_bitmap);
187 if( !e.buf ){
188 putbuf(bd);
189 goto error;
190 }
191 putbuf(bd);
192 e.u.bmp = (char *)e.buf->iobuf;
193 e.type = EXT2_BINODE;
194 break;
195 default:
196 goto error;
197 }
198 return e;
199 error:
200 panic("getext2");
201 return e;
202 }
203 int
get_inode(Xfile * file,uint nr)204 get_inode( Xfile *file, uint nr )
205 {
206 unsigned long block_group, block;
207 Xfs *xf = file->xf;
208 Ext2 ed, es;
209
210 es = getext2(xf, EXT2_SUPER, 0);
211 if(nr > es.u.sb->s_inodes_count ){
212 chat("inode number %d is too big...", nr);
213 putext2(es);
214 errno = Eio;
215 return -1;
216 }
217 putext2(es);
218 block_group = (nr - 1) / xf->inodes_per_group;
219 if( block_group >= xf->ngroups ){
220 chat("block group (%d) > groups count...", block_group);
221 errno = Eio;
222 return -1;
223 }
224 ed = getext2(xf, EXT2_DESC, block_group);
225 block = ed.u.gd->bg_inode_table + (((nr-1) % xf->inodes_per_group) /
226 xf->inodes_per_block);
227 putext2(ed);
228
229 file->bufoffset = (nr-1) % xf->inodes_per_block;
230 file->inbr = nr;
231 file->bufaddr= block;
232
233 return 1;
234 }
235 int
get_file(Xfile * f,char * name)236 get_file( Xfile *f, char *name)
237 {
238 uint offset, nr, i;
239 Xfs *xf = f->xf;
240 Inode *inode;
241 int nblock;
242 DirEntry *dir;
243 Iobuf *buf, *ibuf;
244
245 if( !S_ISDIR(getmode(f)) )
246 return -1;
247 ibuf = getbuf(xf, f->bufaddr);
248 if( !ibuf )
249 return -1;
250 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
251 nblock = (inode->i_blocks * 512) / xf->block_size;
252
253 for(i=0 ; (i < nblock) && (i < EXT2_NDIR_BLOCKS) ; i++){
254 buf = getbuf(xf, inode->i_block[i]);
255 if( !buf ){
256 putbuf(ibuf);
257 return -1;
258 }
259 for(offset=0 ; offset < xf->block_size ; ){
260 dir = (DirEntry *)(buf->iobuf + offset);
261 if( dir->name_len==strlen(name) &&
262 !strncmp(name, dir->name, dir->name_len) ){
263 nr = dir->inode;
264 putbuf(buf);
265 putbuf(ibuf);
266 return nr;
267 }
268 offset += dir->rec_len;
269 }
270 putbuf(buf);
271
272 }
273 putbuf(ibuf);
274 errno = Enonexist;
275 return -1;
276 }
277 char *
getname(Xfile * f,char * str)278 getname(Xfile *f, char *str)
279 {
280 Xfile ft;
281 int offset, i, len;
282 Xfs *xf = f->xf;
283 Inode *inode;
284 int nblock;
285 DirEntry *dir;
286 Iobuf *buf, *ibuf;
287
288 ft = *f;
289 if( get_inode(&ft, f->pinbr) < 0 )
290 return 0;
291 if( !S_ISDIR(getmode(&ft)) )
292 return 0;
293 ibuf = getbuf(xf, ft.bufaddr);
294 if( !ibuf )
295 return 0;
296 inode = ((Inode *)ibuf->iobuf) + ft.bufoffset;
297 nblock = (inode->i_blocks * 512) / xf->block_size;
298
299 for(i=0 ; (i < nblock) && (i < EXT2_NDIR_BLOCKS) ; i++){
300 buf = getbuf(xf, inode->i_block[i]);
301 if( !buf ){
302 putbuf(ibuf);
303 return 0;
304 }
305 for(offset=0 ; offset < xf->block_size ; ){
306 dir = (DirEntry *)(buf->iobuf + offset);
307 if( f->inbr == dir->inode ){
308 len = (dir->name_len < EXT2_NAME_LEN) ? dir->name_len : EXT2_NAME_LEN;
309 if (str == 0)
310 str = malloc(len+1);
311 strncpy(str, dir->name, len);
312 str[len] = 0;
313 putbuf(buf);
314 putbuf(ibuf);
315 return str;
316 }
317 offset += dir->rec_len;
318 }
319 putbuf(buf);
320 }
321 putbuf(ibuf);
322 errno = Enonexist;
323 return 0;
324 }
325 void
dostat(Qid qid,Xfile * f,Dir * dir)326 dostat(Qid qid, Xfile *f, Dir *dir )
327 {
328 Inode *inode;
329 Iobuf *ibuf;
330 char *name;
331
332 memset(dir, 0, sizeof(Dir));
333
334 if( f->inbr == EXT2_ROOT_INODE ){
335 dir->name = estrdup9p("/");
336 dir->qid = (Qid){0,0,QTDIR};
337 dir->mode = DMDIR | 0777;
338 }else{
339 ibuf = getbuf(f->xf, f->bufaddr);
340 if( !ibuf )
341 return;
342 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
343 dir->length = inode->i_size;
344 dir->atime = inode->i_atime;
345 dir->mtime = inode->i_mtime;
346 putbuf(ibuf);
347 name = getname(f, 0);
348 dir->name = name;
349 dir->uid = estrdup9p(mapuid(inode->i_uid));
350 dir->gid = estrdup9p(mapgid(inode->i_gid));
351 dir->qid = qid;
352 dir->mode = getmode(f);
353 if( qid.type & QTDIR )
354 dir->mode |= DMDIR;
355 }
356
357 }
358 int
dowstat(Xfile * f,Dir * stat)359 dowstat(Xfile *f, Dir *stat)
360 {
361 Xfs *xf = f->xf;
362 Inode *inode;
363 Xfile fdir;
364 Iobuf *ibuf;
365 char name[EXT2_NAME_LEN+1];
366
367 /* change name */
368 getname(f, name);
369 if( stat->name && stat->name[0] != 0 && strcmp(name, stat->name) ){
370
371 /* get dir */
372 fdir = *f;
373 if( get_inode(&fdir, f->pinbr) < 0 ){
374 chat("can't get inode %d...", f->pinbr);
375 return -1;
376 }
377
378 ibuf = getbuf(xf, fdir.bufaddr);
379 if( !ibuf )
380 return -1;
381 inode = ((Inode *)ibuf->iobuf) +fdir.bufoffset;
382
383 /* Clean old dir entry */
384 if( delete_entry(xf, inode, f->inbr) < 0 ){
385 chat("delete entry failed...");
386 putbuf(ibuf);
387 return -1;
388 }
389 putbuf(ibuf);
390
391 /* add the new entry */
392 if( add_entry(&fdir, stat->name, f->inbr) < 0 ){
393 chat("add entry failed...");
394 return -1;
395 }
396
397 }
398
399 ibuf = getbuf(xf, f->bufaddr);
400 if( !ibuf )
401 return -1;
402 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
403
404 if (stat->mode != ~0)
405 if( (getmode(f) & 0777) != (stat->mode & 0777) ){
406 inode->i_mode = (getmode(f) & ~0777) | (stat->mode & 0777);
407 dirtybuf(ibuf);
408 }
409 if (stat->mtime != ~0)
410 if( inode->i_mtime != stat->mtime ){
411 inode->i_mtime = stat->mtime;
412 dirtybuf(ibuf);
413 }
414
415 putbuf(ibuf);
416
417 return 1;
418 }
419 long
readfile(Xfile * f,void * vbuf,vlong offset,long count)420 readfile(Xfile *f, void *vbuf, vlong offset, long count)
421 {
422 Xfs *xf = f->xf;
423 Inode *inode;
424 Iobuf *buffer, *ibuf;
425 long rcount;
426 int len, o, cur_block, baddr;
427 uchar *buf;
428
429 buf = vbuf;
430
431 ibuf = getbuf(xf, f->bufaddr);
432 if( !ibuf )
433 return -1;
434 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
435
436 if( offset >= inode->i_size ){
437 putbuf(ibuf);
438 return 0;
439 }
440 if( offset + count > inode->i_size )
441 count = inode->i_size - offset;
442
443 /* fast link */
444 if( S_ISLNK(getmode(f)) && (inode->i_size <= EXT2_N_BLOCKS<<2) ){
445 memcpy(&buf[0], ((char *)inode->i_block)+offset, count);
446 putbuf(ibuf);
447 return count;
448 }
449 chat("read block [ ");
450 cur_block = offset / xf->block_size;
451 o = offset % xf->block_size;
452 rcount = 0;
453 while( count > 0 ){
454 baddr = bmap(f, cur_block++);
455 if( !baddr ){
456 putbuf(ibuf);
457 return -1;
458 }
459 buffer = getbuf(xf, baddr);
460 if( !buffer ){
461 putbuf(ibuf);
462 return -1;
463 }
464 chat("%d ", baddr);
465 len = xf->block_size - o;
466 if( len > count )
467 len = count;
468 memcpy(&buf[rcount], &buffer->iobuf[o], len);
469 rcount += len;
470 count -= len;
471 o = 0;
472 putbuf(buffer);
473 }
474 chat("] ...");
475 inode->i_atime = time(0);
476 dirtybuf(ibuf);
477 putbuf(ibuf);
478 return rcount;
479 }
480 long
readdir(Xfile * f,void * vbuf,vlong offset,long count)481 readdir(Xfile *f, void *vbuf, vlong offset, long count)
482 {
483 int off, i, len;
484 long rcount;
485 Xfs *xf = f->xf;
486 Inode *inode, *tinode;
487 int nblock;
488 DirEntry *edir;
489 Iobuf *buffer, *ibuf, *tbuf;
490 Dir pdir;
491 Xfile ft;
492 uchar *buf;
493 char name[EXT2_NAME_LEN+1];
494 unsigned int dirlen;
495 int index;
496
497 buf = vbuf;
498 if (offset == 0)
499 f->dirindex = 0;
500
501 if( !S_ISDIR(getmode(f)) )
502 return -1;
503
504 ibuf = getbuf(xf, f->bufaddr);
505 if( !ibuf )
506 return -1;
507 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
508 nblock = (inode->i_blocks * 512) / xf->block_size;
509 ft = *f;
510 chat("read block [ ");
511 index = 0;
512 for(i=0, rcount=0 ; (i < nblock) && (i < EXT2_NDIR_BLOCKS) ; i++){
513
514 buffer = getbuf(xf, inode->i_block[i]);
515 if( !buffer ){
516 putbuf(ibuf);
517 return -1;
518 }
519 chat("%d, ", buffer->addr);
520 for(off=0 ; off < xf->block_size ; ){
521
522 edir = (DirEntry *)(buffer->iobuf + off);
523 off += edir->rec_len;
524 if( (edir->name[0] == '.' ) && (edir->name_len == 1))
525 continue;
526 if(edir->name[0] == '.' && edir->name[1] == '.' &&
527 edir->name_len == 2)
528 continue;
529 if( edir->inode == 0 ) /* for lost+found dir ... */
530 continue;
531 if( index++ < f->dirindex )
532 continue;
533
534 if( get_inode(&ft, edir->inode) < 0 ){
535 chat("can't find ino no %d ] ...", edir->inode);
536 error: putbuf(buffer);
537 putbuf(ibuf);
538 return -1;
539 }
540 tbuf = getbuf(xf, ft.bufaddr);
541 if( !tbuf )
542 goto error;
543 tinode = ((Inode *)tbuf->iobuf) + ft.bufoffset;
544
545 memset(&pdir, 0, sizeof(Dir));
546
547 /* fill plan9 dir struct */
548 pdir.name = name;
549 len = (edir->name_len < EXT2_NAME_LEN) ? edir->name_len : EXT2_NAME_LEN;
550 strncpy(pdir.name, edir->name, len);
551 pdir.name[len] = 0;
552 // chat("name %s len %d\n", pdir.name, edir->name_len);
553 pdir.uid = mapuid(tinode->i_uid);
554 pdir.gid = mapgid(tinode->i_gid);
555 pdir.qid.path = edir->inode;
556 pdir.mode = tinode->i_mode;
557 if( edir->inode == EXT2_ROOT_INODE )
558 pdir.qid.path = f->xf->rootqid.path;
559 else if( S_ISDIR( tinode->i_mode) )
560 pdir.qid.type |= QTDIR;
561 if( pdir.qid.type & QTDIR )
562 pdir.mode |= DMDIR;
563 pdir.length = tinode->i_size;
564 pdir.atime = tinode->i_atime;
565 pdir.mtime = tinode->i_mtime;
566
567 putbuf(tbuf);
568
569 dirlen = convD2M(&pdir, &buf[rcount], count-rcount);
570 if ( dirlen <= BIT16SZ ) {
571 chat("] ...");
572 putbuf(buffer);
573 putbuf(ibuf);
574 return rcount;
575 }
576 rcount += dirlen;
577 f->dirindex++;
578
579 }
580 putbuf(buffer);
581 }
582 chat("] ...");
583 putbuf(ibuf);
584 return rcount;
585 }
586 int
bmap(Xfile * f,int block)587 bmap( Xfile *f, int block )
588 {
589 Xfs *xf = f->xf;
590 Inode *inode;
591 Iobuf *buf, *ibuf;
592 int addr;
593 int addr_per_block = xf->addr_per_block;
594 int addr_per_block_bits = ffz(~addr_per_block);
595
596 if(block < 0) {
597 chat("bmap() block < 0 ...");
598 return 0;
599 }
600 if(block >= EXT2_NDIR_BLOCKS + addr_per_block +
601 (1 << (addr_per_block_bits * 2)) +
602 ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
603 chat("bmap() block > big...");
604 return 0;
605 }
606
607 ibuf = getbuf(xf, f->bufaddr);
608 if( !ibuf )
609 return 0;
610 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
611
612 /* direct blocks */
613 if(block < EXT2_NDIR_BLOCKS){
614 putbuf(ibuf);
615 return inode->i_block[block];
616 }
617 block -= EXT2_NDIR_BLOCKS;
618
619 /* indirect blocks*/
620 if(block < addr_per_block) {
621 addr = inode->i_block[EXT2_IND_BLOCK];
622 if (!addr) goto error;
623 buf = getbuf(xf, addr);
624 if( !buf ) goto error;
625 addr = *(((uint *)buf->iobuf) + block);
626 putbuf(buf);
627 putbuf(ibuf);
628 return addr;
629 }
630 block -= addr_per_block;
631
632 /* double indirect blocks */
633 if(block < (1 << (addr_per_block_bits * 2))) {
634 addr = inode->i_block[EXT2_DIND_BLOCK];
635 if (!addr) goto error;
636 buf = getbuf(xf, addr);
637 if( !buf ) goto error;
638 addr = *(((uint *)buf->iobuf) + (block >> addr_per_block_bits));
639 putbuf(buf);
640 buf = getbuf(xf, addr);
641 if( !buf ) goto error;
642 addr = *(((uint *)buf->iobuf) + (block & (addr_per_block - 1)));
643 putbuf(buf);
644 putbuf(ibuf);
645 return addr;
646 }
647 block -= (1 << (addr_per_block_bits * 2));
648
649 /* triple indirect blocks */
650 addr = inode->i_block[EXT2_TIND_BLOCK];
651 if(!addr) goto error;
652 buf = getbuf(xf, addr);
653 if( !buf ) goto error;
654 addr = *(((uint *)buf->iobuf) + (block >> (addr_per_block_bits * 2)));
655 putbuf(buf);
656 if(!addr) goto error;
657 buf = getbuf(xf, addr);
658 if( !buf ) goto error;
659 addr = *(((uint *)buf->iobuf) +
660 ((block >> addr_per_block_bits) & (addr_per_block - 1)));
661 putbuf(buf);
662 if(!addr) goto error;
663 buf = getbuf(xf, addr);
664 if( !buf ) goto error;
665 addr = *(((uint *)buf->iobuf) + (block & (addr_per_block - 1)));
666 putbuf(buf);
667 putbuf(ibuf);
668 return addr;
669 error:
670 putbuf(ibuf);
671 return 0;
672 }
673 long
writefile(Xfile * f,void * vbuf,vlong offset,long count)674 writefile(Xfile *f, void *vbuf, vlong offset, long count)
675 {
676 Xfs *xf = f->xf;
677 Inode *inode;
678 Iobuf *buffer, *ibuf;
679 long w;
680 int len, o, cur_block, baddr;
681 char *buf;
682
683 buf = vbuf;
684
685 ibuf = getbuf(xf, f->bufaddr);
686 if( !ibuf )
687 return -1;
688 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
689
690 chat("write block [ ");
691 cur_block = offset / xf->block_size;
692 o = offset % xf->block_size;
693 w = 0;
694 while( count > 0 ){
695 baddr = getblk(f, cur_block++);
696 if( baddr <= 0 )
697 goto end;
698 buffer = getbuf(xf, baddr);
699 if( !buffer )
700 goto end;
701 chat("%d ", baddr);
702 len = xf->block_size - o;
703 if( len > count )
704 len = count;
705 memcpy(&buffer->iobuf[o], &buf[w], len);
706 dirtybuf(buffer);
707 w += len;
708 count -= len;
709 o = 0;
710 putbuf(buffer);
711 }
712 end:
713 if( inode->i_size < offset + w )
714 inode->i_size = offset + w;
715 inode->i_atime = inode->i_mtime = time(0);
716 dirtybuf(ibuf);
717 putbuf(ibuf);
718 chat("]...");
719 if( errno )
720 return -1;
721 return w;
722 }
723 int
new_block(Xfile * f,int goal)724 new_block( Xfile *f, int goal )
725 {
726 Xfs *xf= f->xf;
727 int group, block, baddr, k, redo;
728 ulong lmap;
729 char *p, *r;
730 Iobuf *buf;
731 Ext2 ed, es, eb;
732
733 es = getext2(xf, EXT2_SUPER, 0);
734 redo = 0;
735
736 repeat:
737
738 if( goal < es.u.sb->s_first_data_block || goal >= es.u.sb->s_blocks_count )
739 goal = es.u.sb->s_first_data_block;
740 group = (goal - es.u.sb->s_first_data_block) / xf->blocks_per_group;
741
742 ed = getext2(xf, EXT2_DESC, group);
743 eb = getext2(xf, EXT2_BBLOCK, group);
744
745 /*
746 * First, test if goal block is free
747 */
748 if( ed.u.gd->bg_free_blocks_count > 0 ){
749 block = (goal - es.u.sb->s_first_data_block) % xf->blocks_per_group;
750
751 if( !test_bit(block, eb.u.bmp) )
752 goto got_block;
753
754 if( block ){
755 /*
756 * goal wasn't free ; search foward for a free
757 * block within the next 32 blocks
758 */
759
760 lmap = (((ulong *)eb.u.bmp)[block>>5]) >>
761 ((block & 31) + 1);
762 if( block < xf->blocks_per_group - 32 )
763 lmap |= (((ulong *)eb.u.bmp)[(block>>5)+1]) <<
764 ( 31-(block & 31) );
765 else
766 lmap |= 0xffffffff << ( 31-(block & 31) );
767
768 if( lmap != 0xffffffffl ){
769 k = ffz(lmap) + 1;
770 if( (block + k) < xf->blocks_per_group ){
771 block += k;
772 goto got_block;
773 }
774 }
775 }
776 /*
777 * Search in the remaider of the group
778 */
779 p = eb.u.bmp + (block>>3);
780 r = memscan(p, 0, (xf->blocks_per_group - block + 7) >>3);
781 k = ( r - eb.u.bmp )<<3;
782 if( k < xf->blocks_per_group ){
783 block = k;
784 goto search_back;
785 }
786 k = find_next_zero_bit((unsigned long *)eb.u.bmp,
787 xf->blocks_per_group>>3, block);
788 if( k < xf->blocks_per_group ){
789 block = k;
790 goto got_block;
791 }
792 }
793
794 /*
795 * Search the rest of groups
796 */
797 putext2(ed); putext2(eb);
798 for(k=0 ; k < xf->ngroups ; k++){
799 group++;
800 if( group >= xf->ngroups )
801 group = 0;
802 ed = getext2(xf, EXT2_DESC, group);
803 if( ed.u.gd->bg_free_blocks_count > 0 )
804 break;
805 putext2(ed);
806 }
807 if( redo && group == xf->ngroups-1 ){
808 putext2(ed);
809 goto full;
810 }
811 if( k >=xf->ngroups ){
812 /*
813 * All groups are full or
814 * we have retry (because the last block) and all other
815 * groups are also full.
816 */
817 full:
818 chat("no free blocks ...");
819 putext2(es);
820 errno = Enospace;
821 return 0;
822 }
823 eb = getext2(xf, EXT2_BBLOCK, group);
824 r = memscan(eb.u.bmp, 0, xf->blocks_per_group>>3);
825 block = (r - eb.u.bmp) <<3;
826 if( block < xf->blocks_per_group )
827 goto search_back;
828 else
829 block = find_first_zero_bit((ulong *)eb.u.bmp,
830 xf->blocks_per_group>>3);
831 if( block >= xf->blocks_per_group ){
832 chat("Free block count courupted for block group %d...", group);
833 putext2(ed); putext2(eb); putext2(es);
834 errno = Ecorrupt;
835 return 0;
836 }
837
838
839 search_back:
840 /*
841 * A free byte was found in the block. Now search backwards up
842 * to 7 bits to find the start of this group of free block.
843 */
844 for(k=0 ; k < 7 && block > 0 &&
845 !test_bit(block-1, eb.u.bmp) ; k++, block--);
846
847 got_block:
848
849 baddr = block + (group * xf->blocks_per_group) +
850 es.u.sb->s_first_data_block;
851
852 if( baddr == ed.u.gd->bg_block_bitmap ||
853 baddr == ed.u.gd->bg_inode_bitmap ){
854 chat("Allocating block in system zone...");
855 putext2(ed); putext2(eb); putext2(es);
856 errno = Eintern;
857 return 0;
858 }
859
860 if( set_bit(block, eb.u.bmp) ){
861 chat("bit already set (%d)...", block);
862 putext2(ed); putext2(eb); putext2(es);
863 errno = Ecorrupt;
864 return 0;
865 }
866 dirtyext2(eb);
867
868 if( baddr >= es.u.sb->s_blocks_count ){
869 chat("block >= blocks count...");
870 errno = Eintern;
871 error:
872 clear_bit(block, eb.u.bmp);
873 putext2(eb); putext2(ed); putext2(es);
874 return 0;
875 }
876
877 buf = getbuf(xf, baddr);
878 if( !buf ){
879 if( !redo ){
880 /*
881 * It's perhaps the last block of the disk and
882 * it can't be acceded because the last sector.
883 * Therefore, we try one more time with goal at 0
884 * to force scanning all groups.
885 */
886 clear_bit(block, eb.u.bmp);
887 putext2(eb); putext2(ed);
888 goal = 0; errno = 0; redo++;
889 goto repeat;
890 }
891 goto error;
892 }
893 memset(&buf->iobuf[0], 0, xf->block_size);
894 dirtybuf(buf);
895 putbuf(buf);
896
897 es.u.sb->s_free_blocks_count--;
898 dirtyext2(es);
899 ed.u.gd->bg_free_blocks_count--;
900 dirtyext2(ed);
901
902 putext2(eb);
903 putext2(ed);
904 putext2(es);
905 chat("new ");
906 return baddr;
907 }
908 int
getblk(Xfile * f,int block)909 getblk(Xfile *f, int block)
910 {
911 Xfs *xf = f->xf;
912 int baddr;
913 int addr_per_block = xf->addr_per_block;
914
915 if (block < 0) {
916 chat("getblk() block < 0 ...");
917 return 0;
918 }
919 if(block > EXT2_NDIR_BLOCKS + addr_per_block +
920 addr_per_block * addr_per_block +
921 addr_per_block * addr_per_block * addr_per_block ){
922 chat("getblk() block > big...");
923 errno = Eintern;
924 return 0;
925 }
926 if( block < EXT2_NDIR_BLOCKS )
927 return inode_getblk(f, block);
928 block -= EXT2_NDIR_BLOCKS;
929 if( block < addr_per_block ){
930 baddr = inode_getblk(f, EXT2_IND_BLOCK);
931 baddr = block_getblk(f, baddr, block);
932 return baddr;
933 }
934 block -= addr_per_block;
935 if( block < addr_per_block * addr_per_block ){
936 baddr = inode_getblk(f, EXT2_DIND_BLOCK);
937 baddr = block_getblk(f, baddr, block / addr_per_block);
938 baddr = block_getblk(f, baddr, block & ( addr_per_block-1));
939 return baddr;
940 }
941 block -= addr_per_block * addr_per_block;
942 baddr = inode_getblk(f, EXT2_TIND_BLOCK);
943 baddr = block_getblk(f, baddr, block / (addr_per_block * addr_per_block));
944 baddr = block_getblk(f, baddr, (block / addr_per_block) & ( addr_per_block-1));
945 return block_getblk(f, baddr, block & ( addr_per_block-1));
946 }
947 int
block_getblk(Xfile * f,int rb,int nr)948 block_getblk(Xfile *f, int rb, int nr)
949 {
950 Xfs *xf = f->xf;
951 Inode *inode;
952 int tmp, goal = 0;
953 int blocks = xf->block_size / 512;
954 Iobuf *buf, *ibuf;
955 uint *p;
956 Ext2 es;
957
958 if( !rb )
959 return 0;
960
961 buf = getbuf(xf, rb);
962 if( !buf )
963 return 0;
964 p = (uint *)(buf->iobuf) + nr;
965 if( *p ){
966 tmp = *p;
967 putbuf(buf);
968 return tmp;
969 }
970
971 for(tmp=nr - 1 ; tmp >= 0 ; tmp--){
972 if( ((uint *)(buf->iobuf))[tmp] ){
973 goal = ((uint *)(buf->iobuf))[tmp];
974 break;
975 }
976 }
977 if( !goal ){
978 es = getext2(xf, EXT2_SUPER, 0);
979 goal = (((f->inbr -1) / xf->inodes_per_group) *
980 xf->blocks_per_group) +
981 es.u.sb->s_first_data_block;
982 putext2(es);
983 }
984
985 tmp = new_block(f, goal);
986 if( !tmp ){
987 putbuf(buf);
988 return 0;
989 }
990
991 *p = tmp;
992 dirtybuf(buf);
993 putbuf(buf);
994
995 ibuf = getbuf(xf, f->bufaddr);
996 if( !ibuf )
997 return -1;
998 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
999 inode->i_blocks += blocks;
1000 dirtybuf(ibuf);
1001 putbuf(ibuf);
1002
1003 return tmp;
1004 }
1005 int
inode_getblk(Xfile * f,int block)1006 inode_getblk(Xfile *f, int block)
1007 {
1008 Xfs *xf = f->xf;
1009 Inode *inode;
1010 Iobuf *ibuf;
1011 int tmp, goal = 0;
1012 int blocks = xf->block_size / 512;
1013 Ext2 es;
1014
1015 ibuf = getbuf(xf, f->bufaddr);
1016 if( !ibuf )
1017 return -1;
1018 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
1019
1020
1021 if( inode->i_block[block] ){
1022 putbuf(ibuf);
1023 return inode->i_block[block];
1024 }
1025
1026 for(tmp=block - 1 ; tmp >= 0 ; tmp--){
1027 if( inode->i_block[tmp] ){
1028 goal = inode->i_block[tmp];
1029 break;
1030 }
1031 }
1032 if( !goal ){
1033 es = getext2(xf, EXT2_SUPER, 0);
1034 goal = (((f->inbr -1) / xf->inodes_per_group) *
1035 xf->blocks_per_group) +
1036 es.u.sb->s_first_data_block;
1037 putext2(es);
1038 }
1039
1040 tmp = new_block(f, goal);
1041 if( !tmp ){
1042 putbuf(ibuf);
1043 return 0;
1044 }
1045
1046 inode->i_block[block] = tmp;
1047 inode->i_blocks += blocks;
1048 dirtybuf(ibuf);
1049 putbuf(ibuf);
1050
1051 return tmp;
1052 }
1053 int
new_inode(Xfile * f,int mode)1054 new_inode(Xfile *f, int mode)
1055 {
1056 Xfs *xf = f->xf;
1057 Inode *inode, *finode;
1058 Iobuf *buf, *ibuf;
1059 int ave,group, i, j;
1060 Ext2 ed, es, eb;
1061
1062 group = -1;
1063
1064 es = getext2(xf, EXT2_SUPER, 0);
1065
1066 if( S_ISDIR(mode) ){ /* create directory inode */
1067 ave = es.u.sb->s_free_inodes_count / xf->ngroups;
1068 for(i=0 ; i < xf->ngroups ; i++){
1069 ed = getext2(xf, EXT2_DESC, i);
1070 if( ed.u.gd->bg_free_inodes_count &&
1071 ed.u.gd->bg_free_inodes_count >= ave ){
1072 if( group<0 || ed.u.gd->bg_free_inodes_count >
1073 ed.u.gd->bg_free_inodes_count )
1074 group = i;
1075 }
1076 putext2(ed);
1077 }
1078
1079 }else{ /* create file inode */
1080 /* Try to put inode in its parent directory */
1081 i = (f->inbr -1) / xf->inodes_per_group;
1082 ed = getext2(xf, EXT2_DESC, i);
1083 if( ed.u.gd->bg_free_inodes_count ){
1084 group = i;
1085 putext2(ed);
1086 }else{
1087 /*
1088 * Use a quadratic hash to find a group whith
1089 * a free inode
1090 */
1091 putext2(ed);
1092 for( j=1 ; j < xf->ngroups ; j <<= 1){
1093 i += j;
1094 if( i >= xf->ngroups )
1095 i -= xf->ngroups;
1096 ed = getext2(xf, EXT2_DESC, i);
1097 if( ed.u.gd->bg_free_inodes_count ){
1098 group = i;
1099 putext2(ed);
1100 break;
1101 }
1102 putext2(ed);
1103 }
1104 }
1105 if( group < 0 ){
1106 /* try a linear search */
1107 i = ((f->inbr -1) / xf->inodes_per_group) + 1;
1108 for(j=2 ; j < xf->ngroups ; j++){
1109 if( ++i >= xf->ngroups )
1110 i = 0;
1111 ed = getext2(xf, EXT2_DESC, i);
1112 if( ed.u.gd->bg_free_inodes_count ){
1113 group = i;
1114 putext2(ed);
1115 break;
1116 }
1117 putext2(ed);
1118 }
1119 }
1120
1121 }
1122 if( group < 0 ){
1123 chat("group < 0...");
1124 putext2(es);
1125 return 0;
1126 }
1127 ed = getext2(xf, EXT2_DESC, group);
1128 eb = getext2(xf, EXT2_BINODE, group);
1129 if( (j = find_first_zero_bit(eb.u.bmp,
1130 xf->inodes_per_group>>3)) < xf->inodes_per_group){
1131 if( set_bit(j, eb.u.bmp) ){
1132 chat("inode %d of group %d is already allocated...", j, group);
1133 putext2(ed); putext2(eb); putext2(es);
1134 errno = Ecorrupt;
1135 return 0;
1136 }
1137 dirtyext2(eb);
1138 }else if( ed.u.gd->bg_free_inodes_count != 0 ){
1139 chat("free inodes count corrupted for group %d...", group);
1140 putext2(ed); putext2(eb); putext2(es);
1141 errno = Ecorrupt;
1142 return 0;
1143 }
1144 i = j;
1145 j += group * xf->inodes_per_group + 1;
1146 if( j < EXT2_FIRST_INO || j >= es.u.sb->s_inodes_count ){
1147 chat("reserved inode or inode > inodes count...");
1148 errno = Ecorrupt;
1149 error:
1150 clear_bit(i, eb.u.bmp);
1151 putext2(eb); putext2(ed); putext2(es);
1152 return 0;
1153 }
1154
1155 buf = getbuf(xf, ed.u.gd->bg_inode_table +
1156 (((j-1) % xf->inodes_per_group) /
1157 xf->inodes_per_block));
1158 if( !buf )
1159 goto error;
1160 inode = ((struct Inode *) buf->iobuf) +
1161 ((j-1) % xf->inodes_per_block);
1162 memset(inode, 0, sizeof(Inode));
1163 inode->i_mode = mode;
1164 inode->i_links_count = 1;
1165 inode->i_uid = DEFAULT_UID;
1166 inode->i_gid = DEFAULT_GID;
1167 inode->i_mtime = inode->i_atime = inode->i_ctime = time(0);
1168 dirtybuf(buf);
1169
1170 ibuf = getbuf(xf, f->bufaddr);
1171 if( !ibuf ){
1172 putbuf(buf);
1173 goto error;
1174 }
1175 finode = ((Inode *)ibuf->iobuf) + f->bufoffset;
1176 inode->i_flags = finode->i_flags;
1177 inode->i_uid = finode->i_uid;
1178 inode->i_gid = finode->i_gid;
1179 dirtybuf(ibuf);
1180 putbuf(ibuf);
1181
1182 putbuf(buf);
1183
1184 ed.u.gd->bg_free_inodes_count--;
1185 if( S_ISDIR(mode) )
1186 ed.u.gd->bg_used_dirs_count++;
1187 dirtyext2(ed);
1188
1189 es.u.sb->s_free_inodes_count--;
1190 dirtyext2(es);
1191
1192 putext2(eb);
1193 putext2(ed);
1194 putext2(es);
1195
1196 return j;
1197 }
1198 int
create_file(Xfile * fdir,char * name,int mode)1199 create_file(Xfile *fdir, char *name, int mode)
1200 {
1201 int inr;
1202
1203 inr = new_inode(fdir, mode);
1204 if( !inr ){
1205 chat("create one new inode failed...");
1206 return -1;
1207 }
1208 if( add_entry(fdir, name, inr) < 0 ){
1209 chat("add entry failed...");
1210 free_inode(fdir->xf, inr);
1211 return -1;
1212 }
1213
1214 return inr;
1215 }
1216 void
free_inode(Xfs * xf,int inr)1217 free_inode( Xfs *xf, int inr)
1218 {
1219 Inode *inode;
1220 ulong b, bg;
1221 Iobuf *buf;
1222 Ext2 ed, es, eb;
1223
1224 bg = (inr -1) / xf->inodes_per_group;
1225 b = (inr -1) % xf->inodes_per_group;
1226
1227 ed = getext2(xf, EXT2_DESC, bg);
1228 buf = getbuf(xf, ed.u.gd->bg_inode_table +
1229 (b / xf->inodes_per_block));
1230 if( !buf ){
1231 putext2(ed);
1232 return;
1233 }
1234 inode = ((struct Inode *) buf->iobuf) +
1235 ((inr-1) % xf->inodes_per_block);
1236
1237 if( S_ISDIR(inode->i_mode) )
1238 ed.u.gd->bg_used_dirs_count--;
1239 memset(inode, 0, sizeof(Inode));
1240 inode->i_dtime = time(0);
1241 dirtybuf(buf);
1242 putbuf(buf);
1243
1244 ed.u.gd->bg_free_inodes_count++;
1245 dirtyext2(ed);
1246 putext2(ed);
1247
1248 eb = getext2(xf, EXT2_BINODE, bg);
1249 clear_bit(b, eb.u.bmp);
1250 dirtyext2(eb);
1251 putext2(eb);
1252
1253 es = getext2(xf, EXT2_SUPER, 0);
1254 es.u.sb->s_free_inodes_count++;
1255 dirtyext2(es); putext2(es);
1256 }
1257 int
create_dir(Xfile * fdir,char * name,int mode)1258 create_dir(Xfile *fdir, char *name, int mode)
1259 {
1260 Xfs *xf = fdir->xf;
1261 DirEntry *de;
1262 Inode *inode;
1263 Iobuf *buf, *ibuf;
1264 Xfile tf;
1265 int inr, baddr;
1266
1267 inr = new_inode(fdir, mode);
1268 if( inr == 0 ){
1269 chat("create one new inode failed...");
1270 return -1;
1271 }
1272 if( add_entry(fdir, name, inr) < 0 ){
1273 chat("add entry failed...");
1274 free_inode(fdir->xf, inr);
1275 return -1;
1276 }
1277
1278 /* create the empty dir */
1279
1280 tf = *fdir;
1281 if( get_inode(&tf, inr) < 0 ){
1282 chat("can't get inode %d...", inr);
1283 free_inode(fdir->xf, inr);
1284 return -1;
1285 }
1286
1287 ibuf = getbuf(xf, tf.bufaddr);
1288 if( !ibuf ){
1289 free_inode(fdir->xf, inr);
1290 return -1;
1291 }
1292 inode = ((Inode *)ibuf->iobuf) + tf.bufoffset;
1293
1294
1295 baddr = inode_getblk(&tf, 0);
1296 if( !baddr ){
1297 putbuf(ibuf);
1298 ibuf = getbuf(xf, fdir->bufaddr);
1299 if( !ibuf ){
1300 free_inode(fdir->xf, inr);
1301 return -1;
1302 }
1303 inode = ((Inode *)ibuf->iobuf) + fdir->bufoffset;
1304 delete_entry(fdir->xf, inode, inr);
1305 putbuf(ibuf);
1306 free_inode(fdir->xf, inr);
1307 return -1;
1308 }
1309
1310 inode->i_size = xf->block_size;
1311 buf = getbuf(xf, baddr);
1312
1313 de = (DirEntry *)buf->iobuf;
1314 de->inode = inr;
1315 de->name_len = 1;
1316 de->rec_len = DIR_REC_LEN(de->name_len);
1317 strcpy(de->name, ".");
1318
1319 de = (DirEntry *)( (char *)de + de->rec_len);
1320 de->inode = fdir->inbr;
1321 de->name_len = 2;
1322 de->rec_len = xf->block_size - DIR_REC_LEN(1);
1323 strcpy(de->name, "..");
1324
1325 dirtybuf(buf);
1326 putbuf(buf);
1327
1328 inode->i_links_count = 2;
1329 dirtybuf(ibuf);
1330 putbuf(ibuf);
1331
1332 ibuf = getbuf(xf, fdir->bufaddr);
1333 if( !ibuf )
1334 return -1;
1335 inode = ((Inode *)ibuf->iobuf) + fdir->bufoffset;
1336
1337 inode->i_links_count++;
1338
1339 dirtybuf(ibuf);
1340 putbuf(ibuf);
1341
1342 return inr;
1343 }
1344 int
add_entry(Xfile * f,char * name,int inr)1345 add_entry(Xfile *f, char *name, int inr)
1346 {
1347 Xfs *xf = f->xf;
1348 DirEntry *de, *de1;
1349 int offset, baddr;
1350 int rec_len, cur_block;
1351 int namelen = strlen(name);
1352 Inode *inode;
1353 Iobuf *buf, *ibuf;
1354
1355 ibuf = getbuf(xf, f->bufaddr);
1356 if( !ibuf )
1357 return -1;
1358 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
1359
1360 if( inode->i_size == 0 ){
1361 chat("add_entry() no entry !!!...");
1362 putbuf(ibuf);
1363 return -1;
1364 }
1365 cur_block = offset = 0;
1366 rec_len = DIR_REC_LEN(namelen);
1367 buf = getbuf(xf, inode->i_block[cur_block++]);
1368 if( !buf ){
1369 putbuf(ibuf);
1370 return -1;
1371 }
1372 de = (DirEntry *)buf->iobuf;
1373
1374 for(;;){
1375 if( ((char *)de) >= (xf->block_size + buf->iobuf) ){
1376 putbuf(buf);
1377 if( cur_block >= EXT2_NDIR_BLOCKS ){
1378 errno = Enospace;
1379 putbuf(ibuf);
1380 return -1;
1381 }
1382 if( (baddr = inode_getblk(f, cur_block++)) == 0 ){
1383 putbuf(ibuf);
1384 return -1;
1385 }
1386 buf = getbuf(xf, baddr);
1387 if( !buf ){
1388 putbuf(ibuf);
1389 return -1;
1390 }
1391 if( inode->i_size <= offset ){
1392 de = (DirEntry *)buf->iobuf;
1393 de->inode = 0;
1394 de->rec_len = xf->block_size;
1395 dirtybuf(buf);
1396 inode->i_size = offset + xf->block_size;
1397 dirtybuf(ibuf);
1398 }else{
1399 de = (DirEntry *)buf->iobuf;
1400 }
1401 }
1402 if( de->inode != 0 && de->name_len == namelen &&
1403 !strncmp(name, de->name, namelen) ){
1404 errno = Eexist;
1405 putbuf(ibuf); putbuf(buf);
1406 return -1;
1407 }
1408 offset += de->rec_len;
1409 if( (de->inode == 0 && de->rec_len >= rec_len) ||
1410 (de->rec_len >= DIR_REC_LEN(de->name_len) + rec_len) ){
1411 if( de->inode ){
1412 de1 = (DirEntry *) ((char *)de + DIR_REC_LEN(de->name_len));
1413 de1->rec_len = de->rec_len - DIR_REC_LEN(de->name_len);
1414 de->rec_len = DIR_REC_LEN(de->name_len);
1415 de = de1;
1416 }
1417 de->inode = inr;
1418 de->name_len = namelen;
1419 memcpy(de->name, name, namelen);
1420 dirtybuf(buf);
1421 putbuf(buf);
1422 inode->i_mtime = inode->i_ctime = time(0);
1423 dirtybuf(ibuf);
1424 putbuf(ibuf);
1425 return 0;
1426 }
1427 de = (DirEntry *)((char *)de + de->rec_len);
1428 }
1429 /* not reached */
1430 }
1431 int
unlink(Xfile * file)1432 unlink( Xfile *file )
1433 {
1434 Xfs *xf = file->xf;
1435 Inode *dir;
1436 int bg, b;
1437 Inode *inode;
1438 Iobuf *buf, *ibuf;
1439 Ext2 ed, es, eb;
1440
1441 if( S_ISDIR(getmode(file)) && !empty_dir(file) ){
1442 chat("non empty directory...");
1443 errno = Eperm;
1444 return -1;
1445 }
1446
1447 es = getext2(xf, EXT2_SUPER, 0);
1448
1449 /* get dir inode */
1450 if( file->pinbr >= es.u.sb->s_inodes_count ){
1451 chat("inode number %d is too big...", file->pinbr);
1452 putext2(es);
1453 errno = Eintern;
1454 return -1;
1455 }
1456 bg = (file->pinbr - 1) / xf->inodes_per_group;
1457 if( bg >= xf->ngroups ){
1458 chat("block group (%d) > groups count...", bg);
1459 putext2(es);
1460 errno = Eintern;
1461 return -1;
1462 }
1463 ed = getext2(xf, EXT2_DESC, bg);
1464 b = ed.u.gd->bg_inode_table +
1465 (((file->pinbr-1) % xf->inodes_per_group) /
1466 xf->inodes_per_block);
1467 putext2(ed);
1468 buf = getbuf(xf, b);
1469 if( !buf ){
1470 putext2(es);
1471 return -1;
1472 }
1473 dir = ((struct Inode *) buf->iobuf) +
1474 ((file->pinbr-1) % xf->inodes_per_block);
1475
1476 /* Clean dir entry */
1477
1478 if( delete_entry(xf, dir, file->inbr) < 0 ){
1479 putbuf(buf);
1480 putext2(es);
1481 return -1;
1482 }
1483 if( S_ISDIR(getmode(file)) ){
1484 dir->i_links_count--;
1485 dirtybuf(buf);
1486 }
1487 putbuf(buf);
1488
1489 /* clean blocks */
1490 ibuf = getbuf(xf, file->bufaddr);
1491 if( !ibuf ){
1492 putext2(es);
1493 return -1;
1494 }
1495 inode = ((Inode *)ibuf->iobuf) + file->bufoffset;
1496
1497 if( !S_ISLNK(getmode(file)) ||
1498 (S_ISLNK(getmode(file)) && (inode->i_size > EXT2_N_BLOCKS<<2)) )
1499 if( free_block_inode(file) < 0 ){
1500 chat("error while freeing blocks...");
1501 putext2(es);
1502 putbuf(ibuf);
1503 return -1;
1504 }
1505
1506
1507 /* clean inode */
1508
1509 bg = (file->inbr -1) / xf->inodes_per_group;
1510 b = (file->inbr -1) % xf->inodes_per_group;
1511
1512 eb = getext2(xf, EXT2_BINODE, bg);
1513 clear_bit(b, eb.u.bmp);
1514 dirtyext2(eb);
1515 putext2(eb);
1516
1517 inode->i_dtime = time(0);
1518 inode->i_links_count--;
1519 if( S_ISDIR(getmode(file)) )
1520 inode->i_links_count = 0;
1521
1522 es.u.sb->s_free_inodes_count++;
1523 dirtyext2(es);
1524 putext2(es);
1525
1526 ed = getext2(xf, EXT2_DESC, bg);
1527 ed.u.gd->bg_free_inodes_count++;
1528 if( S_ISDIR(getmode(file)) )
1529 ed.u.gd->bg_used_dirs_count--;
1530 dirtyext2(ed);
1531 putext2(ed);
1532
1533 dirtybuf(ibuf);
1534 putbuf(ibuf);
1535
1536 return 1;
1537 }
1538 int
empty_dir(Xfile * dir)1539 empty_dir(Xfile *dir)
1540 {
1541 Xfs *xf = dir->xf;
1542 int nblock;
1543 uint offset, i,count;
1544 DirEntry *de;
1545 Inode *inode;
1546 Iobuf *buf, *ibuf;
1547
1548 if( !S_ISDIR(getmode(dir)) )
1549 return 0;
1550
1551 ibuf = getbuf(xf, dir->bufaddr);
1552 if( !ibuf )
1553 return -1;
1554 inode = ((Inode *)ibuf->iobuf) + dir->bufoffset;
1555 nblock = (inode->i_blocks * 512) / xf->block_size;
1556
1557 for(i=0, count=0 ; (i < nblock) && (i < EXT2_NDIR_BLOCKS) ; i++){
1558 buf = getbuf(xf, inode->i_block[i]);
1559 if( !buf ){
1560 putbuf(ibuf);
1561 return 0;
1562 }
1563 for(offset=0 ; offset < xf->block_size ; ){
1564 de = (DirEntry *)(buf->iobuf + offset);
1565 if(de->inode)
1566 count++;
1567 offset += de->rec_len;
1568 }
1569 putbuf(buf);
1570 if( count > 2 ){
1571 putbuf(ibuf);
1572 return 0;
1573 }
1574 }
1575 putbuf(ibuf);
1576 return 1;
1577 }
1578 int
free_block_inode(Xfile * file)1579 free_block_inode(Xfile *file)
1580 {
1581 Xfs *xf = file->xf;
1582 int i, j, k;
1583 ulong b, *y, *z;
1584 uint *x;
1585 int naddr;
1586 Inode *inode;
1587 Iobuf *buf, *buf1, *buf2, *ibuf;
1588
1589 ibuf = getbuf(xf, file->bufaddr);
1590 if( !ibuf )
1591 return -1;
1592 inode = ((Inode *)ibuf->iobuf) + file->bufoffset;
1593
1594 for(i=0 ; i < EXT2_IND_BLOCK ; i++){
1595 x = inode->i_block + i;
1596 if( *x == 0 ){ putbuf(ibuf); return 0; }
1597 free_block(xf, *x);
1598 }
1599 naddr = xf->addr_per_block;
1600
1601 /* indirect blocks */
1602
1603 if( (b=inode->i_block[EXT2_IND_BLOCK]) ){
1604 buf = getbuf(xf, b);
1605 if( !buf ){ putbuf(ibuf); return -1; }
1606 for(i=0 ; i < naddr ; i++){
1607 x = ((uint *)buf->iobuf) + i;
1608 if( *x == 0 ) break;
1609 free_block(xf, *x);
1610 }
1611 free_block(xf, b);
1612 putbuf(buf);
1613 }
1614
1615 /* double indirect block */
1616
1617 if( (b=inode->i_block[EXT2_DIND_BLOCK]) ){
1618 buf = getbuf(xf, b);
1619 if( !buf ){ putbuf(ibuf); return -1; }
1620 for(i=0 ; i < naddr ; i++){
1621 x = ((uint *)buf->iobuf) + i;
1622 if( *x== 0 ) break;
1623 buf1 = getbuf(xf, *x);
1624 if( !buf1 ){ putbuf(buf); putbuf(ibuf); return -1; }
1625 for(j=0 ; j < naddr ; j++){
1626 y = ((ulong *)buf1->iobuf) + j;
1627 if( *y == 0 ) break;
1628 free_block(xf, *y);
1629 }
1630 free_block(xf, *x);
1631 putbuf(buf1);
1632 }
1633 free_block(xf, b);
1634 putbuf(buf);
1635 }
1636
1637 /* triple indirect block */
1638
1639 if( (b=inode->i_block[EXT2_TIND_BLOCK]) ){
1640 buf = getbuf(xf, b);
1641 if( !buf ){ putbuf(ibuf); return -1; }
1642 for(i=0 ; i < naddr ; i++){
1643 x = ((uint *)buf->iobuf) + i;
1644 if( *x == 0 ) break;
1645 buf1 = getbuf(xf, *x);
1646 if( !buf1 ){ putbuf(buf); putbuf(ibuf); return -1; }
1647 for(j=0 ; j < naddr ; j++){
1648 y = ((ulong *)buf1->iobuf) + j;
1649 if( *y == 0 ) break;
1650 buf2 = getbuf(xf, *y);
1651 if( !buf2 ){ putbuf(buf); putbuf(buf1); putbuf(ibuf); return -1; }
1652 for(k=0 ; k < naddr ; k++){
1653 z = ((ulong *)buf2->iobuf) + k;
1654 if( *z == 0 ) break;
1655 free_block(xf, *z);
1656 }
1657 free_block(xf, *y);
1658 putbuf(buf2);
1659 }
1660 free_block(xf, *x);
1661 putbuf(buf1);
1662 }
1663 free_block(xf, b);
1664 putbuf(buf);
1665 }
1666
1667 putbuf(ibuf);
1668 return 0;
1669 }
free_block(Xfs * xf,ulong block)1670 void free_block( Xfs *xf, ulong block )
1671 {
1672 ulong bg;
1673 Ext2 ed, es, eb;
1674
1675 es = getext2(xf, EXT2_SUPER, 0);
1676
1677 bg = (block - es.u.sb->s_first_data_block) / xf->blocks_per_group;
1678 block = (block - es.u.sb->s_first_data_block) % xf->blocks_per_group;
1679
1680 eb = getext2(xf, EXT2_BBLOCK, bg);
1681 clear_bit(block, eb.u.bmp);
1682 dirtyext2(eb);
1683 putext2(eb);
1684
1685 es.u.sb->s_free_blocks_count++;
1686 dirtyext2(es);
1687 putext2(es);
1688
1689 ed = getext2(xf, EXT2_DESC, bg);
1690 ed.u.gd->bg_free_blocks_count++;
1691 dirtyext2(ed);
1692 putext2(ed);
1693
1694 }
1695 int
delete_entry(Xfs * xf,Inode * inode,int inbr)1696 delete_entry(Xfs *xf, Inode *inode, int inbr)
1697 {
1698 int nblock = (inode->i_blocks * 512) / xf->block_size;
1699 uint offset, i;
1700 DirEntry *de, *pde;
1701 Iobuf *buf;
1702
1703 if( !S_ISDIR(inode->i_mode) )
1704 return -1;
1705
1706 for(i=0 ; (i < nblock) && (i < EXT2_NDIR_BLOCKS) ; i++){
1707 buf = getbuf(xf, inode->i_block[i]);
1708 if( !buf )
1709 return -1;
1710 pde = 0;
1711 for(offset=0 ; offset < xf->block_size ; ){
1712 de = (DirEntry *)(buf->iobuf + offset);
1713 if( de->inode == inbr ){
1714 if( pde )
1715 pde->rec_len += de->rec_len;
1716 de->inode = 0;
1717 dirtybuf(buf);
1718 putbuf(buf);
1719 return 1;
1720 }
1721 offset += de->rec_len;
1722 pde = de;
1723 }
1724 putbuf(buf);
1725
1726 }
1727 errno = Enonexist;
1728 return -1;
1729 }
1730 int
truncfile(Xfile * f)1731 truncfile(Xfile *f)
1732 {
1733 Inode *inode;
1734 Iobuf *ibuf;
1735 chat("trunc(fid=%d) ...", f->fid);
1736 ibuf = getbuf(f->xf, f->bufaddr);
1737 if( !ibuf )
1738 return -1;
1739 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
1740
1741 if( free_block_inode(f) < 0 ){
1742 chat("error while freeing blocks...");
1743 putbuf(ibuf);
1744 return -1;
1745 }
1746 inode->i_atime = inode->i_mtime = time(0);
1747 inode->i_blocks = 0;
1748 inode->i_size = 0;
1749 memset(inode->i_block, 0, EXT2_N_BLOCKS*sizeof(ulong));
1750 dirtybuf(ibuf);
1751 putbuf(ibuf);
1752 chat("trunc ok...");
1753 return 0;
1754 }
1755 long
getmode(Xfile * f)1756 getmode(Xfile *f)
1757 {
1758 Iobuf *ibuf;
1759 long mode;
1760
1761 ibuf = getbuf(f->xf, f->bufaddr);
1762 if( !ibuf )
1763 return -1;
1764 mode = (((Inode *)ibuf->iobuf) + f->bufoffset)->i_mode;
1765 putbuf(ibuf);
1766 return mode;
1767 }
1768 void
CleanSuper(Xfs * xf)1769 CleanSuper(Xfs *xf)
1770 {
1771 Ext2 es;
1772
1773 es = getext2(xf, EXT2_SUPER, 0);
1774 es.u.sb->s_state = EXT2_VALID_FS;
1775 dirtyext2(es);
1776 putext2(es);
1777 }
1778 int
test_bit(int i,void * data)1779 test_bit(int i, void *data)
1780 {
1781 char *pt = (char *)data;
1782
1783 return pt[i>>3] & (0x01 << (i&7));
1784 }
1785
1786 int
set_bit(int i,void * data)1787 set_bit(int i, void *data)
1788 {
1789 char *pt;
1790
1791 if( test_bit(i, data) )
1792 return 1; /* bit already set !!! */
1793
1794 pt = (char *)data;
1795 pt[i>>3] |= (0x01 << (i&7));
1796
1797 return 0;
1798 }
1799
1800 int
clear_bit(int i,void * data)1801 clear_bit(int i, void *data)
1802 {
1803 char *pt;
1804
1805 if( !test_bit(i, data) )
1806 return 1; /* bit already clear !!! */
1807
1808 pt = (char *)data;
1809 pt[i>>3] &= ~(0x01 << (i&7));
1810
1811 return 0;
1812 }
1813 void *
memscan(void * data,int c,int count)1814 memscan( void *data, int c, int count )
1815 {
1816 char *pt = (char *)data;
1817
1818 while( count ){
1819 if( *pt == c )
1820 return (void *)pt;
1821 count--;
1822 pt++;
1823 }
1824 return (void *)pt;
1825 }
1826
1827 int
find_first_zero_bit(void * data,int count)1828 find_first_zero_bit( void *data, int count /* in byte */)
1829 {
1830 char *pt = (char *)data;
1831 int n, i;
1832
1833 n = 0;
1834
1835 while( n < count ){
1836 for(i=0 ; i < 8 ; i++)
1837 if( !(*pt & (0x01 << (i&7))) )
1838 return (n<<3) + i;
1839 n++; pt++;
1840 }
1841 return n << 3;
1842 }
1843
1844 int
find_next_zero_bit(void * data,int count,int where)1845 find_next_zero_bit( void *data, int count /* in byte */, int where)
1846 {
1847 char *pt = (((char *)data) + (where >> 3));
1848 int n, i;
1849
1850 n = where >> 3;
1851 i = where & 7;
1852
1853 while( n < count ){
1854 for(; i < 8 ; i++)
1855 if( !(*pt & (0x01 << (i&7))) )
1856 return (n<<3) + i;
1857 n++; pt++; i=0;
1858 }
1859 return n << 3;
1860 }
1861 int
ffz(int x)1862 ffz( int x )
1863 {
1864 int c = 0;
1865 while( x&1 ){
1866 c++;
1867 x >>= 1;
1868 }
1869 return c;
1870 }
1871