static void move_quota_inode(ext2_filsys fs, ext2_ino_t from_ino, ext2_ino_t to_ino, int qtype) { struct ext2_inode inode; char qf_name[QUOTA_NAME_LEN]; /* We need the inode bitmap to be loaded */ if (ext2fs_read_bitmaps(fs)) return; if (ext2fs_read_inode(fs, from_ino, &inode)) return; inode.i_links_count = 1; inode.i_mode = LINUX_S_IFREG | 0600; inode.i_flags = EXT2_IMMUTABLE_FL; if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) inode.i_flags |= EXT4_EXTENTS_FL; ext2fs_write_new_inode(fs, to_ino, &inode); /* unlink the old inode */ quota_get_qf_name(qtype, QFMT_VFS_V1, qf_name); ext2fs_unlink(fs, EXT2_ROOT_INO, qf_name, from_ino, 0); ext2fs_inode_alloc_stats(fs, from_ino, -1); /* Clear out the original inode in the inode-table block. */ memset(&inode, 0, sizeof(struct ext2_inode)); ext2fs_write_inode(fs, from_ino, &inode); }
long rm_file(ext2_filsys fs, ext2_ino_t cwd, char *outfile, ext2_ino_t delfile) { struct ext2_inode inode; long retval; if ((retval = read_inode(fs, delfile, &inode))) return(retval); --inode.i_links_count; if ((retval = write_inode(fs, delfile, &inode))) return(retval); if ((retval = ext2fs_unlink(fs, cwd, outfile, 0, 0))) return(retval); if (inode.i_links_count == 0) return(delete_file(fs, delfile)); return(0); }
static void move_quota_inode(ext2_filsys fs, ext2_ino_t from_ino, ext2_ino_t to_ino, enum quota_type qtype) { struct ext2_inode inode; errcode_t retval; char qf_name[QUOTA_NAME_LEN]; /* We need the inode bitmap to be loaded */ if (ext2fs_read_bitmaps(fs)) return; retval = ext2fs_read_inode(fs, from_ino, &inode); if (retval) { com_err("ext2fs_read_inode", retval, "%s", _("in move_quota_inode")); return; } inode.i_links_count = 1; inode.i_mode = LINUX_S_IFREG | 0600; inode.i_flags = EXT2_IMMUTABLE_FL; if (ext2fs_has_feature_extents(fs->super)) inode.i_flags |= EXT4_EXTENTS_FL; retval = ext2fs_write_new_inode(fs, to_ino, &inode); if (retval) { com_err("ext2fs_write_new_inode", retval, "%s", _("in move_quota_inode")); return; } /* unlink the old inode */ quota_get_qf_name(qtype, QFMT_VFS_V1, qf_name); ext2fs_unlink(fs, EXT2_ROOT_INO, qf_name, from_ino, 0); ext2fs_inode_alloc_stats(fs, from_ino, -1); /* Clear out the original inode in the inode-table block. */ memset(&inode, 0, sizeof(struct ext2_inode)); ext2fs_write_inode(fs, from_ino, &inode); }
void e2fsck_move_ext3_journal(e2fsck_t ctx) { struct ext2_super_block *sb = ctx->fs->super; struct problem_context pctx; struct ext2_inode inode; ext2_filsys fs = ctx->fs; ext2_ino_t ino; errcode_t retval; const char * const * cpp; int group, mount_flags; clear_problem_context(&pctx); /* * If the filesystem is opened read-only, or there is no * journal, then do nothing. */ if ((ctx->options & E2F_OPT_READONLY) || (sb->s_journal_inum == 0) || !(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) return; /* * Read in the journal inode */ if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0) return; /* * If it's necessary to backup the journal inode, do so. */ if ((sb->s_jnl_backup_type == 0) || ((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) && memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) { if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) { memcpy(sb->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4); sb->s_jnl_blocks[16] = inode.i_size; sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; ext2fs_mark_super_dirty(fs); fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; } } /* * If the journal is already the hidden inode, then do nothing */ if (sb->s_journal_inum == EXT2_JOURNAL_INO) return; /* * The journal inode had better have only one link and not be readable. */ if (inode.i_links_count != 1) return; /* * If the filesystem is mounted, or we can't tell whether * or not it's mounted, do nothing. */ retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags); if (retval || (mount_flags & EXT2_MF_MOUNTED)) return; /* * If we can't find the name of the journal inode, then do * nothing. */ for (cpp = journal_names; *cpp; cpp++) { retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp, strlen(*cpp), 0, &ino); if ((retval == 0) && (ino == sb->s_journal_inum)) break; } if (*cpp == 0) return; /* We need the inode bitmap to be loaded */ retval = ext2fs_read_bitmaps(fs); if (retval) return; pctx.str = *cpp; if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx)) return; /* * OK, we've done all the checks, let's actually move the * journal inode. Errors at this point mean we need to force * an ext2 filesystem check. */ if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0) goto err_out; if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0) goto err_out; sb->s_journal_inum = EXT2_JOURNAL_INO; ext2fs_mark_super_dirty(fs); fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; inode.i_links_count = 0; inode.i_dtime = ctx->now; if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0) goto err_out; group = ext2fs_group_of_ino(fs, ino); ext2fs_unmark_inode_bitmap(fs->inode_map, ino); ext2fs_mark_ib_dirty(fs); fs->group_desc[group].bg_free_inodes_count++; fs->super->s_free_inodes_count++; return; err_out: pctx.errcode = retval; fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx); fs->super->s_state &= ~EXT2_VALID_FS; ext2fs_mark_super_dirty(fs); return; }
int op_unlink (const char *path) { int rt; errcode_t rc; char *p_path; char *r_path; ext2_ino_t p_ino; struct ext2_inode p_inode; ext2_ino_t r_ino; struct ext2_vnode *r_vnode; struct ext2_inode *r_inode; ext2_filsys e2fs; FUSE_EXT2_LOCK; e2fs = current_ext2fs(); debugf("enter"); debugf("path = %s", path); rt=do_check_split(path, &p_path, &r_path); if (rt != 0) { debugf("do_check_split: failed"); goto err; } debugf("parent: %s, child: %s", p_path, r_path); rt = do_readinode(e2fs, p_path, &p_ino, &p_inode); if (rt) { debugf("do_readinode(%s, &p_ino, &p_inode); failed", p_path); goto err_free_split; } rt = do_readvnode(e2fs, path, &r_ino, &r_vnode, DONT_OPEN_FILE); if (rt) { debugf("do_readvnode(%s, &r_ino, &r_vnode); failed", path); goto err_free_split; } r_inode = vnode2inode(r_vnode); if(LINUX_S_ISDIR(r_inode->i_mode)) { debugf("%s is a directory", path); vnode_put(r_vnode,0); rt = -EISDIR; goto err_free_split; } rc = ext2fs_unlink(e2fs, p_ino, r_path, r_ino, 0); if (rc) { debugf("ext2fs_unlink(e2fs, %d, %s, %d, 0); failed", p_ino, r_path, r_ino); vnode_put(r_vnode,0); rt = -EIO; goto err_free_split; } if (r_inode->i_links_count > 0) { r_inode->i_links_count -= 1; } p_inode.i_ctime = p_inode.i_mtime = e2fs->now ? e2fs->now : time(NULL); rc = ext2fs_write_inode(e2fs, p_ino, &p_inode); if (rc) { debugf("ext2fs_write_inode(e2fs, p_ino, &p_inode); failed"); vnode_put(r_vnode,1); rt = -EIO; goto err_free_split; } r_inode->i_ctime = e2fs->now ? e2fs->now : time(NULL); rc = vnode_put(r_vnode,1); if (rc) { debugf("vnode_put(r_vnode,1); failed"); rt = -EIO; goto err_free_split; } free_split(p_path, r_path); debugf("leave"); FUSE_EXT2_UNLOCK; return 0; err_free_split: free_split(p_path, r_path); err: FUSE_EXT2_UNLOCK; return rt; }
/* * This routine gets the lost_and_found inode, making it a directory * if necessary */ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) { ext2_filsys fs = ctx->fs; ext2_ino_t ino; blk64_t blk; errcode_t retval; struct ext2_inode inode; char * block; static const char name[] = "lost+found"; struct problem_context pctx; if (ctx->lost_and_found) return ctx->lost_and_found; clear_problem_context(&pctx); retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, sizeof(name)-1, 0, &ino); if (retval && !fix) return 0; if (!retval) { if (ext2fs_check_directory(fs, ino) == 0) { ctx->lost_and_found = ino; return ino; } /* Lost+found isn't a directory! */ if (!fix) return 0; pctx.ino = ino; if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx)) return 0; /* OK, unlink the old /lost+found file. */ pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0); if (pctx.errcode) { pctx.str = "ext2fs_unlink"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } (void) e2fsck_dir_info_set_parent(ctx, ino, 0); e2fsck_adjust_inode_count(ctx, ino, -1); } else if (retval != EXT2_ET_FILE_NOT_FOUND) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); } if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) return 0; /* * Read the inode and block bitmaps in; we'll be messing with * them. */ e2fsck_read_bitmaps(ctx); /* * First, find a free block */ retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); return 0; } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); ext2fs_block_alloc_stats2(fs, blk, +1); /* * Next find a free inode. */ retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, ctx->inode_used_map, &ino); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); return 0; } ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); /* * Now let's create the actual data block for the inode */ retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); return 0; } retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); ext2fs_free_mem(&block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); return 0; } /* * Set up the inode structure */ memset(&inode, 0, sizeof(inode)); inode.i_mode = 040700; inode.i_size = fs->blocksize; inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; inode.i_links_count = 2; ext2fs_iblk_set(fs, &inode, 1); inode.i_block[0] = blk; /* * Next, write out the inode. */ pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode); if (pctx.errcode) { pctx.str = "ext2fs_write_inode"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Finally, create the directory link */ pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); if (pctx.errcode) { pctx.str = "ext2fs_link"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Miscellaneous bookkeeping that needs to be kept straight. */ e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO); e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1); ext2fs_icount_store(ctx->inode_count, ino, 2); ext2fs_icount_store(ctx->inode_link_info, ino, 2); ctx->lost_and_found = ino; quota_data_add(ctx->qctx, &inode, ino, fs->blocksize); quota_data_inodes(ctx->qctx, &inode, ino, +1); #if 0 printf("/lost+found created; inode #%lu\n", ino); #endif return ino; }
/* Name: do_mv() * * Description: * * This function reads the command line arguments and moves or renames files * in an ext2fs file system * * Algorithm: * * Read any command line switches * Get the first source file specification * If we are performing a file swap, call do_swap() * Open the file system * Get the destination and determine if it is a directory * If not, then get the destination's directory and basename * Also check that the number of source files are no more than one * For each source file * Get the directory and basename of the source file * Determine the inode number for the source file * Create the link * Unlink the original source file. * * Global Variables: * * None * * Arguments: * * int argc; The number of arguments * char *argv[]; The command line arguments * * Return Values: * * 0 - the file was move successfully * an error occurred. * * Author: Keith W. Sheffield * Date: 03/20/2002 * * Modification History: * * MM/DD/YY Name Description */ long do_mv(int argc, char *argv[]) { int verbose=0; int force=0; int swap_files=0; int errcnt=0; char *cur_filesys = NULL; ext2_filsys fs = NULL; ext2_ino_t root; ext2_ino_t srcd; ext2_ino_t destd; ext2_ino_t source_file; char *src_dir; char *dest_dir; char *src_name; char *dest_name; char *result_name; long retval; int c; int curidx; #ifdef HAVE_OPTRESET optreset = 1; /* Makes BSD getopt happy */ #endif while ((c = getopt(argc, argv, "vfs")) != EOF) { switch (c) { case 'v': verbose = 1; break; case 'f': force = E2T_FORCE; break; case 's': swap_files = 1; break; default: errcnt++; break; } } curidx = optind; force |= E2T_DO_MV; if (errcnt || argc < curidx+2) { fputs(USAGE, stderr); return(1); } if (swap_files) return(do_swap(force, verbose, curidx, argc, argv)); cur_filesys = argv[curidx++]; if (NULL == (src_dir = strchr(cur_filesys, ':'))) { fprintf(stderr, "Invalid file specification: %s\n", cur_filesys); return(1); } *src_dir++ = '\0'; if ((retval = open_filesystem(cur_filesys, &fs, &root, 1))) { return retval; } /* get the destination directory */ dest_name = NULL; if (strcmp(dest_dir = argv[argc-1], ".") != 0) { /* check to see if the file name already exists in the current * directory and also see if it is a directory. */ if ((retval = ext2fs_namei(fs, root, root, dest_dir, &destd)) || (retval = ext2fs_check_directory(fs, destd))) { if (retval != EXT2_ET_FILE_NOT_FOUND && retval != EXT2_ET_NO_DIRECTORY) { fprintf(stderr, "%s\n",error_message(retval)); ext2fs_close(fs); return(retval); } /* ok, so it's either not there or it's not a directory, so * get the real destination directory and file name. */ if (curidx+1 < argc) { fprintf(stderr, "%s must be a directory!\n", dest_dir); ext2fs_close(fs); return(1); } if (get_file_parts(fs, root, dest_dir, &destd, &dest_dir, &dest_name)) { ext2fs_close(fs); return(-1); } } else /* we have a directory!!! */ dest_name = NULL; } else { destd = root; dest_name = NULL; } do { /* move to the source directory */ if (get_file_parts(fs, root, src_dir, &srcd, &src_dir, &src_name)) { ext2fs_close(fs); return(-1); } /* get the inode number for the source file */ if ((retval = ext2fs_namei(fs, srcd, srcd, src_name, &source_file))) { fprintf(stderr, "%s: source file %s\n",error_message(retval), src_name); ext2fs_close(fs); return(retval); } result_name = (dest_name) ? dest_name : src_name; /* now create the link */ if ((retval = create_hard_link(fs, destd, source_file, result_name, force))) { fprintf(stderr, "Error renaming %s/%s as %s/%s\n", ((src_dir == NULL) ? "." : src_dir), src_name, ((dest_dir == NULL) ? "." : dest_dir), result_name); ext2fs_close(fs); return(1); } if ((retval = ext2fs_unlink(fs, srcd, src_name, 0, 0))) { fprintf(stderr, "%s - %s\n", src_name, error_message(retval)); ext2fs_close(fs); return(retval); } if (verbose) fprintf(stderr, "moved %s/%s as %s/%s\n", ((src_dir == NULL) ? "." : src_dir), src_name, ((dest_dir == NULL) ? "." : dest_dir), result_name); src_dir = argv[curidx++]; } while (curidx < argc); ext2fs_close(fs); return(0); } /* end of do_mv */
static long do_swap(int force, int verbose, int curidx, int argc, char **argv) { char *cur_filesys = NULL; ext2_filsys fs = NULL; ext2_ino_t root; ext2_ino_t file1_dirno; ext2_ino_t file2_dirno; ext2_ino_t file3_dirno; ext2_ino_t file1_no; ext2_ino_t file2_no; char *file1_dir; char *file2_dir; char *file3_dir; char *file1_name; char *file2_name; char *file3_name; long retval; if (curidx + 2 > argc) { fputs(USAGE, stderr); return(1); } cur_filesys = argv[curidx++]; if (NULL == (file1_dir = strchr(cur_filesys, ':'))) { fprintf(stderr, "Invalid file specification: %s\n", cur_filesys); return(1); } *file1_dir++ = '\0'; if ((retval = open_filesystem(cur_filesys, &fs, &root, 1))) { return retval; } /* move to the file 1 directory */ if (get_file_parts(fs, root, file1_dir, &file1_dirno, &file1_dir, &file1_name)) { ext2fs_close(fs); return(-1); } /* get the inode number for the file 1 file */ if ((retval = ext2fs_namei(fs, file1_dirno, file1_dirno, file1_name, &file1_no))) { fprintf(stderr, "%s: file 1 file %s\n",error_message(retval), file1_name); ext2fs_close(fs); return(retval); } /* move to the file 2 directory */ if (get_file_parts(fs, root, argv[curidx++], &file2_dirno, &file2_dir, &file2_name)) { ext2fs_close(fs); return(-1); } /* get the inode number for the file 2 file */ if ((retval = ext2fs_namei(fs, file2_dirno, file2_dirno, file2_name, &file2_no))) { fprintf(stderr, "%s: file 2 file %s\n",error_message(retval), file2_name); ext2fs_close(fs); return(retval); } if (curidx < argc) { /* move to the file 3 directory */ if (get_file_parts(fs, root, argv[curidx++], &file3_dirno, &file3_dir, &file3_name)) { ext2fs_close(fs); return(-1); } /* now move the first file to the 3rd */ if ((retval = create_hard_link(fs, file3_dirno, file1_no, file3_name, force))) { fprintf(stderr, "Error renaming %s/%s as %s/%s\n", ((file1_dir == NULL) ? "." : file1_dir), file1_name, ((file3_dir == NULL) ? "." : file3_dir), file3_name); ext2fs_close(fs); return(1); } if ((retval = ext2fs_unlink(fs, file1_dirno, file1_name, 0, 0))) { fprintf(stderr, "%s - %s\n", file1_name, error_message(retval)); ext2fs_close(fs); return(retval); } /* now move the 2nd file to the 1st */ if ((retval = create_hard_link(fs, file1_dirno, file2_no, file1_name, force))) { fprintf(stderr, "Error renaming %s/%s as %s/%s\n", ((file2_dir == NULL) ? "." : file2_dir), file2_name, ((file1_dir == NULL) ? "." : file1_dir), file1_name); ext2fs_close(fs); return(1); } if ((retval = ext2fs_unlink(fs, file2_dirno, file2_name, 0, 0))) { fprintf(stderr, "%s - %s\n", file2_name, error_message(retval)); ext2fs_close(fs); return(retval); } if (verbose) fprintf(stderr, "renamed file %s/%s as %s/%s\n" "renamed file %s/%s as %s/%s\n", ((file1_dir == NULL) ? "." : file1_dir), file1_name, ((file3_dir == NULL) ? "." : file3_dir), file3_name, ((file2_dir == NULL) ? "." : file2_dir), file2_name, ((file1_dir == NULL) ? "." : file1_dir), file1_name); } else { /* now remove the first file */ if ((retval = ext2fs_unlink(fs, file1_dirno, file1_name, 0, 0))) { fprintf(stderr, "%s - %s\n", file1_name, error_message(retval)); ext2fs_close(fs); return(retval); } /* now move the 2nd file to the 1st */ if ((retval = create_hard_link(fs, file1_dirno, file2_no, file1_name, force))) { fprintf(stderr, "Error renaming %s/%s as %s/%s\n", ((file2_dir == NULL) ? "." : file2_dir), file2_name, ((file1_dir == NULL) ? "." : file1_dir), file1_name); ext2fs_close(fs); return(1); } if ((retval = ext2fs_unlink(fs, file2_dirno, file2_name, 0, 0))) { fprintf(stderr, "%s - %s\n", file2_name, error_message(retval)); ext2fs_close(fs); return(retval); } if ((retval = create_hard_link(fs, file2_dirno, file1_no, file2_name, force))) { fprintf(stderr, "Error renaming %s/%s as %s/%s\n", ((file1_dir == NULL) ? "." : file1_dir), file1_name, ((file2_dir == NULL) ? "." : file2_dir), file2_name); ext2fs_close(fs); return(1); } if (verbose) fprintf(stderr, "swapped files %s/%s <-> %s/%s\n", ((file1_dir == NULL) ? "." : file1_dir), file1_name, ((file2_dir == NULL) ? "." : file2_dir), file2_name); } ext2fs_close(fs); return(0); } /* end of do_swap */
/* * This routine gets the lost_and_found inode, making it a directory * if necessary */ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) { ext2_filsys fs = ctx->fs; ext2_ino_t ino; blk64_t blk; errcode_t retval; struct ext2_inode inode; char * block; static const char name[] = "lost+found"; struct problem_context pctx; int will_rehash, flags; if (ctx->lost_and_found) return ctx->lost_and_found; clear_problem_context(&pctx); will_rehash = e2fsck_dir_will_be_rehashed(ctx, EXT2_ROOT_INO); if (will_rehash) { flags = ctx->fs->flags; ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; } retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, sizeof(name)-1, 0, &ino); if (will_rehash) ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) | (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS); if (retval && !fix) return 0; if (!retval) { /* Lost+found shouldn't have inline data */ retval = ext2fs_read_inode(fs, ino, &inode); if (fix && retval) return 0; if (fix && (inode.i_flags & EXT4_INLINE_DATA_FL)) { if (!fix_problem(ctx, PR_3_LPF_INLINE_DATA, &pctx)) return 0; goto unlink; } if (fix && (inode.i_flags & EXT4_ENCRYPT_FL)) { if (!fix_problem(ctx, PR_3_LPF_ENCRYPTED, &pctx)) return 0; goto unlink; } if (ext2fs_check_directory(fs, ino) == 0) { ctx->lost_and_found = ino; return ino; } /* Lost+found isn't a directory! */ if (!fix) return 0; pctx.ino = ino; if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx)) return 0; unlink: /* OK, unlink the old /lost+found file. */ pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0); if (pctx.errcode) { pctx.str = "ext2fs_unlink"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } (void) e2fsck_dir_info_set_parent(ctx, ino, 0); e2fsck_adjust_inode_count(ctx, ino, -1); /* * If the old lost+found was a directory, we've just * disconnected it from the directory tree, which * means we need to restart the directory tree scan. * The simplest way to do this is restart the whole * e2fsck operation. */ if (LINUX_S_ISDIR(inode.i_mode)) ctx->flags |= E2F_FLAG_RESTART; } else if (retval != EXT2_ET_FILE_NOT_FOUND) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); } if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) return 0; /* * Read the inode and block bitmaps in; we'll be messing with * them. */ e2fsck_read_bitmaps(ctx); /* * First, find a free block */ if (ctx->lnf_repair_block) { blk = ctx->lnf_repair_block; ctx->lnf_repair_block = 0; goto skip_new_block; } retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (retval == EXT2_ET_BLOCK_ALLOC_FAIL && fix_problem(ctx, PR_3_LPF_NO_SPACE, &pctx)) { fix_problem(ctx, PR_3_NO_SPACE_TO_RECOVER, &pctx); ctx->lost_and_found = EXT2_ROOT_INO; return 0; } if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); return 0; } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); skip_new_block: ext2fs_block_alloc_stats2(fs, blk, +1); /* * Next find a free inode. */ retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, ctx->inode_used_map, &ino); if (retval == EXT2_ET_INODE_ALLOC_FAIL && fix_problem(ctx, PR_3_LPF_NO_SPACE, &pctx)) { fix_problem(ctx, PR_3_NO_SPACE_TO_RECOVER, &pctx); ctx->lost_and_found = EXT2_ROOT_INO; return 0; } if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); return 0; } ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); /* * Set up the inode structure */ memset(&inode, 0, sizeof(inode)); inode.i_mode = 040700; inode.i_size = fs->blocksize; inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; inode.i_links_count = 2; ext2fs_iblk_set(fs, &inode, 1); inode.i_block[0] = blk; /* * Next, write out the inode. */ pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode); if (pctx.errcode) { pctx.str = "ext2fs_write_inode"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Now let's create the actual data block for the inode. * Due to metadata_csum, the directory block MUST be written * after the inode is written to disk! */ retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); return 0; } retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); ext2fs_free_mem(&block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); return 0; } /* * Finally, create the directory link */ pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); if (pctx.errcode == EXT2_ET_DIR_NO_SPACE) { pctx.errcode = ext2fs_expand_dir(fs, EXT2_ROOT_INO); if (pctx.errcode) goto link_error; pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); } if (pctx.errcode) { link_error: pctx.str = "ext2fs_link"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Miscellaneous bookkeeping that needs to be kept straight. */ e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO); e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1); ext2fs_icount_store(ctx->inode_count, ino, 2); ext2fs_icount_store(ctx->inode_link_info, ino, 2); ctx->lost_and_found = ino; quota_data_add(ctx->qctx, &inode, ino, fs->blocksize); quota_data_inodes(ctx->qctx, &inode, ino, +1); #if 0 printf("/lost+found created; inode #%lu\n", ino); #endif return ino; }