Exemplo n.º 1
0
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;
}
Exemplo n.º 2
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;
}
Exemplo n.º 3
0
/*
 * 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;
}
Exemplo n.º 4
0
Arquivo: ln.c Projeto: er13/e2tools
/* 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 */
Exemplo n.º 5
0
Arquivo: mv.c Projeto: e2tools/e2tools
/* 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 */
Exemplo n.º 6
0
/*
 * 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;
}