]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ext2srv/ext2subs.c
mothra: fix alt display resizing, filter control characters in panel entries, use...
[plan9front.git] / sys / src / cmd / ext2srv / ext2subs.c
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 > 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 }