360 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2/*3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.4 * All Rights Reserved.5 */6#ifndef __XFS_DIR2_H__7#define __XFS_DIR2_H__8 9#include "xfs_da_format.h"10#include "xfs_da_btree.h"11 12struct xfs_da_args;13struct xfs_inode;14struct xfs_mount;15struct xfs_trans;16struct xfs_dir2_sf_hdr;17struct xfs_dir2_sf_entry;18struct xfs_dir2_data_hdr;19struct xfs_dir2_data_entry;20struct xfs_dir2_data_unused;21struct xfs_dir3_icfree_hdr;22struct xfs_dir3_icleaf_hdr;23 24extern const struct xfs_name xfs_name_dotdot;25extern const struct xfs_name xfs_name_dot;26 27static inline bool28xfs_dir2_samename(29 const struct xfs_name *n1,30 const struct xfs_name *n2)31{32 if (n1 == n2)33 return true;34 if (n1->len != n2->len)35 return false;36 return !memcmp(n1->name, n2->name, n1->len);37}38 39enum xfs_dir2_fmt {40 XFS_DIR2_FMT_SF,41 XFS_DIR2_FMT_BLOCK,42 XFS_DIR2_FMT_LEAF,43 XFS_DIR2_FMT_NODE,44 XFS_DIR2_FMT_ERROR,45};46 47enum xfs_dir2_fmt xfs_dir2_format(struct xfs_da_args *args, int *error);48 49/*50 * Convert inode mode to directory entry filetype51 */52extern unsigned char xfs_mode_to_ftype(int mode);53 54/*55 * Generic directory interface routines56 */57extern void xfs_dir_startup(void);58extern int xfs_da_mount(struct xfs_mount *mp);59extern void xfs_da_unmount(struct xfs_mount *mp);60 61extern int xfs_dir_isempty(struct xfs_inode *dp);62extern int xfs_dir_init(struct xfs_trans *tp, struct xfs_inode *dp,63 struct xfs_inode *pdp);64extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp,65 const struct xfs_name *name, xfs_ino_t inum,66 xfs_extlen_t tot);67extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,68 const struct xfs_name *name, xfs_ino_t *inum,69 struct xfs_name *ci_name);70extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,71 const struct xfs_name *name, xfs_ino_t ino,72 xfs_extlen_t tot);73extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,74 const struct xfs_name *name, xfs_ino_t inum,75 xfs_extlen_t tot);76extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,77 const struct xfs_name *name);78 79int xfs_dir_lookup_args(struct xfs_da_args *args);80int xfs_dir_createname_args(struct xfs_da_args *args);81int xfs_dir_removename_args(struct xfs_da_args *args);82int xfs_dir_replace_args(struct xfs_da_args *args);83 84/*85 * Direct call from the bmap code, bypassing the generic directory layer.86 */87extern int xfs_dir2_sf_to_block(struct xfs_da_args *args);88 89/*90 * Interface routines used by userspace utilities91 */92extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db,93 struct xfs_buf *bp);94 95extern void xfs_dir2_data_freescan(struct xfs_mount *mp,96 struct xfs_dir2_data_hdr *hdr, int *loghead);97extern void xfs_dir2_data_log_entry(struct xfs_da_args *args,98 struct xfs_buf *bp, struct xfs_dir2_data_entry *dep);99extern void xfs_dir2_data_log_header(struct xfs_da_args *args,100 struct xfs_buf *bp);101extern void xfs_dir2_data_log_unused(struct xfs_da_args *args,102 struct xfs_buf *bp, struct xfs_dir2_data_unused *dup);103extern void xfs_dir2_data_make_free(struct xfs_da_args *args,104 struct xfs_buf *bp, xfs_dir2_data_aoff_t offset,105 xfs_dir2_data_aoff_t len, int *needlogp, int *needscanp);106extern int xfs_dir2_data_use_free(struct xfs_da_args *args,107 struct xfs_buf *bp, struct xfs_dir2_data_unused *dup,108 xfs_dir2_data_aoff_t offset, xfs_dir2_data_aoff_t len,109 int *needlogp, int *needscanp);110 111extern struct xfs_dir2_data_free *xfs_dir2_data_freefind(112 struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf,113 struct xfs_dir2_data_unused *dup);114 115extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino);116 117xfs_failaddr_t xfs_dir3_leaf_header_check(struct xfs_buf *bp, xfs_ino_t owner);118xfs_failaddr_t xfs_dir3_data_header_check(struct xfs_buf *bp, xfs_ino_t owner);119xfs_failaddr_t xfs_dir3_block_header_check(struct xfs_buf *bp, xfs_ino_t owner);120 121extern const struct xfs_buf_ops xfs_dir3_block_buf_ops;122extern const struct xfs_buf_ops xfs_dir3_leafn_buf_ops;123extern const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops;124extern const struct xfs_buf_ops xfs_dir3_free_buf_ops;125extern const struct xfs_buf_ops xfs_dir3_data_buf_ops;126 127/*128 * Directory offset/block conversion functions.129 *130 * DB blocks here are logical directory block numbers, not filesystem blocks.131 */132 133/*134 * Convert dataptr to byte in file space135 */136static inline xfs_dir2_off_t137xfs_dir2_dataptr_to_byte(xfs_dir2_dataptr_t dp)138{139 return (xfs_dir2_off_t)dp << XFS_DIR2_DATA_ALIGN_LOG;140}141 142/*143 * Convert byte in file space to dataptr. It had better be aligned.144 */145static inline xfs_dir2_dataptr_t146xfs_dir2_byte_to_dataptr(xfs_dir2_off_t by)147{148 return (xfs_dir2_dataptr_t)(by >> XFS_DIR2_DATA_ALIGN_LOG);149}150 151/*152 * Convert byte in space to (DB) block153 */154static inline xfs_dir2_db_t155xfs_dir2_byte_to_db(struct xfs_da_geometry *geo, xfs_dir2_off_t by)156{157 return (xfs_dir2_db_t)(by >> geo->blklog);158}159 160/*161 * Convert dataptr to a block number162 */163static inline xfs_dir2_db_t164xfs_dir2_dataptr_to_db(struct xfs_da_geometry *geo, xfs_dir2_dataptr_t dp)165{166 return xfs_dir2_byte_to_db(geo, xfs_dir2_dataptr_to_byte(dp));167}168 169/*170 * Convert byte in space to offset in a block171 */172static inline xfs_dir2_data_aoff_t173xfs_dir2_byte_to_off(struct xfs_da_geometry *geo, xfs_dir2_off_t by)174{175 return (xfs_dir2_data_aoff_t)(by & (geo->blksize - 1));176}177 178/*179 * Convert dataptr to a byte offset in a block180 */181static inline xfs_dir2_data_aoff_t182xfs_dir2_dataptr_to_off(struct xfs_da_geometry *geo, xfs_dir2_dataptr_t dp)183{184 return xfs_dir2_byte_to_off(geo, xfs_dir2_dataptr_to_byte(dp));185}186 187/*188 * Convert block and offset to byte in space189 */190static inline xfs_dir2_off_t191xfs_dir2_db_off_to_byte(struct xfs_da_geometry *geo, xfs_dir2_db_t db,192 xfs_dir2_data_aoff_t o)193{194 return ((xfs_dir2_off_t)db << geo->blklog) + o;195}196 197/*198 * Convert block (DB) to block (dablk)199 */200static inline xfs_dablk_t201xfs_dir2_db_to_da(struct xfs_da_geometry *geo, xfs_dir2_db_t db)202{203 return (xfs_dablk_t)(db << (geo->blklog - geo->fsblog));204}205 206/*207 * Convert byte in space to (DA) block208 */209static inline xfs_dablk_t210xfs_dir2_byte_to_da(struct xfs_da_geometry *geo, xfs_dir2_off_t by)211{212 return xfs_dir2_db_to_da(geo, xfs_dir2_byte_to_db(geo, by));213}214 215/*216 * Convert block and offset to dataptr217 */218static inline xfs_dir2_dataptr_t219xfs_dir2_db_off_to_dataptr(struct xfs_da_geometry *geo, xfs_dir2_db_t db,220 xfs_dir2_data_aoff_t o)221{222 return xfs_dir2_byte_to_dataptr(xfs_dir2_db_off_to_byte(geo, db, o));223}224 225/*226 * Convert block (dablk) to block (DB)227 */228static inline xfs_dir2_db_t229xfs_dir2_da_to_db(struct xfs_da_geometry *geo, xfs_dablk_t da)230{231 return (xfs_dir2_db_t)(da >> (geo->blklog - geo->fsblog));232}233 234/*235 * Convert block (dablk) to byte offset in space236 */237static inline xfs_dir2_off_t238xfs_dir2_da_to_byte(struct xfs_da_geometry *geo, xfs_dablk_t da)239{240 return xfs_dir2_db_off_to_byte(geo, xfs_dir2_da_to_db(geo, da), 0);241}242 243/*244 * Directory tail pointer accessor functions. Based on block geometry.245 */246static inline struct xfs_dir2_block_tail *247xfs_dir2_block_tail_p(struct xfs_da_geometry *geo, struct xfs_dir2_data_hdr *hdr)248{249 return ((struct xfs_dir2_block_tail *)250 ((char *)hdr + geo->blksize)) - 1;251}252 253static inline struct xfs_dir2_leaf_tail *254xfs_dir2_leaf_tail_p(struct xfs_da_geometry *geo, struct xfs_dir2_leaf *lp)255{256 return (struct xfs_dir2_leaf_tail *)257 ((char *)lp + geo->blksize -258 sizeof(struct xfs_dir2_leaf_tail));259}260 261/*262 * The Linux API doesn't pass down the total size of the buffer263 * we read into down to the filesystem. With the filldir concept264 * it's not needed for correct information, but the XFS dir2 leaf265 * code wants an estimate of the buffer size to calculate it's266 * readahead window and size the buffers used for mapping to267 * physical blocks.268 *269 * Try to give it an estimate that's good enough, maybe at some270 * point we can change the ->readdir prototype to include the271 * buffer size. For now we use the current glibc buffer size.272 * musl libc hardcodes 2k and dietlibc uses PAGE_SIZE.273 */274#define XFS_READDIR_BUFSIZE (32768)275 276unsigned char xfs_dir3_get_dtype(struct xfs_mount *mp, uint8_t filetype);277unsigned int xfs_dir3_data_end_offset(struct xfs_da_geometry *geo,278 struct xfs_dir2_data_hdr *hdr);279bool xfs_dir2_namecheck(const void *name, size_t length);280 281/*282 * The "ascii-ci" feature was created to speed up case-insensitive lookups for283 * a Samba product. Because of the inherent problems with CI and UTF-8284 * encoding, etc, it was decided that Samba would be configured to export285 * latin1/iso 8859-1 encodings as that covered >90% of the target markets for286 * the product. Hence the "ascii-ci" casefolding code could be encoded into287 * the XFS directory operations and remove all the overhead of casefolding from288 * Samba.289 *290 * To provide consistent hashing behavior between the userspace and kernel,291 * these functions prepare names for hashing by transforming specific bytes292 * to other bytes. Robustness with other encodings is not guaranteed.293 */294static inline bool xfs_ascii_ci_need_xfrm(unsigned char c)295{296 if (c >= 0x41 && c <= 0x5a) /* A-Z */297 return true;298 if (c >= 0xc0 && c <= 0xd6) /* latin A-O with accents */299 return true;300 if (c >= 0xd8 && c <= 0xde) /* latin O-Y with accents */301 return true;302 return false;303}304 305static inline unsigned char xfs_ascii_ci_xfrm(unsigned char c)306{307 if (xfs_ascii_ci_need_xfrm(c))308 c -= 'A' - 'a';309 return c;310}311 312struct xfs_dir_update_params {313 const struct xfs_inode *dp;314 const struct xfs_inode *ip;315 const struct xfs_name *name;316 int delta;317};318 319#ifdef CONFIG_XFS_LIVE_HOOKS320void xfs_dir_update_hook(struct xfs_inode *dp, struct xfs_inode *ip,321 int delta, const struct xfs_name *name);322 323struct xfs_dir_hook {324 struct xfs_hook dirent_hook;325};326 327void xfs_dir_hook_disable(void);328void xfs_dir_hook_enable(void);329 330int xfs_dir_hook_add(struct xfs_mount *mp, struct xfs_dir_hook *hook);331void xfs_dir_hook_del(struct xfs_mount *mp, struct xfs_dir_hook *hook);332void xfs_dir_hook_setup(struct xfs_dir_hook *hook, notifier_fn_t mod_fn);333#else334# define xfs_dir_update_hook(dp, ip, delta, name) ((void)0)335#endif /* CONFIG_XFS_LIVE_HOOKS */336 337struct xfs_parent_args;338 339struct xfs_dir_update {340 struct xfs_inode *dp;341 const struct xfs_name *name;342 struct xfs_inode *ip;343 struct xfs_parent_args *ppargs;344};345 346int xfs_dir_create_child(struct xfs_trans *tp, unsigned int resblks,347 struct xfs_dir_update *du);348int xfs_dir_add_child(struct xfs_trans *tp, unsigned int resblks,349 struct xfs_dir_update *du);350int xfs_dir_remove_child(struct xfs_trans *tp, unsigned int resblks,351 struct xfs_dir_update *du);352 353int xfs_dir_exchange_children(struct xfs_trans *tp, struct xfs_dir_update *du1,354 struct xfs_dir_update *du2, unsigned int spaceres);355int xfs_dir_rename_children(struct xfs_trans *tp, struct xfs_dir_update *du_src,356 struct xfs_dir_update *du_tgt, unsigned int spaceres,357 struct xfs_dir_update *du_wip);358 359#endif /* __XFS_DIR2_H__ */360