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