Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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