errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir) { errcode_t retval; struct expand_dir_struct es; struct ext2_inode inode; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); if (!(fs->flags & EXT2_FLAG_RW)) return EXT2_ET_RO_FILSYS; if (!fs->block_map) return EXT2_ET_NO_BLOCK_BITMAP; retval = ext2fs_check_directory(fs, dir); if (retval) return retval; es.done = 0; es.err = 0; es.goal = 0; es.newblocks = 0; es.dir = dir; retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND, 0, expand_dir_proc, &es); if (es.err) return es.err; if (!es.done) return EXT2_ET_EXPAND_DIR_ERR; /* * Update the size and block count fields in the inode. */ retval = ext2fs_read_inode(fs, dir, &inode); if (retval) return retval; inode.i_size += fs->blocksize; ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); retval = ext2fs_write_inode(fs, dir, &inode); if (retval) return retval; return 0; }
errcode_t ext2fs_dir_iterate2(ext2_filsys fs, ext2_ino_t dir, int flags, char *block_buf, int (*func)(ext2_ino_t dir, int entry, struct ext2_dir_entry *dirent, int offset, int blocksize, char *buf, void *priv_data), void *priv_data) { struct dir_context ctx; errcode_t retval; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); retval = ext2fs_check_directory(fs, dir); if (retval) return retval; ctx.dir = dir; ctx.flags = flags; if (block_buf) ctx.buf = block_buf; else { retval = ext2fs_get_mem(fs->blocksize, (void **) &ctx.buf); if (retval) return retval; } ctx.func = func; ctx.priv_data = priv_data; ctx.errcode = 0; retval = ext2fs_block_iterate2(fs, dir, 0, 0, ext2fs_process_dir_block, &ctx); if (!block_buf) ext2fs_free_mem((void **) &ctx.buf); if (retval) return retval; return ctx.errcode; }
/* * 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: create_hard_link() * * Description: * * This function creates a hard link to an existing file * * Algorithm: * * Check input parameters * Check to see if the new file name already exists * Make sure the new file is not an existing directory * If the file exists, remove it if the del_current flag is set * Add the new file name and it's inode to the current directory. * Get the inode structure for the current inode number * update the number of links * Write the inode structure back out to the file system. * * Global Variables: * * None. * * Arguments: * * ext2_filsys fs; The current file system * ext2_ino_t cwd; The current working directory * ext2_ino_t new_file_ino; The inode number of the new file * char *newfile; The name of the new file * int ln_flags; Flags affecting hard_link action * * Return Values: * * 0 - the new file link was created successfully * any other value indicates an error * * Author: Keith W. Sheffield * Date: 03/05/2002 * * Modification History: * * MM/DD/YY Name Description * 06/30/02 K.Sheffield Directory link flag is now based on the * type of file being linked. This was * causing problems if a directory was * renamed. */ long create_hard_link(ext2_filsys fs, ext2_ino_t cwd, ext2_ino_t new_file_ino, char *newfile, int ln_flags) { ext2_ino_t curr_ino; struct ext2_inode inode; long retval; int dir_flag; if (fs == NULL || newfile == NULL) { fputs("Invalid input parameter. Exiting create_hard_link() with -1\n", stderr); return (-1); } /* check to see if the file name already exists in the current directory */ if ((retval = ext2fs_namei(fs, cwd, cwd, newfile, &curr_ino))) { if (retval != EXT2_ET_FILE_NOT_FOUND) { fprintf(stderr, "%s\n",error_message(retval)); return(retval); } } /* file name exists, let's see if is a directory */ else if ((retval = ext2fs_check_directory(fs, curr_ino))) { if (retval != EXT2_ET_NO_DIRECTORY) { fprintf(stderr, "%s\n",error_message(retval)); return(retval); } /* delete the existing file if needed */ if ((ln_flags & E2T_FORCE) && (curr_ino != new_file_ino)) { if ((retval = rm_file(fs, cwd, newfile, curr_ino))) { fprintf(stderr, "%s\n",error_message(retval)); return(retval); } } else { fprintf(stderr, "ln: %s: File exists\n", newfile); return(1); } } else { /* if we get here, then it's an existing directory */ fprintf(stderr, "%s is a directory!\n", newfile); return(1); } /* read the inode associated with the file */ if ((retval = read_inode(fs, new_file_ino, &inode))) { fprintf(stderr, "%s\n", error_message(retval)); return (retval); } /* determine how to link into the directory based on the type of file */ switch(inode.i_mode & LINUX_S_IFMT) { case LINUX_S_IFREG: dir_flag = EXT2_FT_REG_FILE; break; case LINUX_S_IFLNK: dir_flag = EXT2_FT_SYMLINK; break; case LINUX_S_IFDIR: dir_flag = EXT2_FT_DIR; break; case LINUX_S_IFSOCK: dir_flag = EXT2_FT_SOCK; break; case LINUX_S_IFBLK: dir_flag = EXT2_FT_BLKDEV; break; case LINUX_S_IFCHR: dir_flag = EXT2_FT_CHRDEV; break; case LINUX_S_IFIFO: dir_flag = EXT2_FT_FIFO; break; default: dir_flag = EXT2_FT_UNKNOWN; break; } if ((retval = ext2fs_link(fs, cwd, newfile, new_file_ino, dir_flag))) { /* check to see if we ran out of space in the directory */ if (retval == EXT2_ET_DIR_NO_SPACE) { /* try resizing the directory and try again */ if (0 == (retval = ext2fs_expand_dir(fs, cwd))) retval = ext2fs_link(fs, cwd, newfile, new_file_ino, dir_flag); } if (retval) { fprintf(stderr, "%s\n", error_message(retval)); return retval; } } /* update the inode stat information */ if ((ln_flags & E2T_DO_MV) == 0) { inode.i_links_count++; if ((retval = write_inode(fs, new_file_ino, &inode))) { fprintf(stderr, "%s\n", error_message(retval)); return (retval); } } return(0); } /* end of create_hard_link */
/* 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 */
/* * 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; }