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 } 198 return e; 199 error: 200 panic("getext2"); 201 return e; 202 } 203 int 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 < 0 || 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 } 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 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 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 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 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 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 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 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 * 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 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 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 1862 ffz( int x ) 1863 { 1864 int c = 0; 1865 while( x&1 ){ 1866 c++; 1867 x >>= 1; 1868 } 1869 return c; 1870 } 1871