18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
48fae3551SRodney W. Grimes * Copyright (c) 1980, 1986, 1993
58fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved.
68fae3551SRodney W. Grimes *
78fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
88fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions
98fae3551SRodney W. Grimes * are met:
108fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
118fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
128fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
138fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
148fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
168fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software
178fae3551SRodney W. Grimes * without specific prior written permission.
188fae3551SRodney W. Grimes *
198fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
208fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
218fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
228fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
238fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
248fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
258fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
268fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
278fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
288fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
298fae3551SRodney W. Grimes * SUCH DAMAGE.
308fae3551SRodney W. Grimes */
318fae3551SRodney W. Grimes
328fae3551SRodney W. Grimes #include <sys/param.h>
3377355ce0SKirk McKusick #include <sys/sysctl.h>
34780a5c1eSPeter Wemm
358fae3551SRodney W. Grimes #include <ufs/ufs/dinode.h>
368fae3551SRodney W. Grimes #include <ufs/ufs/dir.h>
377578c6abSKirk McKusick #include <ufs/ffs/fs.h>
3851a5cf90SBruce Evans
39780a5c1eSPeter Wemm #include <err.h>
4077355ce0SKirk McKusick #include <errno.h>
4184fc0d7eSMaxime Henrion #include <stdint.h>
428fae3551SRodney W. Grimes #include <string.h>
43780a5c1eSPeter Wemm
448fae3551SRodney W. Grimes #include "fsck.h"
458fae3551SRodney W. Grimes
468fae3551SRodney W. Grimes #define MINDIRSIZE (sizeof (struct dirtemplate))
478fae3551SRodney W. Grimes
4837776076SKirk McKusick static int fix_extraneous(struct inoinfo *, struct inodesc *);
4937776076SKirk McKusick static int deleteentry(struct inodesc *);
50b70cd7eeSWarner Losh static int blksort(const void *, const void *);
51b70cd7eeSWarner Losh static int pass2check(struct inodesc *);
528fae3551SRodney W. Grimes
5331f4ab50SBruce Evans void
pass2(void)54b70cd7eeSWarner Losh pass2(void)
558fae3551SRodney W. Grimes {
565cc52631SKirk McKusick struct inode ip;
571c85e6a3SKirk McKusick union dinode *dp;
583d438ad6SDavid E. O'Brien struct inoinfo **inpp, *inp;
598fae3551SRodney W. Grimes struct inoinfo **inpend;
608fae3551SRodney W. Grimes struct inodesc curino;
611c85e6a3SKirk McKusick union dinode dino;
621c85e6a3SKirk McKusick int i;
638fae3551SRodney W. Grimes char pathbuf[MAXPATHLEN + 1];
648fae3551SRodney W. Grimes
651dc349abSEd Maste switch (inoinfo(UFS_ROOTINO)->ino_state) {
668fae3551SRodney W. Grimes
678fae3551SRodney W. Grimes case USTATE:
688fae3551SRodney W. Grimes pfatal("ROOT INODE UNALLOCATED");
69b1897c19SJulian Elischer if (reply("ALLOCATE") == 0) {
70b1897c19SJulian Elischer ckfini(0);
71780a5c1eSPeter Wemm exit(EEXIT);
72b1897c19SJulian Elischer }
731dc349abSEd Maste if (allocdir(UFS_ROOTINO, UFS_ROOTINO, 0755) != UFS_ROOTINO)
74780a5c1eSPeter Wemm errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
758fae3551SRodney W. Grimes break;
768fae3551SRodney W. Grimes
778fae3551SRodney W. Grimes case DCLEAR:
788fae3551SRodney W. Grimes pfatal("DUPS/BAD IN ROOT INODE");
798fae3551SRodney W. Grimes if (reply("REALLOCATE")) {
8052f97104SKirk McKusick freedirino(UFS_ROOTINO, UFS_ROOTINO);
811dc349abSEd Maste if (allocdir(UFS_ROOTINO, UFS_ROOTINO, 0755) !=
821dc349abSEd Maste UFS_ROOTINO)
83780a5c1eSPeter Wemm errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
848fae3551SRodney W. Grimes break;
858fae3551SRodney W. Grimes }
86b1897c19SJulian Elischer if (reply("CONTINUE") == 0) {
87b1897c19SJulian Elischer ckfini(0);
88780a5c1eSPeter Wemm exit(EEXIT);
89b1897c19SJulian Elischer }
908fae3551SRodney W. Grimes break;
918fae3551SRodney W. Grimes
928fae3551SRodney W. Grimes case FSTATE:
938fae3551SRodney W. Grimes case FCLEAR:
94af6726e6SDon Lewis case FZLINK:
958fae3551SRodney W. Grimes pfatal("ROOT INODE NOT DIRECTORY");
968fae3551SRodney W. Grimes if (reply("REALLOCATE")) {
971dc349abSEd Maste freeino(UFS_ROOTINO);
981dc349abSEd Maste if (allocdir(UFS_ROOTINO, UFS_ROOTINO, 0755) !=
991dc349abSEd Maste UFS_ROOTINO)
100780a5c1eSPeter Wemm errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
1018fae3551SRodney W. Grimes break;
1028fae3551SRodney W. Grimes }
103b1897c19SJulian Elischer if (reply("FIX") == 0) {
104b1897c19SJulian Elischer ckfini(0);
105780a5c1eSPeter Wemm exit(EEXIT);
106b1897c19SJulian Elischer }
1075cc52631SKirk McKusick ginode(UFS_ROOTINO, &ip);
1085cc52631SKirk McKusick dp = ip.i_dp;
109d8ba45e2SEd Maste DIP_SET(dp, di_mode, DIP(dp, di_mode) & ~IFMT);
110d8ba45e2SEd Maste DIP_SET(dp, di_mode, DIP(dp, di_mode) | IFDIR);
1115cc52631SKirk McKusick inodirty(&ip);
1125cc52631SKirk McKusick irelse(&ip);
1138fae3551SRodney W. Grimes break;
1148fae3551SRodney W. Grimes
1158fae3551SRodney W. Grimes case DSTATE:
116af6726e6SDon Lewis case DZLINK:
1178fae3551SRodney W. Grimes break;
1188fae3551SRodney W. Grimes
1198fae3551SRodney W. Grimes default:
120d33e92f9SJulian Elischer errx(EEXIT, "BAD STATE %d FOR ROOT INODE",
1211dc349abSEd Maste inoinfo(UFS_ROOTINO)->ino_state);
1228fae3551SRodney W. Grimes }
1231dc349abSEd Maste inoinfo(UFS_ROOTINO)->ino_state = DFOUND;
1241dc349abSEd Maste inoinfo(UFS_WINO)->ino_state = FSTATE;
1251dc349abSEd Maste inoinfo(UFS_WINO)->ino_type = DT_WHT;
1268fae3551SRodney W. Grimes /*
1278fae3551SRodney W. Grimes * Sort the directory list into disk block order.
1288fae3551SRodney W. Grimes */
1298fae3551SRodney W. Grimes qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort);
1308fae3551SRodney W. Grimes /*
1318fae3551SRodney W. Grimes * Check the integrity of each directory.
1328fae3551SRodney W. Grimes */
133780a5c1eSPeter Wemm memset(&curino, 0, sizeof(struct inodesc));
1348fae3551SRodney W. Grimes curino.id_type = DATA;
1358fae3551SRodney W. Grimes curino.id_func = pass2check;
1368fae3551SRodney W. Grimes inpend = &inpsort[inplast];
1378fae3551SRodney W. Grimes for (inpp = inpsort; inpp < inpend; inpp++) {
1386db798caSIan Dowse if (got_siginfo) {
13984fc0d7eSMaxime Henrion printf("%s: phase 2: dir %td of %d (%d%%)\n", cdevname,
140bf58d635SIan Dowse inpp - inpsort, (int)inplast,
141bf58d635SIan Dowse (int)((inpp - inpsort) * 100 / inplast));
1426db798caSIan Dowse got_siginfo = 0;
1436db798caSIan Dowse }
1441660ae87SScott Long if (got_sigalarm) {
1451660ae87SScott Long setproctitle("%s p2 %d%%", cdevname,
1461660ae87SScott Long (int)((inpp - inpsort) * 100 / inplast));
1471660ae87SScott Long got_sigalarm = 0;
1481660ae87SScott Long }
1498fae3551SRodney W. Grimes inp = *inpp;
1508fae3551SRodney W. Grimes if (inp->i_isize == 0)
1518fae3551SRodney W. Grimes continue;
1528fae3551SRodney W. Grimes if (inp->i_isize < MINDIRSIZE) {
1538fae3551SRodney W. Grimes direrror(inp->i_number, "DIRECTORY TOO SHORT");
1548fae3551SRodney W. Grimes inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ);
1558fae3551SRodney W. Grimes if (reply("FIX") == 1) {
1565cc52631SKirk McKusick ginode(inp->i_number, &ip);
1575cc52631SKirk McKusick DIP_SET(ip.i_dp, di_size, inp->i_isize);
1585cc52631SKirk McKusick inodirty(&ip);
1595cc52631SKirk McKusick irelse(&ip);
1608fae3551SRodney W. Grimes }
1618fae3551SRodney W. Grimes } else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) {
1628fae3551SRodney W. Grimes getpathname(pathbuf, inp->i_number, inp->i_number);
163b1897c19SJulian Elischer if (usedsoftdep)
16484fc0d7eSMaxime Henrion pfatal("%s %s: LENGTH %jd NOT MULTIPLE OF %d",
16584fc0d7eSMaxime Henrion "DIRECTORY", pathbuf,
16684fc0d7eSMaxime Henrion (intmax_t)inp->i_isize, DIRBLKSIZ);
167b1897c19SJulian Elischer else
16884fc0d7eSMaxime Henrion pwarn("%s %s: LENGTH %jd NOT MULTIPLE OF %d",
16984fc0d7eSMaxime Henrion "DIRECTORY", pathbuf,
17084fc0d7eSMaxime Henrion (intmax_t)inp->i_isize, DIRBLKSIZ);
1718fae3551SRodney W. Grimes if (preen)
1728fae3551SRodney W. Grimes printf(" (ADJUSTED)\n");
1738fae3551SRodney W. Grimes inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ);
1748fae3551SRodney W. Grimes if (preen || reply("ADJUST") == 1) {
1755cc52631SKirk McKusick ginode(inp->i_number, &ip);
1765cc52631SKirk McKusick DIP_SET(ip.i_dp, di_size,
177c3b2344bSScott Long roundup(inp->i_isize, DIRBLKSIZ));
1785cc52631SKirk McKusick inodirty(&ip);
1795cc52631SKirk McKusick irelse(&ip);
1801c85e6a3SKirk McKusick }
1811c85e6a3SKirk McKusick }
1828fae3551SRodney W. Grimes dp = &dino;
1831c85e6a3SKirk McKusick memset(dp, 0, sizeof(struct ufs2_dinode));
184d8ba45e2SEd Maste DIP_SET(dp, di_mode, IFDIR);
185c3b2344bSScott Long DIP_SET(dp, di_size, inp->i_isize);
1861dc349abSEd Maste for (i = 0; i < MIN(inp->i_numblks, UFS_NDADDR); i++)
187c3b2344bSScott Long DIP_SET(dp, di_db[i], inp->i_blks[i]);
1881dc349abSEd Maste if (inp->i_numblks > UFS_NDADDR)
1891dc349abSEd Maste for (i = 0; i < UFS_NIADDR; i++)
1901dc349abSEd Maste DIP_SET(dp, di_ib[i],
1911dc349abSEd Maste inp->i_blks[UFS_NDADDR + i]);
1928fae3551SRodney W. Grimes curino.id_number = inp->i_number;
1938fae3551SRodney W. Grimes curino.id_parent = inp->i_parent;
1948fae3551SRodney W. Grimes (void)ckinode(dp, &curino);
1958fae3551SRodney W. Grimes }
1968fae3551SRodney W. Grimes /*
1978fae3551SRodney W. Grimes * Now that the parents of all directories have been found,
1988fae3551SRodney W. Grimes * make another pass to verify the value of `..'
1998fae3551SRodney W. Grimes */
2008fae3551SRodney W. Grimes for (inpp = inpsort; inpp < inpend; inpp++) {
2018fae3551SRodney W. Grimes inp = *inpp;
2028fae3551SRodney W. Grimes if (inp->i_parent == 0 || inp->i_isize == 0)
2038fae3551SRodney W. Grimes continue;
204d33e92f9SJulian Elischer if (inoinfo(inp->i_parent)->ino_state == DFOUND &&
205fe5e6e2cSKirk McKusick INO_IS_DUNFOUND(inp->i_number)) {
206d33e92f9SJulian Elischer inoinfo(inp->i_number)->ino_state = DFOUND;
207fe5e6e2cSKirk McKusick check_dirdepth(inp);
208fe5e6e2cSKirk McKusick }
2098fae3551SRodney W. Grimes if (inp->i_dotdot == inp->i_parent ||
2108fae3551SRodney W. Grimes inp->i_dotdot == (ino_t)-1)
2118fae3551SRodney W. Grimes continue;
2128fae3551SRodney W. Grimes if (inp->i_dotdot == 0) {
2138fae3551SRodney W. Grimes inp->i_dotdot = inp->i_parent;
2146bae6625SKirk McKusick if (debug)
2156bae6625SKirk McKusick fileerror(inp->i_parent, inp->i_number,
2166bae6625SKirk McKusick "DEFERRED MISSING '..' FIX");
2178fae3551SRodney W. Grimes (void)makeentry(inp->i_number, inp->i_parent, "..");
218d33e92f9SJulian Elischer inoinfo(inp->i_parent)->ino_linkcnt--;
2198fae3551SRodney W. Grimes continue;
2208fae3551SRodney W. Grimes }
22177355ce0SKirk McKusick /*
22277355ce0SKirk McKusick * Here we have:
22377355ce0SKirk McKusick * inp->i_number is directory with bad ".." in it.
22477355ce0SKirk McKusick * inp->i_dotdot is current value of "..".
22577355ce0SKirk McKusick * inp->i_parent is directory to which ".." should point.
22677355ce0SKirk McKusick */
22777355ce0SKirk McKusick getpathname(pathbuf, inp->i_parent, inp->i_number);
228623d7cb6SMatthew D Fleming printf("BAD INODE NUMBER FOR '..' in DIR I=%ju (%s)\n",
229623d7cb6SMatthew D Fleming (uintmax_t)inp->i_number, pathbuf);
23077355ce0SKirk McKusick getpathname(pathbuf, inp->i_dotdot, inp->i_dotdot);
231623d7cb6SMatthew D Fleming printf("CURRENTLY POINTS TO I=%ju (%s), ",
232623d7cb6SMatthew D Fleming (uintmax_t)inp->i_dotdot, pathbuf);
23377355ce0SKirk McKusick getpathname(pathbuf, inp->i_parent, inp->i_parent);
234623d7cb6SMatthew D Fleming printf("SHOULD POINT TO I=%ju (%s)",
235623d7cb6SMatthew D Fleming (uintmax_t)inp->i_parent, pathbuf);
23677355ce0SKirk McKusick if (cursnapshot != 0) {
23777355ce0SKirk McKusick /*
23877355ce0SKirk McKusick * We need to:
23977355ce0SKirk McKusick * setcwd(inp->i_number);
24077355ce0SKirk McKusick * setdotdot(inp->i_dotdot, inp->i_parent);
24177355ce0SKirk McKusick */
24277355ce0SKirk McKusick cmd.value = inp->i_number;
24377355ce0SKirk McKusick if (sysctlbyname("vfs.ffs.setcwd", 0, 0,
24477355ce0SKirk McKusick &cmd, sizeof cmd) == -1) {
24577355ce0SKirk McKusick /* kernel lacks support for these functions */
24677355ce0SKirk McKusick printf(" (IGNORED)\n");
24777355ce0SKirk McKusick continue;
24877355ce0SKirk McKusick }
24977355ce0SKirk McKusick cmd.value = inp->i_dotdot; /* verify same value */
25077355ce0SKirk McKusick cmd.size = inp->i_parent; /* new parent */
25177355ce0SKirk McKusick if (sysctlbyname("vfs.ffs.setdotdot", 0, 0,
25277355ce0SKirk McKusick &cmd, sizeof cmd) == -1) {
25377355ce0SKirk McKusick printf(" (FIX FAILED: %s)\n", strerror(errno));
25477355ce0SKirk McKusick continue;
25577355ce0SKirk McKusick }
25677355ce0SKirk McKusick printf(" (FIXED)\n");
25777355ce0SKirk McKusick inoinfo(inp->i_parent)->ino_linkcnt--;
25877355ce0SKirk McKusick inp->i_dotdot = inp->i_parent;
25977355ce0SKirk McKusick continue;
26077355ce0SKirk McKusick }
26177355ce0SKirk McKusick if (preen)
26277355ce0SKirk McKusick printf(" (FIXED)\n");
26377355ce0SKirk McKusick else if (reply("FIX") == 0)
2648fae3551SRodney W. Grimes continue;
265d33e92f9SJulian Elischer inoinfo(inp->i_dotdot)->ino_linkcnt++;
266d33e92f9SJulian Elischer inoinfo(inp->i_parent)->ino_linkcnt--;
2678fae3551SRodney W. Grimes inp->i_dotdot = inp->i_parent;
268fe5e6e2cSKirk McKusick (void)changeino(inp->i_number, "..", inp->i_parent,
269fe5e6e2cSKirk McKusick getinoinfo(inp->i_parent)->i_depth + 1);
2708fae3551SRodney W. Grimes }
2718fae3551SRodney W. Grimes /*
2728fae3551SRodney W. Grimes * Mark all the directories that can be found from the root.
2738fae3551SRodney W. Grimes */
2748fae3551SRodney W. Grimes propagate();
2758fae3551SRodney W. Grimes }
2768fae3551SRodney W. Grimes
277780a5c1eSPeter Wemm static int
pass2check(struct inodesc * idesc)278b70cd7eeSWarner Losh pass2check(struct inodesc *idesc)
2798fae3551SRodney W. Grimes {
2803d438ad6SDavid E. O'Brien struct direct *dirp = idesc->id_dirp;
28197fea87bSKirk McKusick char dirname[MAXPATHLEN + 1];
2823d438ad6SDavid E. O'Brien struct inoinfo *inp;
2838fae3551SRodney W. Grimes int n, entrysize, ret = 0;
2845cc52631SKirk McKusick struct inode ip;
2851c85e6a3SKirk McKusick union dinode *dp;
286599304a4SPoul-Henning Kamp const char *errmsg;
2876bae6625SKirk McKusick struct direct proto, *newdirp;
2888fae3551SRodney W. Grimes
2898fae3551SRodney W. Grimes /*
2908fae3551SRodney W. Grimes * check for "."
2918fae3551SRodney W. Grimes */
2928fae3551SRodney W. Grimes if (idesc->id_entryno != 0)
2938fae3551SRodney W. Grimes goto chk1;
2948fae3551SRodney W. Grimes if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
2958fae3551SRodney W. Grimes if (dirp->d_ino != idesc->id_number) {
2968fae3551SRodney W. Grimes direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
2976bae6625SKirk McKusick if (reply("FIX") == 1) {
2988fae3551SRodney W. Grimes dirp->d_ino = idesc->id_number;
2998fae3551SRodney W. Grimes ret |= ALTERED;
3008fae3551SRodney W. Grimes }
3016bae6625SKirk McKusick }
302381ee4c2SPoul-Henning Kamp if (dirp->d_type != DT_DIR) {
3038fae3551SRodney W. Grimes direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'");
3046bae6625SKirk McKusick if (reply("FIX") == 1) {
3058fae3551SRodney W. Grimes dirp->d_type = DT_DIR;
3068fae3551SRodney W. Grimes ret |= ALTERED;
3078fae3551SRodney W. Grimes }
3086bae6625SKirk McKusick }
3098fae3551SRodney W. Grimes goto chk1;
3108fae3551SRodney W. Grimes }
3118fae3551SRodney W. Grimes proto.d_ino = idesc->id_number;
3128fae3551SRodney W. Grimes proto.d_type = DT_DIR;
3138fae3551SRodney W. Grimes proto.d_namlen = 1;
3148fae3551SRodney W. Grimes (void)strcpy(proto.d_name, ".");
3158fae3551SRodney W. Grimes entrysize = DIRSIZ(0, &proto);
3166bae6625SKirk McKusick direrror(idesc->id_number, "MISSING '.'");
3176bae6625SKirk McKusick errmsg = "ADD '.' ENTRY";
3186bae6625SKirk McKusick if (dirp->d_reclen < entrysize + DIRSIZ(0, dirp)) {
3196bae6625SKirk McKusick /* Not enough space to add '.', replace first entry with '.' */
3206bae6625SKirk McKusick if (dirp->d_ino != 0) {
3216bae6625SKirk McKusick pwarn("\nFIRST ENTRY IN DIRECTORY CONTAINS %s\n",
3228fae3551SRodney W. Grimes dirp->d_name);
3236bae6625SKirk McKusick errmsg = "REPLACE WITH '.'";
3246bae6625SKirk McKusick }
3256bae6625SKirk McKusick if (reply(errmsg) == 0)
3266bae6625SKirk McKusick goto chk1;
3278fae3551SRodney W. Grimes proto.d_reclen = dirp->d_reclen;
328780a5c1eSPeter Wemm memmove(dirp, &proto, (size_t)entrysize);
3298fae3551SRodney W. Grimes ret |= ALTERED;
3308fae3551SRodney W. Grimes } else {
3316bae6625SKirk McKusick /* Move over first entry and add '.' entry */
3326bae6625SKirk McKusick if (reply(errmsg) == 0)
3336bae6625SKirk McKusick goto chk1;
3346bae6625SKirk McKusick newdirp = (struct direct *)((char *)(dirp) + entrysize);
3356bae6625SKirk McKusick dirp->d_reclen -= entrysize;
3366bae6625SKirk McKusick memmove(newdirp, dirp, dirp->d_reclen);
3378fae3551SRodney W. Grimes proto.d_reclen = entrysize;
338780a5c1eSPeter Wemm memmove(dirp, &proto, (size_t)entrysize);
3398fae3551SRodney W. Grimes idesc->id_entryno++;
3406bae6625SKirk McKusick inoinfo(idesc->id_number)->ino_linkcnt--;
3416bae6625SKirk McKusick dirp = newdirp;
3428fae3551SRodney W. Grimes ret |= ALTERED;
3438fae3551SRodney W. Grimes }
3448fae3551SRodney W. Grimes chk1:
3458fae3551SRodney W. Grimes if (idesc->id_entryno > 1)
3468fae3551SRodney W. Grimes goto chk2;
3478fae3551SRodney W. Grimes inp = getinoinfo(idesc->id_number);
3488fae3551SRodney W. Grimes proto.d_ino = inp->i_parent;
3498fae3551SRodney W. Grimes proto.d_type = DT_DIR;
3508fae3551SRodney W. Grimes proto.d_namlen = 2;
3518fae3551SRodney W. Grimes (void)strcpy(proto.d_name, "..");
3528fae3551SRodney W. Grimes entrysize = DIRSIZ(0, &proto);
3538fae3551SRodney W. Grimes if (idesc->id_entryno == 0) {
3548fae3551SRodney W. Grimes n = DIRSIZ(0, dirp);
3558fae3551SRodney W. Grimes if (dirp->d_reclen < n + entrysize)
3568fae3551SRodney W. Grimes goto chk2;
3578fae3551SRodney W. Grimes proto.d_reclen = dirp->d_reclen - n;
3588fae3551SRodney W. Grimes dirp->d_reclen = n;
3598fae3551SRodney W. Grimes idesc->id_entryno++;
360d33e92f9SJulian Elischer inoinfo(dirp->d_ino)->ino_linkcnt--;
3618fae3551SRodney W. Grimes dirp = (struct direct *)((char *)(dirp) + n);
362780a5c1eSPeter Wemm memset(dirp, 0, (size_t)proto.d_reclen);
3638fae3551SRodney W. Grimes dirp->d_reclen = proto.d_reclen;
3648fae3551SRodney W. Grimes }
3658fae3551SRodney W. Grimes if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
366*11ce203eSKirk McKusick if (dirp->d_ino >= maxino) {
36752f97104SKirk McKusick direrror(idesc->id_number, "BAD INODE NUMBER FOR '..'");
36852f97104SKirk McKusick /*
36952f97104SKirk McKusick * If we know parent set it now, otherwise let it
37052f97104SKirk McKusick * point to the root inode and it will get cleaned
37152f97104SKirk McKusick * up later if that is not correct.
37252f97104SKirk McKusick */
37352f97104SKirk McKusick if (inp->i_parent != 0)
37452f97104SKirk McKusick dirp->d_ino = inp->i_parent;
37552f97104SKirk McKusick else
37652f97104SKirk McKusick dirp->d_ino = UFS_ROOTINO;
37752f97104SKirk McKusick if (reply("FIX") == 1)
37852f97104SKirk McKusick ret |= ALTERED;
37952f97104SKirk McKusick }
3808fae3551SRodney W. Grimes inp->i_dotdot = dirp->d_ino;
381381ee4c2SPoul-Henning Kamp if (dirp->d_type != DT_DIR) {
3828fae3551SRodney W. Grimes direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'");
3838fae3551SRodney W. Grimes dirp->d_type = DT_DIR;
3848fae3551SRodney W. Grimes if (reply("FIX") == 1)
3858fae3551SRodney W. Grimes ret |= ALTERED;
3868fae3551SRodney W. Grimes }
3878fae3551SRodney W. Grimes goto chk2;
3888fae3551SRodney W. Grimes }
3896bae6625SKirk McKusick fileerror(inp->i_parent != 0 ? inp->i_parent : idesc->id_number,
3906bae6625SKirk McKusick idesc->id_number, "MISSING '..'");
3916bae6625SKirk McKusick errmsg = "ADD '..' ENTRY";
3926bae6625SKirk McKusick if (dirp->d_reclen < entrysize + DIRSIZ(0, dirp)) {
3936bae6625SKirk McKusick /* No space to add '..', replace second entry with '..' */
3946bae6625SKirk McKusick if (dirp->d_ino != 0) {
3956bae6625SKirk McKusick pfatal("SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
3968fae3551SRodney W. Grimes dirp->d_name);
3976bae6625SKirk McKusick errmsg = "REPLACE WITH '..'";
3986bae6625SKirk McKusick }
3996bae6625SKirk McKusick if (reply(errmsg) == 0) {
4008fae3551SRodney W. Grimes inp->i_dotdot = (ino_t)-1;
4016bae6625SKirk McKusick goto chk2;
4026bae6625SKirk McKusick }
4036bae6625SKirk McKusick if (proto.d_ino == 0) {
4046bae6625SKirk McKusick /* Defer processing until parent known */
4056bae6625SKirk McKusick idesc->id_entryno++;
4066bae6625SKirk McKusick if (debug)
4076bae6625SKirk McKusick printf("(FIX DEFERRED)\n");
4086bae6625SKirk McKusick }
4096bae6625SKirk McKusick inp->i_dotdot = proto.d_ino;
4108fae3551SRodney W. Grimes proto.d_reclen = dirp->d_reclen;
411780a5c1eSPeter Wemm memmove(dirp, &proto, (size_t)entrysize);
4126bae6625SKirk McKusick ret |= ALTERED;
4136bae6625SKirk McKusick } else {
4146bae6625SKirk McKusick /* Move over second entry and add '..' entry */
4156bae6625SKirk McKusick if (reply(errmsg) == 0) {
4166bae6625SKirk McKusick inp->i_dotdot = (ino_t)-1;
4176bae6625SKirk McKusick goto chk2;
4186bae6625SKirk McKusick }
4196bae6625SKirk McKusick if (proto.d_ino == 0) {
4206bae6625SKirk McKusick /* Defer processing until parent known */
4216bae6625SKirk McKusick idesc->id_entryno++;
4226bae6625SKirk McKusick if (debug)
4236bae6625SKirk McKusick printf("(FIX DEFERRED)\n");
4246bae6625SKirk McKusick }
4256bae6625SKirk McKusick inp->i_dotdot = proto.d_ino;
4266bae6625SKirk McKusick if (dirp->d_ino == 0) {
4276bae6625SKirk McKusick proto.d_reclen = dirp->d_reclen;
4286bae6625SKirk McKusick memmove(dirp, &proto, (size_t)entrysize);
4296bae6625SKirk McKusick } else {
4306bae6625SKirk McKusick newdirp = (struct direct *)((char *)(dirp) + entrysize);
4316bae6625SKirk McKusick dirp->d_reclen -= entrysize;
4326bae6625SKirk McKusick memmove(newdirp, dirp, dirp->d_reclen);
4336bae6625SKirk McKusick proto.d_reclen = entrysize;
4346bae6625SKirk McKusick memmove(dirp, &proto, (size_t)entrysize);
4356bae6625SKirk McKusick if (dirp->d_ino != 0) {
4366bae6625SKirk McKusick idesc->id_entryno++;
4376bae6625SKirk McKusick inoinfo(dirp->d_ino)->ino_linkcnt--;
4386bae6625SKirk McKusick }
4396bae6625SKirk McKusick dirp = newdirp;
4406bae6625SKirk McKusick }
4418fae3551SRodney W. Grimes ret |= ALTERED;
4428fae3551SRodney W. Grimes }
4438fae3551SRodney W. Grimes chk2:
4448fae3551SRodney W. Grimes if (dirp->d_ino == 0)
4458fae3551SRodney W. Grimes return (ret|KEEPON);
4468fae3551SRodney W. Grimes if (dirp->d_namlen <= 2 &&
4478fae3551SRodney W. Grimes dirp->d_name[0] == '.' &&
4488fae3551SRodney W. Grimes idesc->id_entryno >= 2) {
4498fae3551SRodney W. Grimes if (dirp->d_namlen == 1) {
4508fae3551SRodney W. Grimes direrror(idesc->id_number, "EXTRA '.' ENTRY");
4518fae3551SRodney W. Grimes dirp->d_ino = 0;
4528fae3551SRodney W. Grimes if (reply("FIX") == 1)
4538fae3551SRodney W. Grimes ret |= ALTERED;
4548fae3551SRodney W. Grimes return (KEEPON | ret);
4558fae3551SRodney W. Grimes }
4568fae3551SRodney W. Grimes if (dirp->d_name[1] == '.') {
4578fae3551SRodney W. Grimes direrror(idesc->id_number, "EXTRA '..' ENTRY");
4588fae3551SRodney W. Grimes dirp->d_ino = 0;
4598fae3551SRodney W. Grimes if (reply("FIX") == 1)
4608fae3551SRodney W. Grimes ret |= ALTERED;
4618fae3551SRodney W. Grimes return (KEEPON | ret);
4628fae3551SRodney W. Grimes }
4638fae3551SRodney W. Grimes }
4648fae3551SRodney W. Grimes idesc->id_entryno++;
4658fae3551SRodney W. Grimes n = 0;
466*11ce203eSKirk McKusick if (dirp->d_ino >= maxino) {
4678fae3551SRodney W. Grimes fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
4688fae3551SRodney W. Grimes n = reply("REMOVE");
4691dc349abSEd Maste } else if (((dirp->d_ino == UFS_WINO && dirp->d_type != DT_WHT) ||
4701dc349abSEd Maste (dirp->d_ino != UFS_WINO && dirp->d_type == DT_WHT))) {
471780a5c1eSPeter Wemm fileerror(idesc->id_number, dirp->d_ino, "BAD WHITEOUT ENTRY");
4721dc349abSEd Maste dirp->d_ino = UFS_WINO;
473780a5c1eSPeter Wemm dirp->d_type = DT_WHT;
474780a5c1eSPeter Wemm if (reply("FIX") == 1)
475780a5c1eSPeter Wemm ret |= ALTERED;
4768fae3551SRodney W. Grimes } else {
4778fae3551SRodney W. Grimes again:
478d33e92f9SJulian Elischer switch (inoinfo(dirp->d_ino)->ino_state) {
4798fae3551SRodney W. Grimes case USTATE:
4808fae3551SRodney W. Grimes if (idesc->id_entryno <= 2)
4818fae3551SRodney W. Grimes break;
4828fae3551SRodney W. Grimes fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED");
4838fae3551SRodney W. Grimes n = reply("REMOVE");
4848fae3551SRodney W. Grimes break;
4858fae3551SRodney W. Grimes
4868fae3551SRodney W. Grimes case DCLEAR:
4878fae3551SRodney W. Grimes case FCLEAR:
4888fae3551SRodney W. Grimes if (idesc->id_entryno <= 2)
4898fae3551SRodney W. Grimes break;
490d33e92f9SJulian Elischer if (inoinfo(dirp->d_ino)->ino_state == FCLEAR)
4918fae3551SRodney W. Grimes errmsg = "DUP/BAD";
492b1897c19SJulian Elischer else if (!preen && !usedsoftdep)
4938fae3551SRodney W. Grimes errmsg = "ZERO LENGTH DIRECTORY";
49497fea87bSKirk McKusick else if (cursnapshot == 0) {
4958fae3551SRodney W. Grimes n = 1;
4968fae3551SRodney W. Grimes break;
49797fea87bSKirk McKusick } else {
49897fea87bSKirk McKusick getpathname(dirname, idesc->id_number,
49997fea87bSKirk McKusick dirp->d_ino);
500623d7cb6SMatthew D Fleming pwarn("ZERO LENGTH DIRECTORY %s I=%ju",
501623d7cb6SMatthew D Fleming dirname, (uintmax_t)dirp->d_ino);
50297fea87bSKirk McKusick /*
50397fea87bSKirk McKusick * We need to:
50497fea87bSKirk McKusick * setcwd(idesc->id_parent);
50597fea87bSKirk McKusick * rmdir(dirp->d_name);
50697fea87bSKirk McKusick */
50797fea87bSKirk McKusick cmd.value = idesc->id_number;
50897fea87bSKirk McKusick if (sysctlbyname("vfs.ffs.setcwd", 0, 0,
50997fea87bSKirk McKusick &cmd, sizeof cmd) == -1) {
51097fea87bSKirk McKusick /* kernel lacks support */
51197fea87bSKirk McKusick printf(" (IGNORED)\n");
51297fea87bSKirk McKusick n = 1;
51397fea87bSKirk McKusick break;
51497fea87bSKirk McKusick }
51597fea87bSKirk McKusick if (rmdir(dirp->d_name) == -1) {
51697fea87bSKirk McKusick printf(" (REMOVAL FAILED: %s)\n",
51797fea87bSKirk McKusick strerror(errno));
51897fea87bSKirk McKusick n = 1;
51997fea87bSKirk McKusick break;
52097fea87bSKirk McKusick }
52197fea87bSKirk McKusick /* ".." reference to parent is removed */
52297fea87bSKirk McKusick inoinfo(idesc->id_number)->ino_linkcnt--;
52397fea87bSKirk McKusick printf(" (REMOVED)\n");
52497fea87bSKirk McKusick break;
5258fae3551SRodney W. Grimes }
5268fae3551SRodney W. Grimes fileerror(idesc->id_number, dirp->d_ino, errmsg);
5278fae3551SRodney W. Grimes if ((n = reply("REMOVE")) == 1)
5288fae3551SRodney W. Grimes break;
5295cc52631SKirk McKusick ginode(dirp->d_ino, &ip);
5305cc52631SKirk McKusick dp = ip.i_dp;
531d33e92f9SJulian Elischer inoinfo(dirp->d_ino)->ino_state =
532d8ba45e2SEd Maste (DIP(dp, di_mode) & IFMT) == IFDIR ? DSTATE : FSTATE;
5331c85e6a3SKirk McKusick inoinfo(dirp->d_ino)->ino_linkcnt = DIP(dp, di_nlink);
5345cc52631SKirk McKusick irelse(&ip);
5358fae3551SRodney W. Grimes goto again;
5368fae3551SRodney W. Grimes
5378fae3551SRodney W. Grimes case DSTATE:
538af6726e6SDon Lewis case DZLINK:
539d33e92f9SJulian Elischer if (inoinfo(idesc->id_number)->ino_state == DFOUND)
540d33e92f9SJulian Elischer inoinfo(dirp->d_ino)->ino_state = DFOUND;
5417fed38d0SPhilippe Charnier /* FALLTHROUGH */
5428fae3551SRodney W. Grimes
5438fae3551SRodney W. Grimes case DFOUND:
5448fae3551SRodney W. Grimes inp = getinoinfo(dirp->d_ino);
54537776076SKirk McKusick if (idesc->id_entryno > 2) {
546fe5e6e2cSKirk McKusick if (inp->i_parent == 0) {
5478fae3551SRodney W. Grimes inp->i_parent = idesc->id_number;
548fe5e6e2cSKirk McKusick check_dirdepth(inp);
549fe5e6e2cSKirk McKusick } else if ((n = fix_extraneous(inp, idesc))) {
55037776076SKirk McKusick break;
55137776076SKirk McKusick }
552fe5e6e2cSKirk McKusick }
5537fed38d0SPhilippe Charnier /* FALLTHROUGH */
5548fae3551SRodney W. Grimes
5558fae3551SRodney W. Grimes case FSTATE:
556af6726e6SDon Lewis case FZLINK:
557381ee4c2SPoul-Henning Kamp if (dirp->d_type != inoinfo(dirp->d_ino)->ino_type) {
5588fae3551SRodney W. Grimes fileerror(idesc->id_number, dirp->d_ino,
5598fae3551SRodney W. Grimes "BAD TYPE VALUE");
560d33e92f9SJulian Elischer dirp->d_type = inoinfo(dirp->d_ino)->ino_type;
5618fae3551SRodney W. Grimes if (reply("FIX") == 1)
5628fae3551SRodney W. Grimes ret |= ALTERED;
5638fae3551SRodney W. Grimes }
564d33e92f9SJulian Elischer inoinfo(dirp->d_ino)->ino_linkcnt--;
5658fae3551SRodney W. Grimes break;
5668fae3551SRodney W. Grimes
5678fae3551SRodney W. Grimes default:
568623d7cb6SMatthew D Fleming errx(EEXIT, "BAD STATE %d FOR INODE I=%ju",
569623d7cb6SMatthew D Fleming inoinfo(dirp->d_ino)->ino_state,
570623d7cb6SMatthew D Fleming (uintmax_t)dirp->d_ino);
5718fae3551SRodney W. Grimes }
5728fae3551SRodney W. Grimes }
5738fae3551SRodney W. Grimes if (n == 0)
5748fae3551SRodney W. Grimes return (ret|KEEPON);
5758fae3551SRodney W. Grimes dirp->d_ino = 0;
5768fae3551SRodney W. Grimes return (ret|KEEPON|ALTERED);
5778fae3551SRodney W. Grimes }
5788fae3551SRodney W. Grimes
57937776076SKirk McKusick static int
fix_extraneous(struct inoinfo * inp,struct inodesc * idesc)58037776076SKirk McKusick fix_extraneous(struct inoinfo *inp, struct inodesc *idesc)
58137776076SKirk McKusick {
58277355ce0SKirk McKusick char *cp;
5835cc52631SKirk McKusick struct inode ip;
58437776076SKirk McKusick struct inodesc dotdesc;
58537776076SKirk McKusick char oldname[MAXPATHLEN + 1];
58637776076SKirk McKusick char newname[MAXPATHLEN + 1];
58737776076SKirk McKusick
58837776076SKirk McKusick /*
58937776076SKirk McKusick * If we have not yet found "..", look it up now so we know
59037776076SKirk McKusick * which inode the directory itself believes is its parent.
59137776076SKirk McKusick */
59237776076SKirk McKusick if (inp->i_dotdot == 0) {
59337776076SKirk McKusick memset(&dotdesc, 0, sizeof(struct inodesc));
59437776076SKirk McKusick dotdesc.id_type = DATA;
59537776076SKirk McKusick dotdesc.id_number = idesc->id_dirp->d_ino;
59637776076SKirk McKusick dotdesc.id_func = findino;
59737776076SKirk McKusick dotdesc.id_name = strdup("..");
5985cc52631SKirk McKusick ginode(dotdesc.id_number, &ip);
5995cc52631SKirk McKusick if ((ckinode(ip.i_dp, &dotdesc) & FOUND))
60037776076SKirk McKusick inp->i_dotdot = dotdesc.id_parent;
6015cc52631SKirk McKusick irelse(&ip);
602e5d0d1c5SKirk McKusick free(dotdesc.id_name);
60337776076SKirk McKusick }
60437776076SKirk McKusick /*
60537776076SKirk McKusick * We have the previously found old name (inp->i_parent) and the
60637776076SKirk McKusick * just found new name (idesc->id_number). We have five cases:
60737776076SKirk McKusick * 1) ".." is missing - can remove either name, choose to delete
60837776076SKirk McKusick * new one and let fsck create ".." pointing to old name.
60937776076SKirk McKusick * 2) Both new and old are in same directory, choose to delete
61037776076SKirk McKusick * the new name and let fsck fix ".." if it is wrong.
61137776076SKirk McKusick * 3) ".." does not point to the new name, so delete it and let
61237776076SKirk McKusick * fsck fix ".." to point to the old one if it is wrong.
61337776076SKirk McKusick * 4) ".." points to the old name only, so delete the new one.
61437776076SKirk McKusick * 5) ".." points to the new name only, so delete the old one.
61537776076SKirk McKusick *
61637776076SKirk McKusick * For cases 1-4 we eliminate the new name;
61737776076SKirk McKusick * for case 5 we eliminate the old name.
61837776076SKirk McKusick */
61937776076SKirk McKusick if (inp->i_dotdot == 0 || /* Case 1 */
62037776076SKirk McKusick idesc->id_number == inp->i_parent || /* Case 2 */
62137776076SKirk McKusick inp->i_dotdot != idesc->id_number || /* Case 3 */
62237776076SKirk McKusick inp->i_dotdot == inp->i_parent) { /* Case 4 */
62337776076SKirk McKusick getpathname(newname, idesc->id_number, idesc->id_number);
62437776076SKirk McKusick if (strcmp(newname, "/") != 0)
62537776076SKirk McKusick strcat (newname, "/");
62637776076SKirk McKusick strcat(newname, idesc->id_dirp->d_name);
62737776076SKirk McKusick getpathname(oldname, inp->i_number, inp->i_number);
62877355ce0SKirk McKusick pwarn("%s IS AN EXTRANEOUS HARD LINK TO DIRECTORY %s",
62937776076SKirk McKusick newname, oldname);
63037776076SKirk McKusick if (cursnapshot != 0) {
63137776076SKirk McKusick /*
63237776076SKirk McKusick * We need to
63337776076SKirk McKusick * setcwd(idesc->id_number);
63437776076SKirk McKusick * unlink(idesc->id_dirp->d_name);
63537776076SKirk McKusick */
63677355ce0SKirk McKusick cmd.value = idesc->id_number;
63777355ce0SKirk McKusick if (sysctlbyname("vfs.ffs.setcwd", 0, 0,
63877355ce0SKirk McKusick &cmd, sizeof cmd) == -1) {
63937776076SKirk McKusick printf(" (IGNORED)\n");
64037776076SKirk McKusick return (0);
64137776076SKirk McKusick }
642f83a0037SKirk McKusick cmd.value = (intptr_t)idesc->id_dirp->d_name;
64377355ce0SKirk McKusick cmd.size = inp->i_number; /* verify same name */
64477355ce0SKirk McKusick if (sysctlbyname("vfs.ffs.unlink", 0, 0,
64577355ce0SKirk McKusick &cmd, sizeof cmd) == -1) {
64677355ce0SKirk McKusick printf(" (UNLINK FAILED: %s)\n",
64777355ce0SKirk McKusick strerror(errno));
64877355ce0SKirk McKusick return (0);
64977355ce0SKirk McKusick }
65077355ce0SKirk McKusick printf(" (REMOVED)\n");
65177355ce0SKirk McKusick return (0);
65277355ce0SKirk McKusick }
65337776076SKirk McKusick if (preen) {
65437776076SKirk McKusick printf(" (REMOVED)\n");
65537776076SKirk McKusick return (1);
65637776076SKirk McKusick }
65737776076SKirk McKusick return (reply("REMOVE"));
65837776076SKirk McKusick }
65937776076SKirk McKusick /*
66037776076SKirk McKusick * None of the first four cases above, so must be case (5).
66137776076SKirk McKusick * Eliminate the old name and make the new the name the parent.
66237776076SKirk McKusick */
66337776076SKirk McKusick getpathname(oldname, inp->i_parent, inp->i_number);
66437776076SKirk McKusick getpathname(newname, inp->i_number, inp->i_number);
66577355ce0SKirk McKusick pwarn("%s IS AN EXTRANEOUS HARD LINK TO DIRECTORY %s", oldname,
66637776076SKirk McKusick newname);
66737776076SKirk McKusick if (cursnapshot != 0) {
66837776076SKirk McKusick /*
66937776076SKirk McKusick * We need to
67037776076SKirk McKusick * setcwd(inp->i_parent);
67137776076SKirk McKusick * unlink(last component of oldname pathname);
67237776076SKirk McKusick */
67377355ce0SKirk McKusick cmd.value = inp->i_parent;
67477355ce0SKirk McKusick if (sysctlbyname("vfs.ffs.setcwd", 0, 0,
67577355ce0SKirk McKusick &cmd, sizeof cmd) == -1) {
67637776076SKirk McKusick printf(" (IGNORED)\n");
67737776076SKirk McKusick return (0);
67837776076SKirk McKusick }
679b3608ae1SEd Schouten if ((cp = strchr(oldname, '/')) == NULL) {
68077355ce0SKirk McKusick printf(" (IGNORED)\n");
68177355ce0SKirk McKusick return (0);
68277355ce0SKirk McKusick }
683f83a0037SKirk McKusick cmd.value = (intptr_t)(cp + 1);
68477355ce0SKirk McKusick cmd.size = inp->i_number; /* verify same name */
68577355ce0SKirk McKusick if (sysctlbyname("vfs.ffs.unlink", 0, 0,
68677355ce0SKirk McKusick &cmd, sizeof cmd) == -1) {
68777355ce0SKirk McKusick printf(" (UNLINK FAILED: %s)\n",
68877355ce0SKirk McKusick strerror(errno));
68977355ce0SKirk McKusick return (0);
69077355ce0SKirk McKusick }
69177355ce0SKirk McKusick printf(" (REMOVED)\n");
69277355ce0SKirk McKusick inp->i_parent = idesc->id_number; /* reparent to correct dir */
69377355ce0SKirk McKusick return (0);
69477355ce0SKirk McKusick }
69537776076SKirk McKusick if (!preen && !reply("REMOVE"))
69637776076SKirk McKusick return (0);
69737776076SKirk McKusick memset(&dotdesc, 0, sizeof(struct inodesc));
69837776076SKirk McKusick dotdesc.id_type = DATA;
69937776076SKirk McKusick dotdesc.id_number = inp->i_parent; /* directory in which name appears */
70037776076SKirk McKusick dotdesc.id_parent = inp->i_number; /* inode number in entry to delete */
70137776076SKirk McKusick dotdesc.id_func = deleteentry;
7025cc52631SKirk McKusick ginode(dotdesc.id_number, &ip);
7035cc52631SKirk McKusick if ((ckinode(ip.i_dp, &dotdesc) & FOUND) && preen)
70437776076SKirk McKusick printf(" (REMOVED)\n");
7055cc52631SKirk McKusick irelse(&ip);
70637776076SKirk McKusick inp->i_parent = idesc->id_number; /* reparent to correct directory */
70737776076SKirk McKusick inoinfo(inp->i_number)->ino_linkcnt++; /* name gone, return reference */
70837776076SKirk McKusick return (0);
70937776076SKirk McKusick }
71037776076SKirk McKusick
71137776076SKirk McKusick static int
deleteentry(struct inodesc * idesc)71237776076SKirk McKusick deleteentry(struct inodesc *idesc)
71337776076SKirk McKusick {
71437776076SKirk McKusick struct direct *dirp = idesc->id_dirp;
71537776076SKirk McKusick
71637776076SKirk McKusick if (idesc->id_entryno++ < 2 || dirp->d_ino != idesc->id_parent)
71737776076SKirk McKusick return (KEEPON);
71837776076SKirk McKusick dirp->d_ino = 0;
71937776076SKirk McKusick return (ALTERED|STOP|FOUND);
72037776076SKirk McKusick }
72137776076SKirk McKusick
7228fae3551SRodney W. Grimes /*
7238fae3551SRodney W. Grimes * Routine to sort disk blocks.
7248fae3551SRodney W. Grimes */
725780a5c1eSPeter Wemm static int
blksort(const void * arg1,const void * arg2)726b70cd7eeSWarner Losh blksort(const void *arg1, const void *arg2)
7278fae3551SRodney W. Grimes {
7288fae3551SRodney W. Grimes
729599304a4SPoul-Henning Kamp return ((*(struct inoinfo * const *)arg1)->i_blks[0] -
730599304a4SPoul-Henning Kamp (*(struct inoinfo * const *)arg2)->i_blks[0]);
7318fae3551SRodney W. Grimes }
732