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