1 /* $NetBSD: dir.c,v 1.51 2008/07/08 08:14:37 simonb Exp $ */
4 * Copyright (c) 1980, 1986, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95";
37 __RCSID("$NetBSD: dir.c,v 1.51 2008/07/08 08:14:37 simonb Exp $");
41 #include <sys/param.h>
44 #include <ufs/ufs/dinode.h>
45 #include <ufs/ufs/dir.h>
46 #include <ufs/ffs/fs.h>
47 #include <ufs/ffs/ffs_extern.h>
57 const char *lfname
= "lost+found";
60 struct dirtemplate emptydir
= {
62 .dot_reclen
= DIRBLKSIZ
,
64 struct dirtemplate dirhead
= {
71 .dotdot_reclen
= DIRBLKSIZ
- 12,
72 .dotdot_type
= DT_DIR
,
76 struct odirtemplate odirhead
= {
82 .dotdot_reclen
= DIRBLKSIZ
- 12,
87 static int chgino(struct inodesc
*);
88 static int dircheck(struct inodesc
*, struct direct
*);
89 static int expanddir(union dinode
*, char *);
90 static void freedir(ino_t
, ino_t
);
91 static struct direct
*fsck_readdir(struct inodesc
*);
92 static struct bufarea
*getdirblk(daddr_t
, long);
93 static int lftempname(char *, ino_t
);
94 static int mkentry(struct inodesc
*);
95 void reparent(ino_t
, ino_t
);
98 * Propagate connected state through the tree.
101 propagate(ino_t inumber
)
105 inp
= getinoinfo(inumber
);
108 inoinfo(inp
->i_number
)->ino_state
= DMARK
;
110 inoinfo(inp
->i_child
->i_number
)->ino_state
!= DMARK
)
112 else if (inp
->i_number
== inumber
)
114 else if (inp
->i_sibling
)
115 inp
= inp
->i_sibling
;
117 inp
= getinoinfo(inp
->i_parent
);
121 inoinfo(inp
->i_number
)->ino_state
= DFOUND
;
123 inoinfo(inp
->i_child
->i_number
)->ino_state
!= DFOUND
)
125 else if (inp
->i_number
== inumber
)
127 else if (inp
->i_sibling
)
128 inp
= inp
->i_sibling
;
130 inp
= getinoinfo(inp
->i_parent
);
135 reparent(ino_t inumber
, ino_t parent
)
137 struct inoinfo
*inp
, *pinp
;
139 inp
= getinoinfo(inumber
);
140 inp
->i_parent
= inp
->i_dotdot
= parent
;
141 pinp
= getinoinfo(parent
);
142 inp
->i_sibling
= pinp
->i_child
;
148 * Scan each entry in a directory block.
151 dirscan(struct inodesc
*idesc
)
157 #if DIRBLKSIZ > APPLEUFS_DIRBLKSIZ
158 char dbuf
[DIRBLKSIZ
];
160 char dbuf
[APPLEUFS_DIRBLKSIZ
];
163 if (idesc
->id_type
!= DATA
)
164 errexit("wrong type to dirscan %d", idesc
->id_type
);
165 if (idesc
->id_entryno
== 0 &&
166 (idesc
->id_filesize
& (dirblksiz
- 1)) != 0)
167 idesc
->id_filesize
= roundup(idesc
->id_filesize
, dirblksiz
);
168 blksiz
= idesc
->id_numfrags
* sblock
->fs_fsize
;
169 if (chkrange(idesc
->id_blkno
, idesc
->id_numfrags
)) {
170 idesc
->id_filesize
-= blksiz
;
175 * If we are are swapping byte order in directory entries, just swap
176 * this block and return.
180 bp
= getdirblk(idesc
->id_blkno
, blksiz
);
181 for (off
= 0; off
< blksiz
; off
+= iswap16(dp
->d_reclen
)) {
182 dp
= (struct direct
*)(bp
->b_un
.b_buf
+ off
);
183 dp
->d_ino
= bswap32(dp
->d_ino
);
184 dp
->d_reclen
= bswap16(dp
->d_reclen
);
186 u_int8_t tmp
= dp
->d_namlen
;
187 dp
->d_namlen
= dp
->d_type
;
190 if (dp
->d_reclen
== 0)
194 idesc
->id_filesize
-= blksiz
;
195 return (idesc
->id_filesize
> 0 ? KEEPON
: STOP
);
199 for (dp
= fsck_readdir(idesc
); dp
!= NULL
; dp
= fsck_readdir(idesc
)) {
200 dsize
= iswap16(dp
->d_reclen
);
201 if (dsize
> (int)sizeof dbuf
)
203 memmove(dbuf
, dp
, (size_t)dsize
);
204 # if (BYTE_ORDER == LITTLE_ENDIAN)
205 if (!newinofmt
&& !needswap
) {
207 if (!newinofmt
&& needswap
) {
209 struct direct
*tdp
= (struct direct
*)dbuf
;
213 tdp
->d_namlen
= tdp
->d_type
;
216 idesc
->id_dirp
= (struct direct
*)dbuf
;
217 if ((n
= (*idesc
->id_func
)(idesc
)) & ALTERED
) {
218 # if (BYTE_ORDER == LITTLE_ENDIAN)
219 if (!newinofmt
&& !doinglevel2
&& !needswap
) {
221 if (!newinofmt
&& !doinglevel2
&& needswap
) {
226 tdp
= (struct direct
*)dbuf
;
228 tdp
->d_namlen
= tdp
->d_type
;
231 bp
= getdirblk(idesc
->id_blkno
, blksiz
);
232 memmove(bp
->b_un
.b_buf
+ idesc
->id_loc
- dsize
, dbuf
,
240 return (idesc
->id_filesize
> 0 ? KEEPON
: STOP
);
244 * get next entry in a directory.
246 static struct direct
*
247 fsck_readdir(struct inodesc
*idesc
)
249 struct direct
*dp
, *ndp
;
251 long size
, blksiz
, fix
, dploc
;
253 blksiz
= idesc
->id_numfrags
* sblock
->fs_fsize
;
254 bp
= getdirblk(idesc
->id_blkno
, blksiz
);
255 if (idesc
->id_loc
% dirblksiz
== 0 && idesc
->id_filesize
> 0 &&
256 idesc
->id_loc
< blksiz
) {
257 dp
= (struct direct
*)(bp
->b_un
.b_buf
+ idesc
->id_loc
);
258 if (dircheck(idesc
, dp
))
260 if (idesc
->id_fix
== IGNORE
)
262 fix
= dofix(idesc
, "DIRECTORY CORRUPTED");
263 bp
= getdirblk(idesc
->id_blkno
, blksiz
);
264 dp
= (struct direct
*)(bp
->b_un
.b_buf
+ idesc
->id_loc
);
265 dp
->d_reclen
= iswap16(dirblksiz
);
269 dp
->d_name
[0] = '\0';
274 idesc
->id_loc
+= dirblksiz
;
275 idesc
->id_filesize
-= dirblksiz
;
279 if (idesc
->id_filesize
<= 0 || idesc
->id_loc
>= blksiz
)
281 dploc
= idesc
->id_loc
;
282 dp
= (struct direct
*)(bp
->b_un
.b_buf
+ dploc
);
283 idesc
->id_loc
+= iswap16(dp
->d_reclen
);
284 idesc
->id_filesize
-= iswap16(dp
->d_reclen
);
285 if ((idesc
->id_loc
% dirblksiz
) == 0)
287 ndp
= (struct direct
*)(bp
->b_un
.b_buf
+ idesc
->id_loc
);
288 if (idesc
->id_loc
< blksiz
&& idesc
->id_filesize
> 0 &&
289 dircheck(idesc
, ndp
) == 0) {
290 size
= dirblksiz
- (idesc
->id_loc
% dirblksiz
);
291 idesc
->id_loc
+= size
;
292 idesc
->id_filesize
-= size
;
293 if (idesc
->id_fix
== IGNORE
)
295 fix
= dofix(idesc
, "DIRECTORY CORRUPTED");
296 bp
= getdirblk(idesc
->id_blkno
, blksiz
);
297 dp
= (struct direct
*)(bp
->b_un
.b_buf
+ dploc
);
298 dp
->d_reclen
= iswap16(iswap16(dp
->d_reclen
) + size
);
308 * Verify that a directory entry is valid.
309 * This is a superset of the checks made in the kernel.
312 dircheck(struct inodesc
*idesc
, struct direct
*dp
)
319 spaceleft
= dirblksiz
- (idesc
->id_loc
% dirblksiz
);
320 if (iswap32(dp
->d_ino
) >= maxino
||
322 iswap16(dp
->d_reclen
) > spaceleft
||
323 (iswap16(dp
->d_reclen
) & 0x3) != 0)
327 size
= DIRSIZ(!newinofmt
, dp
, needswap
);
328 # if (BYTE_ORDER == LITTLE_ENDIAN)
329 if (!newinofmt
&& !needswap
) {
331 if (!newinofmt
&& needswap
) {
336 namlen
= dp
->d_namlen
;
339 if (iswap16(dp
->d_reclen
) < size
||
340 idesc
->id_filesize
< size
||
341 /* namlen > MAXNAMLEN || */
344 for (cp
= dp
->d_name
, size
= 0; size
< namlen
; size
++)
345 if (*cp
== '\0' || (*cp
++ == '/'))
353 direrror(ino_t ino
, const char *errmesg
)
356 fileerror(ino
, ino
, errmesg
);
360 fileerror(ino_t cwd
, ino_t ino
, const char *errmesg
)
363 char pathbuf
[MAXPATHLEN
+ 1];
366 pwarn("%s ", errmesg
);
369 getpathname(pathbuf
, sizeof(pathbuf
), cwd
, ino
);
370 if (ino
< ROOTINO
|| ino
> maxino
) {
371 pfatal("NAME=%s\n", pathbuf
);
376 mode
= DIP(dp
, mode
);
378 (iswap16(mode
) & IFMT
) == IFDIR
? "DIR" : "FILE", pathbuf
);
381 pfatal("NAME=%s\n", pathbuf
);
385 adjust(struct inodesc
*idesc
, int lcnt
)
391 dp
= ginode(idesc
->id_number
);
392 nlink
= iswap16(DIP(dp
, nlink
));
395 * If we have not hit any unresolved problems, are running
396 * in preen mode, and are on a file system using soft updates,
397 * then just toss any partially allocated files.
399 if (resolved
&& preen
&& usedsoftdep
) {
400 clri(idesc
, "UNREF", 1);
404 * The file system can be marked clean even if
405 * a file is not linked up, but is cleared.
406 * Hence, resolved should not be cleared when
407 * linkup is answered no, but clri is answered yes.
409 saveresolved
= resolved
;
410 if (linkup(idesc
->id_number
, (ino_t
)0, NULL
) == 0) {
411 resolved
= saveresolved
;
412 clri(idesc
, "UNREF", 0);
416 * Account for the new reference created by linkup().
418 dp
= ginode(idesc
->id_number
);
423 pwarn("LINK COUNT %s", (lfdir
== idesc
->id_number
) ? lfname
:
424 ((iswap16(DIP(dp
, mode
)) & IFMT
) == IFDIR
?
426 pinode(idesc
->id_number
);
427 printf(" COUNT %d SHOULD BE %d",
428 nlink
, nlink
- lcnt
);
429 if (preen
|| usedsoftdep
) {
432 pfatal("LINK COUNT INCREASING");
435 printf(" (ADJUSTED)\n");
437 if (preen
|| reply("ADJUST") == 1) {
438 DIP_SET(dp
, nlink
, iswap16(nlink
- lcnt
));
446 mkentry(struct inodesc
*idesc
)
448 struct direct
*dirp
= idesc
->id_dirp
;
449 struct direct newent
;
452 newent
.d_namlen
= strlen(idesc
->id_name
);
453 newlen
= DIRSIZ(0, &newent
, 0);
454 if (dirp
->d_ino
!= 0)
455 oldlen
= DIRSIZ(0, dirp
, 0);
458 if (iswap16(dirp
->d_reclen
) - oldlen
< newlen
)
460 newent
.d_reclen
= iswap16(iswap16(dirp
->d_reclen
) - oldlen
);
461 dirp
->d_reclen
= iswap16(oldlen
);
462 dirp
= (struct direct
*)(((char *)dirp
) + oldlen
);
463 /* ino to be entered is in id_parent */
464 dirp
->d_ino
= iswap32(idesc
->id_parent
);
465 dirp
->d_reclen
= newent
.d_reclen
;
467 dirp
->d_type
= inoinfo(idesc
->id_parent
)->ino_type
;
470 dirp
->d_namlen
= newent
.d_namlen
;
471 memmove(dirp
->d_name
, idesc
->id_name
, (size_t)newent
.d_namlen
+ 1);
472 # if (BYTE_ORDER == LITTLE_ENDIAN)
474 * If the entry was split, dirscan() will only reverse the byte
475 * order of the original entry, and not the new one, before
476 * writing it back out. So, we reverse the byte order here if
479 if (oldlen
!= 0 && !newinofmt
&& !doinglevel2
&& !needswap
) {
481 if (oldlen
!= 0 && !newinofmt
&& !doinglevel2
&& needswap
) {
485 tmp
= dirp
->d_namlen
;
486 dirp
->d_namlen
= dirp
->d_type
;
489 return (ALTERED
|STOP
);
493 chgino(struct inodesc
*idesc
)
495 struct direct
*dirp
= idesc
->id_dirp
;
497 if (memcmp(dirp
->d_name
, idesc
->id_name
, (int)dirp
->d_namlen
+ 1))
499 dirp
->d_ino
= iswap32(idesc
->id_parent
);
501 dirp
->d_type
= inoinfo(idesc
->id_parent
)->ino_type
;
504 return (ALTERED
|STOP
);
508 linkup(ino_t orphan
, ino_t parentdir
, char *name
)
513 struct inodesc idesc
;
514 char tempname
[BUFSIZ
];
518 memset(&idesc
, 0, sizeof(struct inodesc
));
520 mode
= iswap16(DIP(dp
, mode
));
521 nlink
= iswap16(DIP(dp
, nlink
));
522 lostdir
= (mode
& IFMT
) == IFDIR
;
523 pwarn("UNREF %s ", lostdir
? "DIR" : "FILE");
525 if (preen
&& DIP(dp
, size
) == 0)
528 printf(" (RECONNECTED)\n");
530 if (reply("RECONNECT") == 0) {
535 inoinfo(parentdir
)->ino_linkcnt
++;
537 dp
= ginode(ROOTINO
);
538 idesc
.id_name
= lfname
;
539 idesc
.id_type
= DATA
;
540 idesc
.id_func
= findino
;
541 idesc
.id_number
= ROOTINO
;
542 if ((ckinode(dp
, &idesc
) & FOUND
) != 0) {
543 lfdir
= idesc
.id_parent
;
545 pwarn("NO lost+found DIRECTORY");
546 if (preen
|| reply("CREATE")) {
547 lfdir
= allocdir(ROOTINO
, (ino_t
)0, lfmode
);
549 if (makeentry(ROOTINO
, lfdir
, lfname
) != 0) {
552 printf(" (CREATED)\n");
554 freedir(lfdir
, ROOTINO
);
561 reparent(lfdir
, ROOTINO
);
566 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
572 mode
= DIP(dp
, mode
);
573 mode
= iswap16(mode
);
574 if ((mode
& IFMT
) != IFDIR
) {
575 pfatal("lost+found IS NOT A DIRECTORY");
576 if (reply("REALLOCATE") == 0) {
581 lfdir
= allocdir(ROOTINO
, (ino_t
)0, lfmode
);
583 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
587 if ((changeino(ROOTINO
, lfname
, lfdir
) & ALTERED
) == 0) {
588 pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
593 reparent(lfdir
, ROOTINO
);
594 idesc
.id_type
= ADDR
;
595 idesc
.id_func
= pass4check
;
596 idesc
.id_number
= oldlfdir
;
597 adjust(&idesc
, inoinfo(oldlfdir
)->ino_linkcnt
+ 1);
598 inoinfo(oldlfdir
)->ino_linkcnt
= 0;
601 if (inoinfo(lfdir
)->ino_state
!= DFOUND
) {
602 pfatal("SORRY. NO lost+found DIRECTORY\n\n");
606 (void)lftempname(tempname
, orphan
);
607 if (makeentry(lfdir
, orphan
, (name
? name
: tempname
)) == 0) {
608 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
613 inoinfo(orphan
)->ino_linkcnt
--;
615 if ((changeino(orphan
, "..", lfdir
) & ALTERED
) == 0 &&
616 parentdir
!= (ino_t
)-1)
617 (void)makeentry(orphan
, lfdir
, "..");
619 nlink
= DIP(dp
, nlink
);
620 DIP_SET(dp
, nlink
, iswap16(iswap16(nlink
) + 1));
622 inoinfo(lfdir
)->ino_linkcnt
++;
623 reparent(orphan
, lfdir
);
624 pwarn("DIR I=%llu CONNECTED. ", (unsigned long long)orphan
);
625 if (parentdir
!= (ino_t
)-1)
626 printf("PARENT WAS I=%llu\n",
627 (unsigned long long)parentdir
);
635 * fix an entry in a directory.
638 changeino(ino_t dir
, const char *name
, ino_t newnum
)
640 struct inodesc idesc
;
642 memset(&idesc
, 0, sizeof(struct inodesc
));
643 idesc
.id_type
= DATA
;
644 idesc
.id_func
= chgino
;
645 idesc
.id_number
= dir
;
646 idesc
.id_fix
= DONTKNOW
;
647 idesc
.id_name
= name
;
648 idesc
.id_parent
= newnum
; /* new value for name */
649 return (ckinode(ginode(dir
), &idesc
));
653 * make an entry in a directory
656 makeentry(ino_t parent
, ino_t ino
, const char *name
)
659 struct inodesc idesc
;
660 char pathbuf
[MAXPATHLEN
+ 1];
662 if (parent
< ROOTINO
|| parent
>= maxino
||
663 ino
< ROOTINO
|| ino
>= maxino
)
665 memset(&idesc
, 0, sizeof(struct inodesc
));
666 idesc
.id_type
= DATA
;
667 idesc
.id_func
= mkentry
;
668 idesc
.id_number
= parent
;
669 idesc
.id_parent
= ino
; /* this is the inode to enter */
670 idesc
.id_fix
= DONTKNOW
;
671 idesc
.id_name
= name
;
673 if (iswap64(DIP(dp
, size
)) % dirblksiz
) {
675 iswap64(roundup(iswap64(DIP(dp
, size
)), dirblksiz
)));
678 if ((ckinode(dp
, &idesc
) & ALTERED
) != 0)
680 getpathname(pathbuf
, sizeof(pathbuf
), parent
, parent
);
682 if (expanddir(dp
, pathbuf
) == 0)
684 return (ckinode(dp
, &idesc
) & ALTERED
);
688 * Attempt to expand the size of a directory
691 expanddir(union dinode
*dp
, char *name
)
693 daddr_t lastbn
, newblk
, dirblk
;
696 #if DIRBLKSIZ > APPLEUFS_DIRBLKSIZ
697 char firstblk
[DIRBLKSIZ
];
699 char firstblk
[APPLEUFS_DIRBLKSIZ
];
701 struct ufs1_dinode
*dp1
= NULL
;
702 struct ufs2_dinode
*dp2
= NULL
;
709 lastbn
= lblkno(sblock
, iswap64(DIP(dp
, size
)));
710 if (lastbn
>= NDADDR
- 1 || DIP(dp
, db
[lastbn
]) == 0 ||
713 if ((newblk
= allocblk(sblock
->fs_frag
)) == 0)
716 dp2
->di_db
[lastbn
+ 1] = dp2
->di_db
[lastbn
];
717 dp2
->di_db
[lastbn
] = iswap64(newblk
);
718 dp2
->di_size
= iswap64(iswap64(dp2
->di_size
)+sblock
->fs_bsize
);
719 dp2
->di_blocks
= iswap64(iswap64(dp2
->di_blocks
) +
720 btodb(sblock
->fs_bsize
));
721 dirblk
= iswap64(dp2
->di_db
[lastbn
+ 1]);
723 dp1
->di_db
[lastbn
+ 1] = dp1
->di_db
[lastbn
];
724 dp1
->di_db
[lastbn
] = iswap32((int32_t)newblk
);
725 dp1
->di_size
= iswap64(iswap64(dp1
->di_size
)+sblock
->fs_bsize
);
726 dp1
->di_blocks
= iswap32(iswap32(dp1
->di_blocks
) +
727 btodb(sblock
->fs_bsize
));
728 dirblk
= iswap32(dp1
->di_db
[lastbn
+ 1]);
730 bp
= getdirblk(dirblk
, sblksize(sblock
, (daddr_t
)DIP(dp
, size
), lastbn
+ 1));
733 memmove(firstblk
, bp
->b_un
.b_buf
, dirblksiz
);
734 bp
= getdirblk(newblk
, sblock
->fs_bsize
);
737 memmove(bp
->b_un
.b_buf
, firstblk
, dirblksiz
);
738 emptydir
.dot_reclen
= iswap16(dirblksiz
);
739 for (cp
= &bp
->b_un
.b_buf
[dirblksiz
];
740 cp
< &bp
->b_un
.b_buf
[sblock
->fs_bsize
];
742 memmove(cp
, &emptydir
, sizeof emptydir
);
744 bp
= getdirblk(dirblk
, sblksize(sblock
, (daddr_t
)DIP(dp
, size
), lastbn
+ 1));
747 memmove(bp
->b_un
.b_buf
, &emptydir
, sizeof emptydir
);
748 pwarn("NO SPACE LEFT IN %s", name
);
750 printf(" (EXPANDED)\n");
751 else if (reply("EXPAND") == 0)
758 dp2
->di_db
[lastbn
] = dp2
->di_db
[lastbn
+ 1];
759 dp2
->di_db
[lastbn
+ 1] = 0;
760 dp2
->di_size
= iswap64(iswap64(dp2
->di_size
)-sblock
->fs_bsize
);
761 dp2
->di_blocks
= iswap64(iswap64(dp2
->di_blocks
) -
762 btodb(sblock
->fs_bsize
));
764 dp1
->di_db
[lastbn
] = dp1
->di_db
[lastbn
+ 1];
765 dp1
->di_db
[lastbn
+ 1] = 0;
766 dp1
->di_size
= iswap64(iswap64(dp1
->di_size
)-sblock
->fs_bsize
);
767 dp1
->di_blocks
= iswap32(iswap32(dp1
->di_blocks
) -
768 btodb(sblock
->fs_bsize
));
770 freeblk(newblk
, sblock
->fs_frag
);
776 * allocate a new directory
779 allocdir(ino_t parent
, ino_t request
, int mode
)
786 struct dirtemplate
*dirp
;
789 ino
= allocino(request
, IFDIR
|mode
);
792 dirhead
.dot_reclen
= iswap16(12);
793 dirhead
.dotdot_reclen
= iswap16(dirblksiz
- 12);
794 odirhead
.dot_reclen
= iswap16(12);
795 odirhead
.dotdot_reclen
= iswap16(dirblksiz
- 12);
796 odirhead
.dot_namlen
= iswap16(1);
797 odirhead
.dotdot_namlen
= iswap16(2);
801 dirp
= (struct dirtemplate
*)&odirhead
;
802 dirp
->dot_ino
= iswap32(ino
);
803 dirp
->dotdot_ino
= iswap32(parent
);
805 dirblk
= is_ufs2
? iswap64(dp
->dp2
.di_db
[0])
806 : iswap32(dp
->dp1
.di_db
[0]);
807 bp
= getdirblk(dirblk
, sblock
->fs_fsize
);
812 memmove(bp
->b_un
.b_buf
, dirp
, sizeof(struct dirtemplate
));
813 emptydir
.dot_reclen
= iswap16(dirblksiz
);
814 for (cp
= &bp
->b_un
.b_buf
[dirblksiz
];
815 cp
< &bp
->b_un
.b_buf
[sblock
->fs_fsize
];
817 memmove(cp
, &emptydir
, sizeof emptydir
);
819 DIP_SET(dp
, nlink
, iswap16(2));
821 if (ino
== ROOTINO
) {
822 inoinfo(ino
)->ino_linkcnt
= iswap16(DIP(dp
, nlink
));
826 if (inoinfo(parent
)->ino_state
!= DSTATE
&&
827 inoinfo(parent
)->ino_state
!= DFOUND
) {
832 inp
= getinoinfo(ino
);
833 inp
->i_parent
= parent
;
834 inp
->i_dotdot
= parent
;
835 inoinfo(ino
)->ino_state
= inoinfo(parent
)->ino_state
;
836 if (inoinfo(ino
)->ino_state
== DSTATE
) {
837 inoinfo(ino
)->ino_linkcnt
= iswap16(DIP(dp
, nlink
));
838 inoinfo(parent
)->ino_linkcnt
++;
841 DIP_SET(dp
, nlink
, iswap16(iswap16(DIP(dp
, nlink
)) + 1));
847 * free a directory inode
850 freedir(ino_t ino
, ino_t parent
)
856 DIP_SET(dp
, nlink
, iswap16(iswap16(DIP(dp
, nlink
)) - 1));
863 * generate a temporary name for the lost+found directory.
866 lftempname(char *bufp
, ino_t ino
)
873 for (in
= maxino
; in
> 0; in
/= 10)
879 *--cp
= (in
% 10) + '0';
887 * Get a directory block.
888 * Insure that it is held until another is requested.
890 static struct bufarea
*
891 getdirblk(daddr_t blkno
, long size
)
895 pdirbp
->b_flags
&= ~B_INUSE
;
896 pdirbp
= getdatablk(blkno
, size
);