📄 fsckconn.c
字号:
/* * Copyright (c) International Business Machines Corp., 2000-2002 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <config.h>#include "xfsckint.h" /* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * * superblock buffer pointer * * defined in xchkdsk.c */extern struct superblock *sb_ptr; /* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * * fsck aggregate info structure pointer * * defined in xchkdsk.c */extern struct fsck_agg_record *agg_recptr; /* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * * For directory entry processing * * defined in xchkdsk.c */extern uint32_t key_len[2];extern UniChar key[2][JFS_NAME_MAX];extern UniChar ukey[2][JFS_NAME_MAX];extern int32_t Uni_Name_len;extern UniChar Uni_Name[JFS_NAME_MAX];/* VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV * * The following are internal to this file * */int adjust_parent(uint32_t, struct fsck_inode_record *, uint32_t);int reset_parents(struct fsck_inode_record *, uint32_t);/* VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV *//***************************************************************************** * NAME: adjust_parent * * FUNCTION: Add an fsck inode extension record to the parent inode's * fsck inode record so that the directory entry for the * given child will be removed. * * PARAMETERS: * child_ino - input - ordinal number of child inode * child_inorecptr - input - pointer to an fsck record describing the * child inode * parent_ino - input - ordinal number of parent inode * * RETURNS: * success: FSCK_OK * failure: something else */int adjust_parent(uint32_t child_ino, struct fsck_inode_record *child_inorecptr, uint32_t parent_ino){ int adjp_rc = FSCK_OK; struct fsck_inode_ext_record *this_ext; struct fsck_inode_record *parent_inorecptr; int is_aggregate = 0; int alloc_ifnull = 0; adjp_rc = get_inorecptr(is_aggregate, alloc_ifnull, parent_ino, &parent_inorecptr); if ((adjp_rc == FSCK_OK) && (parent_inorecptr == NULL)) { adjp_rc = FSCK_INTERNAL_ERROR_4; fsck_send_msg(fsck_INTERNALERROR, adjp_rc, child_ino, parent_ino, 0); } else if (adjp_rc == FSCK_OK) { /* located the parent's inode record */ adjp_rc = get_inode_extension(&this_ext); if (adjp_rc == FSCK_OK) { /* got extension */ this_ext->ext_type = rmv_direntry_extension; this_ext->inonum = child_ino; this_ext->next = parent_inorecptr->ext_rec; this_ext->ino_type = child_inorecptr->inode_type; parent_inorecptr->ext_rec = this_ext; parent_inorecptr->adj_entries = 1; agg_recptr->corrections_needed = 1; } } return (adjp_rc);}/***************************************************************************** * NAME: adjust_parents * * FUNCTION: Add an fsck inode extension record, to the fsck inode record * of each of the given inode's parent inodes, so that all * directory entries for the given inode will be removed. The * exception is that, if the given inode is a directory inode, * the expected parent may be omitted from this processing. * * PARAMETERS: * ino_recptr - input - pointer to an fsck record describing the inode * ino_idx - input - ordinal number of the inode * * RETURNS: * success: FSCK_OK * failure: something else */int adjust_parents(struct fsck_inode_record *ino_recptr, uint32_t ino_idx){ int adjps_rc = FSCK_OK; struct fsck_inode_ext_record *this_ext; struct fsck_inode_ext_record *rest_of_list; int keep_primary_parent = 0; /* * if this is a directory with illegal hard links then the * inode number in the fsck inode record is the one stored in * the inode on disk. Then if the inode isn't being released * and any observed parent matches the stored parent, that * parent will not be adjusted. */ if ((ino_recptr->inode_type == directory_inode) && (ino_recptr->unxpctd_prnts)) { /* dir with multiple parents */ if (!ino_recptr->selected_to_rls) { /* not being released */ if ((ino_recptr->parent_inonum != ROOT_I) || (!agg_recptr->rootdir_rebuilt)) { keep_primary_parent = 1; } } } else { /* not a dir with multiple parents -- this must be either an * inode approved for released or an unallocated inode with * parents observed. */ /* * the 1st parent observed is in the inode record. Any others are * in extension records. */ if (ino_recptr->parent_inonum != 0) { if ((ino_recptr->parent_inonum != ROOT_I) || (!agg_recptr->rootdir_rebuilt)) { /* either this parent isn't the root or else the root dir has not been rebuilt */ adjps_rc = adjust_parent(ino_idx, ino_recptr, ino_recptr->parent_inonum); ino_recptr->parent_inonum = 0; /* clear it */ } } } /* * detach the extensions list from the inode record */ this_ext = ino_recptr->ext_rec; ino_recptr->ext_rec = NULL; while ((adjps_rc == FSCK_OK) && (this_ext != NULL)) { /* there may be more parents */ rest_of_list = this_ext->next; if (this_ext->ext_type != parent_extension) { /* not a parent */ this_ext->next = ino_recptr->ext_rec; ino_recptr->ext_rec = this_ext; } else { /* parent extension */ if ((this_ext->inonum == ROOT_I) && (agg_recptr->rootdir_rebuilt)) { /* * This parent is the root and the root dir has * been rebuilt. This is equivalent to a parent * marked for release. */ release_inode_extension(this_ext); } else if ((keep_primary_parent) && (this_ext->inonum == ino_recptr->parent_inonum)) { /* * We're keeping the entry for the expected parent. * Just drop the extension record and clear the * 'unexpected parents' flag. When we finish this * routine the inode will be all set. */ release_inode_extension(this_ext); ino_recptr->unxpctd_prnts = 0; } else { /* either not keeping the 'primary' or else this isn't it */ adjps_rc = adjust_parent(ino_idx, ino_recptr, this_ext->inonum); release_inode_extension(this_ext); } } this_ext = rest_of_list; } return (adjps_rc);}/***************************************************************************** * NAME: check_connectedness * * FUNCTION: Verify that, after approved corrections are made, all inodes * in use will be connected to the root directory tree. * * PARAMETERS: none * * NOTES: o A directory inode must have exactly one parent inode. * o A non-directory inode must have at least one parent inode. * * RETURNS: * success: FSCK_OK * failure: something else */int check_connectedness(){ int cc_rc = FSCK_OK; uint32_t ino_idx; struct fsck_inode_record *this_inorec; struct fsck_inode_ext_record *new_ext; int aggregate_inode = 0; struct fsck_ino_msg_info ino_msg_info; struct fsck_ino_msg_info *msg_info_ptr; msg_info_ptr = &ino_msg_info; /* all fileset owned */ msg_info_ptr->msg_inopfx = fsck_fset_inode; /* * detect orphan inodes, including ones which we're about to * orphan by releasing inodes. * * if any non-orphan inode was flagged as a directory with illegal * hard links, see if it's going to be true after we release inodes. * If not, make sure the remaining link matches the one stored in * the inode. */ cc_rc = get_inorecptr_first(aggregate_inode, &ino_idx, &this_inorec); while ((cc_rc == FSCK_OK) && (this_inorec != NULL) && (ino_idx < FILESET_OBJECT_I)) { /* * not interesting until we get past the root inode * and the special fileset inodes. */ cc_rc = get_inorecptr_next(aggregate_inode, &ino_idx, &this_inorec); } while ((cc_rc == FSCK_OK) && (this_inorec != NULL)) { if ((this_inorec->in_use) && (!this_inorec->selected_to_rls)) { /* inode in use and not selected to release */ msg_info_ptr->msg_inonum = ino_idx; if (this_inorec->inode_type == directory_inode) { msg_info_ptr->msg_inotyp = fsck_directory; } else if (this_inorec->inode_type == symlink_inode) { msg_info_ptr->msg_inotyp = fsck_symbolic_link; } else if (this_inorec->inode_type == char_special_inode) { msg_info_ptr->msg_inotyp = fsck_char_special; } else if (this_inorec->inode_type == block_special_inode) { msg_info_ptr->msg_inotyp = fsck_block_special; } else if (this_inorec->inode_type == FIFO_inode) { msg_info_ptr->msg_inotyp = fsck_FIFO; } else if (this_inorec->inode_type == SOCK_inode) { msg_info_ptr->msg_inotyp = fsck_SOCK; } else { /* a regular file */ msg_info_ptr->msg_inotyp = fsck_file; } if (this_inorec->parent_inonum == 0) { /* no parents were observed by fsck */ fsck_send_msg(fsck_INONOPATHS, fsck_ref_msg(msg_info_ptr->msg_inopfx), msg_info_ptr->msg_inonum); } else { /* at least one parent observed by fsck */ /* * make adjustments to child records for * parents which will be released */ cc_rc = reset_parents(this_inorec, ino_idx); } if (cc_rc == FSCK_OK) { if (this_inorec->parent_inonum == 0) { /* unconnected !! */ /* * do not issue a message to inform the user about * this condition since it is a side effect of * the (approved) release of some other inode(s) */ this_inorec->reconnect = 1; agg_recptr->corrections_approved = 1; cc_rc = get_inode_extension(&new_ext); if (cc_rc == FSCK_OK) { /* got an extension record */ new_ext->ext_type = add_direntry_extension; new_ext->inonum = ino_idx; new_ext->ino_type = this_inorec->inode_type; new_ext->next = agg_recptr-> inode_reconn_extens; agg_recptr-> inode_reconn_extens = new_ext; /* increment for the link from * parent after reconnect */ this_inorec->link_count++; } } else { /* else still connected */ if (this_inorec->unxpctd_prnts) { /* multiple parents */ cc_rc = display_paths(ino_idx, this_inorec, msg_info_ptr); if (cc_rc == FSCK_OK) { if (agg_recptr-> processing_readwrite) { cc_rc = adjust_parents (this_inorec, ino_idx); fsck_send_msg (fsck_WILLFIXDIRWHDLKS, fsck_ref_msg(msg_info_ptr->msg_inopfx), msg_info_ptr->msg_inonum); } else { /* no write access */ this_inorec-> unxpctd_prnts = 0; agg_recptr-> ag_dirty = 1; fsck_send_msg (fsck_DIRWHDLKS, fsck_ref_msg(msg_info_ptr->msg_inopfx), msg_info_ptr->msg_inonum); } } } else if ((cc_rc == FSCK_OK) && (this_inorec-> crrct_prnt_inonum)) { /* * a single parent but not the one * named in the implied '..' entry */ cc_rc = display_paths(ino_idx, this_inorec, msg_info_ptr); if (agg_recptr-> processing_readwrite) { fsck_send_msg (fsck_WILLFIXINCREF, fsck_ref_msg(msg_info_ptr->msg_inopfx), msg_info_ptr->msg_inonum, fsck_ref_msg(msg_info_ptr->msg_inopfx), this_inorec->parent_inonum); } else { /* no write access */ this_inorec-> crrct_prnt_inonum = 0; agg_recptr->ag_dirty = 1; fsck_send_msg (fsck_INCINOREF, fsck_ref_msg(msg_info_ptr->msg_inopfx), msg_info_ptr->msg_inonum, fsck_ref_msg(msg_info_ptr->msg_inopfx), this_inorec->parent_inonum); } } } } } if (cc_rc == FSCK_OK) { cc_rc = get_inorecptr_next(aggregate_inode, &ino_idx, &this_inorec); } } return (cc_rc);}/***************************************************************************** * NAME: check_dir_integrity * * FUNCTION: Verify that no directory has more than 1 entry for any * single inode. If a directory does, then that directory * is corrupt. * * RETURNS: * success: FSCK_OK * failure: something else */int check_dir_integrity(){ int cdi_rc = FSCK_OK; uint32_t ino_idx; struct fsck_inode_record *this_inorec; struct fsck_inode_record *that_inorec; int aggregate_inode = 0; int alloc_ifnull = 0; struct fsck_inode_ext_record *this_ext; struct fsck_inode_ext_record *that_ext; int dup_parent_detected = 0; struct fsck_ino_msg_info ino_msg_info; struct fsck_ino_msg_info *msg_info_ptr; msg_info_ptr = &ino_msg_info; /* all fileset owned */ msg_info_ptr->msg_inopfx = fsck_fset_inode; /* * Verify that no inode has multiple links from the same * directory. */ cdi_rc = get_inorecptr_first(aggregate_inode, &ino_idx, &this_inorec); while ((cdi_rc == FSCK_OK) && (this_inorec != NULL) && (ino_idx < FILESET_OBJECT_I)) { /* * not interesting until we get past the root inode * and the special fileset inodes. */ cdi_rc = get_inorecptr_next(aggregate_inode, &ino_idx, &this_inorec); } while ((cdi_rc == FSCK_OK) && (this_inorec != NULL)) { if ((this_inorec->in_use) && (!this_inorec->selected_to_rls) && (this_inorec->inode_type == directory_inode)) { /* directory inode in use and not selected to release */ msg_info_ptr->msg_inotyp = fsck_directory; msg_info_ptr->msg_inonum = ino_idx; if (this_inorec->parent_inonum != 0) { /* at least 1 parent observed by fsck */ if (this_inorec->ext_rec) { /* maybe more parents have been observed */ /* * get the first entry in the extensions * list on the inode record */ this_ext = this_inorec->ext_rec; while ((cdi_rc == FSCK_OK) && (this_ext != NULL)) { /* there may be more parents */ if (this_ext->ext_type == parent_extension) { /* a parent */ cdi_rc = get_inorecptr (aggregate_inode, alloc_ifnull, this_ext->inonum, &that_inorec); if ((cdi_rc == FSCK_OK) && (!that_inorec-> selected_to_rls)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -