xref: /plan9/sys/src/cmd/ext2srv/ext2subs.c (revision c93608cc76758b2be624199c6208a0f90bad298d)
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
getnum(char * s,int * n)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*
idfile(char * f)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
uidfile(char * f)56 uidfile(char *f)
57 {
58 	uidmap = idfile(f);
59 }
60 
61 void
gidfile(char * f)62 gidfile(char *f)
63 {
64 	gidmap = idfile(f);
65 }
66 
67 static char*
mapuid(int id)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*
mapgid(int id)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
ext2fs(Xfs * xf)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
getext2(Xfs * xf,char type,int n)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
get_inode(Xfile * file,uint nr)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
get_file(Xfile * f,char * name)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 *
getname(Xfile * f,char * str)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
dostat(Qid qid,Xfile * f,Dir * dir)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
dowstat(Xfile * f,Dir * stat)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
readfile(Xfile * f,void * vbuf,vlong offset,long count)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
readdir(Xfile * f,void * vbuf,vlong offset,long count)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
bmap(Xfile * f,int block)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
writefile(Xfile * f,void * vbuf,vlong offset,long count)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
new_block(Xfile * f,int goal)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
getblk(Xfile * f,int block)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
block_getblk(Xfile * f,int rb,int nr)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
inode_getblk(Xfile * f,int block)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
new_inode(Xfile * f,int mode)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
create_file(Xfile * fdir,char * name,int mode)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
free_inode(Xfs * xf,int inr)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
create_dir(Xfile * fdir,char * name,int mode)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
add_entry(Xfile * f,char * name,int inr)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
unlink(Xfile * file)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
empty_dir(Xfile * dir)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
free_block_inode(Xfile * file)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 }
free_block(Xfs * xf,ulong block)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
delete_entry(Xfs * xf,Inode * inode,int inbr)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
truncfile(Xfile * f)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
getmode(Xfile * f)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
CleanSuper(Xfs * xf)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
test_bit(int i,void * data)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
set_bit(int i,void * data)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
clear_bit(int i,void * data)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 *
memscan(void * data,int c,int count)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
find_first_zero_bit(void * data,int count)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
find_next_zero_bit(void * data,int count,int where)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
ffz(int x)1862 ffz( int x )
1863 {
1864 	int c = 0;
1865 	while( x&1 ){
1866 		c++;
1867 		x >>= 1;
1868 	}
1869 	return c;
1870 }
1871