/*
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_format.h"
#include "xfs_log_format.h"
#include "xfs_trans_resv.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_mount.h"
#include "xfs_da_format.h"
#include "xfs_da_btree.h"
#include "xfs_inode.h"
#include "xfs_trans.h"
#include "xfs_inode_item.h"
#include "xfs_error.h"
#include "xfs_dir2.h"
#include "xfs_dir2_priv.h"
#include "xfs_trace.h"
#include "xfs_dinode.h"
/*
* Prototypes for internal functions.
*/
static void xfs_dir2_sf_addname_easy(xfs_da_args_t *args,
xfs_dir2_sf_entry_t *sfep,
xfs_dir2_data_aoff_t offset,
int new_isize);
static void xfs_dir2_sf_addname_hard(xfs_da_args_t *args, int objchange,
int new_isize);
static int xfs_dir2_sf_addname_pick(xfs_da_args_t *args, int objchange,
xfs_dir2_sf_entry_t **sfepp,
xfs_dir2_data_aoff_t *offsetp);
#ifdef DEBUG
static void xfs_dir2_sf_check(xfs_da_args_t *args);
#else
#define xfs_dir2_sf_check(args)
#endif /* DEBUG */
#if XFS_BIG_INUMS
static void xfs_dir2_sf_toino4(xfs_da_args_t *args);
static void xfs_dir2_sf_toino8(xfs_da_args_t *args);
#endif /* XFS_BIG_INUMS */
/*
* Given a block directory (dp/block), calculate its size as a shortform (sf)
* directory and a header for the sf directory, if it will fit it the
* space currently present in the inode. If it won't fit, the output
* size is too big (but not accurate).
*/
int /* size for sf form */
xfs_dir2_block_sfsize(
xfs_inode_t *dp, /* incore inode pointer */
xfs_dir2_data_hdr_t *hdr, /* block directory data */
xfs_dir2_sf_hdr_t *sfhp) /* output: header for sf form */
{
xfs_dir2_dataptr_t addr; /* data entry address */
xfs_dir2_leaf_entry_t *blp; /* leaf area of the block */
xfs_dir2_block_tail_t *btp; /* tail area of the block */
int count; /* shortform entry count */
xfs_dir2_data_entry_t *dep; /* data entry in the block */
int i; /* block entry index */
int i8count; /* count of big-inode entries */
int isdot; /* entry is "." */
int isdotdot; /* entry is ".." */
xfs_mount_t *mp; /* mount structure pointer */
int namelen; /* total name bytes */
xfs_ino_t parent = 0; /* parent inode number */
int size=0; /* total computed size */
int has_ftype;
struct xfs_da_geometry *geo;
mp = dp->i_mount;
geo = mp->m_dir_geo;
/*
* if there is a filetype field, add the extra byte to the namelen
* for each entry that we see.
*/
has_ftype = xfs_sb_version_hasftype(&mp->m_sb) ? 1 : 0;
count = i8count = namelen = 0;
btp = xfs_dir2_block_tail_p(geo, hdr);
blp = xfs_dir2_block_leaf_p(btp);
/*
* Iterate over the block's data entries by using the leaf pointers.
*/
for (i = 0; i < be32_to_cpu(btp->count); i++) {
if ((addr = be32_to_cpu(blp[i].address)) == XFS_DIR2_NULL_DATAPTR)
continue;
/*
* Calculate the pointer to the entry at hand.
*/
dep = (xfs_dir2_data_entry_t *)((char *)hdr +
xfs_dir2_dataptr_to_off(geo, addr));
/*
* Detect . and .., so we can special-case them.
* . is not included in sf directories.
* .. is included by just the parent inode number.
*/
isdot = dep->namelen == 1 && dep->name[0] == '.';
isdotdot =
dep->namelen == 2 &&
dep->name[0] ==