static void add_dotdot(struct gfs2_inode *ip) { struct dir_info *di; struct gfs2_sbd *sdp = ip->i_sbd; int err; log_info( _("Adding .. entry to directory %llu (0x%llx) pointing back " "to lost+found\n"), (unsigned long long)ip->i_di.di_num.no_addr, (unsigned long long)ip->i_di.di_num.no_addr); /* If there's a pre-existing .. directory entry, we have to back out the links. */ di = dirtree_find(ip->i_di.di_num.no_addr); if (di && valid_block(sdp, di->dotdot_parent.no_addr)) { struct gfs2_inode *dip; log_debug(_("Directory (0x%llx) already had a " "\"..\" link to (0x%llx).\n"), (unsigned long long)ip->i_di.di_num.no_addr, (unsigned long long)di->dotdot_parent.no_addr); dip = fsck_load_inode(sdp, di->dotdot_parent.no_addr); if (dip->i_di.di_num.no_formal_ino == di->dotdot_parent.no_formal_ino) { decr_link_count(di->dotdot_parent.no_addr, ip->i_di.di_num.no_addr, sdp->gfs1, _(".. unlinked, moving to lost+found")); if (dip->i_di.di_nlink > 0) { dip->i_di.di_nlink--; set_di_nlink(dip); /* keep inode tree in sync */ log_debug(_("Decrementing its links to %d\n"), dip->i_di.di_nlink); bmodified(dip->i_bh); } else if (!dip->i_di.di_nlink) { log_debug(_("Its link count is zero.\n")); } else { log_debug(_("Its link count is %d! Changing " "it to 0.\n"), dip->i_di.di_nlink); dip->i_di.di_nlink = 0; set_di_nlink(dip); /* keep inode tree in sync */ bmodified(dip->i_bh); } } else { log_debug(_("Directory (0x%llx)'s link to parent " "(0x%llx) had a formal inode discrepancy: " "was 0x%llx, expected 0x%llx\n"), (unsigned long long)ip->i_di.di_num.no_addr, (unsigned long long)di->dotdot_parent.no_addr, di->dotdot_parent.no_formal_ino, dip->i_di.di_num.no_formal_ino); log_debug(_("The parent directory was not changed.\n")); } fsck_inode_put(&dip); di = NULL; } else { if (di) log_debug(_("Couldn't find a valid \"..\" entry " "for orphan directory (0x%llx): " "'..' = 0x%llx\n"), (unsigned long long)ip->i_di.di_num.no_addr, (unsigned long long)di->dotdot_parent.no_addr); else log_debug(_("Couldn't find directory (0x%llx) " "in directory tree.\n"), (unsigned long long)ip->i_di.di_num.no_addr); } if (gfs2_dirent_del(ip, "..", 2)) log_warn( _("add_inode_to_lf: Unable to remove " "\"..\" directory entry.\n")); err = dir_add(ip, "..", 2, &(lf_dip->i_di.di_num), (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR)); if (err) { log_crit(_("Error adding .. directory: %s\n"), strerror(errno)); exit(FSCK_ERROR); } }
int incr_link_count(struct gfs2_inum no, struct gfs2_inode *ip, const char *why) { struct inode_info *ii = NULL; uint64_t referenced_from = ip ? ip->i_di.di_num.no_addr : 0; struct dir_info *di; struct gfs2_inode *link_ip; di = dirtree_find(no.no_addr); if (di) { if (di->dinode.no_formal_ino != no.no_formal_ino) return 1; di->counted_links++; whyincr(no.no_addr, why, referenced_from, di->counted_links); return 0; } ii = inodetree_find(no.no_addr); /* If the list has entries, look for one that matches inode_no */ if (ii) { if (ii->di_num.no_formal_ino != no.no_formal_ino) return 1; ii->counted_links++; whyincr(no.no_addr, why, referenced_from, ii->counted_links); return 0; } if (link1_type(&clink1map, no.no_addr) != 1) { link1_set(&clink1map, no.no_addr, 1); whyincr(no.no_addr, why, referenced_from, 1); return 0; } link_ip = fsck_load_inode(ip->i_sbd, no.no_addr); /* Check formal ino against dinode before adding to inode tree. */ if (no.no_formal_ino != ip->i_di.di_num.no_formal_ino) { fsck_inode_put(&link_ip); return 1; } /* Move it from the link1 maps to a real inode tree entry */ link1_set(&nlink1map, no.no_addr, 0); link1_set(&clink1map, no.no_addr, 0); /* If no match was found, it must be a hard link. In theory, it can't be a duplicate because those were resolved in pass1b. Add a new inodetree entry and set its counted links to 2 */ ii = inodetree_insert(no); if (!ii) { log_debug( _("Ref: (0x%llx) Error incrementing link for " "(0x%llx)!\n"), (unsigned long long)referenced_from, (unsigned long long)no.no_addr); fsck_inode_put(&link_ip); return -1; } ii->di_num = link_ip->i_di.di_num; fsck_inode_put(&link_ip); ii->di_nlink = 1; /* Must be 1 or it wouldn't have gotten into the nlink1map */ ii->counted_links = 2; whyincr(no.no_addr, why, referenced_from, ii->counted_links); return 0; }