GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/fsck_ffs/dir.c Lines: 0 352 0.0 %
Date: 2016-12-06 Branches: 0 348 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: dir.c,v 1.32 2015/01/20 18:22:21 deraadt Exp $	*/
2
/*	$NetBSD: dir.c,v 1.20 1996/09/27 22:45:11 christos Exp $	*/
3
4
/*
5
 * Copyright (c) 1980, 1986, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/param.h>	/* DEV_BSIZE roundup btodb */
34
#include <sys/time.h>
35
#include <ufs/ufs/dinode.h>
36
#include <ufs/ufs/dir.h>
37
#include <ufs/ffs/fs.h>
38
39
#include <stdio.h>
40
#include <stdlib.h>
41
#include <string.h>
42
#include <limits.h>
43
44
#include "fsck.h"
45
#include "fsutil.h"
46
#include "extern.h"
47
48
char	*lfname = "lost+found";
49
int	lfmode = 01700;
50
struct	dirtemplate emptydir = { 0, DIRBLKSIZ };
51
struct	dirtemplate dirhead = {
52
	0, 12, DT_DIR, 1, ".",
53
	0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
54
};
55
struct	odirtemplate odirhead = {
56
	0, 12, 1, ".",
57
	0, DIRBLKSIZ - 12, 2, ".."
58
};
59
60
static int expanddir(union dinode *, char *);
61
static void freedir(ino_t, ino_t);
62
static struct direct *fsck_readdir(struct inodesc *);
63
static struct bufarea *getdirblk(daddr_t, long);
64
static int lftempname(char *, ino_t);
65
static int mkentry(struct inodesc *);
66
static int chgino(struct  inodesc *);
67
68
/*
69
 * Propagate connected state through the tree.
70
 */
71
void
72
propagate(ino_t inumber)
73
{
74
	struct	inoinfo *inp;
75
	char	state;
76
77
	inp = getinoinfo(inumber);
78
	state = GET_ISTATE(inp->i_number);
79
	for (;;) {
80
		SET_ISTATE(inp->i_number, state);
81
		if (inp->i_child &&
82
		    GET_ISTATE(inp->i_child->i_number) != state)
83
			inp = inp->i_child;
84
		else if (inp->i_number == inumber)
85
			break;
86
		else if (inp->i_sibling)
87
			inp = inp->i_sibling;
88
		else
89
			inp = getinoinfo(inp->i_parent);
90
	}
91
}
92
93
/*
94
 * Scan each entry in a directory block.
95
 */
96
int
97
dirscan(struct inodesc *idesc)
98
{
99
	struct direct *dp;
100
	struct bufarea *bp;
101
	int dsize, n;
102
	long blksiz;
103
	char dbuf[DIRBLKSIZ];
104
105
	if (idesc->id_type != DATA)
106
		errexit("wrong type to dirscan %d\n", idesc->id_type);
107
	if (idesc->id_entryno == 0 &&
108
	    (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)
109
		idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);
110
	blksiz = idesc->id_numfrags * sblock.fs_fsize;
111
	if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {
112
		idesc->id_filesize -= blksiz;
113
		return (SKIP);
114
	}
115
	idesc->id_loc = 0;
116
	for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
117
		dsize = dp->d_reclen;
118
		memcpy(dbuf, dp, (size_t)dsize);
119
		idesc->id_dirp = (struct direct *)dbuf;
120
		if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
121
			bp = getdirblk(idesc->id_blkno, blksiz);
122
			memcpy(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf,
123
			    (size_t)dsize);
124
			dirty(bp);
125
			sbdirty();
126
		}
127
		if (n & STOP)
128
			return (n);
129
	}
130
	return (idesc->id_filesize > 0 ? KEEPON : STOP);
131
}
132
133
/*
134
 * get next entry in a directory.
135
 */
136
static struct direct *
137
fsck_readdir(struct inodesc *idesc)
138
{
139
	struct direct *dp, *ndp;
140
	struct bufarea *bp;
141
	long size, blksiz, fix, dploc;
142
143
	blksiz = idesc->id_numfrags * sblock.fs_fsize;
144
	bp = getdirblk(idesc->id_blkno, blksiz);
145
	if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
146
	    idesc->id_loc < blksiz) {
147
		dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
148
		if (dircheck(idesc, dp))
149
			goto dpok;
150
		if (idesc->id_fix == IGNORE)
151
			return (0);
152
		fix = dofix(idesc, "DIRECTORY CORRUPTED");
153
		bp = getdirblk(idesc->id_blkno, blksiz);
154
		dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
155
		dp->d_reclen = DIRBLKSIZ;
156
		dp->d_ino = 0;
157
		dp->d_type = 0;
158
		dp->d_namlen = 0;
159
		dp->d_name[0] = '\0';
160
		if (fix)
161
			dirty(bp);
162
		idesc->id_loc += DIRBLKSIZ;
163
		idesc->id_filesize -= DIRBLKSIZ;
164
		return (dp);
165
	}
166
dpok:
167
	if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
168
		return NULL;
169
	dploc = idesc->id_loc;
170
	dp = (struct direct *)(bp->b_un.b_buf + dploc);
171
	idesc->id_loc += dp->d_reclen;
172
	idesc->id_filesize -= dp->d_reclen;
173
	if ((idesc->id_loc % DIRBLKSIZ) == 0)
174
		return (dp);
175
	ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
176
	if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
177
	    dircheck(idesc, ndp) == 0) {
178
		size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
179
		idesc->id_loc += size;
180
		idesc->id_filesize -= size;
181
		if (idesc->id_fix == IGNORE)
182
			return (0);
183
		fix = dofix(idesc, "DIRECTORY CORRUPTED");
184
		bp = getdirblk(idesc->id_blkno, blksiz);
185
		dp = (struct direct *)(bp->b_un.b_buf + dploc);
186
		dp->d_reclen += size;
187
		if (fix)
188
			dirty(bp);
189
	}
190
	return (dp);
191
}
192
193
/*
194
 * Verify that a directory entry is valid.
195
 * This is a superset of the checks made in the kernel.
196
 */
197
int
198
dircheck(struct inodesc *idesc, struct direct *dp)
199
{
200
	int size;
201
	char *cp;
202
	u_char namlen, type;
203
	int spaceleft;
204
205
	spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
206
	if (dp->d_ino >= maxino ||
207
	    dp->d_reclen == 0 ||
208
	    dp->d_reclen > spaceleft ||
209
	    (dp->d_reclen & 0x3) != 0)
210
		return (0);
211
	if (dp->d_ino == 0)
212
		return (1);
213
	size = DIRSIZ(0, dp);
214
	namlen = dp->d_namlen;
215
	type = dp->d_type;
216
	if (dp->d_reclen < size ||
217
	    idesc->id_filesize < size ||
218
	    type > 15)
219
		return (0);
220
	for (cp = dp->d_name, size = 0; size < namlen; size++)
221
		if (*cp == '\0' || (*cp++ == '/'))
222
			return (0);
223
	if (*cp != '\0')
224
		return (0);
225
	return (1);
226
}
227
228
void
229
direrror(ino_t ino, char *errmesg)
230
{
231
	fileerror(ino, ino, errmesg);
232
}
233
234
void
235
fileerror(ino_t cwd, ino_t ino, char *errmesg)
236
{
237
	union dinode *dp;
238
	char pathbuf[PATH_MAX + 1];
239
240
	pwarn("%s ", errmesg);
241
	pinode(ino);
242
	printf("\n");
243
	getpathname(pathbuf, sizeof pathbuf, cwd, ino);
244
	if (ino < ROOTINO || ino > maxino) {
245
		pfatal("NAME=%s\n", pathbuf);
246
		return;
247
	}
248
	dp = ginode(ino);
249
	if (ftypeok(dp))
250
		pfatal("%s=%s\n",
251
		    (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE",
252
		    pathbuf);
253
	else
254
		pfatal("NAME=%s\n", pathbuf);
255
}
256
257
void
258
adjust(struct inodesc *idesc, short lcnt)
259
{
260
	union dinode *dp;
261
262
	dp = ginode(idesc->id_number);
263
	if (DIP(dp, di_nlink) == lcnt) {
264
		if (linkup(idesc->id_number, 0) == 0)
265
			clri(idesc, "UNREF", 0);
266
	} else {
267
		pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
268
			((DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE"));
269
		pinode(idesc->id_number);
270
		printf(" COUNT %d SHOULD BE %d", DIP(dp, di_nlink),
271
		    DIP(dp, di_nlink) - lcnt);
272
		if (preen || usedsoftdep) {
273
			if (lcnt < 0) {
274
				printf("\n");
275
				pfatal("LINK COUNT INCREASING");
276
			}
277
			if (preen)
278
				printf(" (ADJUSTED)\n");
279
		}
280
		if (preen || reply("ADJUST") == 1) {
281
			DIP_SET(dp, di_nlink, DIP(dp, di_nlink) - lcnt);
282
			inodirty();
283
		}
284
	}
285
}
286
287
static int
288
mkentry(struct inodesc *idesc)
289
{
290
	struct direct *dirp = idesc->id_dirp;
291
	struct direct newent;
292
	int newlen, oldlen;
293
294
	newent.d_namlen = strlen(idesc->id_name);
295
	newlen = DIRSIZ(0, &newent);
296
	if (dirp->d_ino != 0)
297
		oldlen = DIRSIZ(0, dirp);
298
	else
299
		oldlen = 0;
300
	if (dirp->d_reclen - oldlen < newlen)
301
		return (KEEPON);
302
	newent.d_reclen = dirp->d_reclen - oldlen;
303
	dirp->d_reclen = oldlen;
304
	dirp = (struct direct *)(((char *)dirp) + oldlen);
305
	dirp->d_ino = idesc->id_parent;	/* ino to be entered is in id_parent */
306
	dirp->d_reclen = newent.d_reclen;
307
	dirp->d_type = GET_ITYPE(idesc->id_parent);
308
	dirp->d_namlen = newent.d_namlen;
309
	memcpy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);
310
	return (ALTERED|STOP);
311
}
312
313
static int
314
chgino(struct inodesc *idesc)
315
{
316
	struct direct *dirp = idesc->id_dirp;
317
318
	if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1))
319
		return (KEEPON);
320
	dirp->d_ino = idesc->id_parent;
321
	dirp->d_type = GET_ITYPE(idesc->id_parent);
322
	return (ALTERED|STOP);
323
}
324
325
int
326
linkup(ino_t orphan, ino_t parentdir)
327
{
328
	union dinode *dp;
329
	int lostdir;
330
	ino_t oldlfdir;
331
	struct inodesc idesc;
332
	char tempname[BUFSIZ];
333
334
	memset(&idesc, 0, sizeof(struct inodesc));
335
	dp = ginode(orphan);
336
	lostdir = (DIP(dp, di_mode) & IFMT) == IFDIR;
337
	pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
338
	pinode(orphan);
339
	if ((preen || usedsoftdep) && DIP(dp, di_size) == 0)
340
		return (0);
341
	if (preen)
342
		printf(" (RECONNECTED)\n");
343
	else
344
		if (reply("RECONNECT") == 0)
345
			return (0);
346
	if (lfdir == 0) {
347
		dp = ginode(ROOTINO);
348
		idesc.id_name = lfname;
349
		idesc.id_type = DATA;
350
		idesc.id_func = findino;
351
		idesc.id_number = ROOTINO;
352
		if ((ckinode(dp, &idesc) & FOUND) != 0) {
353
			lfdir = idesc.id_parent;
354
		} else {
355
			pwarn("NO lost+found DIRECTORY");
356
			if (preen || reply("CREATE")) {
357
				lfdir = allocdir(ROOTINO, 0, lfmode);
358
				if (lfdir != 0) {
359
					if (makeentry(ROOTINO, lfdir, lfname) != 0) {
360
						if (preen)
361
							printf(" (CREATED)\n");
362
					} else {
363
						freedir(lfdir, ROOTINO);
364
						lfdir = 0;
365
						if (preen)
366
							printf("\n");
367
					}
368
				}
369
			}
370
		}
371
		if (lfdir == 0) {
372
			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
373
			printf("\n\n");
374
			return (0);
375
		}
376
	}
377
	dp = ginode(lfdir);
378
	if ((DIP(dp, di_mode) & IFMT) != IFDIR) {
379
		pfatal("lost+found IS NOT A DIRECTORY");
380
		if (reply("REALLOCATE") == 0)
381
			return (0);
382
		oldlfdir = lfdir;
383
		if ((lfdir = allocdir(ROOTINO, 0, lfmode)) == 0) {
384
			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
385
			return (0);
386
		}
387
		if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) {
388
			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
389
			return (0);
390
		}
391
		inodirty();
392
		idesc.id_type = ADDR;
393
		idesc.id_func = pass4check;
394
		idesc.id_number = oldlfdir;
395
		adjust(&idesc, ILNCOUNT(oldlfdir) + 1);
396
		ILNCOUNT(oldlfdir) = 0;
397
		dp = ginode(lfdir);
398
	}
399
	if (GET_ISTATE(lfdir) != DFOUND) {
400
		pfatal("SORRY. NO lost+found DIRECTORY\n\n");
401
		return (0);
402
	}
403
	(void)lftempname(tempname, orphan);
404
	if (makeentry(lfdir, orphan, tempname) == 0) {
405
		pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
406
		printf("\n\n");
407
		return (0);
408
	}
409
	ILNCOUNT(orphan)--;
410
	if (lostdir) {
411
		if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 &&
412
		    parentdir != (ino_t)-1)
413
			(void)makeentry(orphan, lfdir, "..");
414
		dp = ginode(lfdir);
415
		DIP_SET(dp, di_nlink, DIP(dp, di_nlink) + 1);
416
		inodirty();
417
		ILNCOUNT(lfdir)++;
418
		pwarn("DIR I=%llu CONNECTED. ",
419
		    (unsigned long long)orphan);
420
		if (parentdir != (ino_t)-1) {
421
			printf("PARENT WAS I=%llu\n",
422
			    (unsigned long long)parentdir);
423
			/*
424
			 * The parent directory, because of the ordering
425
			 * guarantees, has had the link count incremented
426
			 * for the child, but no entry was made.  This
427
			 * fixes the parent link count so that fsck does
428
			 * not need to be rerun.
429
			 */
430
			ILNCOUNT(parentdir)++;
431
		}
432
		if (preen == 0)
433
			printf("\n");
434
	}
435
	return (1);
436
}
437
438
/*
439
 * fix an entry in a directory.
440
 */
441
int
442
changeino(dir, name, newnum)
443
	ino_t dir;
444
	char *name;
445
	ino_t newnum;
446
{
447
	struct inodesc idesc;
448
449
	memset(&idesc, 0, sizeof(struct inodesc));
450
	idesc.id_type = DATA;
451
	idesc.id_func = chgino;
452
	idesc.id_number = dir;
453
	idesc.id_fix = DONTKNOW;
454
	idesc.id_name = name;
455
	idesc.id_parent = newnum;	/* new value for name */
456
	return (ckinode(ginode(dir), &idesc));
457
}
458
459
/*
460
 * make an entry in a directory
461
 */
462
int
463
makeentry(ino_t parent, ino_t ino, char *name)
464
{
465
	union dinode *dp;
466
	struct inodesc idesc;
467
	char pathbuf[PATH_MAX + 1];
468
469
	if (parent < ROOTINO || parent >= maxino ||
470
	    ino < ROOTINO || ino >= maxino)
471
		return (0);
472
	memset(&idesc, 0, sizeof(struct inodesc));
473
	idesc.id_type = DATA;
474
	idesc.id_func = mkentry;
475
	idesc.id_number = parent;
476
	idesc.id_parent = ino;	/* this is the inode to enter */
477
	idesc.id_fix = DONTKNOW;
478
	idesc.id_name = name;
479
	dp = ginode(parent);
480
	if (DIP(dp, di_size) % DIRBLKSIZ) {
481
		DIP_SET(dp, di_size, roundup(DIP(dp, di_size), DIRBLKSIZ));
482
		inodirty();
483
	}
484
	if ((ckinode(dp, &idesc) & ALTERED) != 0)
485
		return (1);
486
	getpathname(pathbuf, sizeof pathbuf, parent, parent);
487
	dp = ginode(parent);
488
	if (expanddir(dp, pathbuf) == 0)
489
		return (0);
490
	return (ckinode(dp, &idesc) & ALTERED);
491
}
492
493
/*
494
 * Attempt to expand the size of a directory
495
 */
496
static int
497
expanddir(union dinode *dp, char *name)
498
{
499
	daddr_t lastbn, newblk;
500
	struct bufarea *bp;
501
	char *cp, firstblk[DIRBLKSIZ];
502
	u_int64_t dis;
503
504
	dis = lblkno(&sblock, DIP(dp, di_size));
505
	if (dis > (u_int64_t)INT_MAX)
506
		return (0);
507
	lastbn = dis;
508
	if (lastbn >= NDADDR - 1 || DIP(dp, di_db[lastbn]) == 0 ||
509
	    DIP(dp, di_size) == 0)
510
		return (0);
511
	if ((newblk = allocblk(sblock.fs_frag)) == 0)
512
		return (0);
513
	DIP_SET(dp, di_db[lastbn + 1], DIP(dp, di_db[lastbn]));
514
	DIP_SET(dp, di_db[lastbn], newblk);
515
	DIP_SET(dp, di_size, DIP(dp, di_size) + sblock.fs_bsize);
516
	DIP_SET(dp, di_blocks, DIP(dp, di_blocks) + btodb(sblock.fs_bsize));
517
	bp = getdirblk(DIP(dp, di_db[lastbn + 1]),
518
	    sblksize(&sblock, DIP(dp, di_size), lastbn + 1));
519
	if (bp->b_errs)
520
		goto bad;
521
	memcpy(firstblk, bp->b_un.b_buf, DIRBLKSIZ);
522
	bp = getdirblk(newblk, sblock.fs_bsize);
523
	if (bp->b_errs)
524
		goto bad;
525
	memcpy(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
526
	for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
527
	     cp < &bp->b_un.b_buf[sblock.fs_bsize];
528
	     cp += DIRBLKSIZ)
529
		memcpy(cp, &emptydir, sizeof emptydir);
530
	dirty(bp);
531
	bp = getdirblk(DIP(dp, di_db[lastbn + 1]),
532
	    sblksize(&sblock, DIP(dp, di_size), lastbn + 1));
533
	if (bp->b_errs)
534
		goto bad;
535
	memcpy(bp->b_un.b_buf, &emptydir, sizeof emptydir);
536
	pwarn("NO SPACE LEFT IN %s", name);
537
	if (preen)
538
		printf(" (EXPANDED)\n");
539
	else if (reply("EXPAND") == 0)
540
		goto bad;
541
	dirty(bp);
542
	inodirty();
543
	return (1);
544
bad:
545
	DIP_SET(dp, di_db[lastbn], DIP(dp, di_db[lastbn + 1]));
546
	DIP_SET(dp, di_db[lastbn + 1], 0);
547
	DIP_SET(dp, di_size, DIP(dp, di_size) - sblock.fs_bsize);
548
	DIP_SET(dp, di_blocks, DIP(dp, di_blocks) - btodb(sblock.fs_bsize));
549
	freeblk(newblk, sblock.fs_frag);
550
	return (0);
551
}
552
553
/*
554
 * allocate a new directory
555
 */
556
ino_t
557
allocdir(ino_t parent, ino_t request, int mode)
558
{
559
	ino_t ino;
560
	uid_t uid;
561
	gid_t gid;
562
	char *cp;
563
	union dinode *dp;
564
	struct bufarea *bp;
565
	struct dirtemplate *dirp;
566
	struct inoinfo *inp;
567
568
	ino = allocino(request, IFDIR|mode);
569
	dirp = &dirhead;
570
	dirp->dot_ino = ino;
571
	dirp->dotdot_ino = parent;
572
	dp = ginode(ino);
573
	bp = getdirblk(DIP(dp, di_db[0]), sblock.fs_fsize);
574
	if (bp->b_errs) {
575
		freeino(ino);
576
		return (0);
577
	}
578
	memcpy(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate));
579
	for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
580
	     cp < &bp->b_un.b_buf[sblock.fs_fsize];
581
	     cp += DIRBLKSIZ)
582
		memcpy(cp, &emptydir, sizeof emptydir);
583
	dirty(bp);
584
	DIP_SET(dp, di_nlink, 2);
585
	inodirty();
586
	if (ino == ROOTINO) {
587
		ILNCOUNT(ino) = DIP(dp, di_nlink);
588
		cacheino(dp, ino);
589
		return(ino);
590
	}
591
	if (GET_ISTATE(parent) != DSTATE && GET_ISTATE(parent) != DFOUND) {
592
		freeino(ino);
593
		return (0);
594
	}
595
	cacheino(dp, ino);
596
	inp = getinoinfo(ino);
597
	inp->i_parent = parent;
598
	inp->i_dotdot = parent;
599
	SET_ISTATE(ino, GET_ISTATE(parent));
600
	if (GET_ISTATE(ino) == DSTATE) {
601
		ILNCOUNT(ino) = DIP(dp, di_nlink);
602
		ILNCOUNT(parent)++;
603
	}
604
	dp = ginode(parent);
605
	DIP_SET(dp, di_nlink, DIP(dp, di_nlink) + 1);
606
	uid = DIP(dp, di_uid);
607
	gid = DIP(dp, di_gid);
608
	inodirty();
609
	dp = ginode(ino);
610
	DIP_SET(dp, di_uid, uid);
611
	DIP_SET(dp, di_gid, gid);
612
	inodirty();
613
	return (ino);
614
}
615
616
/*
617
 * free a directory inode
618
 */
619
static void
620
freedir(ino_t ino, ino_t parent)
621
{
622
	union dinode *dp;
623
624
	if (ino != parent) {
625
		dp = ginode(parent);
626
		DIP_SET(dp, di_nlink, DIP(dp, di_nlink) - 1);
627
		inodirty();
628
	}
629
	freeino(ino);
630
}
631
632
/*
633
 * generate a temporary name for the lost+found directory.
634
 */
635
static int
636
lftempname(char *bufp, ino_t ino)
637
{
638
	ino_t in;
639
	char *cp;
640
	int namlen;
641
642
	cp = bufp + 2;
643
	for (in = maxino; in > 0; in /= 10)
644
		cp++;
645
	*--cp = 0;
646
	namlen = cp - bufp;
647
	in = ino;
648
	while (cp > bufp) {
649
		*--cp = (in % 10) + '0';
650
		in /= 10;
651
	}
652
	*cp = '#';
653
	return (namlen);
654
}
655
656
/*
657
 * Get a directory block.
658
 * Insure that it is held until another is requested.
659
 */
660
static struct bufarea *
661
getdirblk(daddr_t blkno, long size)
662
{
663
664
	if (pdirbp != 0)
665
		pdirbp->b_flags &= ~B_INUSE;
666
	pdirbp = getdatablk(blkno, size);
667
	return (pdirbp);
668
}