2 * ext2subs.c version 0.20
4 * Some strategic functions come from linux/fs/ext2
5 * kernel sources written by Remy Card.
18 #define putext2(e) putbuf((e).buf)
19 #define dirtyext2(e) dirtybuf((e).buf)
21 static Intmap *uidmap, *gidmap;
24 getnum(char *s, int *n)
28 *n = strtol(s, &r, 10);
42 bin = Bopen(f, OREAD);
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]));
73 if (uidmap && (p = lookupkey(uidmap, id)) != 0)
85 if (gidmap && (p = lookupkey(gidmap, id)) != 0)
94 SuperBlock superblock;
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);
104 if( superblock.s_magic != EXT2_SUPER_MAGIC ){
105 chat("Bad super block...");
109 if( !(superblock.s_state & EXT2_VALID_FS) ){
110 chat("fs not checked...");
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;
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;
128 chat(" blocks of %d bytes are not supported...", xf->block_size);
133 chat("good super block...");
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;
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...");
153 getext2(Xfs *xf, char type, int n)
160 e.buf = getbuf(xf, xf->superaddr);
161 if( !e.buf ) goto error;
162 e.u.sb = (SuperBlock *)(e.buf->iobuf + xf->superoff);
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);
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);
180 e.u.bmp = (char *)e.buf->iobuf;
181 e.type = EXT2_BBLOCK;
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);
192 e.u.bmp = (char *)e.buf->iobuf;
193 e.type = EXT2_BINODE;
204 get_inode( Xfile *file, uint nr )
206 unsigned long block_group, block;
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);
218 block_group = (nr - 1) / xf->inodes_per_group;
219 if( block_group >= xf->ngroups ){
220 chat("block group (%d) > groups count...", block_group);
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);
229 file->bufoffset = (nr-1) % xf->inodes_per_block;
231 file->bufaddr= block;
236 get_file( Xfile *f, char *name)
245 if( !S_ISDIR(getmode(f)) )
247 ibuf = getbuf(xf, f->bufaddr);
250 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
251 nblock = (inode->i_blocks * 512) / xf->block_size;
253 for(i=0 ; (i < nblock) && (i < EXT2_NDIR_BLOCKS) ; i++){
254 buf = getbuf(xf, inode->i_block[i]);
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) ){
268 offset += dir->rec_len;
278 getname(Xfile *f, char *str)
289 if( get_inode(&ft, f->pinbr) < 0 )
291 if( !S_ISDIR(getmode(&ft)) )
293 ibuf = getbuf(xf, ft.bufaddr);
296 inode = ((Inode *)ibuf->iobuf) + ft.bufoffset;
297 nblock = (inode->i_blocks * 512) / xf->block_size;
299 for(i=0 ; (i < nblock) && (i < EXT2_NDIR_BLOCKS) ; i++){
300 buf = getbuf(xf, inode->i_block[i]);
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;
311 strncpy(str, dir->name, len);
317 offset += dir->rec_len;
326 dostat(Qid qid, Xfile *f, Dir *dir )
332 memset(dir, 0, sizeof(Dir));
334 if( f->inbr == EXT2_ROOT_INODE ){
335 dir->name = estrdup9p("/");
336 dir->qid = (Qid){0,0,QTDIR};
337 dir->mode = DMDIR | 0777;
339 ibuf = getbuf(f->xf, f->bufaddr);
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;
347 name = getname(f, 0);
349 dir->uid = estrdup9p(mapuid(inode->i_uid));
350 dir->gid = estrdup9p(mapgid(inode->i_gid));
352 dir->mode = getmode(f);
353 if( qid.type & QTDIR )
359 dowstat(Xfile *f, Dir *stat)
365 char name[EXT2_NAME_LEN+1];
369 if( stat->name && stat->name[0] != 0 && strcmp(name, stat->name) ){
373 if( get_inode(&fdir, f->pinbr) < 0 ){
374 chat("can't get inode %d...", f->pinbr);
378 ibuf = getbuf(xf, fdir.bufaddr);
381 inode = ((Inode *)ibuf->iobuf) +fdir.bufoffset;
383 /* Clean old dir entry */
384 if( delete_entry(xf, inode, f->inbr) < 0 ){
385 chat("delete entry failed...");
391 /* add the new entry */
392 if( add_entry(&fdir, stat->name, f->inbr) < 0 ){
393 chat("add entry failed...");
399 ibuf = getbuf(xf, f->bufaddr);
402 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
404 if (stat->mode != ~0)
405 if( (getmode(f) & 0777) != (stat->mode & 0777) ){
406 inode->i_mode = (getmode(f) & ~0777) | (stat->mode & 0777);
409 if (stat->mtime != ~0)
410 if( inode->i_mtime != stat->mtime ){
411 inode->i_mtime = stat->mtime;
420 readfile(Xfile *f, void *vbuf, vlong offset, long count)
424 Iobuf *buffer, *ibuf;
426 int len, o, cur_block, baddr;
431 ibuf = getbuf(xf, f->bufaddr);
434 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
436 if( offset >= inode->i_size ){
440 if( offset + count > inode->i_size )
441 count = inode->i_size - offset;
444 if( S_ISLNK(getmode(f)) && (inode->i_size <= EXT2_N_BLOCKS<<2) ){
445 memcpy(&buf[0], ((char *)inode->i_block)+offset, count);
449 chat("read block [ ");
450 cur_block = offset / xf->block_size;
451 o = offset % xf->block_size;
454 baddr = bmap(f, cur_block++);
459 buffer = getbuf(xf, baddr);
465 len = xf->block_size - o;
468 memcpy(&buf[rcount], &buffer->iobuf[o], len);
475 inode->i_atime = time(0);
481 readdir(Xfile *f, void *vbuf, vlong offset, long count)
486 Inode *inode, *tinode;
489 Iobuf *buffer, *ibuf, *tbuf;
493 char name[EXT2_NAME_LEN+1];
501 if( !S_ISDIR(getmode(f)) )
504 ibuf = getbuf(xf, f->bufaddr);
507 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
508 nblock = (inode->i_blocks * 512) / xf->block_size;
510 chat("read block [ ");
512 for(i=0, rcount=0 ; (i < nblock) && (i < EXT2_NDIR_BLOCKS) ; i++){
514 buffer = getbuf(xf, inode->i_block[i]);
519 chat("%d, ", buffer->addr);
520 for(off=0 ; off < xf->block_size ; ){
522 edir = (DirEntry *)(buffer->iobuf + off);
523 off += edir->rec_len;
524 if( (edir->name[0] == '.' ) && (edir->name_len == 1))
526 if(edir->name[0] == '.' && edir->name[1] == '.' &&
529 if( edir->inode == 0 ) /* for lost+found dir ... */
531 if( index++ < f->dirindex )
534 if( get_inode(&ft, edir->inode) < 0 ){
535 chat("can't find ino no %d ] ...", edir->inode);
536 error: putbuf(buffer);
540 tbuf = getbuf(xf, ft.bufaddr);
543 tinode = ((Inode *)tbuf->iobuf) + ft.bufoffset;
545 memset(&pdir, 0, sizeof(Dir));
547 /* fill plan9 dir struct */
549 len = (edir->name_len < EXT2_NAME_LEN) ? edir->name_len : EXT2_NAME_LEN;
550 strncpy(pdir.name, edir->name, len);
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 )
563 pdir.length = tinode->i_size;
564 pdir.atime = tinode->i_atime;
565 pdir.mtime = tinode->i_mtime;
569 dirlen = convD2M(&pdir, &buf[rcount], count-rcount);
570 if ( dirlen <= BIT16SZ ) {
587 bmap( Xfile *f, int block )
593 int addr_per_block = xf->addr_per_block;
594 int addr_per_block_bits = ffz(~addr_per_block);
597 chat("bmap() block < 0 ...");
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...");
607 ibuf = getbuf(xf, f->bufaddr);
610 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
613 if(block < EXT2_NDIR_BLOCKS){
615 return inode->i_block[block];
617 block -= EXT2_NDIR_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);
630 block -= addr_per_block;
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));
640 buf = getbuf(xf, addr);
641 if( !buf ) goto error;
642 addr = *(((uint *)buf->iobuf) + (block & (addr_per_block - 1)));
647 block -= (1 << (addr_per_block_bits * 2));
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)));
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)));
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)));
674 writefile(Xfile *f, void *vbuf, vlong offset, long count)
678 Iobuf *buffer, *ibuf;
680 int len, o, cur_block, baddr;
685 ibuf = getbuf(xf, f->bufaddr);
688 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
690 chat("write block [ ");
691 cur_block = offset / xf->block_size;
692 o = offset % xf->block_size;
695 baddr = getblk(f, cur_block++);
698 buffer = getbuf(xf, baddr);
702 len = xf->block_size - o;
705 memcpy(&buffer->iobuf[o], &buf[w], len);
713 if( inode->i_size < offset + w )
714 inode->i_size = offset + w;
715 inode->i_atime = inode->i_mtime = time(0);
724 new_block( Xfile *f, int goal )
727 int group, block, baddr, k, redo;
733 es = getext2(xf, EXT2_SUPER, 0);
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;
742 ed = getext2(xf, EXT2_DESC, group);
743 eb = getext2(xf, EXT2_BBLOCK, group);
746 * First, test if goal block is free
748 if( ed.u.gd->bg_free_blocks_count > 0 ){
749 block = (goal - es.u.sb->s_first_data_block) % xf->blocks_per_group;
751 if( !test_bit(block, eb.u.bmp) )
756 * goal wasn't free ; search foward for a free
757 * block within the next 32 blocks
760 lmap = (((ulong *)eb.u.bmp)[block>>5]) >>
762 if( block < xf->blocks_per_group - 32 )
763 lmap |= (((ulong *)eb.u.bmp)[(block>>5)+1]) <<
766 lmap |= 0xffffffff << ( 31-(block & 31) );
768 if( lmap != 0xffffffffl ){
770 if( (block + k) < xf->blocks_per_group ){
777 * Search in the remaider of the group
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 ){
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 ){
795 * Search the rest of groups
797 putext2(ed); putext2(eb);
798 for(k=0 ; k < xf->ngroups ; k++){
800 if( group >= xf->ngroups )
802 ed = getext2(xf, EXT2_DESC, group);
803 if( ed.u.gd->bg_free_blocks_count > 0 )
807 if( redo && group == xf->ngroups-1 ){
811 if( k >=xf->ngroups ){
813 * All groups are full or
814 * we have retry (because the last block) and all other
815 * groups are also full.
818 chat("no free blocks ...");
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 )
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);
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.
844 for(k=0 ; k < 7 && block > 0 &&
845 !test_bit(block-1, eb.u.bmp) ; k++, block--);
849 baddr = block + (group * xf->blocks_per_group) +
850 es.u.sb->s_first_data_block;
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);
860 if( set_bit(block, eb.u.bmp) ){
861 chat("bit already set (%d)...", block);
862 putext2(ed); putext2(eb); putext2(es);
868 if( baddr >= es.u.sb->s_blocks_count ){
869 chat("block >= blocks count...");
872 clear_bit(block, eb.u.bmp);
873 putext2(eb); putext2(ed); putext2(es);
877 buf = getbuf(xf, baddr);
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.
886 clear_bit(block, eb.u.bmp);
887 putext2(eb); putext2(ed);
888 goal = 0; errno = 0; redo++;
893 memset(&buf->iobuf[0], 0, xf->block_size);
897 es.u.sb->s_free_blocks_count--;
899 ed.u.gd->bg_free_blocks_count--;
909 getblk(Xfile *f, int block)
913 int addr_per_block = xf->addr_per_block;
916 chat("getblk() block < 0 ...");
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...");
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);
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));
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));
948 block_getblk(Xfile *f, int rb, int nr)
953 int blocks = xf->block_size / 512;
961 buf = getbuf(xf, rb);
964 p = (uint *)(buf->iobuf) + nr;
971 for(tmp=nr - 1 ; tmp >= 0 ; tmp--){
972 if( ((uint *)(buf->iobuf))[tmp] ){
973 goal = ((uint *)(buf->iobuf))[tmp];
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;
985 tmp = new_block(f, goal);
995 ibuf = getbuf(xf, f->bufaddr);
998 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
999 inode->i_blocks += blocks;
1006 inode_getblk(Xfile *f, int block)
1012 int blocks = xf->block_size / 512;
1015 ibuf = getbuf(xf, f->bufaddr);
1018 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
1021 if( inode->i_block[block] ){
1023 return inode->i_block[block];
1026 for(tmp=block - 1 ; tmp >= 0 ; tmp--){
1027 if( inode->i_block[tmp] ){
1028 goal = inode->i_block[tmp];
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;
1040 tmp = new_block(f, goal);
1046 inode->i_block[block] = tmp;
1047 inode->i_blocks += blocks;
1054 new_inode(Xfile *f, int mode)
1057 Inode *inode, *finode;
1059 int ave,group, i, j;
1064 es = getext2(xf, EXT2_SUPER, 0);
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 )
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 ){
1088 * Use a quadratic hash to find a group whith
1092 for( j=1 ; j < xf->ngroups ; j <<= 1){
1094 if( i >= xf->ngroups )
1096 ed = getext2(xf, EXT2_DESC, i);
1097 if( ed.u.gd->bg_free_inodes_count ){
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 )
1111 ed = getext2(xf, EXT2_DESC, i);
1112 if( ed.u.gd->bg_free_inodes_count ){
1123 chat("group < 0...");
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);
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);
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...");
1150 clear_bit(i, eb.u.bmp);
1151 putext2(eb); putext2(ed); putext2(es);
1155 buf = getbuf(xf, ed.u.gd->bg_inode_table +
1156 (((j-1) % xf->inodes_per_group) /
1157 xf->inodes_per_block));
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);
1170 ibuf = getbuf(xf, f->bufaddr);
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;
1184 ed.u.gd->bg_free_inodes_count--;
1186 ed.u.gd->bg_used_dirs_count++;
1189 es.u.sb->s_free_inodes_count--;
1199 create_file(Xfile *fdir, char *name, int mode)
1203 inr = new_inode(fdir, mode);
1205 chat("create one new inode failed...");
1208 if( add_entry(fdir, name, inr) < 0 ){
1209 chat("add entry failed...");
1210 free_inode(fdir->xf, inr);
1217 free_inode( Xfs *xf, int inr)
1224 bg = (inr -1) / xf->inodes_per_group;
1225 b = (inr -1) % xf->inodes_per_group;
1227 ed = getext2(xf, EXT2_DESC, bg);
1228 buf = getbuf(xf, ed.u.gd->bg_inode_table +
1229 (b / xf->inodes_per_block));
1234 inode = ((struct Inode *) buf->iobuf) +
1235 ((inr-1) % xf->inodes_per_block);
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);
1244 ed.u.gd->bg_free_inodes_count++;
1248 eb = getext2(xf, EXT2_BINODE, bg);
1249 clear_bit(b, eb.u.bmp);
1253 es = getext2(xf, EXT2_SUPER, 0);
1254 es.u.sb->s_free_inodes_count++;
1255 dirtyext2(es); putext2(es);
1258 create_dir(Xfile *fdir, char *name, int mode)
1267 inr = new_inode(fdir, mode);
1269 chat("create one new inode failed...");
1272 if( add_entry(fdir, name, inr) < 0 ){
1273 chat("add entry failed...");
1274 free_inode(fdir->xf, inr);
1278 /* create the empty dir */
1281 if( get_inode(&tf, inr) < 0 ){
1282 chat("can't get inode %d...", inr);
1283 free_inode(fdir->xf, inr);
1287 ibuf = getbuf(xf, tf.bufaddr);
1289 free_inode(fdir->xf, inr);
1292 inode = ((Inode *)ibuf->iobuf) + tf.bufoffset;
1295 baddr = inode_getblk(&tf, 0);
1298 ibuf = getbuf(xf, fdir->bufaddr);
1300 free_inode(fdir->xf, inr);
1303 inode = ((Inode *)ibuf->iobuf) + fdir->bufoffset;
1304 delete_entry(fdir->xf, inode, inr);
1306 free_inode(fdir->xf, inr);
1310 inode->i_size = xf->block_size;
1311 buf = getbuf(xf, baddr);
1313 de = (DirEntry *)buf->iobuf;
1316 de->rec_len = DIR_REC_LEN(de->name_len);
1317 strcpy(de->name, ".");
1319 de = (DirEntry *)( (char *)de + de->rec_len);
1320 de->inode = fdir->inbr;
1322 de->rec_len = xf->block_size - DIR_REC_LEN(1);
1323 strcpy(de->name, "..");
1328 inode->i_links_count = 2;
1332 ibuf = getbuf(xf, fdir->bufaddr);
1335 inode = ((Inode *)ibuf->iobuf) + fdir->bufoffset;
1337 inode->i_links_count++;
1345 add_entry(Xfile *f, char *name, int inr)
1350 int rec_len, cur_block;
1351 int namelen = strlen(name);
1355 ibuf = getbuf(xf, f->bufaddr);
1358 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
1360 if( inode->i_size == 0 ){
1361 chat("add_entry() no entry !!!...");
1365 cur_block = offset = 0;
1366 rec_len = DIR_REC_LEN(namelen);
1367 buf = getbuf(xf, inode->i_block[cur_block++]);
1372 de = (DirEntry *)buf->iobuf;
1375 if( ((char *)de) >= (xf->block_size + buf->iobuf) ){
1377 if( cur_block >= EXT2_NDIR_BLOCKS ){
1382 if( (baddr = inode_getblk(f, cur_block++)) == 0 ){
1386 buf = getbuf(xf, baddr);
1391 if( inode->i_size <= offset ){
1392 de = (DirEntry *)buf->iobuf;
1394 de->rec_len = xf->block_size;
1396 inode->i_size = offset + xf->block_size;
1399 de = (DirEntry *)buf->iobuf;
1402 if( de->inode != 0 && de->name_len == namelen &&
1403 !strncmp(name, de->name, namelen) ){
1405 putbuf(ibuf); putbuf(buf);
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) ){
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);
1418 de->name_len = namelen;
1419 memcpy(de->name, name, namelen);
1422 inode->i_mtime = inode->i_ctime = time(0);
1427 de = (DirEntry *)((char *)de + de->rec_len);
1432 unlink( Xfile *file )
1441 if( S_ISDIR(getmode(file)) && !empty_dir(file) ){
1442 chat("non empty directory...");
1447 es = getext2(xf, EXT2_SUPER, 0);
1450 if( file->pinbr >= es.u.sb->s_inodes_count ){
1451 chat("inode number %d is too big...", file->pinbr);
1456 bg = (file->pinbr - 1) / xf->inodes_per_group;
1457 if( bg >= xf->ngroups ){
1458 chat("block group (%d) > groups count...", bg);
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);
1468 buf = getbuf(xf, b);
1473 dir = ((struct Inode *) buf->iobuf) +
1474 ((file->pinbr-1) % xf->inodes_per_block);
1476 /* Clean dir entry */
1478 if( delete_entry(xf, dir, file->inbr) < 0 ){
1483 if( S_ISDIR(getmode(file)) ){
1484 dir->i_links_count--;
1490 ibuf = getbuf(xf, file->bufaddr);
1495 inode = ((Inode *)ibuf->iobuf) + file->bufoffset;
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...");
1509 bg = (file->inbr -1) / xf->inodes_per_group;
1510 b = (file->inbr -1) % xf->inodes_per_group;
1512 eb = getext2(xf, EXT2_BINODE, bg);
1513 clear_bit(b, eb.u.bmp);
1517 inode->i_dtime = time(0);
1518 inode->i_links_count--;
1519 if( S_ISDIR(getmode(file)) )
1520 inode->i_links_count = 0;
1522 es.u.sb->s_free_inodes_count++;
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--;
1539 empty_dir(Xfile *dir)
1543 uint offset, i,count;
1548 if( !S_ISDIR(getmode(dir)) )
1551 ibuf = getbuf(xf, dir->bufaddr);
1554 inode = ((Inode *)ibuf->iobuf) + dir->bufoffset;
1555 nblock = (inode->i_blocks * 512) / xf->block_size;
1557 for(i=0, count=0 ; (i < nblock) && (i < EXT2_NDIR_BLOCKS) ; i++){
1558 buf = getbuf(xf, inode->i_block[i]);
1563 for(offset=0 ; offset < xf->block_size ; ){
1564 de = (DirEntry *)(buf->iobuf + offset);
1567 offset += de->rec_len;
1579 free_block_inode(Xfile *file)
1587 Iobuf *buf, *buf1, *buf2, *ibuf;
1589 ibuf = getbuf(xf, file->bufaddr);
1592 inode = ((Inode *)ibuf->iobuf) + file->bufoffset;
1594 for(i=0 ; i < EXT2_IND_BLOCK ; i++){
1595 x = inode->i_block + i;
1596 if( *x == 0 ){ putbuf(ibuf); return 0; }
1599 naddr = xf->addr_per_block;
1601 /* indirect blocks */
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;
1615 /* double indirect block */
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;
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;
1637 /* triple indirect block */
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;
1670 void free_block( Xfs *xf, ulong block )
1675 es = getext2(xf, EXT2_SUPER, 0);
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;
1680 eb = getext2(xf, EXT2_BBLOCK, bg);
1681 clear_bit(block, eb.u.bmp);
1685 es.u.sb->s_free_blocks_count++;
1689 ed = getext2(xf, EXT2_DESC, bg);
1690 ed.u.gd->bg_free_blocks_count++;
1696 delete_entry(Xfs *xf, Inode *inode, int inbr)
1698 int nblock = (inode->i_blocks * 512) / xf->block_size;
1703 if( !S_ISDIR(inode->i_mode) )
1706 for(i=0 ; (i < nblock) && (i < EXT2_NDIR_BLOCKS) ; i++){
1707 buf = getbuf(xf, inode->i_block[i]);
1711 for(offset=0 ; offset < xf->block_size ; ){
1712 de = (DirEntry *)(buf->iobuf + offset);
1713 if( de->inode == inbr ){
1715 pde->rec_len += de->rec_len;
1721 offset += de->rec_len;
1735 chat("trunc(fid=%d) ...", f->fid);
1736 ibuf = getbuf(f->xf, f->bufaddr);
1739 inode = ((Inode *)ibuf->iobuf) + f->bufoffset;
1741 if( free_block_inode(f) < 0 ){
1742 chat("error while freeing blocks...");
1746 inode->i_atime = inode->i_mtime = time(0);
1747 inode->i_blocks = 0;
1749 memset(inode->i_block, 0, EXT2_N_BLOCKS*sizeof(ulong));
1752 chat("trunc ok...");
1761 ibuf = getbuf(f->xf, f->bufaddr);
1764 mode = (((Inode *)ibuf->iobuf) + f->bufoffset)->i_mode;
1773 es = getext2(xf, EXT2_SUPER, 0);
1774 es.u.sb->s_state = EXT2_VALID_FS;
1779 test_bit(int i, void *data)
1781 char *pt = (char *)data;
1783 return pt[i>>3] & (0x01 << (i&7));
1787 set_bit(int i, void *data)
1791 if( test_bit(i, data) )
1792 return 1; /* bit already set !!! */
1795 pt[i>>3] |= (0x01 << (i&7));
1801 clear_bit(int i, void *data)
1805 if( !test_bit(i, data) )
1806 return 1; /* bit already clear !!! */
1809 pt[i>>3] &= ~(0x01 << (i&7));
1814 memscan( void *data, int c, int count )
1816 char *pt = (char *)data;
1828 find_first_zero_bit( void *data, int count /* in byte */)
1830 char *pt = (char *)data;
1836 for(i=0 ; i < 8 ; i++)
1837 if( !(*pt & (0x01 << (i&7))) )
1845 find_next_zero_bit( void *data, int count /* in byte */, int where)
1847 char *pt = (((char *)data) + (where >> 3));
1855 if( !(*pt & (0x01 << (i&7))) )