/* Link an inode number to a directory */ static errcode_t add_link(ext2_filsys fs, ext2_ino_t parent_ino, ext2_ino_t ino, const char *name) { struct ext2_inode inode; errcode_t retval; retval = ext2fs_read_inode(fs, ino, &inode); if (retval) { com_err(__func__, retval, _("while reading inode %u"), ino); return retval; } retval = ext2fs_link(fs, parent_ino, name, ino, ext2_file_type(inode.i_mode)); if (retval == EXT2_ET_DIR_NO_SPACE) { retval = ext2fs_expand_dir(fs, parent_ino); if (retval) { com_err(__func__, retval, _("while expanding directory")); return retval; } retval = ext2fs_link(fs, parent_ino, name, ino, ext2_file_type(inode.i_mode)); } if (retval) { com_err(__func__, retval, _("while linking \"%s\""), name); return retval; } inode.i_links_count++; retval = ext2fs_write_inode(fs, ino, &inode); if (retval) com_err(__func__, retval, _("while writing inode %u"), ino); return retval; }
/* * This routine will connect a file to lost+found */ int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino) { ext2_filsys fs = ctx->fs; errcode_t retval; char name[80]; struct problem_context pctx; struct ext2_inode inode; int file_type = 0; clear_problem_context(&pctx); pctx.ino = ino; if (!ctx->bad_lost_and_found && !ctx->lost_and_found) { if (e2fsck_get_lost_and_found(ctx, 1) == 0) ctx->bad_lost_and_found++; } if (ctx->bad_lost_and_found) { fix_problem(ctx, PR_3_NO_LPF, &pctx); return 1; } sprintf(name, "#%u", ino); if (ext2fs_read_inode(fs, ino, &inode) == 0) file_type = ext2_file_type(inode.i_mode); retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type); if (retval == EXT2_ET_DIR_NO_SPACE) { if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx)) return 1; retval = e2fsck_expand_directory(ctx, ctx->lost_and_found, 1, 0); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx); return 1; } retval = ext2fs_link(fs, ctx->lost_and_found, name, ino, file_type); } if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_CANT_RECONNECT, &pctx); return 1; } e2fsck_adjust_inode_count(ctx, ino, 1); return 0; }
/* * Check the directory filetype (if present) */ static _INLINE_ int check_filetype(e2fsck_t ctx, struct ext2_dir_entry *dirent, ext2_ino_t dir_ino EXT2FS_ATTR((unused)), struct problem_context *pctx) { int filetype = dirent->name_len >> 8; int should_be = EXT2_FT_UNKNOWN; struct ext2_inode inode; if (!(ctx->fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)) { if (filetype == 0 || !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx)) return 0; dirent->name_len = dirent->name_len & 0xFF; return 1; } if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, dirent->inode)) { should_be = EXT2_FT_DIR; } else if (ext2fs_test_inode_bitmap2(ctx->inode_reg_map, dirent->inode)) { should_be = EXT2_FT_REG_FILE; } else if (ctx->inode_bad_map && ext2fs_test_inode_bitmap2(ctx->inode_bad_map, dirent->inode)) should_be = 0; else { e2fsck_read_inode(ctx, dirent->inode, &inode, "check_filetype"); should_be = ext2_file_type(inode.i_mode); } if (filetype == should_be) return 0; pctx->num = should_be; if (fix_problem(ctx, filetype ? PR_2_BAD_FILETYPE : PR_2_SET_FILETYPE, pctx) == 0) return 0; dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8; return 1; }
int ext2Link(ext2_vd *vd, const char *old_path, const char *new_path) { ext2_inode_t *dir_ni = NULL, *ni = NULL; char *dir = NULL; char *name = NULL; errcode_t err = 0; // Sanity check if (!vd || !vd->fs) { errno = ENODEV; return -1; } if(!(vd->fs->flags & EXT2_FLAG_RW)) { errno = EACCES; return -1; } // You cannot link between devices if(vd != ext2GetVolume(new_path)) { errno = EXDEV; return -1; } // Get the actual paths of the entry old_path = ext2RealPath(old_path); new_path = ext2RealPath(new_path); if (!old_path || !new_path) return -1; // Lock ext2Lock(vd); //check for existing in new path ni = ext2OpenEntry(vd, new_path); if (ni) { errno = EEXIST; goto cleanup; } dir = strdup(new_path); if (!dir) { errno = ENOMEM; err = -1; goto cleanup; } char * ptr = strrchr(dir, '/'); if (ptr) { name = strdup(ptr+1); *ptr = 0; } else name = strdup(dir); // Find the entry ni = ext2OpenEntry(vd, old_path); if (!ni) { err = -1; goto cleanup; } // Open the entries new parent directory dir_ni = ext2OpenEntry(vd, dir); if (!dir_ni) { err = -1; goto cleanup; } do { // Link the entry to its new parent err = ext2fs_link(vd->fs, dir_ni->ino, name, ni->ino, ext2_file_type(ni->ni.i_mode)); if (err == EXT2_ET_DIR_NO_SPACE) { if (ext2fs_expand_dir(vd->fs, dir_ni->ino) != 0) goto cleanup; } else if(err != EXT2_ET_OK) { errno = EMLINK; goto cleanup; } } while(err == EXT2_ET_DIR_NO_SPACE); ni->ni.i_links_count++; // Update entry times ext2UpdateTimes(vd, ni, EXT2_UPDATE_MCTIME); // Sync the entry to disc ext2Sync(vd, ni); cleanup: if(dir_ni) ext2CloseEntry(vd, dir_ni); if(ni) ext2CloseEntry(vd, ni); if(dir) mem_free(dir); if(name) mem_free(name); // Unlock ext2Unlock(vd); return err; }