17c478bd9Sstevel@tonic-gate /* 2355d6bb5Sswilcox * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 77c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 87c478bd9Sstevel@tonic-gate 97c478bd9Sstevel@tonic-gate /* 107c478bd9Sstevel@tonic-gate * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. 117c478bd9Sstevel@tonic-gate * All rights reserved. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 147c478bd9Sstevel@tonic-gate * provided that: (1) source distributions retain this entire copyright 157c478bd9Sstevel@tonic-gate * notice and comment, and (2) distributions including binaries display 167c478bd9Sstevel@tonic-gate * the following acknowledgement: ``This product includes software 177c478bd9Sstevel@tonic-gate * developed by the University of California, Berkeley and its contributors'' 187c478bd9Sstevel@tonic-gate * in the documentation or other materials provided with the distribution 197c478bd9Sstevel@tonic-gate * and in all advertising materials mentioning features or use of this 207c478bd9Sstevel@tonic-gate * software. Neither the name of the University nor the names of its 217c478bd9Sstevel@tonic-gate * contributors may be used to endorse or promote products derived 227c478bd9Sstevel@tonic-gate * from this software without specific prior written permission. 237c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 247c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 257c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 297c478bd9Sstevel@tonic-gate 30355d6bb5Sswilcox #include <stdio.h> 31355d6bb5Sswilcox #include <stdlib.h> 32355d6bb5Sswilcox #include <unistd.h> 33355d6bb5Sswilcox #include <string.h> 347c478bd9Sstevel@tonic-gate #include <sys/param.h> 357c478bd9Sstevel@tonic-gate #include <sys/types.h> 367c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 377c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h> 387c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 397c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h> 407c478bd9Sstevel@tonic-gate #define _KERNEL 417c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h> 427c478bd9Sstevel@tonic-gate #undef _KERNEL 437c478bd9Sstevel@tonic-gate #include "fsck.h" 447c478bd9Sstevel@tonic-gate 45355d6bb5Sswilcox static int pass3acheck(struct inodesc *); 467c478bd9Sstevel@tonic-gate static void setcurino(struct inodesc *, struct dinode *, struct inoinfo *); 477c478bd9Sstevel@tonic-gate 48355d6bb5Sswilcox void 49355d6bb5Sswilcox pass3a(void) 507c478bd9Sstevel@tonic-gate { 51355d6bb5Sswilcox caddr_t flow; 527c478bd9Sstevel@tonic-gate struct inoinfo **inpp, *inp; 53355d6bb5Sswilcox fsck_ino_t orphan; 547c478bd9Sstevel@tonic-gate int loopcnt; 55355d6bb5Sswilcox int state; 56355d6bb5Sswilcox struct shadowclientinfo *sci, *sci_victim, *sci_prev, **sci_rootp; 577c478bd9Sstevel@tonic-gate struct inodesc curino; 587c478bd9Sstevel@tonic-gate struct dinode *dp; 59355d6bb5Sswilcox struct inodesc idesc; 60355d6bb5Sswilcox char namebuf[MAXNAMLEN + 1]; 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) { 637c478bd9Sstevel@tonic-gate inp = *inpp; 64355d6bb5Sswilcox state = statemap[inp->i_number]; 657c478bd9Sstevel@tonic-gate if (inp->i_number == UFSROOTINO || 66355d6bb5Sswilcox (inp->i_parent != 0 && !S_IS_DUNFOUND(state))) 677c478bd9Sstevel@tonic-gate continue; 68355d6bb5Sswilcox if (state == DCLEAR || state == USTATE || (state & INORPHAN)) 697c478bd9Sstevel@tonic-gate continue; 70355d6bb5Sswilcox /* 71355d6bb5Sswilcox * If we are running with logging and we come 72355d6bb5Sswilcox * across unreferenced directories, we just leave 73355d6bb5Sswilcox * them in DSTATE which will cause them to be pitched 74355d6bb5Sswilcox * in pass 4. 75355d6bb5Sswilcox */ 76355d6bb5Sswilcox if (preen && !iscorrupt && islog && S_IS_DUNFOUND(state)) { 77355d6bb5Sswilcox if (inp->i_dotdot >= UFSROOTINO) { 78355d6bb5Sswilcox LINK_RANGE(flow, lncntp[inp->i_dotdot], 1); 79355d6bb5Sswilcox if (flow != NULL) { 80355d6bb5Sswilcox dp = ginode(inp->i_dotdot); 81355d6bb5Sswilcox LINK_CLEAR(flow, inp->i_dotdot, 82355d6bb5Sswilcox dp->di_mode, &idesc); 83355d6bb5Sswilcox if (statemap[inp->i_dotdot] == USTATE) 84355d6bb5Sswilcox continue; 85355d6bb5Sswilcox } 86355d6bb5Sswilcox TRACK_LNCNTP(inp->i_dotdot, 87355d6bb5Sswilcox lncntp[inp->i_dotdot]++); 88355d6bb5Sswilcox } 89355d6bb5Sswilcox continue; 90355d6bb5Sswilcox } 91355d6bb5Sswilcox 927c478bd9Sstevel@tonic-gate for (loopcnt = 0; ; loopcnt++) { 937c478bd9Sstevel@tonic-gate orphan = inp->i_number; 94355d6bb5Sswilcox /* 95355d6bb5Sswilcox * Skip out if we aren't connected to the name 96355d6bb5Sswilcox * space, or our parent is connected, or we've 97355d6bb5Sswilcox * looked at too many directories. Our parent 98355d6bb5Sswilcox * being connected means that orphan is the 99355d6bb5Sswilcox * first ancestor of *inpp with questionable 100355d6bb5Sswilcox * antecedents. 101355d6bb5Sswilcox */ 1027c478bd9Sstevel@tonic-gate if (inp->i_parent == 0 || 103355d6bb5Sswilcox !INO_IS_DUNFOUND(inp->i_parent) || 1047c478bd9Sstevel@tonic-gate loopcnt > numdirs) 1057c478bd9Sstevel@tonic-gate break; 1067c478bd9Sstevel@tonic-gate inp = getinoinfo(inp->i_parent); 107355d6bb5Sswilcox /* 108355d6bb5Sswilcox * Can't happen, because a non-zero parent's already 109355d6bb5Sswilcox * been seen and therefore cached. 110355d6bb5Sswilcox */ 111355d6bb5Sswilcox if (inp == NULL) 112355d6bb5Sswilcox errexit("pass3 could not find cached " 113355d6bb5Sswilcox "inode I=%d\n", 114355d6bb5Sswilcox inp->i_parent); 1157c478bd9Sstevel@tonic-gate } 116355d6bb5Sswilcox 117355d6bb5Sswilcox /* 118355d6bb5Sswilcox * Already did this one. Don't bother the user 119355d6bb5Sswilcox * with redundant questions. 120355d6bb5Sswilcox */ 121355d6bb5Sswilcox if (statemap[orphan] & INORPHAN) 122355d6bb5Sswilcox continue; 123355d6bb5Sswilcox 1247c478bd9Sstevel@tonic-gate /* 1257c478bd9Sstevel@tonic-gate * A link count of 0 with parent and .. inodes of 0 1267c478bd9Sstevel@tonic-gate * indicates a partly deleted directory. 1277c478bd9Sstevel@tonic-gate * Clear it. 1287c478bd9Sstevel@tonic-gate */ 129355d6bb5Sswilcox dp = ginode(orphan); 1307c478bd9Sstevel@tonic-gate if (dp->di_nlink == 0 && inp->i_dotdot == 0 && 1317c478bd9Sstevel@tonic-gate inp->i_parent == 0) { 132355d6bb5Sswilcox /* 133355d6bb5Sswilcox * clri() just uses curino.id_number; in other 134355d6bb5Sswilcox * words, it won't use the callback that setcurino() 135355d6bb5Sswilcox * puts in. 136355d6bb5Sswilcox */ 1377c478bd9Sstevel@tonic-gate setcurino(&curino, dp, inp); 138355d6bb5Sswilcox clri(&curino, "UNREF", CLRI_VERBOSE, CLRI_NOP_OK); 139355d6bb5Sswilcox 140355d6bb5Sswilcox /* 141355d6bb5Sswilcox * If we didn't clear it, at least mark it so 142355d6bb5Sswilcox * we don't waste time on it again. 143355d6bb5Sswilcox */ 144355d6bb5Sswilcox if (statemap[orphan] != USTATE) { 145355d6bb5Sswilcox statemap[orphan] |= INORPHAN; 146355d6bb5Sswilcox } 1477c478bd9Sstevel@tonic-gate continue; 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate 150355d6bb5Sswilcox /* 151355d6bb5Sswilcox * We can call linkup() multiple times on the same directory 152355d6bb5Sswilcox * inode, if we were told not to reconnect it the first time. 153355d6bb5Sswilcox * This is because we find it as a disconnected parent of 154355d6bb5Sswilcox * of its children (and mark it found), and then finally get 155355d6bb5Sswilcox * to it in the inpsort array. This is better than in the 156355d6bb5Sswilcox * past, where we'd call it every time we found it as a 157355d6bb5Sswilcox * child's parent. Ideally, we'd suppress even the second 158355d6bb5Sswilcox * query, but that confuses pass 4's interpretation of 159355d6bb5Sswilcox * the state flags. 160355d6bb5Sswilcox */ 161355d6bb5Sswilcox if (loopcnt <= countdirs) { 162355d6bb5Sswilcox if (linkup(orphan, inp->i_dotdot, NULL)) { 163355d6bb5Sswilcox /* 164355d6bb5Sswilcox * Bookkeeping for any sort of relinked 165355d6bb5Sswilcox * directory. 166355d6bb5Sswilcox */ 167355d6bb5Sswilcox inp->i_dotdot = lfdir; 168355d6bb5Sswilcox inp->i_parent = inp->i_dotdot; 169355d6bb5Sswilcox statemap[orphan] &= ~(INORPHAN); 170355d6bb5Sswilcox } else { 171355d6bb5Sswilcox statemap[orphan] |= INORPHAN; 172355d6bb5Sswilcox } 173355d6bb5Sswilcox propagate(); 174355d6bb5Sswilcox continue; 175355d6bb5Sswilcox } 176355d6bb5Sswilcox 177355d6bb5Sswilcox /* 178355d6bb5Sswilcox * We visited more directories than exist in the 179355d6bb5Sswilcox * filesystem. The only way to do that is if there's 180355d6bb5Sswilcox * a loop. 181355d6bb5Sswilcox */ 182355d6bb5Sswilcox pfatal("ORPHANED DIRECTORY LOOP DETECTED I=%d\n", orphan); 183355d6bb5Sswilcox 184355d6bb5Sswilcox /* 185355d6bb5Sswilcox * Can never get here with inp->i_parent zero, because 186355d6bb5Sswilcox * of the interactions between the for() and the 187355d6bb5Sswilcox * if (loopcnt <= countdirs) above. 188355d6bb5Sswilcox */ 189355d6bb5Sswilcox init_inodesc(&idesc); 190355d6bb5Sswilcox idesc.id_type = DATA; 191355d6bb5Sswilcox idesc.id_number = inp->i_parent; 192355d6bb5Sswilcox idesc.id_parent = orphan; 193355d6bb5Sswilcox idesc.id_func = findname; 194355d6bb5Sswilcox idesc.id_name = namebuf; 195355d6bb5Sswilcox namebuf[0] = '\0'; 196355d6bb5Sswilcox 197355d6bb5Sswilcox /* 198355d6bb5Sswilcox * Theoretically, this lookup via ckinode can't fail 199355d6bb5Sswilcox * (if orphan doesn't exist in i_parent, then i_parent 200*b9a41fd3Sswilcox * would not have been filled in by pass2check()). 201355d6bb5Sswilcox * However, if we're interactive, we want to at least 202355d6bb5Sswilcox * attempt to continue. The worst case is that it 203355d6bb5Sswilcox * gets reconnected as #nnn into lost+found instead of 204355d6bb5Sswilcox * to its old parent with its old name. 205355d6bb5Sswilcox */ 206355d6bb5Sswilcox if ((ckinode(ginode(inp->i_parent), 207355d6bb5Sswilcox &idesc, CKI_TRAVERSE) & FOUND) == 0) 208355d6bb5Sswilcox pfatal("COULD NOT FIND NAME IN PARENT DIRECTORY"); 209355d6bb5Sswilcox 210355d6bb5Sswilcox if (linkup(orphan, inp->i_parent, namebuf)) { 211355d6bb5Sswilcox if (cleardirentry(inp->i_parent, orphan) & FOUND) { 212355d6bb5Sswilcox LFDIR_LINK_RANGE_NORVAL(flow, lncntp[lfdir], 1, 213355d6bb5Sswilcox &idesc); 214355d6bb5Sswilcox TRACK_LNCNTP(orphan, lncntp[orphan]++); 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate inp->i_parent = inp->i_dotdot = lfdir; 217355d6bb5Sswilcox LFDIR_LINK_RANGE_NORVAL(flow, lncntp[lfdir], -1, 218355d6bb5Sswilcox &idesc); 219355d6bb5Sswilcox TRACK_LNCNTP(lfdir, lncntp[lfdir]--); 2207c478bd9Sstevel@tonic-gate statemap[orphan] = DFOUND; 221355d6bb5Sswilcox } else { 222355d6bb5Sswilcox /* 223355d6bb5Sswilcox * Represents a on-disk leak, not an inconsistency, 224355d6bb5Sswilcox * so don't set iscorrupt. Such leaks are harmless 225355d6bb5Sswilcox * in the context of discrepancies that the kernel 226355d6bb5Sswilcox * will panic over. 227355d6bb5Sswilcox * 228355d6bb5Sswilcox * We don't care if tsearch() returns non-NULL 229355d6bb5Sswilcox * != orphan, since there's no dynamic memory 230355d6bb5Sswilcox * to free here. 231355d6bb5Sswilcox */ 232355d6bb5Sswilcox if (tsearch((void *)orphan, &limbo_dirs, 233355d6bb5Sswilcox ino_t_cmp) == NULL) 234355d6bb5Sswilcox errexit("out of memory"); 235355d6bb5Sswilcox statemap[orphan] |= INORPHAN; 236355d6bb5Sswilcox continue; 237355d6bb5Sswilcox } 2387c478bd9Sstevel@tonic-gate propagate(); 2397c478bd9Sstevel@tonic-gate } 240355d6bb5Sswilcox 241355d6bb5Sswilcox /* 242355d6bb5Sswilcox * The essence of the inner loop is to update the inode of 243355d6bb5Sswilcox * every shadow or attribute inode's lncntp[] by the number of 244355d6bb5Sswilcox * links we've found to them in pass 2 and above. Logically, 245355d6bb5Sswilcox * all that is needed is just the one line: 246355d6bb5Sswilcox * 247355d6bb5Sswilcox * lncntp[sci->shadow] -= sci->totalclients; 248355d6bb5Sswilcox * 249355d6bb5Sswilcox * However, there's the possibility of wrapping the link count 250355d6bb5Sswilcox * (this is especially true for shadows, which are expected to 251355d6bb5Sswilcox * be shared amongst many files). This means that we have to 252355d6bb5Sswilcox * range-check before changing anything, and if the check 253355d6bb5Sswilcox * fails, offer to clear the shadow or attribute. If we do 254355d6bb5Sswilcox * clear it, then we have to remove it from the linked list of 255355d6bb5Sswilcox * all of the type of inodes that we're going through. 256355d6bb5Sswilcox * 257355d6bb5Sswilcox * Just to make things a little more complicated, these are 258355d6bb5Sswilcox * singly-linked lists, so we have to do all the extra 259355d6bb5Sswilcox * bookkeeping that goes along with that as well. 260355d6bb5Sswilcox * 261355d6bb5Sswilcox * The only connection between the shadowclientinfo and 262355d6bb5Sswilcox * attrclientinfo lists is that they use the same underlying 263355d6bb5Sswilcox * struct. Both need this scan, so the outer loop is just to 264355d6bb5Sswilcox * pick which one we're working on at the moment. There is no 265355d6bb5Sswilcox * requirement as to which of these lists is scanned first. 266355d6bb5Sswilcox */ 267355d6bb5Sswilcox for (loopcnt = 0; loopcnt < 2; loopcnt++) { 268355d6bb5Sswilcox if (loopcnt == 0) 269355d6bb5Sswilcox sci_rootp = &shadowclientinfo; 270355d6bb5Sswilcox else 271355d6bb5Sswilcox sci_rootp = &attrclientinfo; 272355d6bb5Sswilcox 273355d6bb5Sswilcox sci = *sci_rootp; 274355d6bb5Sswilcox sci_prev = NULL; 275355d6bb5Sswilcox while (sci != NULL) { 276355d6bb5Sswilcox sci_victim = NULL; 277355d6bb5Sswilcox LINK_RANGE(flow, lncntp[sci->shadow], 278355d6bb5Sswilcox -(sci->totalClients)); 279355d6bb5Sswilcox if (flow != NULL) { 280355d6bb5Sswilcox /* 281355d6bb5Sswilcox * Overflowed the link count. 282355d6bb5Sswilcox */ 283355d6bb5Sswilcox dp = ginode(sci->shadow); 284355d6bb5Sswilcox LINK_CLEAR(flow, sci->shadow, dp->di_mode, 285355d6bb5Sswilcox &idesc); 286355d6bb5Sswilcox if (statemap[sci->shadow] == USTATE) { 287355d6bb5Sswilcox /* 288355d6bb5Sswilcox * It's been cleared, fix the 289355d6bb5Sswilcox * lists. 290355d6bb5Sswilcox */ 291355d6bb5Sswilcox if (sci_prev == NULL) { 292355d6bb5Sswilcox *sci_rootp = sci->next; 293355d6bb5Sswilcox } else { 294355d6bb5Sswilcox sci_prev->next = sci->next; 295355d6bb5Sswilcox } 296355d6bb5Sswilcox sci_victim = sci; 297355d6bb5Sswilcox } 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate 300355d6bb5Sswilcox /* 301355d6bb5Sswilcox * If we did not clear the shadow, then we 302355d6bb5Sswilcox * need to update the count and advance the 303355d6bb5Sswilcox * previous pointer. Otherwise, finish the 304355d6bb5Sswilcox * clean up once we're done with the struct. 305355d6bb5Sswilcox */ 306355d6bb5Sswilcox if (sci_victim == NULL) { 307355d6bb5Sswilcox TRACK_LNCNTP(sci->shadow, 308355d6bb5Sswilcox lncntp[sci->shadow] -= sci->totalClients); 309355d6bb5Sswilcox sci_prev = sci; 3107c478bd9Sstevel@tonic-gate } 311355d6bb5Sswilcox sci = sci->next; 312355d6bb5Sswilcox if (sci_victim != NULL) 313355d6bb5Sswilcox deshadow(sci_victim, NULL); 314355d6bb5Sswilcox } 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate /* 3207c478bd9Sstevel@tonic-gate * This is used to verify the cflags of files 321355d6bb5Sswilcox * under a directory that used to be an attrdir. 3227c478bd9Sstevel@tonic-gate */ 3237c478bd9Sstevel@tonic-gate 324355d6bb5Sswilcox static int 325355d6bb5Sswilcox pass3acheck(struct inodesc *idesc) 3267c478bd9Sstevel@tonic-gate { 3277c478bd9Sstevel@tonic-gate struct direct *dirp = idesc->id_dirp; 328355d6bb5Sswilcox int n = 0, ret = 0; 3297c478bd9Sstevel@tonic-gate struct dinode *dp, *pdirp; 330355d6bb5Sswilcox int isattr; 331355d6bb5Sswilcox int dirtype; 332355d6bb5Sswilcox int inotype; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate if (dirp->d_ino == 0) 3357c478bd9Sstevel@tonic-gate return (KEEPON); 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate idesc->id_entryno++; 3387c478bd9Sstevel@tonic-gate if ((strcmp(dirp->d_name, ".") == 0) || 3397c478bd9Sstevel@tonic-gate (strcmp(dirp->d_name, "..") == 0)) { 3407c478bd9Sstevel@tonic-gate return (KEEPON); 3417c478bd9Sstevel@tonic-gate } 3427c478bd9Sstevel@tonic-gate 343355d6bb5Sswilcox switch (statemap[dirp->d_ino] & ~(INDELAYD)) { 3447c478bd9Sstevel@tonic-gate case DSTATE: 3457c478bd9Sstevel@tonic-gate case DFOUND: 3467c478bd9Sstevel@tonic-gate case FSTATE: 3477c478bd9Sstevel@tonic-gate /* 348355d6bb5Sswilcox * Accept DSTATE and DFOUND so we can handle normal 349355d6bb5Sswilcox * directories as well as xattr directories. 350355d6bb5Sswilcox * 3517c478bd9Sstevel@tonic-gate * For extended attribute directories .. may point 3527c478bd9Sstevel@tonic-gate * to a file. In this situation we don't want 3537c478bd9Sstevel@tonic-gate * to decrement link count as it was already 354355d6bb5Sswilcox * decremented when the entry was seen and decremented 3557c478bd9Sstevel@tonic-gate * in the directory it actually lives in. 3567c478bd9Sstevel@tonic-gate */ 3577c478bd9Sstevel@tonic-gate dp = ginode(dirp->d_ino); 3587c478bd9Sstevel@tonic-gate isattr = (dp->di_cflags & IXATTR); 359355d6bb5Sswilcox inotype = (dp->di_mode & IFMT); 3607c478bd9Sstevel@tonic-gate pdirp = ginode(idesc->id_number); 3617c478bd9Sstevel@tonic-gate dirtype = (pdirp->di_mode & IFMT); 362355d6bb5Sswilcox /* 363355d6bb5Sswilcox * IXATTR indicates that an object is itself an extended 364355d6bb5Sswilcox * attribute. An IFMT of IFATTRDIR means we are looking 365355d6bb5Sswilcox * at a directory which contains files which should all 366355d6bb5Sswilcox * have IXATTR set. The IFATTRDIR case was handled in 367355d6bb5Sswilcox * pass 2b. 368355d6bb5Sswilcox * 369355d6bb5Sswilcox * Note that the following code actually handles 370355d6bb5Sswilcox * anything that's marked as an extended attribute but 371355d6bb5Sswilcox * in a regular directory, not just files. 372355d6bb5Sswilcox */ 3737c478bd9Sstevel@tonic-gate if ((dirtype == IFDIR) && isattr) { 3747c478bd9Sstevel@tonic-gate fileerror(idesc->id_number, dirp->d_ino, 375355d6bb5Sswilcox "%s I=%d should NOT be marked as extended attribute\n", 376355d6bb5Sswilcox (inotype == IFDIR) ? "Directory" : "File", 377355d6bb5Sswilcox dirp->d_ino); 3787c478bd9Sstevel@tonic-gate dp = ginode(dirp->d_ino); 3797c478bd9Sstevel@tonic-gate dp->di_cflags &= ~IXATTR; 3807c478bd9Sstevel@tonic-gate if ((n = reply("FIX")) == 1) { 3817c478bd9Sstevel@tonic-gate inodirty(); 382355d6bb5Sswilcox } else { 383355d6bb5Sswilcox iscorrupt = 1; 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate if (n != 0) 3867c478bd9Sstevel@tonic-gate return (KEEPON | ALTERED); 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate break; 3897c478bd9Sstevel@tonic-gate default: 3907c478bd9Sstevel@tonic-gate errexit("PASS3: BAD STATE %d FOR INODE I=%d", 3917c478bd9Sstevel@tonic-gate statemap[dirp->d_ino], dirp->d_ino); 392355d6bb5Sswilcox /* NOTREACHED */ 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate if (n == 0) 3957c478bd9Sstevel@tonic-gate return (ret|KEEPON); 3967c478bd9Sstevel@tonic-gate return (ret|KEEPON|ALTERED); 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate static void 400355d6bb5Sswilcox setcurino(struct inodesc *idesc, struct dinode *dp, struct inoinfo *inp) 4017c478bd9Sstevel@tonic-gate { 402355d6bb5Sswilcox (void) memmove((void *)&dp->di_db[0], (void *)&inp->i_blks[0], 403355d6bb5Sswilcox inp->i_blkssize); 404355d6bb5Sswilcox 405355d6bb5Sswilcox init_inodesc(idesc); 406355d6bb5Sswilcox idesc->id_number = inp->i_number; 407355d6bb5Sswilcox idesc->id_parent = inp->i_parent; 408355d6bb5Sswilcox idesc->id_fix = DONTKNOW; 409355d6bb5Sswilcox idesc->id_type = DATA; 410355d6bb5Sswilcox idesc->id_func = pass3acheck; 411355d6bb5Sswilcox } 412355d6bb5Sswilcox 413355d6bb5Sswilcox void 414355d6bb5Sswilcox maybe_convert_attrdir_to_dir(fsck_ino_t orphan) 415355d6bb5Sswilcox { 416355d6bb5Sswilcox struct dinode *dp = ginode(orphan); 417355d6bb5Sswilcox struct inoinfo *inp = getinoinfo(orphan); 418355d6bb5Sswilcox struct inodesc idesc; 419355d6bb5Sswilcox 420355d6bb5Sswilcox if (dp->di_cflags & IXATTR) { 421355d6bb5Sswilcox dp->di_cflags &= ~IXATTR; 422355d6bb5Sswilcox inodirty(); 423355d6bb5Sswilcox } 424355d6bb5Sswilcox 425355d6bb5Sswilcox if ((dp->di_mode & IFMT) == IFATTRDIR) { 426355d6bb5Sswilcox dp->di_mode &= ~IFATTRDIR; 427355d6bb5Sswilcox dp->di_mode |= IFDIR; 428355d6bb5Sswilcox inodirty(); 429355d6bb5Sswilcox 430355d6bb5Sswilcox setcurino(&idesc, dp, inp); 431355d6bb5Sswilcox idesc.id_fix = FIX; 432355d6bb5Sswilcox idesc.id_filesize = dp->di_size; 433355d6bb5Sswilcox (void) ckinode(dp, &idesc, CKI_TRAVERSE); 434355d6bb5Sswilcox } 4357c478bd9Sstevel@tonic-gate } 436