1 1.47 joerg /* $NetBSD: dir.c,v 1.47 2020/04/03 19:36:33 joerg Exp $ */ 2 1.1 perseant 3 1.1 perseant /* 4 1.1 perseant * Copyright (c) 1980, 1986, 1993 5 1.1 perseant * The Regents of the University of California. All rights reserved. 6 1.1 perseant * 7 1.1 perseant * Redistribution and use in source and binary forms, with or without 8 1.1 perseant * modification, are permitted provided that the following conditions 9 1.1 perseant * are met: 10 1.1 perseant * 1. Redistributions of source code must retain the above copyright 11 1.1 perseant * notice, this list of conditions and the following disclaimer. 12 1.1 perseant * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 perseant * notice, this list of conditions and the following disclaimer in the 14 1.1 perseant * documentation and/or other materials provided with the distribution. 15 1.11 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 perseant * may be used to endorse or promote products derived from this software 17 1.1 perseant * without specific prior written permission. 18 1.1 perseant * 19 1.1 perseant * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 perseant * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 perseant * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 perseant * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 perseant * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 perseant * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 perseant * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 perseant * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 perseant * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 perseant * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 perseant * SUCH DAMAGE. 30 1.1 perseant */ 31 1.1 perseant 32 1.8 perseant #include <sys/types.h> 33 1.1 perseant #include <sys/param.h> 34 1.1 perseant #include <sys/time.h> 35 1.8 perseant #include <sys/buf.h> 36 1.8 perseant #include <sys/mount.h> 37 1.8 perseant 38 1.1 perseant #include <ufs/lfs/lfs.h> 39 1.35 dholland #include <ufs/lfs/lfs_accessors.h> 40 1.31 dholland #include <ufs/lfs/lfs_inode.h> 41 1.1 perseant 42 1.8 perseant #include <err.h> 43 1.1 perseant #include <stdio.h> 44 1.1 perseant #include <stdlib.h> 45 1.1 perseant #include <string.h> 46 1.1 perseant 47 1.8 perseant #include "bufcache.h" 48 1.19 christos #include "lfs_user.h" 49 1.8 perseant 50 1.1 perseant #include "fsck.h" 51 1.1 perseant #include "fsutil.h" 52 1.1 perseant #include "extern.h" 53 1.1 perseant 54 1.16 christos const char *lfname = "lost+found"; 55 1.44 dholland #if 0 56 1.29 dholland struct lfs_dirtemplate emptydir = { 57 1.21 christos .dot_ino = 0, 58 1.30 dholland .dot_reclen = LFS_DIRBLKSIZ, 59 1.21 christos }; 60 1.29 dholland struct lfs_dirtemplate dirhead = { 61 1.21 christos .dot_ino = 0, 62 1.21 christos .dot_reclen = 12, 63 1.29 dholland .dot_type = LFS_DT_DIR, 64 1.21 christos .dot_namlen = 1, 65 1.21 christos .dot_name = ".", 66 1.21 christos .dotdot_ino = 0, 67 1.30 dholland .dotdot_reclen = LFS_DIRBLKSIZ - 12, 68 1.29 dholland .dotdot_type = LFS_DT_DIR, 69 1.21 christos .dotdot_namlen = 2, 70 1.21 christos .dotdot_name = ".." 71 1.1 perseant }; 72 1.29 dholland struct lfs_odirtemplate odirhead = { 73 1.21 christos .dot_ino = 0, 74 1.21 christos .dot_reclen = 12, 75 1.21 christos .dot_namlen = 1, 76 1.21 christos .dot_name = ".", 77 1.21 christos .dotdot_ino = 0, 78 1.30 dholland .dotdot_reclen = LFS_DIRBLKSIZ - 12, 79 1.21 christos .dotdot_namlen = 2, 80 1.21 christos .dotdot_name = ".." 81 1.1 perseant }; 82 1.38 dholland #endif 83 1.1 perseant 84 1.36 dholland static int expanddir(struct uvnode *, union lfs_dinode *, char *); 85 1.8 perseant static void freedir(ino_t, ino_t); 86 1.46 dholland static LFS_DIRHEADER *fsck_readdir(struct uvnode *, struct inodesc *); 87 1.8 perseant static int lftempname(char *, ino_t); 88 1.8 perseant static int mkentry(struct inodesc *); 89 1.8 perseant static int chgino(struct inodesc *); 90 1.1 perseant 91 1.1 perseant /* 92 1.1 perseant * Propagate connected state through the tree. 93 1.1 perseant */ 94 1.1 perseant void 95 1.14 xtraeme propagate(void) 96 1.1 perseant { 97 1.8 perseant struct inoinfo **inpp, *inp, *pinp; 98 1.1 perseant struct inoinfo **inpend; 99 1.1 perseant 100 1.1 perseant /* 101 1.1 perseant * Create a list of children for each directory. 102 1.1 perseant */ 103 1.1 perseant inpend = &inpsort[inplast]; 104 1.1 perseant for (inpp = inpsort; inpp < inpend; inpp++) { 105 1.1 perseant inp = *inpp; 106 1.1 perseant if (inp->i_parent == 0 || 107 1.27 dholland inp->i_number == ULFS_ROOTINO) 108 1.1 perseant continue; 109 1.1 perseant pinp = getinoinfo(inp->i_parent); 110 1.1 perseant inp->i_parentp = pinp; 111 1.1 perseant inp->i_sibling = pinp->i_child; 112 1.1 perseant pinp->i_child = inp; 113 1.1 perseant } 114 1.27 dholland inp = getinoinfo(ULFS_ROOTINO); 115 1.1 perseant while (inp) { 116 1.1 perseant statemap[inp->i_number] = DFOUND; 117 1.1 perseant if (inp->i_child && 118 1.1 perseant statemap[inp->i_child->i_number] == DSTATE) 119 1.1 perseant inp = inp->i_child; 120 1.1 perseant else if (inp->i_sibling) 121 1.1 perseant inp = inp->i_sibling; 122 1.1 perseant else 123 1.1 perseant inp = inp->i_parentp; 124 1.1 perseant } 125 1.1 perseant } 126 1.1 perseant 127 1.1 perseant /* 128 1.1 perseant * Scan each entry in a directory block. 129 1.1 perseant */ 130 1.1 perseant int 131 1.8 perseant dirscan(struct inodesc *idesc) 132 1.1 perseant { 133 1.46 dholland LFS_DIRHEADER *dp; 134 1.8 perseant struct ubuf *bp; 135 1.8 perseant int dsize, n; 136 1.8 perseant long blksiz; 137 1.30 dholland char dbuf[LFS_DIRBLKSIZ]; 138 1.8 perseant struct uvnode *vp; 139 1.1 perseant 140 1.1 perseant if (idesc->id_type != DATA) 141 1.23 lukem errexit("wrong type to dirscan %d", idesc->id_type); 142 1.1 perseant if (idesc->id_entryno == 0 && 143 1.30 dholland (idesc->id_filesize & (LFS_DIRBLKSIZ - 1)) != 0) 144 1.30 dholland idesc->id_filesize = roundup(idesc->id_filesize, LFS_DIRBLKSIZ); 145 1.34 dholland blksiz = idesc->id_numfrags * lfs_sb_getfsize(fs); 146 1.25 mlelstv if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 147 1.1 perseant idesc->id_filesize -= blksiz; 148 1.1 perseant return (SKIP); 149 1.1 perseant } 150 1.1 perseant idesc->id_loc = 0; 151 1.8 perseant 152 1.8 perseant vp = vget(fs, idesc->id_number); 153 1.8 perseant for (dp = fsck_readdir(vp, idesc); dp != NULL; 154 1.8 perseant dp = fsck_readdir(vp, idesc)) { 155 1.39 dholland dsize = lfs_dir_getreclen(fs, dp); 156 1.8 perseant memcpy(dbuf, dp, (size_t) dsize); 157 1.46 dholland idesc->id_dirp = (LFS_DIRHEADER *) dbuf; 158 1.8 perseant if ((n = (*idesc->id_func) (idesc)) & ALTERED) { 159 1.33 chopps bread(vp, idesc->id_lblkno, blksiz, 0, &bp); 160 1.8 perseant memcpy(bp->b_data + idesc->id_loc - dsize, dbuf, 161 1.8 perseant (size_t) dsize); 162 1.8 perseant VOP_BWRITE(bp); 163 1.1 perseant sbdirty(); 164 1.1 perseant } 165 1.3 perseant if (n & STOP) 166 1.1 perseant return (n); 167 1.1 perseant } 168 1.1 perseant return (idesc->id_filesize > 0 ? KEEPON : STOP); 169 1.1 perseant } 170 1.1 perseant 171 1.1 perseant /* 172 1.1 perseant * get next entry in a directory. 173 1.1 perseant */ 174 1.46 dholland static LFS_DIRHEADER * 175 1.8 perseant fsck_readdir(struct uvnode *vp, struct inodesc *idesc) 176 1.1 perseant { 177 1.46 dholland LFS_DIRHEADER *dp, *ndp; 178 1.8 perseant struct ubuf *bp; 179 1.8 perseant long size, blksiz, fix, dploc; 180 1.1 perseant 181 1.34 dholland blksiz = idesc->id_numfrags * lfs_sb_getfsize(fs); 182 1.33 chopps bread(vp, idesc->id_lblkno, blksiz, 0, &bp); 183 1.30 dholland if (idesc->id_loc % LFS_DIRBLKSIZ == 0 && idesc->id_filesize > 0 && 184 1.1 perseant idesc->id_loc < blksiz) { 185 1.46 dholland dp = (LFS_DIRHEADER *) (bp->b_data + idesc->id_loc); 186 1.1 perseant if (dircheck(idesc, dp)) 187 1.1 perseant goto dpok; 188 1.22 ad brelse(bp, 0); 189 1.1 perseant if (idesc->id_fix == IGNORE) 190 1.1 perseant return (0); 191 1.1 perseant fix = dofix(idesc, "DIRECTORY CORRUPTED"); 192 1.33 chopps bread(vp, idesc->id_lblkno, blksiz, 0, &bp); 193 1.46 dholland dp = (LFS_DIRHEADER *) (bp->b_data + idesc->id_loc); 194 1.39 dholland lfs_dir_setino(fs, dp, 0); 195 1.38 dholland lfs_dir_settype(fs, dp, LFS_DT_UNKNOWN); 196 1.38 dholland lfs_dir_setnamlen(fs, dp, 0); 197 1.40 dholland lfs_dir_setreclen(fs, dp, LFS_DIRBLKSIZ); 198 1.40 dholland /* for now at least, don't zero the old contents */ 199 1.42 dholland /*lfs_copydirname(fs, lfs_dir_nameptr(fs, dp), "", 0, LFS_DIRBLKSIZ);*/ 200 1.42 dholland lfs_dir_nameptr(fs, dp)[0] = '\0'; 201 1.1 perseant if (fix) 202 1.8 perseant VOP_BWRITE(bp); 203 1.8 perseant else 204 1.22 ad brelse(bp, 0); 205 1.30 dholland idesc->id_loc += LFS_DIRBLKSIZ; 206 1.30 dholland idesc->id_filesize -= LFS_DIRBLKSIZ; 207 1.1 perseant return (dp); 208 1.1 perseant } 209 1.1 perseant dpok: 210 1.8 perseant if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) { 211 1.22 ad brelse(bp, 0); 212 1.1 perseant return NULL; 213 1.8 perseant } 214 1.1 perseant dploc = idesc->id_loc; 215 1.46 dholland dp = (LFS_DIRHEADER *) (bp->b_data + dploc); 216 1.39 dholland idesc->id_loc += lfs_dir_getreclen(fs, dp); 217 1.39 dholland idesc->id_filesize -= lfs_dir_getreclen(fs, dp); 218 1.30 dholland if ((idesc->id_loc % LFS_DIRBLKSIZ) == 0) { 219 1.22 ad brelse(bp, 0); 220 1.8 perseant return dp; 221 1.8 perseant } 222 1.46 dholland ndp = (LFS_DIRHEADER *) (bp->b_data + idesc->id_loc); 223 1.1 perseant if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && 224 1.1 perseant dircheck(idesc, ndp) == 0) { 225 1.22 ad brelse(bp, 0); 226 1.30 dholland size = LFS_DIRBLKSIZ - (idesc->id_loc % LFS_DIRBLKSIZ); 227 1.1 perseant idesc->id_loc += size; 228 1.1 perseant idesc->id_filesize -= size; 229 1.1 perseant if (idesc->id_fix == IGNORE) 230 1.8 perseant return 0; 231 1.1 perseant fix = dofix(idesc, "DIRECTORY CORRUPTED"); 232 1.33 chopps bread(vp, idesc->id_lblkno, blksiz, 0, &bp); 233 1.46 dholland dp = (LFS_DIRHEADER *) (bp->b_data + dploc); 234 1.39 dholland lfs_dir_setreclen(fs, dp, lfs_dir_getreclen(fs, dp) + size); 235 1.1 perseant if (fix) 236 1.8 perseant VOP_BWRITE(bp); 237 1.8 perseant else 238 1.22 ad brelse(bp, 0); 239 1.8 perseant } else 240 1.22 ad brelse(bp, 0); 241 1.8 perseant 242 1.1 perseant return (dp); 243 1.1 perseant } 244 1.1 perseant 245 1.1 perseant /* 246 1.1 perseant * Verify that a directory entry is valid. 247 1.1 perseant * This is a superset of the checks made in the kernel. 248 1.1 perseant */ 249 1.1 perseant int 250 1.46 dholland dircheck(struct inodesc *idesc, LFS_DIRHEADER *dp) 251 1.1 perseant { 252 1.8 perseant int size; 253 1.40 dholland const char *cp; 254 1.8 perseant u_char namlen, type; 255 1.8 perseant int spaceleft; 256 1.1 perseant 257 1.30 dholland spaceleft = LFS_DIRBLKSIZ - (idesc->id_loc % LFS_DIRBLKSIZ); 258 1.39 dholland if (lfs_dir_getino(fs, dp) >= maxino || 259 1.39 dholland lfs_dir_getreclen(fs, dp) == 0 || 260 1.39 dholland lfs_dir_getreclen(fs, dp) > spaceleft || 261 1.39 dholland (lfs_dir_getreclen(fs, dp) & 0x3) != 0) { 262 1.3 perseant pwarn("ino too large, reclen=0, reclen>space, or reclen&3!=0\n"); 263 1.39 dholland pwarn("dp->d_ino = 0x%jx\tdp->d_reclen = 0x%x\n", 264 1.39 dholland (uintmax_t)lfs_dir_getino(fs, dp), 265 1.39 dholland lfs_dir_getreclen(fs, dp)); 266 1.39 dholland pwarn("maxino = %ju\tspaceleft = 0x%x\n", 267 1.39 dholland (uintmax_t)maxino, spaceleft); 268 1.3 perseant return (0); 269 1.3 perseant } 270 1.39 dholland if (lfs_dir_getino(fs, dp) == 0) 271 1.1 perseant return (1); 272 1.38 dholland size = LFS_DIRSIZ(fs, dp); 273 1.38 dholland namlen = lfs_dir_getnamlen(fs, dp); 274 1.38 dholland type = lfs_dir_gettype(fs, dp); 275 1.39 dholland if (lfs_dir_getreclen(fs, dp) < size || 276 1.1 perseant idesc->id_filesize < size || 277 1.8 perseant /* namlen > MAXNAMLEN || */ 278 1.3 perseant type > 15) { 279 1.3 perseant printf("reclen<size, filesize<size, namlen too large, or type>15\n"); 280 1.1 perseant return (0); 281 1.3 perseant } 282 1.42 dholland cp = lfs_dir_nameptr(fs, dp); 283 1.40 dholland for (size = 0; size < namlen; size++) 284 1.1 perseant if (*cp == '\0' || (*cp++ == '/')) { 285 1.3 perseant printf("name contains NUL or /\n"); 286 1.1 perseant return (0); 287 1.3 perseant } 288 1.1 perseant if (*cp != '\0') { 289 1.3 perseant printf("name size misstated\n"); 290 1.1 perseant return (0); 291 1.3 perseant } 292 1.1 perseant return (1); 293 1.1 perseant } 294 1.1 perseant 295 1.1 perseant void 296 1.17 christos direrror(ino_t ino, const char *errmesg) 297 1.1 perseant { 298 1.1 perseant 299 1.1 perseant fileerror(ino, ino, errmesg); 300 1.1 perseant } 301 1.1 perseant 302 1.1 perseant void 303 1.17 christos fileerror(ino_t cwd, ino_t ino, const char *errmesg) 304 1.1 perseant { 305 1.8 perseant char pathbuf[MAXPATHLEN + 1]; 306 1.8 perseant struct uvnode *vp; 307 1.1 perseant 308 1.1 perseant pwarn("%s ", errmesg); 309 1.1 perseant pinode(ino); 310 1.1 perseant printf("\n"); 311 1.20 perseant pwarn("PARENT=%lld\n", (long long)cwd); 312 1.10 itojun getpathname(pathbuf, sizeof(pathbuf), cwd, ino); 313 1.27 dholland if (ino < ULFS_ROOTINO || ino >= maxino) { 314 1.1 perseant pfatal("NAME=%s\n", pathbuf); 315 1.1 perseant return; 316 1.1 perseant } 317 1.8 perseant vp = vget(fs, ino); 318 1.8 perseant if (vp == NULL) 319 1.3 perseant pfatal("INO is NULL\n"); 320 1.3 perseant else { 321 1.8 perseant if (ftypeok(VTOD(vp))) 322 1.3 perseant pfatal("%s=%s\n", 323 1.37 dholland (lfs_dino_getmode(fs, VTOI(vp)->i_din) & LFS_IFMT) == LFS_IFDIR ? 324 1.8 perseant "DIR" : "FILE", pathbuf); 325 1.3 perseant else 326 1.3 perseant pfatal("NAME=%s\n", pathbuf); 327 1.3 perseant } 328 1.1 perseant } 329 1.1 perseant 330 1.1 perseant void 331 1.8 perseant adjust(struct inodesc *idesc, short lcnt) 332 1.1 perseant { 333 1.8 perseant struct uvnode *vp; 334 1.36 dholland union lfs_dinode *dp; 335 1.36 dholland 336 1.36 dholland /* 337 1.36 dholland * XXX: (1) since lcnt is apparently a delta, rename it; (2) 338 1.36 dholland * why is it a value to *subtract*? that is unnecessarily 339 1.36 dholland * confusing. 340 1.36 dholland */ 341 1.1 perseant 342 1.8 perseant vp = vget(fs, idesc->id_number); 343 1.8 perseant dp = VTOD(vp); 344 1.36 dholland if (lfs_dino_getnlink(fs, dp) == lcnt) { 345 1.8 perseant if (linkup(idesc->id_number, (ino_t) 0) == 0) 346 1.1 perseant clri(idesc, "UNREF", 0); 347 1.1 perseant } else { 348 1.1 perseant pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : 349 1.36 dholland ((lfs_dino_getmode(fs, dp) & LFS_IFMT) == LFS_IFDIR ? "DIR" : "FILE")); 350 1.1 perseant pinode(idesc->id_number); 351 1.1 perseant printf(" COUNT %d SHOULD BE %d", 352 1.36 dholland lfs_dino_getnlink(fs, dp), lfs_dino_getnlink(fs, dp) - lcnt); 353 1.1 perseant if (preen) { 354 1.1 perseant if (lcnt < 0) { 355 1.1 perseant printf("\n"); 356 1.1 perseant pfatal("LINK COUNT INCREASING"); 357 1.1 perseant } 358 1.1 perseant printf(" (ADJUSTED)\n"); 359 1.1 perseant } 360 1.1 perseant if (preen || reply("ADJUST") == 1) { 361 1.36 dholland lfs_dino_setnlink(fs, dp, 362 1.36 dholland lfs_dino_getnlink(fs, dp) - lcnt); 363 1.8 perseant inodirty(VTOI(vp)); 364 1.1 perseant } 365 1.1 perseant } 366 1.1 perseant } 367 1.1 perseant 368 1.1 perseant static int 369 1.8 perseant mkentry(struct inodesc *idesc) 370 1.1 perseant { 371 1.46 dholland LFS_DIRHEADER *dirp = idesc->id_dirp; 372 1.38 dholland unsigned namlen; 373 1.40 dholland unsigned newreclen, oldreclen; 374 1.1 perseant 375 1.40 dholland /* figure the length needed for id_name */ 376 1.38 dholland namlen = strlen(idesc->id_name); 377 1.45 dholland newreclen = LFS_DIRECTSIZ(fs, namlen); 378 1.40 dholland 379 1.40 dholland /* find the minimum record length for the existing name */ 380 1.39 dholland if (lfs_dir_getino(fs, dirp) != 0) 381 1.40 dholland oldreclen = LFS_DIRSIZ(fs, dirp); 382 1.1 perseant else 383 1.40 dholland oldreclen = 0; 384 1.40 dholland 385 1.40 dholland /* Can we insert here? */ 386 1.40 dholland if (lfs_dir_getreclen(fs, dirp) - oldreclen < newreclen) 387 1.1 perseant return (KEEPON); 388 1.40 dholland 389 1.40 dholland /* Divide the record; all but oldreclen goes to the new record */ 390 1.40 dholland newreclen = lfs_dir_getreclen(fs, dirp) - oldreclen; 391 1.40 dholland lfs_dir_setreclen(fs, dirp, oldreclen); 392 1.40 dholland 393 1.40 dholland /* advance the pointer to the new record */ 394 1.40 dholland dirp = LFS_NEXTDIR(fs, dirp); 395 1.40 dholland 396 1.40 dholland /* write record; ino to be entered is in id_parent */ 397 1.39 dholland lfs_dir_setino(fs, dirp, idesc->id_parent); 398 1.40 dholland lfs_dir_setreclen(fs, dirp, newreclen); 399 1.38 dholland lfs_dir_settype(fs, dirp, typemap[idesc->id_parent]); 400 1.38 dholland lfs_dir_setnamlen(fs, dirp, namlen); 401 1.42 dholland lfs_copydirname(fs, lfs_dir_nameptr(fs, dirp), idesc->id_name, 402 1.41 dholland namlen, newreclen); 403 1.41 dholland 404 1.3 perseant return (ALTERED | STOP); 405 1.1 perseant } 406 1.1 perseant 407 1.1 perseant static int 408 1.8 perseant chgino(struct inodesc *idesc) 409 1.1 perseant { 410 1.46 dholland LFS_DIRHEADER *dirp = idesc->id_dirp; 411 1.38 dholland int namlen; 412 1.1 perseant 413 1.38 dholland namlen = lfs_dir_getnamlen(fs, dirp); 414 1.42 dholland if (memcmp(lfs_dir_nameptr(fs, dirp), idesc->id_name, namlen + 1)) 415 1.1 perseant return (KEEPON); 416 1.39 dholland lfs_dir_setino(fs, dirp, idesc->id_parent); 417 1.38 dholland lfs_dir_settype(fs, dirp, typemap[idesc->id_parent]); 418 1.3 perseant return (ALTERED | STOP); 419 1.1 perseant } 420 1.1 perseant 421 1.1 perseant int 422 1.3 perseant linkup(ino_t orphan, ino_t parentdir) 423 1.1 perseant { 424 1.36 dholland union lfs_dinode *dp; 425 1.8 perseant int lostdir; 426 1.8 perseant ino_t oldlfdir; 427 1.8 perseant struct inodesc idesc; 428 1.8 perseant char tempname[BUFSIZ]; 429 1.8 perseant struct uvnode *vp; 430 1.1 perseant 431 1.1 perseant memset(&idesc, 0, sizeof(struct inodesc)); 432 1.8 perseant vp = vget(fs, orphan); 433 1.8 perseant dp = VTOD(vp); 434 1.36 dholland lostdir = (lfs_dino_getmode(fs, dp) & LFS_IFMT) == LFS_IFDIR; 435 1.1 perseant pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 436 1.1 perseant pinode(orphan); 437 1.36 dholland if (preen && lfs_dino_getsize(fs, dp) == 0) 438 1.1 perseant return (0); 439 1.1 perseant if (preen) 440 1.1 perseant printf(" (RECONNECTED)\n"); 441 1.3 perseant else if (reply("RECONNECT") == 0) 442 1.3 perseant return (0); 443 1.1 perseant if (lfdir == 0) { 444 1.27 dholland dp = ginode(ULFS_ROOTINO); 445 1.1 perseant idesc.id_name = lfname; 446 1.1 perseant idesc.id_type = DATA; 447 1.1 perseant idesc.id_func = findino; 448 1.27 dholland idesc.id_number = ULFS_ROOTINO; 449 1.1 perseant if ((ckinode(dp, &idesc) & FOUND) != 0) { 450 1.1 perseant lfdir = idesc.id_parent; 451 1.1 perseant } else { 452 1.1 perseant pwarn("NO lost+found DIRECTORY"); 453 1.1 perseant if (preen || reply("CREATE")) { 454 1.27 dholland lfdir = allocdir(ULFS_ROOTINO, (ino_t) 0, lfmode); 455 1.1 perseant if (lfdir != 0) { 456 1.27 dholland if (makeentry(ULFS_ROOTINO, lfdir, lfname) != 0) { 457 1.1 perseant if (preen) 458 1.1 perseant printf(" (CREATED)\n"); 459 1.1 perseant } else { 460 1.27 dholland freedir(lfdir, ULFS_ROOTINO); 461 1.1 perseant lfdir = 0; 462 1.1 perseant if (preen) 463 1.1 perseant printf("\n"); 464 1.1 perseant } 465 1.1 perseant } 466 1.1 perseant } 467 1.1 perseant } 468 1.1 perseant if (lfdir == 0) { 469 1.1 perseant pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY"); 470 1.1 perseant printf("\n\n"); 471 1.1 perseant return (0); 472 1.1 perseant } 473 1.1 perseant } 474 1.8 perseant vp = vget(fs, lfdir); 475 1.8 perseant dp = VTOD(vp); 476 1.36 dholland if ((lfs_dino_getmode(fs, dp) & LFS_IFMT) != LFS_IFDIR) { 477 1.1 perseant pfatal("lost+found IS NOT A DIRECTORY"); 478 1.1 perseant if (reply("REALLOCATE") == 0) 479 1.1 perseant return (0); 480 1.1 perseant oldlfdir = lfdir; 481 1.27 dholland if ((lfdir = allocdir(ULFS_ROOTINO, (ino_t) 0, lfmode)) == 0) { 482 1.1 perseant pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 483 1.1 perseant return (0); 484 1.1 perseant } 485 1.27 dholland if ((changeino(ULFS_ROOTINO, lfname, lfdir) & ALTERED) == 0) { 486 1.1 perseant pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); 487 1.1 perseant return (0); 488 1.1 perseant } 489 1.8 perseant inodirty(VTOI(vp)); 490 1.1 perseant idesc.id_type = ADDR; 491 1.1 perseant idesc.id_func = pass4check; 492 1.1 perseant idesc.id_number = oldlfdir; 493 1.1 perseant adjust(&idesc, lncntp[oldlfdir] + 1); 494 1.1 perseant lncntp[oldlfdir] = 0; 495 1.8 perseant vp = vget(fs, lfdir); 496 1.8 perseant dp = VTOD(vp); 497 1.1 perseant } 498 1.1 perseant if (statemap[lfdir] != DFOUND) { 499 1.1 perseant pfatal("SORRY. NO lost+found DIRECTORY\n\n"); 500 1.1 perseant return (0); 501 1.1 perseant } 502 1.8 perseant (void) lftempname(tempname, orphan); 503 1.1 perseant if (makeentry(lfdir, orphan, tempname) == 0) { 504 1.1 perseant pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 505 1.1 perseant printf("\n\n"); 506 1.1 perseant return (0); 507 1.1 perseant } 508 1.1 perseant lncntp[orphan]--; 509 1.1 perseant if (lostdir) { 510 1.1 perseant if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && 511 1.8 perseant parentdir != (ino_t) - 1) 512 1.8 perseant (void) makeentry(orphan, lfdir, ".."); 513 1.8 perseant vp = vget(fs, lfdir); 514 1.37 dholland lfs_dino_setnlink(fs, VTOI(vp)->i_din, 515 1.37 dholland lfs_dino_getnlink(fs, VTOI(vp)->i_din) + 1); 516 1.8 perseant inodirty(VTOI(vp)); 517 1.1 perseant lncntp[lfdir]++; 518 1.18 christos pwarn("DIR I=%llu CONNECTED. ", (unsigned long long)orphan); 519 1.8 perseant if (parentdir != (ino_t) - 1) 520 1.18 christos printf("PARENT WAS I=%llu\n", 521 1.18 christos (unsigned long long)parentdir); 522 1.1 perseant if (preen == 0) 523 1.1 perseant printf("\n"); 524 1.1 perseant } 525 1.1 perseant return (1); 526 1.1 perseant } 527 1.1 perseant 528 1.1 perseant /* 529 1.1 perseant * fix an entry in a directory. 530 1.1 perseant */ 531 1.1 perseant int 532 1.16 christos changeino(ino_t dir, const char *name, ino_t newnum) 533 1.1 perseant { 534 1.8 perseant struct inodesc idesc; 535 1.1 perseant 536 1.1 perseant memset(&idesc, 0, sizeof(struct inodesc)); 537 1.1 perseant idesc.id_type = DATA; 538 1.1 perseant idesc.id_func = chgino; 539 1.1 perseant idesc.id_number = dir; 540 1.1 perseant idesc.id_fix = DONTKNOW; 541 1.1 perseant idesc.id_name = name; 542 1.1 perseant idesc.id_parent = newnum; /* new value for name */ 543 1.8 perseant 544 1.1 perseant return (ckinode(ginode(dir), &idesc)); 545 1.1 perseant } 546 1.1 perseant 547 1.1 perseant /* 548 1.1 perseant * make an entry in a directory 549 1.1 perseant */ 550 1.1 perseant int 551 1.16 christos makeentry(ino_t parent, ino_t ino, const char *name) 552 1.3 perseant { 553 1.36 dholland union lfs_dinode *dp; 554 1.8 perseant struct inodesc idesc; 555 1.8 perseant char pathbuf[MAXPATHLEN + 1]; 556 1.8 perseant struct uvnode *vp; 557 1.36 dholland uint64_t size; 558 1.3 perseant 559 1.27 dholland if (parent < ULFS_ROOTINO || parent >= maxino || 560 1.27 dholland ino < ULFS_ROOTINO || ino >= maxino) 561 1.1 perseant return (0); 562 1.1 perseant memset(&idesc, 0, sizeof(struct inodesc)); 563 1.1 perseant idesc.id_type = DATA; 564 1.1 perseant idesc.id_func = mkentry; 565 1.1 perseant idesc.id_number = parent; 566 1.1 perseant idesc.id_parent = ino; /* this is the inode to enter */ 567 1.1 perseant idesc.id_fix = DONTKNOW; 568 1.1 perseant idesc.id_name = name; 569 1.8 perseant vp = vget(fs, parent); 570 1.8 perseant dp = VTOD(vp); 571 1.36 dholland size = lfs_dino_getsize(fs, dp); 572 1.36 dholland if (size % LFS_DIRBLKSIZ) { 573 1.36 dholland size = roundup(size, LFS_DIRBLKSIZ); 574 1.36 dholland lfs_dino_setsize(fs, dp, size); 575 1.8 perseant inodirty(VTOI(vp)); 576 1.1 perseant } 577 1.1 perseant if ((ckinode(dp, &idesc) & ALTERED) != 0) 578 1.1 perseant return (1); 579 1.10 itojun getpathname(pathbuf, sizeof(pathbuf), parent, parent); 580 1.8 perseant vp = vget(fs, parent); 581 1.8 perseant dp = VTOD(vp); 582 1.8 perseant if (expanddir(vp, dp, pathbuf) == 0) 583 1.1 perseant return (0); 584 1.1 perseant return (ckinode(dp, &idesc) & ALTERED); 585 1.1 perseant } 586 1.1 perseant 587 1.1 perseant /* 588 1.44 dholland * Initialize a completely empty directory block. 589 1.44 dholland * (block size is LFS_DIRBLKSIZ) 590 1.44 dholland */ 591 1.44 dholland static void 592 1.44 dholland zerodirblk(void *buf) 593 1.44 dholland { 594 1.46 dholland LFS_DIRHEADER *dirp; 595 1.44 dholland 596 1.44 dholland dirp = buf; 597 1.44 dholland lfs_dir_setino(fs, dirp, 0); 598 1.44 dholland lfs_dir_setreclen(fs, dirp, LFS_DIRBLKSIZ); 599 1.44 dholland lfs_dir_settype(fs, dirp, LFS_DT_UNKNOWN); 600 1.44 dholland lfs_dir_setnamlen(fs, dirp, 0); 601 1.44 dholland lfs_copydirname(fs, lfs_dir_nameptr(fs, dirp), "", 0, 602 1.44 dholland LFS_DIRBLKSIZ); 603 1.44 dholland } 604 1.44 dholland 605 1.44 dholland /* 606 1.1 perseant * Attempt to expand the size of a directory 607 1.1 perseant */ 608 1.1 perseant static int 609 1.36 dholland expanddir(struct uvnode *vp, union lfs_dinode *dp, char *name) 610 1.1 perseant { 611 1.15 perseant daddr_t lastbn; 612 1.8 perseant struct ubuf *bp; 613 1.30 dholland char *cp, firstblk[LFS_DIRBLKSIZ]; 614 1.1 perseant 615 1.36 dholland lastbn = lfs_lblkno(fs, lfs_dino_getsize(fs, dp)); 616 1.36 dholland if (lastbn >= ULFS_NDADDR - 1 || lfs_dino_getdb(fs, dp, lastbn) == 0 || 617 1.36 dholland lfs_dino_getsize(fs, dp) == 0) 618 1.1 perseant return (0); 619 1.36 dholland lfs_dino_setdb(fs, dp, lastbn + 1, lfs_dino_getdb(fs, dp, lastbn)); 620 1.36 dholland lfs_dino_setdb(fs, dp, lastbn, 0); 621 1.34 dholland bp = getblk(vp, lastbn, lfs_sb_getbsize(fs)); 622 1.8 perseant VOP_BWRITE(bp); 623 1.36 dholland lfs_dino_setsize(fs, dp, 624 1.36 dholland lfs_dino_getsize(fs, dp) + lfs_sb_getbsize(fs)); 625 1.36 dholland lfs_dino_setblocks(fs, dp, 626 1.36 dholland lfs_dino_getblocks(fs, dp) + lfs_btofsb(fs, lfs_sb_getbsize(fs))); 627 1.36 dholland bread(vp, lfs_dino_getdb(fs, dp, lastbn + 1), 628 1.33 chopps (long) lfs_dblksize(fs, dp, lastbn + 1), 0, &bp); 629 1.8 perseant if (bp->b_flags & B_ERROR) 630 1.1 perseant goto bad; 631 1.30 dholland memcpy(firstblk, bp->b_data, LFS_DIRBLKSIZ); 632 1.34 dholland bread(vp, lastbn, lfs_sb_getbsize(fs), 0, &bp); 633 1.8 perseant if (bp->b_flags & B_ERROR) 634 1.1 perseant goto bad; 635 1.30 dholland memcpy(bp->b_data, firstblk, LFS_DIRBLKSIZ); 636 1.30 dholland for (cp = &bp->b_data[LFS_DIRBLKSIZ]; 637 1.34 dholland cp < &bp->b_data[lfs_sb_getbsize(fs)]; 638 1.30 dholland cp += LFS_DIRBLKSIZ) 639 1.44 dholland zerodirblk(cp); 640 1.8 perseant VOP_BWRITE(bp); 641 1.36 dholland bread(vp, lfs_dino_getdb(fs, dp, lastbn + 1), 642 1.33 chopps (long) lfs_dblksize(fs, dp, lastbn + 1), 0, &bp); 643 1.8 perseant if (bp->b_flags & B_ERROR) 644 1.1 perseant goto bad; 645 1.44 dholland zerodirblk(bp->b_data); 646 1.1 perseant pwarn("NO SPACE LEFT IN %s", name); 647 1.1 perseant if (preen) 648 1.1 perseant printf(" (EXPANDED)\n"); 649 1.1 perseant else if (reply("EXPAND") == 0) 650 1.1 perseant goto bad; 651 1.8 perseant VOP_BWRITE(bp); 652 1.8 perseant inodirty(VTOI(vp)); 653 1.1 perseant return (1); 654 1.1 perseant bad: 655 1.36 dholland lfs_dino_setdb(fs, dp, lastbn, lfs_dino_getdb(fs, dp, lastbn + 1)); 656 1.36 dholland lfs_dino_setdb(fs, dp, lastbn + 1, 0); 657 1.36 dholland lfs_dino_setsize(fs, dp, 658 1.36 dholland lfs_dino_getsize(fs, dp) - lfs_sb_getbsize(fs)); 659 1.36 dholland lfs_dino_setblocks(fs, dp, 660 1.36 dholland lfs_dino_getblocks(fs, dp) - lfs_btofsb(fs, lfs_sb_getbsize(fs))); 661 1.1 perseant return (0); 662 1.1 perseant } 663 1.1 perseant 664 1.1 perseant /* 665 1.1 perseant * allocate a new directory 666 1.1 perseant */ 667 1.1 perseant int 668 1.3 perseant allocdir(ino_t parent, ino_t request, int mode) 669 1.3 perseant { 670 1.8 perseant ino_t ino; 671 1.8 perseant char *cp; 672 1.36 dholland union lfs_dinode *dp; 673 1.8 perseant struct ubuf *bp; 674 1.46 dholland LFS_DIRHEADER *dirp; 675 1.8 perseant struct uvnode *vp; 676 1.1 perseant 677 1.28 dholland ino = allocino(request, LFS_IFDIR | mode); 678 1.8 perseant vp = vget(fs, ino); 679 1.8 perseant dp = VTOD(vp); 680 1.36 dholland bread(vp, lfs_dino_getdb(fs, dp, 0), lfs_sb_getfsize(fs), 0, &bp); 681 1.8 perseant if (bp->b_flags & B_ERROR) { 682 1.22 ad brelse(bp, 0); 683 1.1 perseant freeino(ino); 684 1.1 perseant return (0); 685 1.1 perseant } 686 1.46 dholland dirp = (LFS_DIRHEADER *)bp->b_data; 687 1.44 dholland /* . */ 688 1.44 dholland lfs_dir_setino(fs, dirp, ino); 689 1.45 dholland lfs_dir_setreclen(fs, dirp, LFS_DIRECTSIZ(fs, 1)); 690 1.44 dholland lfs_dir_settype(fs, dirp, LFS_DT_DIR); 691 1.44 dholland lfs_dir_setnamlen(fs, dirp, 1); 692 1.44 dholland lfs_copydirname(fs, lfs_dir_nameptr(fs, dirp), ".", 1, 693 1.45 dholland LFS_DIRECTSIZ(fs, 1)); 694 1.44 dholland /* .. */ 695 1.44 dholland dirp = LFS_NEXTDIR(fs, dirp); 696 1.44 dholland lfs_dir_setino(fs, dirp, parent); 697 1.45 dholland lfs_dir_setreclen(fs, dirp, LFS_DIRBLKSIZ - LFS_DIRECTSIZ(fs, 1)); 698 1.44 dholland lfs_dir_settype(fs, dirp, LFS_DT_DIR); 699 1.44 dholland lfs_dir_setnamlen(fs, dirp, 2); 700 1.44 dholland lfs_copydirname(fs, lfs_dir_nameptr(fs, dirp), "..", 2, 701 1.45 dholland LFS_DIRBLKSIZ - LFS_DIRECTSIZ(fs, 1)); 702 1.30 dholland for (cp = &bp->b_data[LFS_DIRBLKSIZ]; 703 1.34 dholland cp < &bp->b_data[lfs_sb_getfsize(fs)]; 704 1.44 dholland cp += LFS_DIRBLKSIZ) { 705 1.44 dholland zerodirblk(cp); 706 1.44 dholland } 707 1.8 perseant VOP_BWRITE(bp); 708 1.36 dholland lfs_dino_setnlink(fs, dp, 2); 709 1.8 perseant inodirty(VTOI(vp)); 710 1.27 dholland if (ino == ULFS_ROOTINO) { 711 1.36 dholland lncntp[ino] = lfs_dino_getnlink(fs, dp); 712 1.1 perseant cacheino(dp, ino); 713 1.3 perseant return (ino); 714 1.1 perseant } 715 1.1 perseant if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) { 716 1.1 perseant freeino(ino); 717 1.1 perseant return (0); 718 1.1 perseant } 719 1.1 perseant cacheino(dp, ino); 720 1.1 perseant statemap[ino] = statemap[parent]; 721 1.1 perseant if (statemap[ino] == DSTATE) { 722 1.36 dholland lncntp[ino] = lfs_dino_getnlink(fs, dp); 723 1.1 perseant lncntp[parent]++; 724 1.1 perseant } 725 1.8 perseant vp = vget(fs, parent); 726 1.8 perseant dp = VTOD(vp); 727 1.36 dholland lfs_dino_setnlink(fs, dp, lfs_dino_getnlink(fs, dp) + 1); 728 1.8 perseant inodirty(VTOI(vp)); 729 1.1 perseant return (ino); 730 1.1 perseant } 731 1.1 perseant 732 1.1 perseant /* 733 1.1 perseant * free a directory inode 734 1.1 perseant */ 735 1.1 perseant static void 736 1.3 perseant freedir(ino_t ino, ino_t parent) 737 1.1 perseant { 738 1.8 perseant struct uvnode *vp; 739 1.1 perseant 740 1.1 perseant if (ino != parent) { 741 1.8 perseant vp = vget(fs, parent); 742 1.37 dholland lfs_dino_setnlink(fs, VTOI(vp)->i_din, 743 1.37 dholland lfs_dino_getnlink(fs, VTOI(vp)->i_din) - 1); 744 1.8 perseant inodirty(VTOI(vp)); 745 1.1 perseant } 746 1.1 perseant freeino(ino); 747 1.1 perseant } 748 1.1 perseant 749 1.1 perseant /* 750 1.1 perseant * generate a temporary name for the lost+found directory. 751 1.1 perseant */ 752 1.1 perseant static int 753 1.3 perseant lftempname(char *bufp, ino_t ino) 754 1.3 perseant { 755 1.8 perseant ino_t in; 756 1.8 perseant char *cp; 757 1.8 perseant int namlen; 758 1.1 perseant 759 1.1 perseant cp = bufp + 2; 760 1.1 perseant for (in = maxino; in > 0; in /= 10) 761 1.1 perseant cp++; 762 1.1 perseant *--cp = 0; 763 1.1 perseant namlen = cp - bufp; 764 1.1 perseant in = ino; 765 1.1 perseant while (cp > bufp) { 766 1.1 perseant *--cp = (in % 10) + '0'; 767 1.1 perseant in /= 10; 768 1.1 perseant } 769 1.1 perseant *cp = '#'; 770 1.1 perseant return (namlen); 771 1.1 perseant } 772