diff options
Diffstat (limited to 'fs/hfs')
| -rw-r--r-- | fs/hfs/.kunitconfig | 7 | ||||
| -rw-r--r-- | fs/hfs/Kconfig | 15 | ||||
| -rw-r--r-- | fs/hfs/Makefile | 2 | ||||
| -rw-r--r-- | fs/hfs/bfind.c | 2 | ||||
| -rw-r--r-- | fs/hfs/bnode.c | 52 | ||||
| -rw-r--r-- | fs/hfs/brec.c | 2 | ||||
| -rw-r--r-- | fs/hfs/btree.c | 2 | ||||
| -rw-r--r-- | fs/hfs/btree.h | 113 | ||||
| -rw-r--r-- | fs/hfs/catalog.c | 2 | ||||
| -rw-r--r-- | fs/hfs/hfs.h | 269 | ||||
| -rw-r--r-- | fs/hfs/hfs_fs.h | 89 | ||||
| -rw-r--r-- | fs/hfs/inode.c | 3 | ||||
| -rw-r--r-- | fs/hfs/string.c | 5 | ||||
| -rw-r--r-- | fs/hfs/string_test.c | 133 |
14 files changed, 283 insertions, 413 deletions
diff --git a/fs/hfs/.kunitconfig b/fs/hfs/.kunitconfig new file mode 100644 index 000000000000..5caa9af1e3bb --- /dev/null +++ b/fs/hfs/.kunitconfig @@ -0,0 +1,7 @@ +CONFIG_KUNIT=y +CONFIG_HFS_FS=y +CONFIG_HFS_KUNIT_TEST=y +CONFIG_BLOCK=y +CONFIG_BUFFER_HEAD=y +CONFIG_NLS=y +CONFIG_LEGACY_DIRECT_IO=y diff --git a/fs/hfs/Kconfig b/fs/hfs/Kconfig index 5ea5cd8ecea9..7f3cbe43b4b7 100644 --- a/fs/hfs/Kconfig +++ b/fs/hfs/Kconfig @@ -13,3 +13,18 @@ config HFS_FS To compile this file system support as a module, choose M here: the module will be called hfs. + +config HFS_KUNIT_TEST + tristate "KUnit tests for HFS filesystem" if !KUNIT_ALL_TESTS + depends on HFS_FS && KUNIT + default KUNIT_ALL_TESTS + help + This builds KUnit tests for the HFS filesystem. + + KUnit tests run during boot and output the results to the debug + log in TAP format (https://testanything.org/). Only useful for + kernel devs running KUnit test harness and are not for inclusion + into a production build. + + For more information on KUnit and unit tests in general please + refer to the KUnit documentation in Documentation/dev-tools/kunit/. diff --git a/fs/hfs/Makefile b/fs/hfs/Makefile index b65459bf3dc4..a7c9ce6b4609 100644 --- a/fs/hfs/Makefile +++ b/fs/hfs/Makefile @@ -9,3 +9,5 @@ hfs-objs := bitmap.o bfind.o bnode.o brec.o btree.o \ catalog.o dir.o extent.o inode.o attr.o mdb.o \ part_tbl.o string.o super.o sysdep.o trans.o +# KUnit tests +obj-$(CONFIG_HFS_KUNIT_TEST) += string_test.o diff --git a/fs/hfs/bfind.c b/fs/hfs/bfind.c index c2f840c49e60..d56e47bdc517 100644 --- a/fs/hfs/bfind.c +++ b/fs/hfs/bfind.c @@ -167,7 +167,7 @@ release: return res; } -int hfs_brec_read(struct hfs_find_data *fd, void *rec, int rec_len) +int hfs_brec_read(struct hfs_find_data *fd, void *rec, u32 rec_len) { int res; diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c index fcfffe75d84e..13d58c51fc46 100644 --- a/fs/hfs/bnode.c +++ b/fs/hfs/bnode.c @@ -16,14 +16,14 @@ #include "btree.h" static inline -bool is_bnode_offset_valid(struct hfs_bnode *node, int off) +bool is_bnode_offset_valid(struct hfs_bnode *node, u32 off) { bool is_valid = off < node->tree->node_size; if (!is_valid) { pr_err("requested invalid offset: " "NODE: id %u, type %#x, height %u, " - "node_size %u, offset %d\n", + "node_size %u, offset %u\n", node->this, node->type, node->height, node->tree->node_size, off); } @@ -32,7 +32,7 @@ bool is_bnode_offset_valid(struct hfs_bnode *node, int off) } static inline -int check_and_correct_requested_length(struct hfs_bnode *node, int off, int len) +u32 check_and_correct_requested_length(struct hfs_bnode *node, u32 off, u32 len) { unsigned int node_size; @@ -42,12 +42,12 @@ int check_and_correct_requested_length(struct hfs_bnode *node, int off, int len) node_size = node->tree->node_size; if ((off + len) > node_size) { - int new_len = (int)node_size - off; + u32 new_len = node_size - off; pr_err("requested length has been corrected: " "NODE: id %u, type %#x, height %u, " - "node_size %u, offset %d, " - "requested_len %d, corrected_len %d\n", + "node_size %u, offset %u, " + "requested_len %u, corrected_len %u\n", node->this, node->type, node->height, node->tree->node_size, off, len, new_len); @@ -57,12 +57,12 @@ int check_and_correct_requested_length(struct hfs_bnode *node, int off, int len) return len; } -void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len) +void hfs_bnode_read(struct hfs_bnode *node, void *buf, u32 off, u32 len) { struct page *page; - int pagenum; - int bytes_read; - int bytes_to_read; + u32 pagenum; + u32 bytes_read; + u32 bytes_to_read; if (!is_bnode_offset_valid(node, off)) return; @@ -70,7 +70,7 @@ void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len) if (len == 0) { pr_err("requested zero length: " "NODE: id %u, type %#x, height %u, " - "node_size %u, offset %d, len %d\n", + "node_size %u, offset %u, len %u\n", node->this, node->type, node->height, node->tree->node_size, off, len); return; @@ -86,7 +86,7 @@ void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len) if (pagenum >= node->tree->pages_per_bnode) break; page = node->page[pagenum]; - bytes_to_read = min_t(int, len - bytes_read, PAGE_SIZE - off); + bytes_to_read = min_t(u32, len - bytes_read, PAGE_SIZE - off); memcpy_from_page(buf + bytes_read, page, off, bytes_to_read); @@ -95,7 +95,7 @@ void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len) } } -u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off) +u16 hfs_bnode_read_u16(struct hfs_bnode *node, u32 off) { __be16 data; // optimize later... @@ -103,7 +103,7 @@ u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off) return be16_to_cpu(data); } -u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off) +u8 hfs_bnode_read_u8(struct hfs_bnode *node, u32 off) { u8 data; // optimize later... @@ -111,10 +111,10 @@ u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off) return data; } -void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off) +void hfs_bnode_read_key(struct hfs_bnode *node, void *key, u32 off) { struct hfs_btree *tree; - int key_len; + u32 key_len; tree = node->tree; if (node->type == HFS_NODE_LEAF || @@ -125,14 +125,14 @@ void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off) if (key_len > sizeof(hfs_btree_key) || key_len < 1) { memset(key, 0, sizeof(hfs_btree_key)); - pr_err("hfs: Invalid key length: %d\n", key_len); + pr_err("hfs: Invalid key length: %u\n", key_len); return; } hfs_bnode_read(node, key, off, key_len); } -void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len) +void hfs_bnode_write(struct hfs_bnode *node, void *buf, u32 off, u32 len) { struct page *page; @@ -142,7 +142,7 @@ void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len) if (len == 0) { pr_err("requested zero length: " "NODE: id %u, type %#x, height %u, " - "node_size %u, offset %d, len %d\n", + "node_size %u, offset %u, len %u\n", node->this, node->type, node->height, node->tree->node_size, off, len); return; @@ -157,20 +157,20 @@ void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len) set_page_dirty(page); } -void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data) +void hfs_bnode_write_u16(struct hfs_bnode *node, u32 off, u16 data) { __be16 v = cpu_to_be16(data); // optimize later... hfs_bnode_write(node, &v, off, 2); } -void hfs_bnode_write_u8(struct hfs_bnode *node, int off, u8 data) +void hfs_bnode_write_u8(struct hfs_bnode *node, u32 off, u8 data) { // optimize later... hfs_bnode_write(node, &data, off, 1); } -void hfs_bnode_clear(struct hfs_bnode *node, int off, int len) +void hfs_bnode_clear(struct hfs_bnode *node, u32 off, u32 len) { struct page *page; @@ -180,7 +180,7 @@ void hfs_bnode_clear(struct hfs_bnode *node, int off, int len) if (len == 0) { pr_err("requested zero length: " "NODE: id %u, type %#x, height %u, " - "node_size %u, offset %d, len %d\n", + "node_size %u, offset %u, len %u\n", node->this, node->type, node->height, node->tree->node_size, off, len); return; @@ -195,8 +195,8 @@ void hfs_bnode_clear(struct hfs_bnode *node, int off, int len) set_page_dirty(page); } -void hfs_bnode_copy(struct hfs_bnode *dst_node, int dst, - struct hfs_bnode *src_node, int src, int len) +void hfs_bnode_copy(struct hfs_bnode *dst_node, u32 dst, + struct hfs_bnode *src_node, u32 src, u32 len) { struct page *src_page, *dst_page; @@ -216,7 +216,7 @@ void hfs_bnode_copy(struct hfs_bnode *dst_node, int dst, set_page_dirty(dst_page); } -void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len) +void hfs_bnode_move(struct hfs_bnode *node, u32 dst, u32 src, u32 len) { struct page *page; void *ptr; diff --git a/fs/hfs/brec.c b/fs/hfs/brec.c index e49a141c87e5..5a2f740ddefd 100644 --- a/fs/hfs/brec.c +++ b/fs/hfs/brec.c @@ -62,7 +62,7 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec) return retval; } -int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len) +int hfs_brec_insert(struct hfs_find_data *fd, void *entry, u32 entry_len) { struct hfs_btree *tree; struct hfs_bnode *node, *new_node; diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c index 54c20d01c342..7bc425283d49 100644 --- a/fs/hfs/btree.c +++ b/fs/hfs/btree.c @@ -259,7 +259,7 @@ static struct hfs_bnode *hfs_bmap_new_bmap(struct hfs_bnode *prev, u32 idx) } /* Make sure @tree has enough space for the @rsvd_nodes */ -int hfs_bmap_reserve(struct hfs_btree *tree, int rsvd_nodes) +int hfs_bmap_reserve(struct hfs_btree *tree, u32 rsvd_nodes) { struct inode *inode = tree->inode; u32 count; diff --git a/fs/hfs/btree.h b/fs/hfs/btree.h index 0e6baee93245..99be858b2446 100644 --- a/fs/hfs/btree.h +++ b/fs/hfs/btree.h @@ -86,87 +86,46 @@ struct hfs_find_data { /* btree.c */ -extern struct hfs_btree *hfs_btree_open(struct super_block *, u32, btree_keycmp); -extern void hfs_btree_close(struct hfs_btree *); -extern void hfs_btree_write(struct hfs_btree *); -extern int hfs_bmap_reserve(struct hfs_btree *, int); -extern struct hfs_bnode * hfs_bmap_alloc(struct hfs_btree *); +extern struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, + btree_keycmp keycmp); +extern void hfs_btree_close(struct hfs_btree *tree); +extern void hfs_btree_write(struct hfs_btree *tree); +extern int hfs_bmap_reserve(struct hfs_btree *tree, u32 rsvd_nodes); +extern struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree); extern void hfs_bmap_free(struct hfs_bnode *node); /* bnode.c */ -extern void hfs_bnode_read(struct hfs_bnode *, void *, int, int); -extern u16 hfs_bnode_read_u16(struct hfs_bnode *, int); -extern u8 hfs_bnode_read_u8(struct hfs_bnode *, int); -extern void hfs_bnode_read_key(struct hfs_bnode *, void *, int); -extern void hfs_bnode_write(struct hfs_bnode *, void *, int, int); -extern void hfs_bnode_write_u16(struct hfs_bnode *, int, u16); -extern void hfs_bnode_write_u8(struct hfs_bnode *, int, u8); -extern void hfs_bnode_clear(struct hfs_bnode *, int, int); -extern void hfs_bnode_copy(struct hfs_bnode *, int, - struct hfs_bnode *, int, int); -extern void hfs_bnode_move(struct hfs_bnode *, int, int, int); -extern void hfs_bnode_dump(struct hfs_bnode *); -extern void hfs_bnode_unlink(struct hfs_bnode *); -extern struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *, u32); -extern struct hfs_bnode *hfs_bnode_find(struct hfs_btree *, u32); -extern void hfs_bnode_unhash(struct hfs_bnode *); -extern void hfs_bnode_free(struct hfs_bnode *); -extern struct hfs_bnode *hfs_bnode_create(struct hfs_btree *, u32); -extern void hfs_bnode_get(struct hfs_bnode *); -extern void hfs_bnode_put(struct hfs_bnode *); +extern void hfs_bnode_read(struct hfs_bnode *node, void *buf, u32 off, u32 len); +extern u16 hfs_bnode_read_u16(struct hfs_bnode *node, u32 off); +extern u8 hfs_bnode_read_u8(struct hfs_bnode *node, u32 off); +extern void hfs_bnode_read_key(struct hfs_bnode *node, void *key, u32 off); +extern void hfs_bnode_write(struct hfs_bnode *node, void *buf, u32 off, u32 len); +extern void hfs_bnode_write_u16(struct hfs_bnode *node, u32 off, u16 data); +extern void hfs_bnode_write_u8(struct hfs_bnode *node, u32 off, u8 data); +extern void hfs_bnode_clear(struct hfs_bnode *node, u32 off, u32 len); +extern void hfs_bnode_copy(struct hfs_bnode *dst_node, u32 dst, + struct hfs_bnode *src_node, u32 src, u32 len); +extern void hfs_bnode_move(struct hfs_bnode *node, u32 dst, u32 src, u32 len); +extern void hfs_bnode_dump(struct hfs_bnode *node); +extern void hfs_bnode_unlink(struct hfs_bnode *node); +extern struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid); +extern struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num); +extern void hfs_bnode_unhash(struct hfs_bnode *node); +extern void hfs_bnode_free(struct hfs_bnode *node); +extern struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num); +extern void hfs_bnode_get(struct hfs_bnode *node); +extern void hfs_bnode_put(struct hfs_bnode *node); /* brec.c */ -extern u16 hfs_brec_lenoff(struct hfs_bnode *, u16, u16 *); -extern u16 hfs_brec_keylen(struct hfs_bnode *, u16); -extern int hfs_brec_insert(struct hfs_find_data *, void *, int); -extern int hfs_brec_remove(struct hfs_find_data *); +extern u16 hfs_brec_lenoff(struct hfs_bnode *node, u16 rec, u16 *off); +extern u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec); +extern int hfs_brec_insert(struct hfs_find_data *fd, void *entry, u32 entry_len); +extern int hfs_brec_remove(struct hfs_find_data *fd); /* bfind.c */ -extern int hfs_find_init(struct hfs_btree *, struct hfs_find_data *); -extern void hfs_find_exit(struct hfs_find_data *); -extern int __hfs_brec_find(struct hfs_bnode *, struct hfs_find_data *); -extern int hfs_brec_find(struct hfs_find_data *); -extern int hfs_brec_read(struct hfs_find_data *, void *, int); -extern int hfs_brec_goto(struct hfs_find_data *, int); - - -struct hfs_bnode_desc { - __be32 next; /* (V) Number of the next node at this level */ - __be32 prev; /* (V) Number of the prev node at this level */ - u8 type; /* (F) The type of node */ - u8 height; /* (F) The level of this node (leaves=1) */ - __be16 num_recs; /* (V) The number of records in this node */ - u16 reserved; -} __packed; - -#define HFS_NODE_INDEX 0x00 /* An internal (index) node */ -#define HFS_NODE_HEADER 0x01 /* The tree header node (node 0) */ -#define HFS_NODE_MAP 0x02 /* Holds part of the bitmap of used nodes */ -#define HFS_NODE_LEAF 0xFF /* A leaf (ndNHeight==1) node */ - -struct hfs_btree_header_rec { - __be16 depth; /* (V) The number of levels in this B-tree */ - __be32 root; /* (V) The node number of the root node */ - __be32 leaf_count; /* (V) The number of leaf records */ - __be32 leaf_head; /* (V) The number of the first leaf node */ - __be32 leaf_tail; /* (V) The number of the last leaf node */ - __be16 node_size; /* (F) The number of bytes in a node (=512) */ - __be16 max_key_len; /* (F) The length of a key in an index node */ - __be32 node_count; /* (V) The total number of nodes */ - __be32 free_nodes; /* (V) The number of unused nodes */ - u16 reserved1; - __be32 clump_size; /* (F) clump size. not usually used. */ - u8 btree_type; /* (F) BTree type */ - u8 reserved2; - __be32 attributes; /* (F) attributes */ - u32 reserved3[16]; -} __packed; - -#define BTREE_ATTR_BADCLOSE 0x00000001 /* b-tree not closed properly. not - used by hfsplus. */ -#define HFS_TREE_BIGKEYS 0x00000002 /* key length is u16 instead of u8. - used by hfsplus. */ -#define HFS_TREE_VARIDXKEYS 0x00000004 /* variable key length instead of - max key length. use din catalog - b-tree but not in extents - b-tree (hfsplus). */ +extern int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd); +extern void hfs_find_exit(struct hfs_find_data *fd); +extern int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd); +extern int hfs_brec_find(struct hfs_find_data *fd); +extern int hfs_brec_read(struct hfs_find_data *fd, void *rec, u32 rec_len); +extern int hfs_brec_goto(struct hfs_find_data *fd, int cnt); diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index caebabb6642f..b80ba40e3877 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c @@ -322,9 +322,9 @@ int hfs_correct_next_unused_CNID(struct super_block *sb, u32 cnid) } } + node_id = node->prev; hfs_bnode_put(node); - node_id = node->prev; } while (node_id >= leaf_head); return -ENOENT; diff --git a/fs/hfs/hfs.h b/fs/hfs/hfs.h index 6f194d0768b6..3f2293ff6fdd 100644 --- a/fs/hfs/hfs.h +++ b/fs/hfs/hfs.h @@ -9,274 +9,7 @@ #ifndef _HFS_H #define _HFS_H -/* offsets to various blocks */ -#define HFS_DD_BLK 0 /* Driver Descriptor block */ -#define HFS_PMAP_BLK 1 /* First block of partition map */ -#define HFS_MDB_BLK 2 /* Block (w/i partition) of MDB */ - -/* magic numbers for various disk blocks */ -#define HFS_DRVR_DESC_MAGIC 0x4552 /* "ER": driver descriptor map */ -#define HFS_OLD_PMAP_MAGIC 0x5453 /* "TS": old-type partition map */ -#define HFS_NEW_PMAP_MAGIC 0x504D /* "PM": new-type partition map */ -#define HFS_SUPER_MAGIC 0x4244 /* "BD": HFS MDB (super block) */ -#define HFS_MFS_SUPER_MAGIC 0xD2D7 /* MFS MDB (super block) */ - -/* various FIXED size parameters */ -#define HFS_SECTOR_SIZE 512 /* size of an HFS sector */ -#define HFS_SECTOR_SIZE_BITS 9 /* log_2(HFS_SECTOR_SIZE) */ -#define HFS_NAMELEN 31 /* maximum length of an HFS filename */ -#define HFS_MAX_NAMELEN 128 -#define HFS_MAX_VALENCE 32767U - -/* Meanings of the drAtrb field of the MDB, - * Reference: _Inside Macintosh: Files_ p. 2-61 - */ -#define HFS_SB_ATTRIB_HLOCK (1 << 7) -#define HFS_SB_ATTRIB_UNMNT (1 << 8) -#define HFS_SB_ATTRIB_SPARED (1 << 9) -#define HFS_SB_ATTRIB_INCNSTNT (1 << 11) -#define HFS_SB_ATTRIB_SLOCK (1 << 15) - -/* Some special File ID numbers */ -#define HFS_POR_CNID 1 /* Parent Of the Root */ -#define HFS_ROOT_CNID 2 /* ROOT directory */ -#define HFS_EXT_CNID 3 /* EXTents B-tree */ -#define HFS_CAT_CNID 4 /* CATalog B-tree */ -#define HFS_BAD_CNID 5 /* BAD blocks file */ -#define HFS_ALLOC_CNID 6 /* ALLOCation file (HFS+) */ -#define HFS_START_CNID 7 /* STARTup file (HFS+) */ -#define HFS_ATTR_CNID 8 /* ATTRibutes file (HFS+) */ -#define HFS_EXCH_CNID 15 /* ExchangeFiles temp id */ -#define HFS_FIRSTUSER_CNID 16 - -/* values for hfs_cat_rec.cdrType */ -#define HFS_CDR_DIR 0x01 /* folder (directory) */ -#define HFS_CDR_FIL 0x02 /* file */ -#define HFS_CDR_THD 0x03 /* folder (directory) thread */ -#define HFS_CDR_FTH 0x04 /* file thread */ - -/* legal values for hfs_ext_key.FkType and hfs_file.fork */ -#define HFS_FK_DATA 0x00 -#define HFS_FK_RSRC 0xFF - -/* bits in hfs_fil_entry.Flags */ -#define HFS_FIL_LOCK 0x01 /* locked */ -#define HFS_FIL_THD 0x02 /* file thread */ -#define HFS_FIL_DOPEN 0x04 /* data fork open */ -#define HFS_FIL_ROPEN 0x08 /* resource fork open */ -#define HFS_FIL_DIR 0x10 /* directory (always clear) */ -#define HFS_FIL_NOCOPY 0x40 /* copy-protected file */ -#define HFS_FIL_USED 0x80 /* open */ - -/* bits in hfs_dir_entry.Flags. dirflags is 16 bits. */ -#define HFS_DIR_LOCK 0x01 /* locked */ -#define HFS_DIR_THD 0x02 /* directory thread */ -#define HFS_DIR_INEXPFOLDER 0x04 /* in a shared area */ -#define HFS_DIR_MOUNTED 0x08 /* mounted */ -#define HFS_DIR_DIR 0x10 /* directory (always set) */ -#define HFS_DIR_EXPFOLDER 0x20 /* share point */ - -/* bits hfs_finfo.fdFlags */ -#define HFS_FLG_INITED 0x0100 -#define HFS_FLG_LOCKED 0x1000 -#define HFS_FLG_INVISIBLE 0x4000 - -/*======== HFS structures as they appear on the disk ========*/ - -/* Pascal-style string of up to 31 characters */ -struct hfs_name { - u8 len; - u8 name[HFS_NAMELEN]; -} __packed; - -struct hfs_point { - __be16 v; - __be16 h; -} __packed; - -struct hfs_rect { - __be16 top; - __be16 left; - __be16 bottom; - __be16 right; -} __packed; - -struct hfs_finfo { - __be32 fdType; - __be32 fdCreator; - __be16 fdFlags; - struct hfs_point fdLocation; - __be16 fdFldr; -} __packed; - -struct hfs_fxinfo { - __be16 fdIconID; - u8 fdUnused[8]; - __be16 fdComment; - __be32 fdPutAway; -} __packed; - -struct hfs_dinfo { - struct hfs_rect frRect; - __be16 frFlags; - struct hfs_point frLocation; - __be16 frView; -} __packed; - -struct hfs_dxinfo { - struct hfs_point frScroll; - __be32 frOpenChain; - __be16 frUnused; - __be16 frComment; - __be32 frPutAway; -} __packed; - -union hfs_finder_info { - struct { - struct hfs_finfo finfo; - struct hfs_fxinfo fxinfo; - } file; - struct { - struct hfs_dinfo dinfo; - struct hfs_dxinfo dxinfo; - } dir; -} __packed; - -/* Cast to a pointer to a generic bkey */ -#define HFS_BKEY(X) (((void)((X)->KeyLen)), ((struct hfs_bkey *)(X))) - -/* The key used in the catalog b-tree: */ -struct hfs_cat_key { - u8 key_len; /* number of bytes in the key */ - u8 reserved; /* padding */ - __be32 ParID; /* CNID of the parent dir */ - struct hfs_name CName; /* The filename of the entry */ -} __packed; - -/* The key used in the extents b-tree: */ -struct hfs_ext_key { - u8 key_len; /* number of bytes in the key */ - u8 FkType; /* HFS_FK_{DATA,RSRC} */ - __be32 FNum; /* The File ID of the file */ - __be16 FABN; /* allocation blocks number*/ -} __packed; - -typedef union hfs_btree_key { - u8 key_len; /* number of bytes in the key */ - struct hfs_cat_key cat; - struct hfs_ext_key ext; -} hfs_btree_key; - -#define HFS_MAX_CAT_KEYLEN (sizeof(struct hfs_cat_key) - sizeof(u8)) -#define HFS_MAX_EXT_KEYLEN (sizeof(struct hfs_ext_key) - sizeof(u8)) - -typedef union hfs_btree_key btree_key; - -struct hfs_extent { - __be16 block; - __be16 count; -}; -typedef struct hfs_extent hfs_extent_rec[3]; - -/* The catalog record for a file */ -struct hfs_cat_file { - s8 type; /* The type of entry */ - u8 reserved; - u8 Flags; /* Flags such as read-only */ - s8 Typ; /* file version number = 0 */ - struct hfs_finfo UsrWds; /* data used by the Finder */ - __be32 FlNum; /* The CNID */ - __be16 StBlk; /* obsolete */ - __be32 LgLen; /* The logical EOF of the data fork*/ - __be32 PyLen; /* The physical EOF of the data fork */ - __be16 RStBlk; /* obsolete */ - __be32 RLgLen; /* The logical EOF of the rsrc fork */ - __be32 RPyLen; /* The physical EOF of the rsrc fork */ - __be32 CrDat; /* The creation date */ - __be32 MdDat; /* The modified date */ - __be32 BkDat; /* The last backup date */ - struct hfs_fxinfo FndrInfo; /* more data for the Finder */ - __be16 ClpSize; /* number of bytes to allocate - when extending files */ - hfs_extent_rec ExtRec; /* first extent record - for the data fork */ - hfs_extent_rec RExtRec; /* first extent record - for the resource fork */ - u32 Resrv; /* reserved by Apple */ -} __packed; - -/* the catalog record for a directory */ -struct hfs_cat_dir { - s8 type; /* The type of entry */ - u8 reserved; - __be16 Flags; /* flags */ - __be16 Val; /* Valence: number of files and - dirs in the directory */ - __be32 DirID; /* The CNID */ - __be32 CrDat; /* The creation date */ - __be32 MdDat; /* The modification date */ - __be32 BkDat; /* The last backup date */ - struct hfs_dinfo UsrInfo; /* data used by the Finder */ - struct hfs_dxinfo FndrInfo; /* more data used by Finder */ - u8 Resrv[16]; /* reserved by Apple */ -} __packed; - -/* the catalog record for a thread */ -struct hfs_cat_thread { - s8 type; /* The type of entry */ - u8 reserved[9]; /* reserved by Apple */ - __be32 ParID; /* CNID of parent directory */ - struct hfs_name CName; /* The name of this entry */ -} __packed; - -/* A catalog tree record */ -typedef union hfs_cat_rec { - s8 type; /* The type of entry */ - struct hfs_cat_file file; - struct hfs_cat_dir dir; - struct hfs_cat_thread thread; -} hfs_cat_rec; - -struct hfs_mdb { - __be16 drSigWord; /* Signature word indicating fs type */ - __be32 drCrDate; /* fs creation date/time */ - __be32 drLsMod; /* fs modification date/time */ - __be16 drAtrb; /* fs attributes */ - __be16 drNmFls; /* number of files in root directory */ - __be16 drVBMSt; /* location (in 512-byte blocks) - of the volume bitmap */ - __be16 drAllocPtr; /* location (in allocation blocks) - to begin next allocation search */ - __be16 drNmAlBlks; /* number of allocation blocks */ - __be32 drAlBlkSiz; /* bytes in an allocation block */ - __be32 drClpSiz; /* clumpsize, the number of bytes to - allocate when extending a file */ - __be16 drAlBlSt; /* location (in 512-byte blocks) - of the first allocation block */ - __be32 drNxtCNID; /* CNID to assign to the next - file or directory created */ - __be16 drFreeBks; /* number of free allocation blocks */ - u8 drVN[28]; /* the volume label */ - __be32 drVolBkUp; /* fs backup date/time */ - __be16 drVSeqNum; /* backup sequence number */ - __be32 drWrCnt; /* fs write count */ - __be32 drXTClpSiz; /* clumpsize for the extents B-tree */ - __be32 drCTClpSiz; /* clumpsize for the catalog B-tree */ - __be16 drNmRtDirs; /* number of directories in - the root directory */ - __be32 drFilCnt; /* number of files in the fs */ - __be32 drDirCnt; /* number of directories in the fs */ - u8 drFndrInfo[32]; /* data used by the Finder */ - __be16 drEmbedSigWord; /* embedded volume signature */ - __be32 drEmbedExtent; /* starting block number (xdrStABN) - and number of allocation blocks - (xdrNumABlks) occupied by embedded - volume */ - __be32 drXTFlSize; /* bytes in the extents B-tree */ - hfs_extent_rec drXTExtRec; /* extents B-tree's first 3 extents */ - __be32 drCTFlSize; /* bytes in the catalog B-tree */ - hfs_extent_rec drCTExtRec; /* catalog B-tree's first 3 extents */ -} __packed; +#include <linux/hfs_common.h> /*======== Data structures kept in memory ========*/ diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h index fff149af89da..e94dbc04a1e4 100644 --- a/fs/hfs/hfs_fs.h +++ b/fs/hfs/hfs_fs.h @@ -18,7 +18,6 @@ #include <asm/byteorder.h> #include <linux/uaccess.h> -#include <linux/hfs_common.h> #include "hfs.h" @@ -140,74 +139,90 @@ struct hfs_sb_info { #define HFS_FLG_ALT_MDB_DIRTY 2 /* bitmap.c */ -extern u32 hfs_vbm_search_free(struct super_block *, u32, u32 *); -extern int hfs_clear_vbm_bits(struct super_block *, u16, u16); +extern u32 hfs_vbm_search_free(struct super_block *sb, u32 goal, u32 *num_bits); +extern int hfs_clear_vbm_bits(struct super_block *sb, u16 start, u16 count); /* catalog.c */ -extern int hfs_cat_keycmp(const btree_key *, const btree_key *); +extern int hfs_cat_keycmp(const btree_key *key1, const btree_key *key2); struct hfs_find_data; -extern int hfs_cat_find_brec(struct super_block *, u32, struct hfs_find_data *); -extern int hfs_cat_create(u32, struct inode *, const struct qstr *, struct inode *); -extern int hfs_cat_delete(u32, struct inode *, const struct qstr *); -extern int hfs_cat_move(u32, struct inode *, const struct qstr *, - struct inode *, const struct qstr *); -extern void hfs_cat_build_key(struct super_block *, btree_key *, u32, const struct qstr *); +extern int hfs_cat_find_brec(struct super_block *sb, u32 cnid, + struct hfs_find_data *fd); +extern int hfs_cat_create(u32 cnid, struct inode *dir, + const struct qstr *str, struct inode *inode); +extern int hfs_cat_delete(u32 cnid, struct inode *dir, const struct qstr *str); +extern int hfs_cat_move(u32 cnid, struct inode *src_dir, + const struct qstr *src_name, + struct inode *dst_dir, + const struct qstr *dst_name); +extern void hfs_cat_build_key(struct super_block *sb, btree_key *key, + u32 parent, const struct qstr *name); /* dir.c */ extern const struct file_operations hfs_dir_operations; extern const struct inode_operations hfs_dir_inode_operations; /* extent.c */ -extern int hfs_ext_keycmp(const btree_key *, const btree_key *); +extern int hfs_ext_keycmp(const btree_key *key1, const btree_key *key2); extern u16 hfs_ext_find_block(struct hfs_extent *ext, u16 off); -extern int hfs_free_fork(struct super_block *, struct hfs_cat_file *, int); -extern int hfs_ext_write_extent(struct inode *); -extern int hfs_extend_file(struct inode *); -extern void hfs_file_truncate(struct inode *); +extern int hfs_free_fork(struct super_block *sb, + struct hfs_cat_file *file, int type); +extern int hfs_ext_write_extent(struct inode *inode); +extern int hfs_extend_file(struct inode *inode); +extern void hfs_file_truncate(struct inode *inode); -extern int hfs_get_block(struct inode *, sector_t, struct buffer_head *, int); +extern int hfs_get_block(struct inode *inode, sector_t block, + struct buffer_head *bh_result, int create); /* inode.c */ extern const struct address_space_operations hfs_aops; extern const struct address_space_operations hfs_btree_aops; int hfs_write_begin(const struct kiocb *iocb, struct address_space *mapping, - loff_t pos, unsigned len, struct folio **foliop, void **fsdata); -extern struct inode *hfs_new_inode(struct inode *, const struct qstr *, umode_t); -extern void hfs_inode_write_fork(struct inode *, struct hfs_extent *, __be32 *, __be32 *); -extern int hfs_write_inode(struct inode *, struct writeback_control *); -extern int hfs_inode_setattr(struct mnt_idmap *, struct dentry *, - struct iattr *); + loff_t pos, unsigned int len, struct folio **foliop, + void **fsdata); +extern struct inode *hfs_new_inode(struct inode *dir, const struct qstr *name, + umode_t mode); +extern void hfs_inode_write_fork(struct inode *inode, struct hfs_extent *ext, + __be32 *log_size, __be32 *phys_size); +extern int hfs_write_inode(struct inode *inode, struct writeback_control *wbc); +extern int hfs_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry, + struct iattr *attr); extern void hfs_inode_read_fork(struct inode *inode, struct hfs_extent *ext, - __be32 log_size, __be32 phys_size, u32 clump_size); -extern struct inode *hfs_iget(struct super_block *, struct hfs_cat_key *, hfs_cat_rec *); -extern void hfs_evict_inode(struct inode *); -extern void hfs_delete_inode(struct inode *); + __be32 __log_size, __be32 phys_size, + u32 clump_size); +extern struct inode *hfs_iget(struct super_block *sb, struct hfs_cat_key *key, + hfs_cat_rec *rec); +extern void hfs_evict_inode(struct inode *inode); +extern void hfs_delete_inode(struct inode *inode); /* attr.c */ extern const struct xattr_handler * const hfs_xattr_handlers[]; /* mdb.c */ -extern int hfs_mdb_get(struct super_block *); -extern void hfs_mdb_commit(struct super_block *); -extern void hfs_mdb_close(struct super_block *); -extern void hfs_mdb_put(struct super_block *); +extern int hfs_mdb_get(struct super_block *sb); +extern void hfs_mdb_commit(struct super_block *sb); +extern void hfs_mdb_close(struct super_block *sb); +extern void hfs_mdb_put(struct super_block *sb); /* part_tbl.c */ -extern int hfs_part_find(struct super_block *, sector_t *, sector_t *); +extern int hfs_part_find(struct super_block *sb, + sector_t *part_start, sector_t *part_size); /* string.c */ extern const struct dentry_operations hfs_dentry_operations; -extern int hfs_hash_dentry(const struct dentry *, struct qstr *); -extern int hfs_strcmp(const unsigned char *, unsigned int, - const unsigned char *, unsigned int); +extern int hfs_hash_dentry(const struct dentry *dentry, struct qstr *this); +extern int hfs_strcmp(const unsigned char *s1, unsigned int len1, + const unsigned char *s2, unsigned int len2); extern int hfs_compare_dentry(const struct dentry *dentry, - unsigned int len, const char *str, const struct qstr *name); + unsigned int len, const char *str, + const struct qstr *name); /* trans.c */ -extern void hfs_asc2mac(struct super_block *, struct hfs_name *, const struct qstr *); -extern int hfs_mac2asc(struct super_block *, char *, const struct hfs_name *); +extern void hfs_asc2mac(struct super_block *sb, + struct hfs_name *out, const struct qstr *in); +extern int hfs_mac2asc(struct super_block *sb, + char *out, const struct hfs_name *in); /* super.c */ extern void hfs_mark_mdb_dirty(struct super_block *sb); diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 81ad93e6312f..524db1389737 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -45,7 +45,8 @@ static void hfs_write_failed(struct address_space *mapping, loff_t to) } int hfs_write_begin(const struct kiocb *iocb, struct address_space *mapping, - loff_t pos, unsigned len, struct folio **foliop, void **fsdata) + loff_t pos, unsigned int len, struct folio **foliop, + void **fsdata) { int ret; diff --git a/fs/hfs/string.c b/fs/hfs/string.c index 3912209153a8..0cfa35e82abc 100644 --- a/fs/hfs/string.c +++ b/fs/hfs/string.c @@ -16,6 +16,8 @@ #include "hfs_fs.h" #include <linux/dcache.h> +#include <kunit/visibility.h> + /*================ File-local variables ================*/ /* @@ -65,6 +67,7 @@ int hfs_hash_dentry(const struct dentry *dentry, struct qstr *this) this->hash = end_name_hash(hash); return 0; } +EXPORT_SYMBOL_IF_KUNIT(hfs_hash_dentry); /* * Compare two strings in the HFS filename character ordering @@ -87,6 +90,7 @@ int hfs_strcmp(const unsigned char *s1, unsigned int len1, } return len1 - len2; } +EXPORT_SYMBOL_IF_KUNIT(hfs_strcmp); /* * Test for equality of two strings in the HFS filename character ordering. @@ -112,3 +116,4 @@ int hfs_compare_dentry(const struct dentry *dentry, } return 0; } +EXPORT_SYMBOL_IF_KUNIT(hfs_compare_dentry); diff --git a/fs/hfs/string_test.c b/fs/hfs/string_test.c new file mode 100644 index 000000000000..e1bf6f954312 --- /dev/null +++ b/fs/hfs/string_test.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit tests for HFS string operations + * + * Copyright (C) 2025 Viacheslav Dubeyko <slava@dubeyko.com> + */ + +#include <kunit/test.h> +#include <linux/dcache.h> +#include "hfs_fs.h" + +/* Test hfs_strcmp function */ +static void hfs_strcmp_test(struct kunit *test) +{ + /* Test equal strings */ + KUNIT_EXPECT_EQ(test, 0, hfs_strcmp("hello", 5, "hello", 5)); + KUNIT_EXPECT_EQ(test, 0, hfs_strcmp("test", 4, "test", 4)); + KUNIT_EXPECT_EQ(test, 0, hfs_strcmp("", 0, "", 0)); + + /* Test unequal strings */ + KUNIT_EXPECT_NE(test, 0, hfs_strcmp("hello", 5, "world", 5)); + KUNIT_EXPECT_NE(test, 0, hfs_strcmp("test", 4, "testing", 7)); + + /* Test different lengths */ + KUNIT_EXPECT_LT(test, hfs_strcmp("test", 4, "testing", 7), 0); + KUNIT_EXPECT_GT(test, hfs_strcmp("testing", 7, "test", 4), 0); + + /* Test case insensitive comparison (HFS should handle case) */ + KUNIT_EXPECT_EQ(test, 0, hfs_strcmp("Test", 4, "TEST", 4)); + KUNIT_EXPECT_EQ(test, 0, hfs_strcmp("hello", 5, "HELLO", 5)); + + /* Test with special characters */ + KUNIT_EXPECT_EQ(test, 0, hfs_strcmp("file.txt", 8, "file.txt", 8)); + KUNIT_EXPECT_NE(test, 0, hfs_strcmp("file.txt", 8, "file.dat", 8)); + + /* Test boundary cases */ + KUNIT_EXPECT_EQ(test, 0, hfs_strcmp("a", 1, "a", 1)); + KUNIT_EXPECT_NE(test, 0, hfs_strcmp("a", 1, "b", 1)); +} + +/* Test hfs_hash_dentry function */ +static void hfs_hash_dentry_test(struct kunit *test) +{ + struct qstr test_name1, test_name2, test_name3; + struct dentry dentry = {}; + char name1[] = "testfile"; + char name2[] = "TestFile"; + char name3[] = "different"; + + /* Initialize test strings */ + test_name1.name = name1; + test_name1.len = strlen(name1); + test_name1.hash = 0; + + test_name2.name = name2; + test_name2.len = strlen(name2); + test_name2.hash = 0; + + test_name3.name = name3; + test_name3.len = strlen(name3); + test_name3.hash = 0; + + /* Test hashing */ + KUNIT_EXPECT_EQ(test, 0, hfs_hash_dentry(&dentry, &test_name1)); + KUNIT_EXPECT_EQ(test, 0, hfs_hash_dentry(&dentry, &test_name2)); + KUNIT_EXPECT_EQ(test, 0, hfs_hash_dentry(&dentry, &test_name3)); + + /* Case insensitive names should hash the same */ + KUNIT_EXPECT_EQ(test, test_name1.hash, test_name2.hash); + + /* Different names should have different hashes */ + KUNIT_EXPECT_NE(test, test_name1.hash, test_name3.hash); +} + +/* Test hfs_compare_dentry function */ +static void hfs_compare_dentry_test(struct kunit *test) +{ + struct qstr test_name; + struct dentry dentry = {}; + char name[] = "TestFile"; + + test_name.name = name; + test_name.len = strlen(name); + + /* Test exact match */ + KUNIT_EXPECT_EQ(test, 0, hfs_compare_dentry(&dentry, 8, + "TestFile", &test_name)); + + /* Test case insensitive match */ + KUNIT_EXPECT_EQ(test, 0, hfs_compare_dentry(&dentry, 8, + "testfile", &test_name)); + KUNIT_EXPECT_EQ(test, 0, hfs_compare_dentry(&dentry, 8, + "TESTFILE", &test_name)); + + /* Test different names */ + KUNIT_EXPECT_EQ(test, 1, hfs_compare_dentry(&dentry, 8, + "DiffFile", &test_name)); + + /* Test different lengths */ + KUNIT_EXPECT_EQ(test, 1, hfs_compare_dentry(&dentry, 7, + "TestFil", &test_name)); + KUNIT_EXPECT_EQ(test, 1, hfs_compare_dentry(&dentry, 9, + "TestFiles", &test_name)); + + /* Test empty string */ + test_name.name = ""; + test_name.len = 0; + KUNIT_EXPECT_EQ(test, 0, hfs_compare_dentry(&dentry, 0, "", &test_name)); + + /* Test HFS_NAMELEN boundary */ + test_name.name = "This_is_a_very_long_filename_that_exceeds_normal_limits"; + test_name.len = strlen(test_name.name); + KUNIT_EXPECT_EQ(test, 0, hfs_compare_dentry(&dentry, HFS_NAMELEN, + "This_is_a_very_long_filename_th", &test_name)); +} + +static struct kunit_case hfs_string_test_cases[] = { + KUNIT_CASE(hfs_strcmp_test), + KUNIT_CASE(hfs_hash_dentry_test), + KUNIT_CASE(hfs_compare_dentry_test), + {} +}; + +static struct kunit_suite hfs_string_test_suite = { + .name = "hfs_string", + .test_cases = hfs_string_test_cases, +}; + +kunit_test_suite(hfs_string_test_suite); + +MODULE_DESCRIPTION("KUnit tests for HFS string operations"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); |
