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}
|