Deleted Added
full compact
pass2.c (202107) pass2.c (202109)
1/*
2 * Copyright (c) 1980, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#if 0
31#ifndef lint
32static const char sccsid[] = "@(#)pass2.c 8.9 (Berkeley) 4/28/95";
33#endif /* not lint */
34#endif
35#include <sys/cdefs.h>
1/*
2 * Copyright (c) 1980, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#if 0
31#ifndef lint
32static const char sccsid[] = "@(#)pass2.c 8.9 (Berkeley) 4/28/95";
33#endif /* not lint */
34#endif
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: head/sbin/fsck_ffs/pass2.c 202107 2010-01-11 19:52:40Z mckusick $");
36__FBSDID("$FreeBSD: head/sbin/fsck_ffs/pass2.c 202109 2010-01-11 20:05:38Z mckusick $");
37
38#include <sys/param.h>
37
38#include <sys/param.h>
39#include <sys/sysctl.h>
39
40#include <ufs/ufs/dinode.h>
41#include <ufs/ufs/dir.h>
42#include <ufs/ffs/fs.h>
43
44#include <err.h>
40
41#include <ufs/ufs/dinode.h>
42#include <ufs/ufs/dir.h>
43#include <ufs/ffs/fs.h>
44
45#include <err.h>
46#include <errno.h>
45#include <stdint.h>
46#include <string.h>
47
48#include "fsck.h"
49
50#define MINDIRSIZE (sizeof (struct dirtemplate))
51
52static int fix_extraneous(struct inoinfo *, struct inodesc *);
53static int deleteentry(struct inodesc *);
54static int blksort(const void *, const void *);
55static int pass2check(struct inodesc *);
56
57void
58pass2(void)
59{
60 union dinode *dp;
61 struct inoinfo **inpp, *inp;
62 struct inoinfo **inpend;
63 struct inodesc curino;
64 union dinode dino;
65 int i;
66 char pathbuf[MAXPATHLEN + 1];
67
68 switch (inoinfo(ROOTINO)->ino_state) {
69
70 case USTATE:
71 pfatal("ROOT INODE UNALLOCATED");
72 if (reply("ALLOCATE") == 0) {
73 ckfini(0);
74 exit(EEXIT);
75 }
76 if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
77 errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
78 break;
79
80 case DCLEAR:
81 pfatal("DUPS/BAD IN ROOT INODE");
82 if (reply("REALLOCATE")) {
83 freeino(ROOTINO);
84 if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
85 errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
86 break;
87 }
88 if (reply("CONTINUE") == 0) {
89 ckfini(0);
90 exit(EEXIT);
91 }
92 break;
93
94 case FSTATE:
95 case FCLEAR:
96 case FZLINK:
97 pfatal("ROOT INODE NOT DIRECTORY");
98 if (reply("REALLOCATE")) {
99 freeino(ROOTINO);
100 if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
101 errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
102 break;
103 }
104 if (reply("FIX") == 0) {
105 ckfini(0);
106 exit(EEXIT);
107 }
108 dp = ginode(ROOTINO);
109 DIP_SET(dp, di_mode, DIP(dp, di_mode) & ~IFMT);
110 DIP_SET(dp, di_mode, DIP(dp, di_mode) | IFDIR);
111 inodirty();
112 break;
113
114 case DSTATE:
115 case DZLINK:
116 break;
117
118 default:
119 errx(EEXIT, "BAD STATE %d FOR ROOT INODE",
120 inoinfo(ROOTINO)->ino_state);
121 }
122 inoinfo(ROOTINO)->ino_state = DFOUND;
123 inoinfo(WINO)->ino_state = FSTATE;
124 inoinfo(WINO)->ino_type = DT_WHT;
125 /*
126 * Sort the directory list into disk block order.
127 */
128 qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort);
129 /*
130 * Check the integrity of each directory.
131 */
132 memset(&curino, 0, sizeof(struct inodesc));
133 curino.id_type = DATA;
134 curino.id_func = pass2check;
135 inpend = &inpsort[inplast];
136 for (inpp = inpsort; inpp < inpend; inpp++) {
137 if (got_siginfo) {
138 printf("%s: phase 2: dir %td of %d (%d%%)\n", cdevname,
139 inpp - inpsort, (int)inplast,
140 (int)((inpp - inpsort) * 100 / inplast));
141 got_siginfo = 0;
142 }
143 if (got_sigalarm) {
144 setproctitle("%s p2 %d%%", cdevname,
145 (int)((inpp - inpsort) * 100 / inplast));
146 got_sigalarm = 0;
147 }
148 inp = *inpp;
149 if (inp->i_isize == 0)
150 continue;
151 if (inp->i_isize < MINDIRSIZE) {
152 direrror(inp->i_number, "DIRECTORY TOO SHORT");
153 inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ);
154 if (reply("FIX") == 1) {
155 dp = ginode(inp->i_number);
156 DIP_SET(dp, di_size, inp->i_isize);
157 inodirty();
158 }
159 } else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) {
160 getpathname(pathbuf, inp->i_number, inp->i_number);
161 if (usedsoftdep)
162 pfatal("%s %s: LENGTH %jd NOT MULTIPLE OF %d",
163 "DIRECTORY", pathbuf,
164 (intmax_t)inp->i_isize, DIRBLKSIZ);
165 else
166 pwarn("%s %s: LENGTH %jd NOT MULTIPLE OF %d",
167 "DIRECTORY", pathbuf,
168 (intmax_t)inp->i_isize, DIRBLKSIZ);
169 if (preen)
170 printf(" (ADJUSTED)\n");
171 inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ);
172 if (preen || reply("ADJUST") == 1) {
173 dp = ginode(inp->i_number);
174 DIP_SET(dp, di_size,
175 roundup(inp->i_isize, DIRBLKSIZ));
176 inodirty();
177 }
178 }
179 dp = &dino;
180 memset(dp, 0, sizeof(struct ufs2_dinode));
181 DIP_SET(dp, di_mode, IFDIR);
182 DIP_SET(dp, di_size, inp->i_isize);
183 for (i = 0;
184 i < (inp->i_numblks<NDADDR ? inp->i_numblks : NDADDR);
185 i++)
186 DIP_SET(dp, di_db[i], inp->i_blks[i]);
187 if (inp->i_numblks > NDADDR)
188 for (i = 0; i < NIADDR; i++)
189 DIP_SET(dp, di_ib[i], inp->i_blks[NDADDR + i]);
190 curino.id_number = inp->i_number;
191 curino.id_parent = inp->i_parent;
192 (void)ckinode(dp, &curino);
193 }
194 /*
195 * Now that the parents of all directories have been found,
196 * make another pass to verify the value of `..'
197 */
198 for (inpp = inpsort; inpp < inpend; inpp++) {
199 inp = *inpp;
200 if (inp->i_parent == 0 || inp->i_isize == 0)
201 continue;
202 if (inoinfo(inp->i_parent)->ino_state == DFOUND &&
203 INO_IS_DUNFOUND(inp->i_number))
204 inoinfo(inp->i_number)->ino_state = DFOUND;
205 if (inp->i_dotdot == inp->i_parent ||
206 inp->i_dotdot == (ino_t)-1)
207 continue;
208 if (inp->i_dotdot == 0) {
209 inp->i_dotdot = inp->i_parent;
210 fileerror(inp->i_parent, inp->i_number, "MISSING '..'");
211 if (reply("FIX") == 0)
212 continue;
213 (void)makeentry(inp->i_number, inp->i_parent, "..");
214 inoinfo(inp->i_parent)->ino_linkcnt--;
215 continue;
216 }
47#include <stdint.h>
48#include <string.h>
49
50#include "fsck.h"
51
52#define MINDIRSIZE (sizeof (struct dirtemplate))
53
54static int fix_extraneous(struct inoinfo *, struct inodesc *);
55static int deleteentry(struct inodesc *);
56static int blksort(const void *, const void *);
57static int pass2check(struct inodesc *);
58
59void
60pass2(void)
61{
62 union dinode *dp;
63 struct inoinfo **inpp, *inp;
64 struct inoinfo **inpend;
65 struct inodesc curino;
66 union dinode dino;
67 int i;
68 char pathbuf[MAXPATHLEN + 1];
69
70 switch (inoinfo(ROOTINO)->ino_state) {
71
72 case USTATE:
73 pfatal("ROOT INODE UNALLOCATED");
74 if (reply("ALLOCATE") == 0) {
75 ckfini(0);
76 exit(EEXIT);
77 }
78 if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
79 errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
80 break;
81
82 case DCLEAR:
83 pfatal("DUPS/BAD IN ROOT INODE");
84 if (reply("REALLOCATE")) {
85 freeino(ROOTINO);
86 if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
87 errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
88 break;
89 }
90 if (reply("CONTINUE") == 0) {
91 ckfini(0);
92 exit(EEXIT);
93 }
94 break;
95
96 case FSTATE:
97 case FCLEAR:
98 case FZLINK:
99 pfatal("ROOT INODE NOT DIRECTORY");
100 if (reply("REALLOCATE")) {
101 freeino(ROOTINO);
102 if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
103 errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
104 break;
105 }
106 if (reply("FIX") == 0) {
107 ckfini(0);
108 exit(EEXIT);
109 }
110 dp = ginode(ROOTINO);
111 DIP_SET(dp, di_mode, DIP(dp, di_mode) & ~IFMT);
112 DIP_SET(dp, di_mode, DIP(dp, di_mode) | IFDIR);
113 inodirty();
114 break;
115
116 case DSTATE:
117 case DZLINK:
118 break;
119
120 default:
121 errx(EEXIT, "BAD STATE %d FOR ROOT INODE",
122 inoinfo(ROOTINO)->ino_state);
123 }
124 inoinfo(ROOTINO)->ino_state = DFOUND;
125 inoinfo(WINO)->ino_state = FSTATE;
126 inoinfo(WINO)->ino_type = DT_WHT;
127 /*
128 * Sort the directory list into disk block order.
129 */
130 qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort);
131 /*
132 * Check the integrity of each directory.
133 */
134 memset(&curino, 0, sizeof(struct inodesc));
135 curino.id_type = DATA;
136 curino.id_func = pass2check;
137 inpend = &inpsort[inplast];
138 for (inpp = inpsort; inpp < inpend; inpp++) {
139 if (got_siginfo) {
140 printf("%s: phase 2: dir %td of %d (%d%%)\n", cdevname,
141 inpp - inpsort, (int)inplast,
142 (int)((inpp - inpsort) * 100 / inplast));
143 got_siginfo = 0;
144 }
145 if (got_sigalarm) {
146 setproctitle("%s p2 %d%%", cdevname,
147 (int)((inpp - inpsort) * 100 / inplast));
148 got_sigalarm = 0;
149 }
150 inp = *inpp;
151 if (inp->i_isize == 0)
152 continue;
153 if (inp->i_isize < MINDIRSIZE) {
154 direrror(inp->i_number, "DIRECTORY TOO SHORT");
155 inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ);
156 if (reply("FIX") == 1) {
157 dp = ginode(inp->i_number);
158 DIP_SET(dp, di_size, inp->i_isize);
159 inodirty();
160 }
161 } else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) {
162 getpathname(pathbuf, inp->i_number, inp->i_number);
163 if (usedsoftdep)
164 pfatal("%s %s: LENGTH %jd NOT MULTIPLE OF %d",
165 "DIRECTORY", pathbuf,
166 (intmax_t)inp->i_isize, DIRBLKSIZ);
167 else
168 pwarn("%s %s: LENGTH %jd NOT MULTIPLE OF %d",
169 "DIRECTORY", pathbuf,
170 (intmax_t)inp->i_isize, DIRBLKSIZ);
171 if (preen)
172 printf(" (ADJUSTED)\n");
173 inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ);
174 if (preen || reply("ADJUST") == 1) {
175 dp = ginode(inp->i_number);
176 DIP_SET(dp, di_size,
177 roundup(inp->i_isize, DIRBLKSIZ));
178 inodirty();
179 }
180 }
181 dp = &dino;
182 memset(dp, 0, sizeof(struct ufs2_dinode));
183 DIP_SET(dp, di_mode, IFDIR);
184 DIP_SET(dp, di_size, inp->i_isize);
185 for (i = 0;
186 i < (inp->i_numblks<NDADDR ? inp->i_numblks : NDADDR);
187 i++)
188 DIP_SET(dp, di_db[i], inp->i_blks[i]);
189 if (inp->i_numblks > NDADDR)
190 for (i = 0; i < NIADDR; i++)
191 DIP_SET(dp, di_ib[i], inp->i_blks[NDADDR + i]);
192 curino.id_number = inp->i_number;
193 curino.id_parent = inp->i_parent;
194 (void)ckinode(dp, &curino);
195 }
196 /*
197 * Now that the parents of all directories have been found,
198 * make another pass to verify the value of `..'
199 */
200 for (inpp = inpsort; inpp < inpend; inpp++) {
201 inp = *inpp;
202 if (inp->i_parent == 0 || inp->i_isize == 0)
203 continue;
204 if (inoinfo(inp->i_parent)->ino_state == DFOUND &&
205 INO_IS_DUNFOUND(inp->i_number))
206 inoinfo(inp->i_number)->ino_state = DFOUND;
207 if (inp->i_dotdot == inp->i_parent ||
208 inp->i_dotdot == (ino_t)-1)
209 continue;
210 if (inp->i_dotdot == 0) {
211 inp->i_dotdot = inp->i_parent;
212 fileerror(inp->i_parent, inp->i_number, "MISSING '..'");
213 if (reply("FIX") == 0)
214 continue;
215 (void)makeentry(inp->i_number, inp->i_parent, "..");
216 inoinfo(inp->i_parent)->ino_linkcnt--;
217 continue;
218 }
217 fileerror(inp->i_parent, inp->i_number,
218 "BAD INODE NUMBER FOR '..'");
219 if (reply("FIX") == 0)
219 /*
220 * Here we have:
221 * inp->i_number is directory with bad ".." in it.
222 * inp->i_dotdot is current value of "..".
223 * inp->i_parent is directory to which ".." should point.
224 */
225 getpathname(pathbuf, inp->i_parent, inp->i_number);
226 printf("BAD INODE NUMBER FOR '..' in DIR I=%d (%s)\n",
227 inp->i_number, pathbuf);
228 getpathname(pathbuf, inp->i_dotdot, inp->i_dotdot);
229 printf("CURRENTLY POINTS TO I=%d (%s), ", inp->i_dotdot,
230 pathbuf);
231 getpathname(pathbuf, inp->i_parent, inp->i_parent);
232 printf("SHOULD POINT TO I=%d (%s)", inp->i_parent, pathbuf);
233 if (cursnapshot != 0) {
234 /*
235 * We need to:
236 * setcwd(inp->i_number);
237 * setdotdot(inp->i_dotdot, inp->i_parent);
238 */
239 cmd.value = inp->i_number;
240 if (sysctlbyname("vfs.ffs.setcwd", 0, 0,
241 &cmd, sizeof cmd) == -1) {
242 /* kernel lacks support for these functions */
243 printf(" (IGNORED)\n");
244 continue;
245 }
246 cmd.value = inp->i_dotdot; /* verify same value */
247 cmd.size = inp->i_parent; /* new parent */
248 if (sysctlbyname("vfs.ffs.setdotdot", 0, 0,
249 &cmd, sizeof cmd) == -1) {
250 printf(" (FIX FAILED: %s)\n", strerror(errno));
251 continue;
252 }
253 printf(" (FIXED)\n");
254 inoinfo(inp->i_parent)->ino_linkcnt--;
255 inp->i_dotdot = inp->i_parent;
220 continue;
256 continue;
257 }
258 if (preen)
259 printf(" (FIXED)\n");
260 else if (reply("FIX") == 0)
261 continue;
221 inoinfo(inp->i_dotdot)->ino_linkcnt++;
222 inoinfo(inp->i_parent)->ino_linkcnt--;
223 inp->i_dotdot = inp->i_parent;
224 (void)changeino(inp->i_number, "..", inp->i_parent);
225 }
226 /*
227 * Mark all the directories that can be found from the root.
228 */
229 propagate();
230}
231
232static int
233pass2check(struct inodesc *idesc)
234{
235 struct direct *dirp = idesc->id_dirp;
236 struct inoinfo *inp;
237 int n, entrysize, ret = 0;
238 union dinode *dp;
239 const char *errmsg;
240 struct direct proto;
241
242 /*
243 * check for "."
244 */
245 if (dirp->d_ino > maxino)
246 goto chk2;
247 if (idesc->id_entryno != 0)
248 goto chk1;
249 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
250 if (dirp->d_ino != idesc->id_number) {
251 direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
252 dirp->d_ino = idesc->id_number;
253 if (reply("FIX") == 1)
254 ret |= ALTERED;
255 }
256 if (dirp->d_type != DT_DIR) {
257 direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'");
258 dirp->d_type = DT_DIR;
259 if (reply("FIX") == 1)
260 ret |= ALTERED;
261 }
262 goto chk1;
263 }
264 direrror(idesc->id_number, "MISSING '.'");
265 proto.d_ino = idesc->id_number;
266 proto.d_type = DT_DIR;
267 proto.d_namlen = 1;
268 (void)strcpy(proto.d_name, ".");
269 entrysize = DIRSIZ(0, &proto);
270 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
271 pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
272 dirp->d_name);
273 } else if (dirp->d_reclen < entrysize) {
274 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
275 } else if (dirp->d_reclen < 2 * entrysize) {
276 proto.d_reclen = dirp->d_reclen;
277 memmove(dirp, &proto, (size_t)entrysize);
278 if (reply("FIX") == 1)
279 ret |= ALTERED;
280 } else {
281 n = dirp->d_reclen - entrysize;
282 proto.d_reclen = entrysize;
283 memmove(dirp, &proto, (size_t)entrysize);
284 idesc->id_entryno++;
285 inoinfo(dirp->d_ino)->ino_linkcnt--;
286 dirp = (struct direct *)((char *)(dirp) + entrysize);
287 memset(dirp, 0, (size_t)n);
288 dirp->d_reclen = n;
289 if (reply("FIX") == 1)
290 ret |= ALTERED;
291 }
292chk1:
293 if (idesc->id_entryno > 1)
294 goto chk2;
295 inp = getinoinfo(idesc->id_number);
296 proto.d_ino = inp->i_parent;
297 proto.d_type = DT_DIR;
298 proto.d_namlen = 2;
299 (void)strcpy(proto.d_name, "..");
300 entrysize = DIRSIZ(0, &proto);
301 if (idesc->id_entryno == 0) {
302 n = DIRSIZ(0, dirp);
303 if (dirp->d_reclen < n + entrysize)
304 goto chk2;
305 proto.d_reclen = dirp->d_reclen - n;
306 dirp->d_reclen = n;
307 idesc->id_entryno++;
308 inoinfo(dirp->d_ino)->ino_linkcnt--;
309 dirp = (struct direct *)((char *)(dirp) + n);
310 memset(dirp, 0, (size_t)proto.d_reclen);
311 dirp->d_reclen = proto.d_reclen;
312 }
313 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
314 inp->i_dotdot = dirp->d_ino;
315 if (dirp->d_type != DT_DIR) {
316 direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'");
317 dirp->d_type = DT_DIR;
318 if (reply("FIX") == 1)
319 ret |= ALTERED;
320 }
321 goto chk2;
322 }
323 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
324 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
325 pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
326 dirp->d_name);
327 inp->i_dotdot = (ino_t)-1;
328 } else if (dirp->d_reclen < entrysize) {
329 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
330 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
331 inp->i_dotdot = (ino_t)-1;
332 } else if (inp->i_parent != 0) {
333 /*
334 * We know the parent, so fix now.
335 */
336 inp->i_dotdot = inp->i_parent;
337 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
338 proto.d_reclen = dirp->d_reclen;
339 memmove(dirp, &proto, (size_t)entrysize);
340 if (reply("FIX") == 1)
341 ret |= ALTERED;
342 }
343 idesc->id_entryno++;
344 if (dirp->d_ino != 0)
345 inoinfo(dirp->d_ino)->ino_linkcnt--;
346 return (ret|KEEPON);
347chk2:
348 if (dirp->d_ino == 0)
349 return (ret|KEEPON);
350 if (dirp->d_namlen <= 2 &&
351 dirp->d_name[0] == '.' &&
352 idesc->id_entryno >= 2) {
353 if (dirp->d_namlen == 1) {
354 direrror(idesc->id_number, "EXTRA '.' ENTRY");
355 dirp->d_ino = 0;
356 if (reply("FIX") == 1)
357 ret |= ALTERED;
358 return (KEEPON | ret);
359 }
360 if (dirp->d_name[1] == '.') {
361 direrror(idesc->id_number, "EXTRA '..' ENTRY");
362 dirp->d_ino = 0;
363 if (reply("FIX") == 1)
364 ret |= ALTERED;
365 return (KEEPON | ret);
366 }
367 }
368 idesc->id_entryno++;
369 n = 0;
370 if (dirp->d_ino > maxino) {
371 fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
372 n = reply("REMOVE");
373 } else if (((dirp->d_ino == WINO && dirp->d_type != DT_WHT) ||
374 (dirp->d_ino != WINO && dirp->d_type == DT_WHT))) {
375 fileerror(idesc->id_number, dirp->d_ino, "BAD WHITEOUT ENTRY");
376 dirp->d_ino = WINO;
377 dirp->d_type = DT_WHT;
378 if (reply("FIX") == 1)
379 ret |= ALTERED;
380 } else {
381again:
382 switch (inoinfo(dirp->d_ino)->ino_state) {
383 case USTATE:
384 if (idesc->id_entryno <= 2)
385 break;
386 fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED");
387 n = reply("REMOVE");
388 break;
389
390 case DCLEAR:
391 case FCLEAR:
392 if (idesc->id_entryno <= 2)
393 break;
394 if (inoinfo(dirp->d_ino)->ino_state == FCLEAR)
395 errmsg = "DUP/BAD";
396 else if (!preen && !usedsoftdep)
397 errmsg = "ZERO LENGTH DIRECTORY";
398 else {
399 n = 1;
400 break;
401 }
402 fileerror(idesc->id_number, dirp->d_ino, errmsg);
403 if ((n = reply("REMOVE")) == 1)
404 break;
405 dp = ginode(dirp->d_ino);
406 inoinfo(dirp->d_ino)->ino_state =
407 (DIP(dp, di_mode) & IFMT) == IFDIR ? DSTATE : FSTATE;
408 inoinfo(dirp->d_ino)->ino_linkcnt = DIP(dp, di_nlink);
409 goto again;
410
411 case DSTATE:
412 case DZLINK:
413 if (inoinfo(idesc->id_number)->ino_state == DFOUND)
414 inoinfo(dirp->d_ino)->ino_state = DFOUND;
415 /* FALLTHROUGH */
416
417 case DFOUND:
418 inp = getinoinfo(dirp->d_ino);
419 if (idesc->id_entryno > 2) {
420 if (inp->i_parent == 0)
421 inp->i_parent = idesc->id_number;
422 else if ((n = fix_extraneous(inp, idesc)) == 1)
423 break;
424 }
425 /* FALLTHROUGH */
426
427 case FSTATE:
428 case FZLINK:
429 if (dirp->d_type != inoinfo(dirp->d_ino)->ino_type) {
430 fileerror(idesc->id_number, dirp->d_ino,
431 "BAD TYPE VALUE");
432 dirp->d_type = inoinfo(dirp->d_ino)->ino_type;
433 if (reply("FIX") == 1)
434 ret |= ALTERED;
435 }
436 inoinfo(dirp->d_ino)->ino_linkcnt--;
437 break;
438
439 default:
440 errx(EEXIT, "BAD STATE %d FOR INODE I=%d",
441 inoinfo(dirp->d_ino)->ino_state, dirp->d_ino);
442 }
443 }
444 if (n == 0)
445 return (ret|KEEPON);
446 dirp->d_ino = 0;
447 return (ret|KEEPON|ALTERED);
448}
449
450static int
451fix_extraneous(struct inoinfo *inp, struct inodesc *idesc)
452{
262 inoinfo(inp->i_dotdot)->ino_linkcnt++;
263 inoinfo(inp->i_parent)->ino_linkcnt--;
264 inp->i_dotdot = inp->i_parent;
265 (void)changeino(inp->i_number, "..", inp->i_parent);
266 }
267 /*
268 * Mark all the directories that can be found from the root.
269 */
270 propagate();
271}
272
273static int
274pass2check(struct inodesc *idesc)
275{
276 struct direct *dirp = idesc->id_dirp;
277 struct inoinfo *inp;
278 int n, entrysize, ret = 0;
279 union dinode *dp;
280 const char *errmsg;
281 struct direct proto;
282
283 /*
284 * check for "."
285 */
286 if (dirp->d_ino > maxino)
287 goto chk2;
288 if (idesc->id_entryno != 0)
289 goto chk1;
290 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
291 if (dirp->d_ino != idesc->id_number) {
292 direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
293 dirp->d_ino = idesc->id_number;
294 if (reply("FIX") == 1)
295 ret |= ALTERED;
296 }
297 if (dirp->d_type != DT_DIR) {
298 direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'");
299 dirp->d_type = DT_DIR;
300 if (reply("FIX") == 1)
301 ret |= ALTERED;
302 }
303 goto chk1;
304 }
305 direrror(idesc->id_number, "MISSING '.'");
306 proto.d_ino = idesc->id_number;
307 proto.d_type = DT_DIR;
308 proto.d_namlen = 1;
309 (void)strcpy(proto.d_name, ".");
310 entrysize = DIRSIZ(0, &proto);
311 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
312 pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
313 dirp->d_name);
314 } else if (dirp->d_reclen < entrysize) {
315 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
316 } else if (dirp->d_reclen < 2 * entrysize) {
317 proto.d_reclen = dirp->d_reclen;
318 memmove(dirp, &proto, (size_t)entrysize);
319 if (reply("FIX") == 1)
320 ret |= ALTERED;
321 } else {
322 n = dirp->d_reclen - entrysize;
323 proto.d_reclen = entrysize;
324 memmove(dirp, &proto, (size_t)entrysize);
325 idesc->id_entryno++;
326 inoinfo(dirp->d_ino)->ino_linkcnt--;
327 dirp = (struct direct *)((char *)(dirp) + entrysize);
328 memset(dirp, 0, (size_t)n);
329 dirp->d_reclen = n;
330 if (reply("FIX") == 1)
331 ret |= ALTERED;
332 }
333chk1:
334 if (idesc->id_entryno > 1)
335 goto chk2;
336 inp = getinoinfo(idesc->id_number);
337 proto.d_ino = inp->i_parent;
338 proto.d_type = DT_DIR;
339 proto.d_namlen = 2;
340 (void)strcpy(proto.d_name, "..");
341 entrysize = DIRSIZ(0, &proto);
342 if (idesc->id_entryno == 0) {
343 n = DIRSIZ(0, dirp);
344 if (dirp->d_reclen < n + entrysize)
345 goto chk2;
346 proto.d_reclen = dirp->d_reclen - n;
347 dirp->d_reclen = n;
348 idesc->id_entryno++;
349 inoinfo(dirp->d_ino)->ino_linkcnt--;
350 dirp = (struct direct *)((char *)(dirp) + n);
351 memset(dirp, 0, (size_t)proto.d_reclen);
352 dirp->d_reclen = proto.d_reclen;
353 }
354 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
355 inp->i_dotdot = dirp->d_ino;
356 if (dirp->d_type != DT_DIR) {
357 direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'");
358 dirp->d_type = DT_DIR;
359 if (reply("FIX") == 1)
360 ret |= ALTERED;
361 }
362 goto chk2;
363 }
364 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
365 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
366 pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
367 dirp->d_name);
368 inp->i_dotdot = (ino_t)-1;
369 } else if (dirp->d_reclen < entrysize) {
370 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
371 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
372 inp->i_dotdot = (ino_t)-1;
373 } else if (inp->i_parent != 0) {
374 /*
375 * We know the parent, so fix now.
376 */
377 inp->i_dotdot = inp->i_parent;
378 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
379 proto.d_reclen = dirp->d_reclen;
380 memmove(dirp, &proto, (size_t)entrysize);
381 if (reply("FIX") == 1)
382 ret |= ALTERED;
383 }
384 idesc->id_entryno++;
385 if (dirp->d_ino != 0)
386 inoinfo(dirp->d_ino)->ino_linkcnt--;
387 return (ret|KEEPON);
388chk2:
389 if (dirp->d_ino == 0)
390 return (ret|KEEPON);
391 if (dirp->d_namlen <= 2 &&
392 dirp->d_name[0] == '.' &&
393 idesc->id_entryno >= 2) {
394 if (dirp->d_namlen == 1) {
395 direrror(idesc->id_number, "EXTRA '.' ENTRY");
396 dirp->d_ino = 0;
397 if (reply("FIX") == 1)
398 ret |= ALTERED;
399 return (KEEPON | ret);
400 }
401 if (dirp->d_name[1] == '.') {
402 direrror(idesc->id_number, "EXTRA '..' ENTRY");
403 dirp->d_ino = 0;
404 if (reply("FIX") == 1)
405 ret |= ALTERED;
406 return (KEEPON | ret);
407 }
408 }
409 idesc->id_entryno++;
410 n = 0;
411 if (dirp->d_ino > maxino) {
412 fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
413 n = reply("REMOVE");
414 } else if (((dirp->d_ino == WINO && dirp->d_type != DT_WHT) ||
415 (dirp->d_ino != WINO && dirp->d_type == DT_WHT))) {
416 fileerror(idesc->id_number, dirp->d_ino, "BAD WHITEOUT ENTRY");
417 dirp->d_ino = WINO;
418 dirp->d_type = DT_WHT;
419 if (reply("FIX") == 1)
420 ret |= ALTERED;
421 } else {
422again:
423 switch (inoinfo(dirp->d_ino)->ino_state) {
424 case USTATE:
425 if (idesc->id_entryno <= 2)
426 break;
427 fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED");
428 n = reply("REMOVE");
429 break;
430
431 case DCLEAR:
432 case FCLEAR:
433 if (idesc->id_entryno <= 2)
434 break;
435 if (inoinfo(dirp->d_ino)->ino_state == FCLEAR)
436 errmsg = "DUP/BAD";
437 else if (!preen && !usedsoftdep)
438 errmsg = "ZERO LENGTH DIRECTORY";
439 else {
440 n = 1;
441 break;
442 }
443 fileerror(idesc->id_number, dirp->d_ino, errmsg);
444 if ((n = reply("REMOVE")) == 1)
445 break;
446 dp = ginode(dirp->d_ino);
447 inoinfo(dirp->d_ino)->ino_state =
448 (DIP(dp, di_mode) & IFMT) == IFDIR ? DSTATE : FSTATE;
449 inoinfo(dirp->d_ino)->ino_linkcnt = DIP(dp, di_nlink);
450 goto again;
451
452 case DSTATE:
453 case DZLINK:
454 if (inoinfo(idesc->id_number)->ino_state == DFOUND)
455 inoinfo(dirp->d_ino)->ino_state = DFOUND;
456 /* FALLTHROUGH */
457
458 case DFOUND:
459 inp = getinoinfo(dirp->d_ino);
460 if (idesc->id_entryno > 2) {
461 if (inp->i_parent == 0)
462 inp->i_parent = idesc->id_number;
463 else if ((n = fix_extraneous(inp, idesc)) == 1)
464 break;
465 }
466 /* FALLTHROUGH */
467
468 case FSTATE:
469 case FZLINK:
470 if (dirp->d_type != inoinfo(dirp->d_ino)->ino_type) {
471 fileerror(idesc->id_number, dirp->d_ino,
472 "BAD TYPE VALUE");
473 dirp->d_type = inoinfo(dirp->d_ino)->ino_type;
474 if (reply("FIX") == 1)
475 ret |= ALTERED;
476 }
477 inoinfo(dirp->d_ino)->ino_linkcnt--;
478 break;
479
480 default:
481 errx(EEXIT, "BAD STATE %d FOR INODE I=%d",
482 inoinfo(dirp->d_ino)->ino_state, dirp->d_ino);
483 }
484 }
485 if (n == 0)
486 return (ret|KEEPON);
487 dirp->d_ino = 0;
488 return (ret|KEEPON|ALTERED);
489}
490
491static int
492fix_extraneous(struct inoinfo *inp, struct inodesc *idesc)
493{
494 char *cp;
453 struct inodesc dotdesc;
454 char oldname[MAXPATHLEN + 1];
455 char newname[MAXPATHLEN + 1];
456
457 /*
458 * If we have not yet found "..", look it up now so we know
459 * which inode the directory itself believes is its parent.
460 */
461 if (inp->i_dotdot == 0) {
462 memset(&dotdesc, 0, sizeof(struct inodesc));
463 dotdesc.id_type = DATA;
464 dotdesc.id_number = idesc->id_dirp->d_ino;
465 dotdesc.id_func = findino;
466 dotdesc.id_name = strdup("..");
467 if ((ckinode(ginode(dotdesc.id_number), &dotdesc) & FOUND))
468 inp->i_dotdot = dotdesc.id_parent;
469 }
470 /*
471 * We have the previously found old name (inp->i_parent) and the
472 * just found new name (idesc->id_number). We have five cases:
473 * 1) ".." is missing - can remove either name, choose to delete
474 * new one and let fsck create ".." pointing to old name.
475 * 2) Both new and old are in same directory, choose to delete
476 * the new name and let fsck fix ".." if it is wrong.
477 * 3) ".." does not point to the new name, so delete it and let
478 * fsck fix ".." to point to the old one if it is wrong.
479 * 4) ".." points to the old name only, so delete the new one.
480 * 5) ".." points to the new name only, so delete the old one.
481 *
482 * For cases 1-4 we eliminate the new name;
483 * for case 5 we eliminate the old name.
484 */
485 if (inp->i_dotdot == 0 || /* Case 1 */
486 idesc->id_number == inp->i_parent || /* Case 2 */
487 inp->i_dotdot != idesc->id_number || /* Case 3 */
488 inp->i_dotdot == inp->i_parent) { /* Case 4 */
489 getpathname(newname, idesc->id_number, idesc->id_number);
490 if (strcmp(newname, "/") != 0)
491 strcat (newname, "/");
492 strcat(newname, idesc->id_dirp->d_name);
493 getpathname(oldname, inp->i_number, inp->i_number);
495 struct inodesc dotdesc;
496 char oldname[MAXPATHLEN + 1];
497 char newname[MAXPATHLEN + 1];
498
499 /*
500 * If we have not yet found "..", look it up now so we know
501 * which inode the directory itself believes is its parent.
502 */
503 if (inp->i_dotdot == 0) {
504 memset(&dotdesc, 0, sizeof(struct inodesc));
505 dotdesc.id_type = DATA;
506 dotdesc.id_number = idesc->id_dirp->d_ino;
507 dotdesc.id_func = findino;
508 dotdesc.id_name = strdup("..");
509 if ((ckinode(ginode(dotdesc.id_number), &dotdesc) & FOUND))
510 inp->i_dotdot = dotdesc.id_parent;
511 }
512 /*
513 * We have the previously found old name (inp->i_parent) and the
514 * just found new name (idesc->id_number). We have five cases:
515 * 1) ".." is missing - can remove either name, choose to delete
516 * new one and let fsck create ".." pointing to old name.
517 * 2) Both new and old are in same directory, choose to delete
518 * the new name and let fsck fix ".." if it is wrong.
519 * 3) ".." does not point to the new name, so delete it and let
520 * fsck fix ".." to point to the old one if it is wrong.
521 * 4) ".." points to the old name only, so delete the new one.
522 * 5) ".." points to the new name only, so delete the old one.
523 *
524 * For cases 1-4 we eliminate the new name;
525 * for case 5 we eliminate the old name.
526 */
527 if (inp->i_dotdot == 0 || /* Case 1 */
528 idesc->id_number == inp->i_parent || /* Case 2 */
529 inp->i_dotdot != idesc->id_number || /* Case 3 */
530 inp->i_dotdot == inp->i_parent) { /* Case 4 */
531 getpathname(newname, idesc->id_number, idesc->id_number);
532 if (strcmp(newname, "/") != 0)
533 strcat (newname, "/");
534 strcat(newname, idesc->id_dirp->d_name);
535 getpathname(oldname, inp->i_number, inp->i_number);
494 pwarn("%s IS AN EXTRANEOUS HARD LINK TO DIRECTORY %s\n",
536 pwarn("%s IS AN EXTRANEOUS HARD LINK TO DIRECTORY %s",
495 newname, oldname);
496 if (cursnapshot != 0) {
497 /*
498 * We need to
499 * setcwd(idesc->id_number);
500 * unlink(idesc->id_dirp->d_name);
501 */
537 newname, oldname);
538 if (cursnapshot != 0) {
539 /*
540 * We need to
541 * setcwd(idesc->id_number);
542 * unlink(idesc->id_dirp->d_name);
543 */
502 printf(" (IGNORED)\n");
544 cmd.value = idesc->id_number;
545 if (sysctlbyname("vfs.ffs.setcwd", 0, 0,
546 &cmd, sizeof cmd) == -1) {
547 printf(" (IGNORED)\n");
548 return (0);
549 }
550 cmd.value = (int)idesc->id_dirp->d_name;
551 cmd.size = inp->i_number; /* verify same name */
552 if (sysctlbyname("vfs.ffs.unlink", 0, 0,
553 &cmd, sizeof cmd) == -1) {
554 printf(" (UNLINK FAILED: %s)\n",
555 strerror(errno));
556 return (0);
557 }
558 printf(" (REMOVED)\n");
503 return (0);
504 }
505 if (preen) {
506 printf(" (REMOVED)\n");
507 return (1);
508 }
509 return (reply("REMOVE"));
510 }
511 /*
512 * None of the first four cases above, so must be case (5).
513 * Eliminate the old name and make the new the name the parent.
514 */
515 getpathname(oldname, inp->i_parent, inp->i_number);
516 getpathname(newname, inp->i_number, inp->i_number);
559 return (0);
560 }
561 if (preen) {
562 printf(" (REMOVED)\n");
563 return (1);
564 }
565 return (reply("REMOVE"));
566 }
567 /*
568 * None of the first four cases above, so must be case (5).
569 * Eliminate the old name and make the new the name the parent.
570 */
571 getpathname(oldname, inp->i_parent, inp->i_number);
572 getpathname(newname, inp->i_number, inp->i_number);
517 pwarn("%s IS AN EXTRANEOUS HARD LINK TO DIRECTORY %s\n", oldname,
573 pwarn("%s IS AN EXTRANEOUS HARD LINK TO DIRECTORY %s", oldname,
518 newname);
519 if (cursnapshot != 0) {
520 /*
521 * We need to
522 * setcwd(inp->i_parent);
523 * unlink(last component of oldname pathname);
524 */
574 newname);
575 if (cursnapshot != 0) {
576 /*
577 * We need to
578 * setcwd(inp->i_parent);
579 * unlink(last component of oldname pathname);
580 */
525 printf(" (IGNORED)\n");
581 cmd.value = inp->i_parent;
582 if (sysctlbyname("vfs.ffs.setcwd", 0, 0,
583 &cmd, sizeof cmd) == -1) {
584 printf(" (IGNORED)\n");
585 return (0);
586 }
587 if ((cp = rindex(oldname, '/')) == NULL) {
588 printf(" (IGNORED)\n");
589 return (0);
590 }
591 cmd.value = (int)(cp + 1);
592 cmd.size = inp->i_number; /* verify same name */
593 if (sysctlbyname("vfs.ffs.unlink", 0, 0,
594 &cmd, sizeof cmd) == -1) {
595 printf(" (UNLINK FAILED: %s)\n",
596 strerror(errno));
597 return (0);
598 }
599 printf(" (REMOVED)\n");
600 inp->i_parent = idesc->id_number; /* reparent to correct dir */
526 return (0);
527 }
528 if (!preen && !reply("REMOVE"))
529 return (0);
530 memset(&dotdesc, 0, sizeof(struct inodesc));
531 dotdesc.id_type = DATA;
532 dotdesc.id_number = inp->i_parent; /* directory in which name appears */
533 dotdesc.id_parent = inp->i_number; /* inode number in entry to delete */
534 dotdesc.id_func = deleteentry;
535 if ((ckinode(ginode(dotdesc.id_number), &dotdesc) & FOUND) && preen)
536 printf(" (REMOVED)\n");
537 inp->i_parent = idesc->id_number; /* reparent to correct directory */
538 inoinfo(inp->i_number)->ino_linkcnt++; /* name gone, return reference */
539 return (0);
540}
541
542static int
543deleteentry(struct inodesc *idesc)
544{
545 struct direct *dirp = idesc->id_dirp;
546
547 if (idesc->id_entryno++ < 2 || dirp->d_ino != idesc->id_parent)
548 return (KEEPON);
549 dirp->d_ino = 0;
550 return (ALTERED|STOP|FOUND);
551}
552
553/*
554 * Routine to sort disk blocks.
555 */
556static int
557blksort(const void *arg1, const void *arg2)
558{
559
560 return ((*(struct inoinfo * const *)arg1)->i_blks[0] -
561 (*(struct inoinfo * const *)arg2)->i_blks[0]);
562}
601 return (0);
602 }
603 if (!preen && !reply("REMOVE"))
604 return (0);
605 memset(&dotdesc, 0, sizeof(struct inodesc));
606 dotdesc.id_type = DATA;
607 dotdesc.id_number = inp->i_parent; /* directory in which name appears */
608 dotdesc.id_parent = inp->i_number; /* inode number in entry to delete */
609 dotdesc.id_func = deleteentry;
610 if ((ckinode(ginode(dotdesc.id_number), &dotdesc) & FOUND) && preen)
611 printf(" (REMOVED)\n");
612 inp->i_parent = idesc->id_number; /* reparent to correct directory */
613 inoinfo(inp->i_number)->ino_linkcnt++; /* name gone, return reference */
614 return (0);
615}
616
617static int
618deleteentry(struct inodesc *idesc)
619{
620 struct direct *dirp = idesc->id_dirp;
621
622 if (idesc->id_entryno++ < 2 || dirp->d_ino != idesc->id_parent)
623 return (KEEPON);
624 dirp->d_ino = 0;
625 return (ALTERED|STOP|FOUND);
626}
627
628/*
629 * Routine to sort disk blocks.
630 */
631static int
632blksort(const void *arg1, const void *arg2)
633{
634
635 return ((*(struct inoinfo * const *)arg1)->i_blks[0] -
636 (*(struct inoinfo * const *)arg2)->i_blks[0]);
637}