aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hfs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/hfs
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'fs/hfs')
-rw-r--r--fs/hfs/Makefile10
-rw-r--r--fs/hfs/attr.c121
-rw-r--r--fs/hfs/bfind.c210
-rw-r--r--fs/hfs/bitmap.c243
-rw-r--r--fs/hfs/bnode.c498
-rw-r--r--fs/hfs/brec.c496
-rw-r--r--fs/hfs/btree.c327
-rw-r--r--fs/hfs/btree.h168
-rw-r--r--fs/hfs/catalog.c347
-rw-r--r--fs/hfs/dir.c330
-rw-r--r--fs/hfs/extent.c527
-rw-r--r--fs/hfs/hfs.h287
-rw-r--r--fs/hfs/hfs_fs.h286
-rw-r--r--fs/hfs/inode.c636
-rw-r--r--fs/hfs/mdb.c343
-rw-r--r--fs/hfs/part_tbl.c117
-rw-r--r--fs/hfs/string.c115
-rw-r--r--fs/hfs/super.c395
-rw-r--r--fs/hfs/sysdep.c40
-rw-r--r--fs/hfs/trans.c72
20 files changed, 5568 insertions, 0 deletions
diff --git a/fs/hfs/Makefile b/fs/hfs/Makefile
new file mode 100644
index 000000000000..c41f5a85f42d
--- /dev/null
+++ b/fs/hfs/Makefile
@@ -0,0 +1,10 @@
1#
2# Makefile for the Linux hfs filesystem routines.
3#
4
5obj-$(CONFIG_HFS_FS) += hfs.o
6
7hfs-objs := bitmap.o bfind.o bnode.o brec.o btree.o \
8 catalog.o dir.o extent.o inode.o attr.o mdb.o \
9 part_tbl.o string.o super.o sysdep.o trans.o
10
diff --git a/fs/hfs/attr.c b/fs/hfs/attr.c
new file mode 100644
index 000000000000..e057ec542a6a
--- /dev/null
+++ b/fs/hfs/attr.c
@@ -0,0 +1,121 @@
1/*
2 * linux/fs/hfs/attr.c
3 *
4 * (C) 2003 Ardis Technologies <roman@ardistech.com>
5 *
6 * Export hfs data via xattr
7 */
8
9
10#include <linux/fs.h>
11#include <linux/xattr.h>
12
13#include "hfs_fs.h"
14#include "btree.h"
15
16int hfs_setxattr(struct dentry *dentry, const char *name,
17 const void *value, size_t size, int flags)
18{
19 struct inode *inode = dentry->d_inode;
20 struct hfs_find_data fd;
21 hfs_cat_rec rec;
22 struct hfs_cat_file *file;
23 int res;
24
25 if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
26 return -EOPNOTSUPP;
27
28 res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd);
29 if (res)
30 return res;
31 fd.search_key->cat = HFS_I(inode)->cat_key;
32 res = hfs_brec_find(&fd);
33 if (res)
34 goto out;
35 hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
36 sizeof(struct hfs_cat_file));
37 file = &rec.file;
38
39 if (!strcmp(name, "hfs.type")) {
40 if (size == 4)
41 memcpy(&file->UsrWds.fdType, value, 4);
42 else
43 res = -ERANGE;
44 } else if (!strcmp(name, "hfs.creator")) {
45 if (size == 4)
46 memcpy(&file->UsrWds.fdCreator, value, 4);
47 else
48 res = -ERANGE;
49 } else
50 res = -EOPNOTSUPP;
51 if (!res)
52 hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
53 sizeof(struct hfs_cat_file));
54out:
55 hfs_find_exit(&fd);
56 return res;
57}
58
59ssize_t hfs_getxattr(struct dentry *dentry, const char *name,
60 void *value, size_t size)
61{
62 struct inode *inode = dentry->d_inode;
63 struct hfs_find_data fd;
64 hfs_cat_rec rec;
65 struct hfs_cat_file *file;
66 ssize_t res = 0;
67
68 if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
69 return -EOPNOTSUPP;
70
71 if (size) {
72 res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd);
73 if (res)
74 return res;
75 fd.search_key->cat = HFS_I(inode)->cat_key;
76 res = hfs_brec_find(&fd);
77 if (res)
78 goto out;
79 hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
80 sizeof(struct hfs_cat_file));
81 }
82 file = &rec.file;
83
84 if (!strcmp(name, "hfs.type")) {
85 if (size >= 4) {
86 memcpy(value, &file->UsrWds.fdType, 4);
87 res = 4;
88 } else
89 res = size ? -ERANGE : 4;
90 } else if (!strcmp(name, "hfs.creator")) {
91 if (size >= 4) {
92 memcpy(value, &file->UsrWds.fdCreator, 4);
93 res = 4;
94 } else
95 res = size ? -ERANGE : 4;
96 } else
97 res = -ENODATA;
98out:
99 if (size)
100 hfs_find_exit(&fd);
101 return res;
102}
103
104#define HFS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type"))
105
106ssize_t hfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
107{
108 struct inode *inode = dentry->d_inode;
109
110 if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
111 return -EOPNOTSUPP;
112
113 if (!buffer || !size)
114 return HFS_ATTRLIST_SIZE;
115 if (size < HFS_ATTRLIST_SIZE)
116 return -ERANGE;
117 strcpy(buffer, "hfs.type");
118 strcpy(buffer + sizeof("hfs.type"), "hfs.creator");
119
120 return HFS_ATTRLIST_SIZE;
121}
diff --git a/fs/hfs/bfind.c b/fs/hfs/bfind.c
new file mode 100644
index 000000000000..89450ae32228
--- /dev/null
+++ b/fs/hfs/bfind.c
@@ -0,0 +1,210 @@
1/*
2 * linux/fs/hfs/bfind.c
3 *
4 * Copyright (C) 2001
5 * Brad Boyer (flar@allandria.com)
6 * (C) 2003 Ardis Technologies <roman@ardistech.com>
7 *
8 * Search routines for btrees
9 */
10
11#include <linux/slab.h>
12#include "btree.h"
13
14int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
15{
16 void *ptr;
17
18 fd->tree = tree;
19 fd->bnode = NULL;
20 ptr = kmalloc(tree->max_key_len * 2 + 4, GFP_KERNEL);
21 if (!ptr)
22 return -ENOMEM;
23 fd->search_key = ptr;
24 fd->key = ptr + tree->max_key_len + 2;
25 dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", tree->cnid, __builtin_return_address(0));
26 down(&tree->tree_lock);
27 return 0;
28}
29
30void hfs_find_exit(struct hfs_find_data *fd)
31{
32 hfs_bnode_put(fd->bnode);
33 kfree(fd->search_key);
34 dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n", fd->tree->cnid, __builtin_return_address(0));
35 up(&fd->tree->tree_lock);
36 fd->tree = NULL;
37}
38
39/* Find the record in bnode that best matches key (not greater than...)*/
40int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
41{
42 int cmpval;
43 u16 off, len, keylen;
44 int rec;
45 int b, e;
46 int res;
47
48 b = 0;
49 e = bnode->num_recs - 1;
50 res = -ENOENT;
51 do {
52 rec = (e + b) / 2;
53 len = hfs_brec_lenoff(bnode, rec, &off);
54 keylen = hfs_brec_keylen(bnode, rec);
55 hfs_bnode_read(bnode, fd->key, off, keylen);
56 cmpval = bnode->tree->keycmp(fd->key, fd->search_key);
57 if (!cmpval) {
58 e = rec;
59 res = 0;
60 goto done;
61 }
62 if (cmpval < 0)
63 b = rec + 1;
64 else
65 e = rec - 1;
66 } while (b <= e);
67 //printk("%d: %d,%d,%d\n", bnode->this, b, e, rec);
68 if (rec != e && e >= 0) {
69 len = hfs_brec_lenoff(bnode, e, &off);
70 keylen = hfs_brec_keylen(bnode, e);
71 hfs_bnode_read(bnode, fd->key, off, keylen);
72 }
73done:
74 fd->record = e;
75 fd->keyoffset = off;
76 fd->keylength = keylen;
77 fd->entryoffset = off + keylen;
78 fd->entrylength = len - keylen;
79 return res;
80}
81
82/* Traverse a B*Tree from the root to a leaf finding best fit to key */
83/* Return allocated copy of node found, set recnum to best record */
84int hfs_brec_find(struct hfs_find_data *fd)
85{
86 struct hfs_btree *tree;
87 struct hfs_bnode *bnode;
88 u32 nidx, parent;
89 __be32 data;
90 int height, res;
91
92 tree = fd->tree;
93 if (fd->bnode)
94 hfs_bnode_put(fd->bnode);
95 fd->bnode = NULL;
96 nidx = tree->root;
97 if (!nidx)
98 return -ENOENT;
99 height = tree->depth;
100 res = 0;
101 parent = 0;
102 for (;;) {
103 bnode = hfs_bnode_find(tree, nidx);
104 if (IS_ERR(bnode)) {
105 res = PTR_ERR(bnode);
106 bnode = NULL;
107 break;
108 }
109 if (bnode->height != height)
110 goto invalid;
111 if (bnode->type != (--height ? HFS_NODE_INDEX : HFS_NODE_LEAF))
112 goto invalid;
113 bnode->parent = parent;
114
115 res = __hfs_brec_find(bnode, fd);
116 if (!height)
117 break;
118 if (fd->record < 0)
119 goto release;
120
121 parent = nidx;
122 hfs_bnode_read(bnode, &data, fd->entryoffset, 4);
123 nidx = be32_to_cpu(data);
124 hfs_bnode_put(bnode);
125 }
126 fd->bnode = bnode;
127 return res;
128
129invalid:
130 printk("HFS: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n",
131 height, bnode->height, bnode->type, nidx, parent);
132 res = -EIO;
133release:
134 hfs_bnode_put(bnode);
135 return res;
136}
137
138int hfs_brec_read(struct hfs_find_data *fd, void *rec, int rec_len)
139{
140 int res;
141
142 res = hfs_brec_find(fd);
143 if (res)
144 return res;
145 if (fd->entrylength > rec_len)
146 return -EINVAL;
147 hfs_bnode_read(fd->bnode, rec, fd->entryoffset, fd->entrylength);
148 return 0;
149}
150
151int hfs_brec_goto(struct hfs_find_data *fd, int cnt)
152{
153 struct hfs_btree *tree;
154 struct hfs_bnode *bnode;
155 int idx, res = 0;
156 u16 off, len, keylen;
157
158 bnode = fd->bnode;
159 tree = bnode->tree;
160
161 if (cnt < 0) {
162 cnt = -cnt;
163 while (cnt > fd->record) {
164 cnt -= fd->record + 1;
165 fd->record = bnode->num_recs - 1;
166 idx = bnode->prev;
167 if (!idx) {
168 res = -ENOENT;
169 goto out;
170 }
171 hfs_bnode_put(bnode);
172 bnode = hfs_bnode_find(tree, idx);
173 if (IS_ERR(bnode)) {
174 res = PTR_ERR(bnode);
175 bnode = NULL;
176 goto out;
177 }
178 }
179 fd->record -= cnt;
180 } else {
181 while (cnt >= bnode->num_recs - fd->record) {
182 cnt -= bnode->num_recs - fd->record;
183 fd->record = 0;
184 idx = bnode->next;
185 if (!idx) {
186 res = -ENOENT;
187 goto out;
188 }
189 hfs_bnode_put(bnode);
190 bnode = hfs_bnode_find(tree, idx);
191 if (IS_ERR(bnode)) {
192 res = PTR_ERR(bnode);
193 bnode = NULL;
194 goto out;
195 }
196 }
197 fd->record += cnt;
198 }
199
200 len = hfs_brec_lenoff(bnode, fd->record, &off);
201 keylen = hfs_brec_keylen(bnode, fd->record);
202 fd->keyoffset = off;
203 fd->keylength = keylen;
204 fd->entryoffset = off + keylen;
205 fd->entrylength = len - keylen;
206 hfs_bnode_read(bnode, fd->key, off, keylen);
207out:
208 fd->bnode = bnode;
209 return res;
210}
diff --git a/fs/hfs/bitmap.c b/fs/hfs/bitmap.c
new file mode 100644
index 000000000000..24e75798ddf0
--- /dev/null
+++ b/fs/hfs/bitmap.c
@@ -0,0 +1,243 @@
1/*
2 * linux/fs/hfs/bitmap.c
3 *
4 * Copyright (C) 1996-1997 Paul H. Hargrove
5 * (C) 2003 Ardis Technologies <roman@ardistech.com>
6 * This file may be distributed under the terms of the GNU General Public License.
7 *
8 * Based on GPLed code Copyright (C) 1995 Michael Dreher
9 *
10 * This file contains the code to modify the volume bitmap:
11 * search/set/clear bits.
12 */
13
14#include "hfs_fs.h"
15
16/*
17 * hfs_find_zero_bit()
18 *
19 * Description:
20 * Given a block of memory, its length in bits, and a starting bit number,
21 * determine the number of the first zero bits (in left-to-right ordering)
22 * in that range.
23 *
24 * Returns >= 'size' if no zero bits are found in the range.
25 *
26 * Accesses memory in 32-bit aligned chunks of 32-bits and thus
27 * may read beyond the 'size'th bit.
28 */
29static u32 hfs_find_set_zero_bits(__be32 *bitmap, u32 size, u32 offset, u32 *max)
30{
31 __be32 *curr, *end;
32 u32 mask, start, len, n;
33 __be32 val;
34 int i;
35
36 len = *max;
37 if (!len)
38 return size;
39
40 curr = bitmap + (offset / 32);
41 end = bitmap + ((size + 31) / 32);
42
43 /* scan the first partial u32 for zero bits */
44 val = *curr;
45 if (~val) {
46 n = be32_to_cpu(val);
47 i = offset % 32;
48 mask = (1U << 31) >> i;
49 for (; i < 32; mask >>= 1, i++) {
50 if (!(n & mask))
51 goto found;
52 }
53 }
54
55 /* scan complete u32s for the first zero bit */
56 while (++curr < end) {
57 val = *curr;
58 if (~val) {
59 n = be32_to_cpu(val);
60 mask = 1 << 31;
61 for (i = 0; i < 32; mask >>= 1, i++) {
62 if (!(n & mask))
63 goto found;
64 }
65 }
66 }
67 return size;
68
69found:
70 start = (curr - bitmap) * 32 + i;
71 if (start >= size)
72 return start;
73 /* do any partial u32 at the start */
74 len = min(size - start, len);
75 while (1) {
76 n |= mask;
77 if (++i >= 32)
78 break;
79 mask >>= 1;
80 if (!--len || n & mask)
81 goto done;
82 }
83 if (!--len)
84 goto done;
85 *curr++ = cpu_to_be32(n);
86 /* do full u32s */
87 while (1) {
88 n = be32_to_cpu(*curr);
89 if (len < 32)
90 break;
91 if (n) {
92 len = 32;
93 break;
94 }
95 *curr++ = cpu_to_be32(0xffffffff);
96 len -= 32;
97 }
98 /* do any partial u32 at end */
99 mask = 1U << 31;
100 for (i = 0; i < len; i++) {
101 if (n & mask)
102 break;
103 n |= mask;
104 mask >>= 1;
105 }
106done:
107 *curr = cpu_to_be32(n);
108 *max = (curr - bitmap) * 32 + i - start;
109 return start;
110}
111
112/*
113 * hfs_vbm_search_free()
114 *
115 * Description:
116 * Search for 'num_bits' consecutive cleared bits in the bitmap blocks of
117 * the hfs MDB. 'mdb' had better be locked or the returned range
118 * may be no longer free, when this functions returns!
119 * XXX Currently the search starts from bit 0, but it should start with
120 * the bit number stored in 's_alloc_ptr' of the MDB.
121 * Input Variable(s):
122 * struct hfs_mdb *mdb: Pointer to the hfs MDB
123 * u16 *num_bits: Pointer to the number of cleared bits
124 * to search for
125 * Output Variable(s):
126 * u16 *num_bits: The number of consecutive clear bits of the
127 * returned range. If the bitmap is fragmented, this will be less than
128 * requested and it will be zero, when the disk is full.
129 * Returns:
130 * The number of the first bit of the range of cleared bits which has been
131 * found. When 'num_bits' is zero, this is invalid!
132 * Preconditions:
133 * 'mdb' points to a "valid" (struct hfs_mdb).
134 * 'num_bits' points to a variable of type (u16), which contains
135 * the number of cleared bits to find.
136 * Postconditions:
137 * 'num_bits' is set to the length of the found sequence.
138 */
139u32 hfs_vbm_search_free(struct super_block *sb, u32 goal, u32 *num_bits)
140{
141 void *bitmap;
142 u32 pos;
143
144 /* make sure we have actual work to perform */
145 if (!*num_bits)
146 return 0;
147
148 down(&HFS_SB(sb)->bitmap_lock);
149 bitmap = HFS_SB(sb)->bitmap;
150
151 pos = hfs_find_set_zero_bits(bitmap, HFS_SB(sb)->fs_ablocks, goal, num_bits);
152 if (pos >= HFS_SB(sb)->fs_ablocks) {
153 if (goal)
154 pos = hfs_find_set_zero_bits(bitmap, goal, 0, num_bits);
155 if (pos >= HFS_SB(sb)->fs_ablocks) {
156 *num_bits = pos = 0;
157 goto out;
158 }
159 }
160
161 dprint(DBG_BITMAP, "alloc_bits: %u,%u\n", pos, *num_bits);
162 HFS_SB(sb)->free_ablocks -= *num_bits;
163 hfs_bitmap_dirty(sb);
164out:
165 up(&HFS_SB(sb)->bitmap_lock);
166 return pos;
167}
168
169
170/*
171 * hfs_clear_vbm_bits()
172 *
173 * Description:
174 * Clear the requested bits in the volume bitmap of the hfs filesystem
175 * Input Variable(s):
176 * struct hfs_mdb *mdb: Pointer to the hfs MDB
177 * u16 start: The offset of the first bit
178 * u16 count: The number of bits
179 * Output Variable(s):
180 * None
181 * Returns:
182 * 0: no error
183 * -1: One of the bits was already clear. This is a strange
184 * error and when it happens, the filesystem must be repaired!
185 * -2: One or more of the bits are out of range of the bitmap.
186 * Preconditions:
187 * 'mdb' points to a "valid" (struct hfs_mdb).
188 * Postconditions:
189 * Starting with bit number 'start', 'count' bits in the volume bitmap
190 * are cleared. The affected bitmap blocks are marked "dirty", the free
191 * block count of the MDB is updated and the MDB is marked dirty.
192 */
193int hfs_clear_vbm_bits(struct super_block *sb, u16 start, u16 count)
194{
195 __be32 *curr;
196 u32 mask;
197 int i, len;
198
199 /* is there any actual work to be done? */
200 if (!count)
201 return 0;
202
203 dprint(DBG_BITMAP, "clear_bits: %u,%u\n", start, count);
204 /* are all of the bits in range? */
205 if ((start + count) > HFS_SB(sb)->fs_ablocks)
206 return -2;
207
208 down(&HFS_SB(sb)->bitmap_lock);
209 /* bitmap is always on a 32-bit boundary */
210 curr = HFS_SB(sb)->bitmap + (start / 32);
211 len = count;
212
213 /* do any partial u32 at the start */
214 i = start % 32;
215 if (i) {
216 int j = 32 - i;
217 mask = 0xffffffffU << j;
218 if (j > count) {
219 mask |= 0xffffffffU >> (i + count);
220 *curr &= cpu_to_be32(mask);
221 goto out;
222 }
223 *curr++ &= cpu_to_be32(mask);
224 count -= j;
225 }
226
227 /* do full u32s */
228 while (count >= 32) {
229 *curr++ = 0;
230 count -= 32;
231 }
232 /* do any partial u32 at end */
233 if (count) {
234 mask = 0xffffffffU >> count;
235 *curr &= cpu_to_be32(mask);
236 }
237out:
238 HFS_SB(sb)->free_ablocks += len;
239 up(&HFS_SB(sb)->bitmap_lock);
240 hfs_bitmap_dirty(sb);
241
242 return 0;
243}
diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c
new file mode 100644
index 000000000000..6ad1211f84ed
--- /dev/null
+++ b/fs/hfs/bnode.c
@@ -0,0 +1,498 @@
1/*
2 * linux/fs/hfs/bnode.c
3 *
4 * Copyright (C) 2001
5 * Brad Boyer (flar@allandria.com)
6 * (C) 2003 Ardis Technologies <roman@ardistech.com>
7 *
8 * Handle basic btree node operations
9 */
10
11#include <linux/pagemap.h>
12#include <linux/swap.h>
13
14#include "btree.h"
15
16#define REF_PAGES 0
17
18void hfs_bnode_read(struct hfs_bnode *node, void *buf,
19 int off, int len)
20{
21 struct page *page;
22
23 off += node->page_offset;
24 page = node->page[0];
25
26 memcpy(buf, kmap(page) + off, len);
27 kunmap(page);
28}
29
30u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off)
31{
32 __be16 data;
33 // optimize later...
34 hfs_bnode_read(node, &data, off, 2);
35 return be16_to_cpu(data);
36}
37
38u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off)
39{
40 u8 data;
41 // optimize later...
42 hfs_bnode_read(node, &data, off, 1);
43 return data;
44}
45
46void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
47{
48 struct hfs_btree *tree;
49 int key_len;
50
51 tree = node->tree;
52 if (node->type == HFS_NODE_LEAF ||
53 tree->attributes & HFS_TREE_VARIDXKEYS)
54 key_len = hfs_bnode_read_u8(node, off) + 1;
55 else
56 key_len = tree->max_key_len + 1;
57
58 hfs_bnode_read(node, key, off, key_len);
59}
60
61void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
62{
63 struct page *page;
64
65 off += node->page_offset;
66 page = node->page[0];
67
68 memcpy(kmap(page) + off, buf, len);
69 kunmap(page);
70 set_page_dirty(page);
71}
72
73void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data)
74{
75 __be16 v = cpu_to_be16(data);
76 // optimize later...
77 hfs_bnode_write(node, &v, off, 2);
78}
79
80void hfs_bnode_write_u8(struct hfs_bnode *node, int off, u8 data)
81{
82 // optimize later...
83 hfs_bnode_write(node, &data, off, 1);
84}
85
86void hfs_bnode_clear(struct hfs_bnode *node, int off, int len)
87{
88 struct page *page;
89
90 off += node->page_offset;
91 page = node->page[0];
92
93 memset(kmap(page) + off, 0, len);
94 kunmap(page);
95 set_page_dirty(page);
96}
97
98void hfs_bnode_copy(struct hfs_bnode *dst_node, int dst,
99 struct hfs_bnode *src_node, int src, int len)
100{
101 struct hfs_btree *tree;
102 struct page *src_page, *dst_page;
103
104 dprint(DBG_BNODE_MOD, "copybytes: %u,%u,%u\n", dst, src, len);
105 if (!len)
106 return;
107 tree = src_node->tree;
108 src += src_node->page_offset;
109 dst += dst_node->page_offset;
110 src_page = src_node->page[0];
111 dst_page = dst_node->page[0];
112
113 memcpy(kmap(dst_page) + dst, kmap(src_page) + src, len);
114 kunmap(src_page);
115 kunmap(dst_page);
116 set_page_dirty(dst_page);
117}
118
119void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
120{
121 struct page *page;
122 void *ptr;
123
124 dprint(DBG_BNODE_MOD, "movebytes: %u,%u,%u\n", dst, src, len);
125 if (!len)
126 return;
127 src += node->page_offset;
128 dst += node->page_offset;
129 page = node->page[0];
130 ptr = kmap(page);
131 memmove(ptr + dst, ptr + src, len);
132 kunmap(page);
133 set_page_dirty(page);
134}
135
136void hfs_bnode_dump(struct hfs_bnode *node)
137{
138 struct hfs_bnode_desc desc;
139 __be32 cnid;
140 int i, off, key_off;
141
142 dprint(DBG_BNODE_MOD, "bnode: %d\n", node->this);
143 hfs_bnode_read(node, &desc, 0, sizeof(desc));
144 dprint(DBG_BNODE_MOD, "%d, %d, %d, %d, %d\n",
145 be32_to_cpu(desc.next), be32_to_cpu(desc.prev),
146 desc.type, desc.height, be16_to_cpu(desc.num_recs));
147
148 off = node->tree->node_size - 2;
149 for (i = be16_to_cpu(desc.num_recs); i >= 0; off -= 2, i--) {
150 key_off = hfs_bnode_read_u16(node, off);
151 dprint(DBG_BNODE_MOD, " %d", key_off);
152 if (i && node->type == HFS_NODE_INDEX) {
153 int tmp;
154
155 if (node->tree->attributes & HFS_TREE_VARIDXKEYS)
156 tmp = (hfs_bnode_read_u8(node, key_off) | 1) + 1;
157 else
158 tmp = node->tree->max_key_len + 1;
159 dprint(DBG_BNODE_MOD, " (%d,%d", tmp, hfs_bnode_read_u8(node, key_off));
160 hfs_bnode_read(node, &cnid, key_off + tmp, 4);
161 dprint(DBG_BNODE_MOD, ",%d)", be32_to_cpu(cnid));
162 } else if (i && node->type == HFS_NODE_LEAF) {
163 int tmp;
164
165 tmp = hfs_bnode_read_u8(node, key_off);
166 dprint(DBG_BNODE_MOD, " (%d)", tmp);
167 }
168 }
169 dprint(DBG_BNODE_MOD, "\n");
170}
171
172void hfs_bnode_unlink(struct hfs_bnode *node)
173{
174 struct hfs_btree *tree;
175 struct hfs_bnode *tmp;
176 __be32 cnid;
177
178 tree = node->tree;
179 if (node->prev) {
180 tmp = hfs_bnode_find(tree, node->prev);
181 if (IS_ERR(tmp))
182 return;
183 tmp->next = node->next;
184 cnid = cpu_to_be32(tmp->next);
185 hfs_bnode_write(tmp, &cnid, offsetof(struct hfs_bnode_desc, next), 4);
186 hfs_bnode_put(tmp);
187 } else if (node->type == HFS_NODE_LEAF)
188 tree->leaf_head = node->next;
189
190 if (node->next) {
191 tmp = hfs_bnode_find(tree, node->next);
192 if (IS_ERR(tmp))
193 return;
194 tmp->prev = node->prev;
195 cnid = cpu_to_be32(tmp->prev);
196 hfs_bnode_write(tmp, &cnid, offsetof(struct hfs_bnode_desc, prev), 4);
197 hfs_bnode_put(tmp);
198 } else if (node->type == HFS_NODE_LEAF)
199 tree->leaf_tail = node->prev;
200
201 // move down?
202 if (!node->prev && !node->next) {
203 printk("hfs_btree_del_level\n");
204 }
205 if (!node->parent) {
206 tree->root = 0;
207 tree->depth = 0;
208 }
209 set_bit(HFS_BNODE_DELETED, &node->flags);
210}
211
212static inline int hfs_bnode_hash(u32 num)
213{
214 num = (num >> 16) + num;
215 num += num >> 8;
216 return num & (NODE_HASH_SIZE - 1);
217}
218
219struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid)
220{
221 struct hfs_bnode *node;
222
223 if (cnid >= tree->node_count) {
224 printk("HFS: request for non-existent node %d in B*Tree\n", cnid);
225 return NULL;
226 }
227
228 for (node = tree->node_hash[hfs_bnode_hash(cnid)];
229 node; node = node->next_hash) {
230 if (node->this == cnid) {
231 return node;
232 }
233 }
234 return NULL;
235}
236
237static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
238{
239 struct super_block *sb;
240 struct hfs_bnode *node, *node2;
241 struct address_space *mapping;
242 struct page *page;
243 int size, block, i, hash;
244 loff_t off;
245
246 if (cnid >= tree->node_count) {
247 printk("HFS: request for non-existent node %d in B*Tree\n", cnid);
248 return NULL;
249 }
250
251 sb = tree->inode->i_sb;
252 size = sizeof(struct hfs_bnode) + tree->pages_per_bnode *
253 sizeof(struct page *);
254 node = kmalloc(size, GFP_KERNEL);
255 if (!node)
256 return NULL;
257 memset(node, 0, size);
258 node->tree = tree;
259 node->this = cnid;
260 set_bit(HFS_BNODE_NEW, &node->flags);
261 atomic_set(&node->refcnt, 1);
262 dprint(DBG_BNODE_REFS, "new_node(%d:%d): 1\n",
263 node->tree->cnid, node->this);
264 init_waitqueue_head(&node->lock_wq);
265 spin_lock(&tree->hash_lock);
266 node2 = hfs_bnode_findhash(tree, cnid);
267 if (!node2) {
268 hash = hfs_bnode_hash(cnid);
269 node->next_hash = tree->node_hash[hash];
270 tree->node_hash[hash] = node;
271 tree->node_hash_cnt++;
272 } else {
273 spin_unlock(&tree->hash_lock);
274 kfree(node);
275 wait_event(node2->lock_wq, !test_bit(HFS_BNODE_NEW, &node2->flags));
276 return node2;
277 }
278 spin_unlock(&tree->hash_lock);
279
280 mapping = tree->inode->i_mapping;
281 off = (loff_t)cnid * tree->node_size;
282 block = off >> PAGE_CACHE_SHIFT;
283 node->page_offset = off & ~PAGE_CACHE_MASK;
284 for (i = 0; i < tree->pages_per_bnode; i++) {
285 page = read_cache_page(mapping, block++, (filler_t *)mapping->a_ops->readpage, NULL);
286 if (IS_ERR(page))
287 goto fail;
288 if (PageError(page)) {
289 page_cache_release(page);
290 goto fail;
291 }
292#if !REF_PAGES
293 page_cache_release(page);
294#endif
295 node->page[i] = page;
296 }
297
298 return node;
299fail:
300 set_bit(HFS_BNODE_ERROR, &node->flags);
301 return node;
302}
303
304void hfs_bnode_unhash(struct hfs_bnode *node)
305{
306 struct hfs_bnode **p;
307
308 dprint(DBG_BNODE_REFS, "remove_node(%d:%d): %d\n",
309 node->tree->cnid, node->this, atomic_read(&node->refcnt));
310 for (p = &node->tree->node_hash[hfs_bnode_hash(node->this)];
311 *p && *p != node; p = &(*p)->next_hash)
312 ;
313 if (!*p)
314 BUG();
315 *p = node->next_hash;
316 node->tree->node_hash_cnt--;
317}
318
319/* Load a particular node out of a tree */
320struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num)
321{
322 struct hfs_bnode *node;
323 struct hfs_bnode_desc *desc;
324 int i, rec_off, off, next_off;
325 int entry_size, key_size;
326
327 spin_lock(&tree->hash_lock);
328 node = hfs_bnode_findhash(tree, num);
329 if (node) {
330 hfs_bnode_get(node);
331 spin_unlock(&tree->hash_lock);
332 wait_event(node->lock_wq, !test_bit(HFS_BNODE_NEW, &node->flags));
333 if (test_bit(HFS_BNODE_ERROR, &node->flags))
334 goto node_error;
335 return node;
336 }
337 spin_unlock(&tree->hash_lock);
338 node = __hfs_bnode_create(tree, num);
339 if (!node)
340 return ERR_PTR(-ENOMEM);
341 if (test_bit(HFS_BNODE_ERROR, &node->flags))
342 goto node_error;
343 if (!test_bit(HFS_BNODE_NEW, &node->flags))
344 return node;
345
346 desc = (struct hfs_bnode_desc *)(kmap(node->page[0]) + node->page_offset);
347 node->prev = be32_to_cpu(desc->prev);
348 node->next = be32_to_cpu(desc->next);
349 node->num_recs = be16_to_cpu(desc->num_recs);
350 node->type = desc->type;
351 node->height = desc->height;
352 kunmap(node->page[0]);
353
354 switch (node->type) {
355 case HFS_NODE_HEADER:
356 case HFS_NODE_MAP:
357 if (node->height != 0)
358 goto node_error;
359 break;
360 case HFS_NODE_LEAF:
361 if (node->height != 1)
362 goto node_error;
363 break;
364 case HFS_NODE_INDEX:
365 if (node->height <= 1 || node->height > tree->depth)
366 goto node_error;
367 break;
368 default:
369 goto node_error;
370 }
371
372 rec_off = tree->node_size - 2;
373 off = hfs_bnode_read_u16(node, rec_off);
374 if (off != sizeof(struct hfs_bnode_desc))
375 goto node_error;
376 for (i = 1; i <= node->num_recs; off = next_off, i++) {
377 rec_off -= 2;
378 next_off = hfs_bnode_read_u16(node, rec_off);
379 if (next_off <= off ||
380 next_off > tree->node_size ||
381 next_off & 1)
382 goto node_error;
383 entry_size = next_off - off;
384 if (node->type != HFS_NODE_INDEX &&
385 node->type != HFS_NODE_LEAF)
386 continue;
387 key_size = hfs_bnode_read_u8(node, off) + 1;
388 if (key_size >= entry_size /*|| key_size & 1*/)
389 goto node_error;
390 }
391 clear_bit(HFS_BNODE_NEW, &node->flags);
392 wake_up(&node->lock_wq);
393 return node;
394
395node_error:
396 set_bit(HFS_BNODE_ERROR, &node->flags);
397 clear_bit(HFS_BNODE_NEW, &node->flags);
398 wake_up(&node->lock_wq);
399 hfs_bnode_put(node);
400 return ERR_PTR(-EIO);
401}
402
403void hfs_bnode_free(struct hfs_bnode *node)
404{
405 //int i;
406
407 //for (i = 0; i < node->tree->pages_per_bnode; i++)
408 // if (node->page[i])
409 // page_cache_release(node->page[i]);
410 kfree(node);
411}
412
413struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num)
414{
415 struct hfs_bnode *node;
416 struct page **pagep;
417 int i;
418
419 spin_lock(&tree->hash_lock);
420 node = hfs_bnode_findhash(tree, num);
421 spin_unlock(&tree->hash_lock);
422 if (node)
423 BUG();
424 node = __hfs_bnode_create(tree, num);
425 if (!node)
426 return ERR_PTR(-ENOMEM);
427 if (test_bit(HFS_BNODE_ERROR, &node->flags)) {
428 hfs_bnode_put(node);
429 return ERR_PTR(-EIO);
430 }
431
432 pagep = node->page;
433 memset(kmap(*pagep) + node->page_offset, 0,
434 min((int)PAGE_CACHE_SIZE, (int)tree->node_size));
435 set_page_dirty(*pagep);
436 kunmap(*pagep);
437 for (i = 1; i < tree->pages_per_bnode; i++) {
438 memset(kmap(*++pagep), 0, PAGE_CACHE_SIZE);
439 set_page_dirty(*pagep);
440 kunmap(*pagep);
441 }
442 clear_bit(HFS_BNODE_NEW, &node->flags);
443 wake_up(&node->lock_wq);
444
445 return node;
446}
447
448void hfs_bnode_get(struct hfs_bnode *node)
449{
450 if (node) {
451 atomic_inc(&node->refcnt);
452#if REF_PAGES
453 {
454 int i;
455 for (i = 0; i < node->tree->pages_per_bnode; i++)
456 get_page(node->page[i]);
457 }
458#endif
459 dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n",
460 node->tree->cnid, node->this, atomic_read(&node->refcnt));
461 }
462}
463
464/* Dispose of resources used by a node */
465void hfs_bnode_put(struct hfs_bnode *node)
466{
467 if (node) {
468 struct hfs_btree *tree = node->tree;
469 int i;
470
471 dprint(DBG_BNODE_REFS, "put_node(%d:%d): %d\n",
472 node->tree->cnid, node->this, atomic_read(&node->refcnt));
473 if (!atomic_read(&node->refcnt))
474 BUG();
475 if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock)) {
476#if REF_PAGES
477 for (i = 0; i < tree->pages_per_bnode; i++)
478 put_page(node->page[i]);
479#endif
480 return;
481 }
482 for (i = 0; i < tree->pages_per_bnode; i++) {
483 mark_page_accessed(node->page[i]);
484#if REF_PAGES
485 put_page(node->page[i]);
486#endif
487 }
488
489 if (test_bit(HFS_BNODE_DELETED, &node->flags)) {
490 hfs_bnode_unhash(node);
491 spin_unlock(&tree->hash_lock);
492 hfs_bmap_free(node);
493 hfs_bnode_free(node);
494 return;
495 }
496 spin_unlock(&tree->hash_lock);
497 }
498}
diff --git a/fs/hfs/brec.c b/fs/hfs/brec.c
new file mode 100644
index 000000000000..7d8fff2c25fc
--- /dev/null
+++ b/fs/hfs/brec.c
@@ -0,0 +1,496 @@
1/*
2 * linux/fs/hfs/brec.c
3 *
4 * Copyright (C) 2001
5 * Brad Boyer (flar@allandria.com)
6 * (C) 2003 Ardis Technologies <roman@ardistech.com>
7 *
8 * Handle individual btree records
9 */
10
11#include "btree.h"
12
13static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd);
14static int hfs_brec_update_parent(struct hfs_find_data *fd);
15static int hfs_btree_inc_height(struct hfs_btree *tree);
16
17/* Get the length and offset of the given record in the given node */
18u16 hfs_brec_lenoff(struct hfs_bnode *node, u16 rec, u16 *off)
19{
20 __be16 retval[2];
21 u16 dataoff;
22
23 dataoff = node->tree->node_size - (rec + 2) * 2;
24 hfs_bnode_read(node, retval, dataoff, 4);
25 *off = be16_to_cpu(retval[1]);
26 return be16_to_cpu(retval[0]) - *off;
27}
28
29/* Get the length of the key from a keyed record */
30u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
31{
32 u16 retval, recoff;
33
34 if (node->type != HFS_NODE_INDEX && node->type != HFS_NODE_LEAF)
35 return 0;
36
37 if ((node->type == HFS_NODE_INDEX) &&
38 !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) {
39 if (node->tree->attributes & HFS_TREE_BIGKEYS)
40 retval = node->tree->max_key_len + 2;
41 else
42 retval = node->tree->max_key_len + 1;
43 } else {
44 recoff = hfs_bnode_read_u16(node, node->tree->node_size - (rec + 1) * 2);
45 if (!recoff)
46 return 0;
47 if (node->tree->attributes & HFS_TREE_BIGKEYS)
48 retval = hfs_bnode_read_u16(node, recoff) + 2;
49 else
50 retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1;
51 }
52 return retval;
53}
54
55int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
56{
57 struct hfs_btree *tree;
58 struct hfs_bnode *node, *new_node;
59 int size, key_len, rec;
60 int data_off, end_off;
61 int idx_rec_off, data_rec_off, end_rec_off;
62 __be32 cnid;
63
64 tree = fd->tree;
65 if (!fd->bnode) {
66 if (!tree->root)
67 hfs_btree_inc_height(tree);
68 fd->bnode = hfs_bnode_find(tree, tree->leaf_head);
69 if (IS_ERR(fd->bnode))
70 return PTR_ERR(fd->bnode);
71 fd->record = -1;
72 }
73 new_node = NULL;
74 key_len = (fd->search_key->key_len | 1) + 1;
75again:
76 /* new record idx and complete record size */
77 rec = fd->record + 1;
78 size = key_len + entry_len;
79
80 node = fd->bnode;
81 hfs_bnode_dump(node);
82 /* get last offset */
83 end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
84 end_off = hfs_bnode_read_u16(node, end_rec_off);
85 end_rec_off -= 2;
86 dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n", rec, size, end_off, end_rec_off);
87 if (size > end_rec_off - end_off) {
88 if (new_node)
89 panic("not enough room!\n");
90 new_node = hfs_bnode_split(fd);
91 if (IS_ERR(new_node))
92 return PTR_ERR(new_node);
93 goto again;
94 }
95 if (node->type == HFS_NODE_LEAF) {
96 tree->leaf_count++;
97 mark_inode_dirty(tree->inode);
98 }
99 node->num_recs++;
100 /* write new last offset */
101 hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
102 hfs_bnode_write_u16(node, end_rec_off, end_off + size);
103 data_off = end_off;
104 data_rec_off = end_rec_off + 2;
105 idx_rec_off = tree->node_size - (rec + 1) * 2;
106 if (idx_rec_off == data_rec_off)
107 goto skip;
108 /* move all following entries */
109 do {
110 data_off = hfs_bnode_read_u16(node, data_rec_off + 2);
111 hfs_bnode_write_u16(node, data_rec_off, data_off + size);
112 data_rec_off += 2;
113 } while (data_rec_off < idx_rec_off);
114
115 /* move data away */
116 hfs_bnode_move(node, data_off + size, data_off,
117 end_off - data_off);
118
119skip:
120 hfs_bnode_write(node, fd->search_key, data_off, key_len);
121 hfs_bnode_write(node, entry, data_off + key_len, entry_len);
122 hfs_bnode_dump(node);
123
124 if (new_node) {
125 /* update parent key if we inserted a key
126 * at the start of the first node
127 */
128 if (!rec && new_node != node)
129 hfs_brec_update_parent(fd);
130
131 hfs_bnode_put(fd->bnode);
132 if (!new_node->parent) {
133 hfs_btree_inc_height(tree);
134 new_node->parent = tree->root;
135 }
136 fd->bnode = hfs_bnode_find(tree, new_node->parent);
137
138 /* create index data entry */
139 cnid = cpu_to_be32(new_node->this);
140 entry = &cnid;
141 entry_len = sizeof(cnid);
142
143 /* get index key */
144 hfs_bnode_read_key(new_node, fd->search_key, 14);
145 __hfs_brec_find(fd->bnode, fd);
146
147 hfs_bnode_put(new_node);
148 new_node = NULL;
149
150 if (tree->attributes & HFS_TREE_VARIDXKEYS)
151 key_len = fd->search_key->key_len + 1;
152 else {
153 fd->search_key->key_len = tree->max_key_len;
154 key_len = tree->max_key_len + 1;
155 }
156 goto again;
157 }
158
159 if (!rec)
160 hfs_brec_update_parent(fd);
161
162 return 0;
163}
164
165int hfs_brec_remove(struct hfs_find_data *fd)
166{
167 struct hfs_btree *tree;
168 struct hfs_bnode *node, *parent;
169 int end_off, rec_off, data_off, size;
170
171 tree = fd->tree;
172 node = fd->bnode;
173again:
174 rec_off = tree->node_size - (fd->record + 2) * 2;
175 end_off = tree->node_size - (node->num_recs + 1) * 2;
176
177 if (node->type == HFS_NODE_LEAF) {
178 tree->leaf_count--;
179 mark_inode_dirty(tree->inode);
180 }
181 hfs_bnode_dump(node);
182 dprint(DBG_BNODE_MOD, "remove_rec: %d, %d\n", fd->record, fd->keylength + fd->entrylength);
183 if (!--node->num_recs) {
184 hfs_bnode_unlink(node);
185 if (!node->parent)
186 return 0;
187 parent = hfs_bnode_find(tree, node->parent);
188 if (IS_ERR(parent))
189 return PTR_ERR(parent);
190 hfs_bnode_put(node);
191 node = fd->bnode = parent;
192
193 __hfs_brec_find(node, fd);
194 goto again;
195 }
196 hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
197
198 if (rec_off == end_off)
199 goto skip;
200 size = fd->keylength + fd->entrylength;
201
202 do {
203 data_off = hfs_bnode_read_u16(node, rec_off);
204 hfs_bnode_write_u16(node, rec_off + 2, data_off - size);
205 rec_off -= 2;
206 } while (rec_off >= end_off);
207
208 /* fill hole */
209 hfs_bnode_move(node, fd->keyoffset, fd->keyoffset + size,
210 data_off - fd->keyoffset - size);
211skip:
212 hfs_bnode_dump(node);
213 if (!fd->record)
214 hfs_brec_update_parent(fd);
215 return 0;
216}
217
218static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
219{
220 struct hfs_btree *tree;
221 struct hfs_bnode *node, *new_node;
222 struct hfs_bnode_desc node_desc;
223 int num_recs, new_rec_off, new_off, old_rec_off;
224 int data_start, data_end, size;
225
226 tree = fd->tree;
227 node = fd->bnode;
228 new_node = hfs_bmap_alloc(tree);
229 if (IS_ERR(new_node))
230 return new_node;
231 hfs_bnode_get(node);
232 dprint(DBG_BNODE_MOD, "split_nodes: %d - %d - %d\n",
233 node->this, new_node->this, node->next);
234 new_node->next = node->next;
235 new_node->prev = node->this;
236 new_node->parent = node->parent;
237 new_node->type = node->type;
238 new_node->height = node->height;
239
240 size = tree->node_size / 2 - node->num_recs * 2 - 14;
241 old_rec_off = tree->node_size - 4;
242 num_recs = 1;
243 for (;;) {
244 data_start = hfs_bnode_read_u16(node, old_rec_off);
245 if (data_start > size)
246 break;
247 old_rec_off -= 2;
248 if (++num_recs < node->num_recs)
249 continue;
250 /* panic? */
251 hfs_bnode_put(node);
252 hfs_bnode_put(new_node);
253 return ERR_PTR(-ENOSPC);
254 }
255
256 if (fd->record + 1 < num_recs) {
257 /* new record is in the lower half,
258 * so leave some more space there
259 */
260 old_rec_off += 2;
261 num_recs--;
262 data_start = hfs_bnode_read_u16(node, old_rec_off);
263 } else {
264 hfs_bnode_put(node);
265 hfs_bnode_get(new_node);
266 fd->bnode = new_node;
267 fd->record -= num_recs;
268 fd->keyoffset -= data_start - 14;
269 fd->entryoffset -= data_start - 14;
270 }
271 new_node->num_recs = node->num_recs - num_recs;
272 node->num_recs = num_recs;
273
274 new_rec_off = tree->node_size - 2;
275 new_off = 14;
276 size = data_start - new_off;
277 num_recs = new_node->num_recs;
278 data_end = data_start;
279 while (num_recs) {
280 hfs_bnode_write_u16(new_node, new_rec_off, new_off);
281 old_rec_off -= 2;
282 new_rec_off -= 2;
283 data_end = hfs_bnode_read_u16(node, old_rec_off);
284 new_off = data_end - size;
285 num_recs--;
286 }
287 hfs_bnode_write_u16(new_node, new_rec_off, new_off);
288 hfs_bnode_copy(new_node, 14, node, data_start, data_end - data_start);
289
290 /* update new bnode header */
291 node_desc.next = cpu_to_be32(new_node->next);
292 node_desc.prev = cpu_to_be32(new_node->prev);
293 node_desc.type = new_node->type;
294 node_desc.height = new_node->height;
295 node_desc.num_recs = cpu_to_be16(new_node->num_recs);
296 node_desc.reserved = 0;
297 hfs_bnode_write(new_node, &node_desc, 0, sizeof(node_desc));
298
299 /* update previous bnode header */
300 node->next = new_node->this;
301 hfs_bnode_read(node, &node_desc, 0, sizeof(node_desc));
302 node_desc.next = cpu_to_be32(node->next);
303 node_desc.num_recs = cpu_to_be16(node->num_recs);
304 hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc));
305
306 /* update next bnode header */
307 if (new_node->next) {
308 struct hfs_bnode *next_node = hfs_bnode_find(tree, new_node->next);
309 next_node->prev = new_node->this;
310 hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc));
311 node_desc.prev = cpu_to_be32(next_node->prev);
312 hfs_bnode_write(next_node, &node_desc, 0, sizeof(node_desc));
313 hfs_bnode_put(next_node);
314 } else if (node->this == tree->leaf_tail) {
315 /* if there is no next node, this might be the new tail */
316 tree->leaf_tail = new_node->this;
317 mark_inode_dirty(tree->inode);
318 }
319
320 hfs_bnode_dump(node);
321 hfs_bnode_dump(new_node);
322 hfs_bnode_put(node);
323
324 return new_node;
325}
326
327static int hfs_brec_update_parent(struct hfs_find_data *fd)
328{
329 struct hfs_btree *tree;
330 struct hfs_bnode *node, *new_node, *parent;
331 int newkeylen, diff;
332 int rec, rec_off, end_rec_off;
333 int start_off, end_off;
334
335 tree = fd->tree;
336 node = fd->bnode;
337 new_node = NULL;
338 if (!node->parent)
339 return 0;
340
341again:
342 parent = hfs_bnode_find(tree, node->parent);
343 if (IS_ERR(parent))
344 return PTR_ERR(parent);
345 __hfs_brec_find(parent, fd);
346 hfs_bnode_dump(parent);
347 rec = fd->record;
348
349 /* size difference between old and new key */
350 if (tree->attributes & HFS_TREE_VARIDXKEYS)
351 newkeylen = (hfs_bnode_read_u8(node, 14) | 1) + 1;
352 else
353 fd->keylength = newkeylen = tree->max_key_len + 1;
354 dprint(DBG_BNODE_MOD, "update_rec: %d, %d, %d\n", rec, fd->keylength, newkeylen);
355
356 rec_off = tree->node_size - (rec + 2) * 2;
357 end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
358 diff = newkeylen - fd->keylength;
359 if (!diff)
360 goto skip;
361 if (diff > 0) {
362 end_off = hfs_bnode_read_u16(parent, end_rec_off);
363 if (end_rec_off - end_off < diff) {
364
365 printk("splitting index node...\n");
366 fd->bnode = parent;
367 new_node = hfs_bnode_split(fd);
368 if (IS_ERR(new_node))
369 return PTR_ERR(new_node);
370 parent = fd->bnode;
371 rec = fd->record;
372 rec_off = tree->node_size - (rec + 2) * 2;
373 end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
374 }
375 }
376
377 end_off = start_off = hfs_bnode_read_u16(parent, rec_off);
378 hfs_bnode_write_u16(parent, rec_off, start_off + diff);
379 start_off -= 4; /* move previous cnid too */
380
381 while (rec_off > end_rec_off) {
382 rec_off -= 2;
383 end_off = hfs_bnode_read_u16(parent, rec_off);
384 hfs_bnode_write_u16(parent, rec_off, end_off + diff);
385 }
386 hfs_bnode_move(parent, start_off + diff, start_off,
387 end_off - start_off);
388skip:
389 hfs_bnode_copy(parent, fd->keyoffset, node, 14, newkeylen);
390 if (!(tree->attributes & HFS_TREE_VARIDXKEYS))
391 hfs_bnode_write_u8(parent, fd->keyoffset, newkeylen - 1);
392 hfs_bnode_dump(parent);
393
394 hfs_bnode_put(node);
395 node = parent;
396
397 if (new_node) {
398 __be32 cnid;
399
400 fd->bnode = hfs_bnode_find(tree, new_node->parent);
401 /* create index key and entry */
402 hfs_bnode_read_key(new_node, fd->search_key, 14);
403 cnid = cpu_to_be32(new_node->this);
404
405 __hfs_brec_find(fd->bnode, fd);
406 hfs_brec_insert(fd, &cnid, sizeof(cnid));
407 hfs_bnode_put(fd->bnode);
408 hfs_bnode_put(new_node);
409
410 if (!rec) {
411 if (new_node == node)
412 goto out;
413 /* restore search_key */
414 hfs_bnode_read_key(node, fd->search_key, 14);
415 }
416 }
417
418 if (!rec && node->parent)
419 goto again;
420out:
421 fd->bnode = node;
422 return 0;
423}
424
425static int hfs_btree_inc_height(struct hfs_btree *tree)
426{
427 struct hfs_bnode *node, *new_node;
428 struct hfs_bnode_desc node_desc;
429 int key_size, rec;
430 __be32 cnid;
431
432 node = NULL;
433 if (tree->root) {
434 node = hfs_bnode_find(tree, tree->root);
435 if (IS_ERR(node))
436 return PTR_ERR(node);
437 }
438 new_node = hfs_bmap_alloc(tree);
439 if (IS_ERR(new_node)) {
440 hfs_bnode_put(node);
441 return PTR_ERR(new_node);
442 }
443
444 tree->root = new_node->this;
445 if (!tree->depth) {
446 tree->leaf_head = tree->leaf_tail = new_node->this;
447 new_node->type = HFS_NODE_LEAF;
448 new_node->num_recs = 0;
449 } else {
450 new_node->type = HFS_NODE_INDEX;
451 new_node->num_recs = 1;
452 }
453 new_node->parent = 0;
454 new_node->next = 0;
455 new_node->prev = 0;
456 new_node->height = ++tree->depth;
457
458 node_desc.next = cpu_to_be32(new_node->next);
459 node_desc.prev = cpu_to_be32(new_node->prev);
460 node_desc.type = new_node->type;
461 node_desc.height = new_node->height;
462 node_desc.num_recs = cpu_to_be16(new_node->num_recs);
463 node_desc.reserved = 0;
464 hfs_bnode_write(new_node, &node_desc, 0, sizeof(node_desc));
465
466 rec = tree->node_size - 2;
467 hfs_bnode_write_u16(new_node, rec, 14);
468
469 if (node) {
470 /* insert old root idx into new root */
471 node->parent = tree->root;
472 if (node->type == HFS_NODE_LEAF ||
473 tree->attributes & HFS_TREE_VARIDXKEYS)
474 key_size = hfs_bnode_read_u8(node, 14) + 1;
475 else
476 key_size = tree->max_key_len + 1;
477 hfs_bnode_copy(new_node, 14, node, 14, key_size);
478
479 if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) {
480 key_size = tree->max_key_len + 1;
481 hfs_bnode_write_u8(new_node, 14, tree->max_key_len);
482 }
483 key_size = (key_size + 1) & -2;
484 cnid = cpu_to_be32(node->this);
485 hfs_bnode_write(new_node, &cnid, 14 + key_size, 4);
486
487 rec -= 2;
488 hfs_bnode_write_u16(new_node, rec, 14 + key_size + 4);
489
490 hfs_bnode_put(node);
491 }
492 hfs_bnode_put(new_node);
493 mark_inode_dirty(tree->inode);
494
495 return 0;
496}
diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c
new file mode 100644
index 000000000000..394725efa1c8
--- /dev/null
+++ b/fs/hfs/btree.c
@@ -0,0 +1,327 @@
1/*
2 * linux/fs/hfs/btree.c
3 *
4 * Copyright (C) 2001
5 * Brad Boyer (flar@allandria.com)
6 * (C) 2003 Ardis Technologies <roman@ardistech.com>
7 *
8 * Handle opening/closing btree
9 */
10
11#include <linux/pagemap.h>
12
13#include "btree.h"
14
15/* Get a reference to a B*Tree and do some initial checks */
16struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp keycmp)
17{
18 struct hfs_btree *tree;
19 struct hfs_btree_header_rec *head;
20 struct address_space *mapping;
21 struct page *page;
22 unsigned int size;
23
24 tree = kmalloc(sizeof(*tree), GFP_KERNEL);
25 if (!tree)
26 return NULL;
27 memset(tree, 0, sizeof(*tree));
28
29 init_MUTEX(&tree->tree_lock);
30 spin_lock_init(&tree->hash_lock);
31 /* Set the correct compare function */
32 tree->sb = sb;
33 tree->cnid = id;
34 tree->keycmp = keycmp;
35
36 tree->inode = iget_locked(sb, id);
37 if (!tree->inode)
38 goto free_tree;
39 if (!(tree->inode->i_state & I_NEW))
40 BUG();
41 {
42 struct hfs_mdb *mdb = HFS_SB(sb)->mdb;
43 HFS_I(tree->inode)->flags = 0;
44 init_MUTEX(&HFS_I(tree->inode)->extents_lock);
45 switch (id) {
46 case HFS_EXT_CNID:
47 hfs_inode_read_fork(tree->inode, mdb->drXTExtRec, mdb->drXTFlSize,
48 mdb->drXTFlSize, be32_to_cpu(mdb->drXTClpSiz));
49 tree->inode->i_mapping->a_ops = &hfs_btree_aops;
50 break;
51 case HFS_CAT_CNID:
52 hfs_inode_read_fork(tree->inode, mdb->drCTExtRec, mdb->drCTFlSize,
53 mdb->drCTFlSize, be32_to_cpu(mdb->drCTClpSiz));
54 tree->inode->i_mapping->a_ops = &hfs_btree_aops;
55 break;
56 default:
57 BUG();
58 }
59 }
60 unlock_new_inode(tree->inode);
61
62 mapping = tree->inode->i_mapping;
63 page = read_cache_page(mapping, 0, (filler_t *)mapping->a_ops->readpage, NULL);
64 if (IS_ERR(page))
65 goto free_tree;
66
67 /* Load the header */
68 head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc));
69 tree->root = be32_to_cpu(head->root);
70 tree->leaf_count = be32_to_cpu(head->leaf_count);
71 tree->leaf_head = be32_to_cpu(head->leaf_head);
72 tree->leaf_tail = be32_to_cpu(head->leaf_tail);
73 tree->node_count = be32_to_cpu(head->node_count);
74 tree->free_nodes = be32_to_cpu(head->free_nodes);
75 tree->attributes = be32_to_cpu(head->attributes);
76 tree->node_size = be16_to_cpu(head->node_size);
77 tree->max_key_len = be16_to_cpu(head->max_key_len);
78 tree->depth = be16_to_cpu(head->depth);
79
80 size = tree->node_size;
81 if (!size || size & (size - 1))
82 goto fail_page;
83 if (!tree->node_count)
84 goto fail_page;
85 tree->node_size_shift = ffs(size) - 1;
86 tree->pages_per_bnode = (tree->node_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
87
88 kunmap(page);
89 page_cache_release(page);
90 return tree;
91
92 fail_page:
93 tree->inode->i_mapping->a_ops = &hfs_aops;
94 page_cache_release(page);
95 free_tree:
96 iput(tree->inode);
97 kfree(tree);
98 return NULL;
99}
100
101/* Release resources used by a btree */
102void hfs_btree_close(struct hfs_btree *tree)
103{
104 struct hfs_bnode *node;
105 int i;
106
107 if (!tree)
108 return;
109
110 for (i = 0; i < NODE_HASH_SIZE; i++) {
111 while ((node = tree->node_hash[i])) {
112 tree->node_hash[i] = node->next_hash;
113 if (atomic_read(&node->refcnt))
114 printk("HFS: node %d:%d still has %d user(s)!\n",
115 node->tree->cnid, node->this, atomic_read(&node->refcnt));
116 hfs_bnode_free(node);
117 tree->node_hash_cnt--;
118 }
119 }
120 iput(tree->inode);
121 kfree(tree);
122}
123
124void hfs_btree_write(struct hfs_btree *tree)
125{
126 struct hfs_btree_header_rec *head;
127 struct hfs_bnode *node;
128 struct page *page;
129
130 node = hfs_bnode_find(tree, 0);
131 if (IS_ERR(node))
132 /* panic? */
133 return;
134 /* Load the header */
135 page = node->page[0];
136 head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc));
137
138 head->root = cpu_to_be32(tree->root);
139 head->leaf_count = cpu_to_be32(tree->leaf_count);
140 head->leaf_head = cpu_to_be32(tree->leaf_head);
141 head->leaf_tail = cpu_to_be32(tree->leaf_tail);
142 head->node_count = cpu_to_be32(tree->node_count);
143 head->free_nodes = cpu_to_be32(tree->free_nodes);
144 head->attributes = cpu_to_be32(tree->attributes);
145 head->depth = cpu_to_be16(tree->depth);
146
147 kunmap(page);
148 set_page_dirty(page);
149 hfs_bnode_put(node);
150}
151
152static struct hfs_bnode *hfs_bmap_new_bmap(struct hfs_bnode *prev, u32 idx)
153{
154 struct hfs_btree *tree = prev->tree;
155 struct hfs_bnode *node;
156 struct hfs_bnode_desc desc;
157 __be32 cnid;
158
159 node = hfs_bnode_create(tree, idx);
160 if (IS_ERR(node))
161 return node;
162
163 if (!tree->free_nodes)
164 panic("FIXME!!!");
165 tree->free_nodes--;
166 prev->next = idx;
167 cnid = cpu_to_be32(idx);
168 hfs_bnode_write(prev, &cnid, offsetof(struct hfs_bnode_desc, next), 4);
169
170 node->type = HFS_NODE_MAP;
171 node->num_recs = 1;
172 hfs_bnode_clear(node, 0, tree->node_size);
173 desc.next = 0;
174 desc.prev = 0;
175 desc.type = HFS_NODE_MAP;
176 desc.height = 0;
177 desc.num_recs = cpu_to_be16(1);
178 desc.reserved = 0;
179 hfs_bnode_write(node, &desc, 0, sizeof(desc));
180 hfs_bnode_write_u16(node, 14, 0x8000);
181 hfs_bnode_write_u16(node, tree->node_size - 2, 14);
182 hfs_bnode_write_u16(node, tree->node_size - 4, tree->node_size - 6);
183
184 return node;
185}
186
187struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
188{
189 struct hfs_bnode *node, *next_node;
190 struct page **pagep;
191 u32 nidx, idx;
192 u16 off, len;
193 u8 *data, byte, m;
194 int i;
195
196 while (!tree->free_nodes) {
197 struct inode *inode = tree->inode;
198 u32 count;
199 int res;
200
201 res = hfs_extend_file(inode);
202 if (res)
203 return ERR_PTR(res);
204 HFS_I(inode)->phys_size = inode->i_size =
205 (loff_t)HFS_I(inode)->alloc_blocks *
206 HFS_SB(tree->sb)->alloc_blksz;
207 HFS_I(inode)->fs_blocks = inode->i_size >>
208 tree->sb->s_blocksize_bits;
209 inode_set_bytes(inode, inode->i_size);
210 count = inode->i_size >> tree->node_size_shift;
211 tree->free_nodes = count - tree->node_count;
212 tree->node_count = count;
213 }
214
215 nidx = 0;
216 node = hfs_bnode_find(tree, nidx);
217 if (IS_ERR(node))
218 return node;
219 len = hfs_brec_lenoff(node, 2, &off);
220
221 off += node->page_offset;
222 pagep = node->page + (off >> PAGE_CACHE_SHIFT);
223 data = kmap(*pagep);
224 off &= ~PAGE_CACHE_MASK;
225 idx = 0;
226
227 for (;;) {
228 while (len) {
229 byte = data[off];
230 if (byte != 0xff) {
231 for (m = 0x80, i = 0; i < 8; m >>= 1, i++) {
232 if (!(byte & m)) {
233 idx += i;
234 data[off] |= m;
235 set_page_dirty(*pagep);
236 kunmap(*pagep);
237 tree->free_nodes--;
238 mark_inode_dirty(tree->inode);
239 hfs_bnode_put(node);
240 return hfs_bnode_create(tree, idx);
241 }
242 }
243 }
244 if (++off >= PAGE_CACHE_SIZE) {
245 kunmap(*pagep);
246 data = kmap(*++pagep);
247 off = 0;
248 }
249 idx += 8;
250 len--;
251 }
252 kunmap(*pagep);
253 nidx = node->next;
254 if (!nidx) {
255 printk("create new bmap node...\n");
256 next_node = hfs_bmap_new_bmap(node, idx);
257 } else
258 next_node = hfs_bnode_find(tree, nidx);
259 hfs_bnode_put(node);
260 if (IS_ERR(next_node))
261 return next_node;
262 node = next_node;
263
264 len = hfs_brec_lenoff(node, 0, &off);
265 off += node->page_offset;
266 pagep = node->page + (off >> PAGE_CACHE_SHIFT);
267 data = kmap(*pagep);
268 off &= ~PAGE_CACHE_MASK;
269 }
270}
271
272void hfs_bmap_free(struct hfs_bnode *node)
273{
274 struct hfs_btree *tree;
275 struct page *page;
276 u16 off, len;
277 u32 nidx;
278 u8 *data, byte, m;
279
280 dprint(DBG_BNODE_MOD, "btree_free_node: %u\n", node->this);
281 tree = node->tree;
282 nidx = node->this;
283 node = hfs_bnode_find(tree, 0);
284 if (IS_ERR(node))
285 return;
286 len = hfs_brec_lenoff(node, 2, &off);
287 while (nidx >= len * 8) {
288 u32 i;
289
290 nidx -= len * 8;
291 i = node->next;
292 hfs_bnode_put(node);
293 if (!i) {
294 /* panic */;
295 printk("HFS: unable to free bnode %u. bmap not found!\n", node->this);
296 return;
297 }
298 node = hfs_bnode_find(tree, i);
299 if (IS_ERR(node))
300 return;
301 if (node->type != HFS_NODE_MAP) {
302 /* panic */;
303 printk("HFS: invalid bmap found! (%u,%d)\n", node->this, node->type);
304 hfs_bnode_put(node);
305 return;
306 }
307 len = hfs_brec_lenoff(node, 0, &off);
308 }
309 off += node->page_offset + nidx / 8;
310 page = node->page[off >> PAGE_CACHE_SHIFT];
311 data = kmap(page);
312 off &= ~PAGE_CACHE_MASK;
313 m = 1 << (~nidx & 7);
314 byte = data[off];
315 if (!(byte & m)) {
316 printk("HFS: trying to free free bnode %u(%d)\n", node->this, node->type);
317 kunmap(page);
318 hfs_bnode_put(node);
319 return;
320 }
321 data[off] = byte & ~m;
322 set_page_dirty(page);
323 kunmap(page);
324 hfs_bnode_put(node);
325 tree->free_nodes++;
326 mark_inode_dirty(tree->inode);
327}
diff --git a/fs/hfs/btree.h b/fs/hfs/btree.h
new file mode 100644
index 000000000000..cc51905ac21d
--- /dev/null
+++ b/fs/hfs/btree.h
@@ -0,0 +1,168 @@
1/*
2 * linux/fs/hfs/btree.h
3 *
4 * Copyright (C) 2001
5 * Brad Boyer (flar@allandria.com)
6 * (C) 2003 Ardis Technologies <roman@ardistech.com>
7 */
8
9#include "hfs_fs.h"
10
11typedef int (*btree_keycmp)(const btree_key *, const btree_key *);
12
13#define NODE_HASH_SIZE 256
14
15/* A HFS BTree held in memory */
16struct hfs_btree {
17 struct super_block *sb;
18 struct inode *inode;
19 btree_keycmp keycmp;
20
21 u32 cnid;
22 u32 root;
23 u32 leaf_count;
24 u32 leaf_head;
25 u32 leaf_tail;
26 u32 node_count;
27 u32 free_nodes;
28 u32 attributes;
29
30 unsigned int node_size;
31 unsigned int node_size_shift;
32 unsigned int max_key_len;
33 unsigned int depth;
34
35 //unsigned int map1_size, map_size;
36 struct semaphore tree_lock;
37
38 unsigned int pages_per_bnode;
39 spinlock_t hash_lock;
40 struct hfs_bnode *node_hash[NODE_HASH_SIZE];
41 int node_hash_cnt;
42};
43
44/* A HFS BTree node in memory */
45struct hfs_bnode {
46 struct hfs_btree *tree;
47
48 u32 prev;
49 u32 this;
50 u32 next;
51 u32 parent;
52
53 u16 num_recs;
54 u8 type;
55 u8 height;
56
57 struct hfs_bnode *next_hash;
58 unsigned long flags;
59 wait_queue_head_t lock_wq;
60 atomic_t refcnt;
61 unsigned int page_offset;
62 struct page *page[0];
63};
64
65#define HFS_BNODE_ERROR 0
66#define HFS_BNODE_NEW 1
67#define HFS_BNODE_DELETED 2
68
69struct hfs_find_data {
70 btree_key *key;
71 btree_key *search_key;
72 struct hfs_btree *tree;
73 struct hfs_bnode *bnode;
74 int record;
75 int keyoffset, keylength;
76 int entryoffset, entrylength;
77};
78
79
80/* btree.c */
81extern struct hfs_btree *hfs_btree_open(struct super_block *, u32, btree_keycmp);
82extern void hfs_btree_close(struct hfs_btree *);
83extern void hfs_btree_write(struct hfs_btree *);
84extern struct hfs_bnode * hfs_bmap_alloc(struct hfs_btree *);
85extern void hfs_bmap_free(struct hfs_bnode *node);
86
87/* bnode.c */
88extern void hfs_bnode_read(struct hfs_bnode *, void *, int, int);
89extern u16 hfs_bnode_read_u16(struct hfs_bnode *, int);
90extern u8 hfs_bnode_read_u8(struct hfs_bnode *, int);
91extern void hfs_bnode_read_key(struct hfs_bnode *, void *, int);
92extern void hfs_bnode_write(struct hfs_bnode *, void *, int, int);
93extern void hfs_bnode_write_u16(struct hfs_bnode *, int, u16);
94extern void hfs_bnode_write_u8(struct hfs_bnode *, int, u8);
95extern void hfs_bnode_clear(struct hfs_bnode *, int, int);
96extern void hfs_bnode_copy(struct hfs_bnode *, int,
97 struct hfs_bnode *, int, int);
98extern void hfs_bnode_move(struct hfs_bnode *, int, int, int);
99extern void hfs_bnode_dump(struct hfs_bnode *);
100extern void hfs_bnode_unlink(struct hfs_bnode *);
101extern struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *, u32);
102extern struct hfs_bnode *hfs_bnode_find(struct hfs_btree *, u32);
103extern void hfs_bnode_unhash(struct hfs_bnode *);
104extern void hfs_bnode_free(struct hfs_bnode *);
105extern struct hfs_bnode *hfs_bnode_create(struct hfs_btree *, u32);
106extern void hfs_bnode_get(struct hfs_bnode *);
107extern void hfs_bnode_put(struct hfs_bnode *);
108
109/* brec.c */
110extern u16 hfs_brec_lenoff(struct hfs_bnode *, u16, u16 *);
111extern u16 hfs_brec_keylen(struct hfs_bnode *, u16);
112extern int hfs_brec_insert(struct hfs_find_data *, void *, int);
113extern int hfs_brec_remove(struct hfs_find_data *);
114
115/* bfind.c */
116extern int hfs_find_init(struct hfs_btree *, struct hfs_find_data *);
117extern void hfs_find_exit(struct hfs_find_data *);
118extern int __hfs_brec_find(struct hfs_bnode *, struct hfs_find_data *);
119extern int hfs_brec_find(struct hfs_find_data *);
120extern int hfs_brec_read(struct hfs_find_data *, void *, int);
121extern int hfs_brec_goto(struct hfs_find_data *, int);
122
123
124struct hfs_bnode_desc {
125 __be32 next; /* (V) Number of the next node at this level */
126 __be32 prev; /* (V) Number of the prev node at this level */
127 u8 type; /* (F) The type of node */
128 u8 height; /* (F) The level of this node (leaves=1) */
129 __be16 num_recs; /* (V) The number of records in this node */
130 u16 reserved;
131} __packed;
132
133#define HFS_NODE_INDEX 0x00 /* An internal (index) node */
134#define HFS_NODE_HEADER 0x01 /* The tree header node (node 0) */
135#define HFS_NODE_MAP 0x02 /* Holds part of the bitmap of used nodes */
136#define HFS_NODE_LEAF 0xFF /* A leaf (ndNHeight==1) node */
137
138struct hfs_btree_header_rec {
139 __be16 depth; /* (V) The number of levels in this B-tree */
140 __be32 root; /* (V) The node number of the root node */
141 __be32 leaf_count; /* (V) The number of leaf records */
142 __be32 leaf_head; /* (V) The number of the first leaf node */
143 __be32 leaf_tail; /* (V) The number of the last leaf node */
144 __be16 node_size; /* (F) The number of bytes in a node (=512) */
145 __be16 max_key_len; /* (F) The length of a key in an index node */
146 __be32 node_count; /* (V) The total number of nodes */
147 __be32 free_nodes; /* (V) The number of unused nodes */
148 u16 reserved1;
149 __be32 clump_size; /* (F) clump size. not usually used. */
150 u8 btree_type; /* (F) BTree type */
151 u8 reserved2;
152 __be32 attributes; /* (F) attributes */
153 u32 reserved3[16];
154} __packed;
155
156#define HFS_NODE_INDEX 0x00 /* An internal (index) node */
157#define HFS_NODE_HEADER 0x01 /* The tree header node (node 0) */
158#define HFS_NODE_MAP 0x02 /* Holds part of the bitmap of used nodes */
159#define HFS_NODE_LEAF 0xFF /* A leaf (ndNHeight==1) node */
160
161#define BTREE_ATTR_BADCLOSE 0x00000001 /* b-tree not closed properly. not
162 used by hfsplus. */
163#define HFS_TREE_BIGKEYS 0x00000002 /* key length is u16 instead of u8.
164 used by hfsplus. */
165#define HFS_TREE_VARIDXKEYS 0x00000004 /* variable key length instead of
166 max key length. use din catalog
167 b-tree but not in extents
168 b-tree (hfsplus). */
diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c
new file mode 100644
index 000000000000..65dedefcabfc
--- /dev/null
+++ b/fs/hfs/catalog.c
@@ -0,0 +1,347 @@
1/*
2 * linux/fs/hfs/catalog.c
3 *
4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * (C) 2003 Ardis Technologies <roman@ardistech.com>
6 * This file may be distributed under the terms of the GNU General Public License.
7 *
8 * This file contains the functions related to the catalog B-tree.
9 *
10 * Cache code shamelessly stolen from
11 * linux/fs/inode.c Copyright (C) 1991, 1992 Linus Torvalds
12 * re-shamelessly stolen Copyright (C) 1997 Linus Torvalds
13 */
14
15#include "hfs_fs.h"
16#include "btree.h"
17
18/*
19 * hfs_cat_build_key()
20 *
21 * Given the ID of the parent and the name build a search key.
22 */
23void hfs_cat_build_key(btree_key *key, u32 parent, struct qstr *name)
24{
25 key->cat.reserved = 0;
26 key->cat.ParID = cpu_to_be32(parent);
27 if (name) {
28 hfs_triv2mac(&key->cat.CName, name);
29 key->key_len = 6 + key->cat.CName.len;
30 } else {
31 memset(&key->cat.CName, 0, sizeof(struct hfs_name));
32 key->key_len = 6;
33 }
34}
35
36static int hfs_cat_build_record(hfs_cat_rec *rec, u32 cnid, struct inode *inode)
37{
38 __be32 mtime = hfs_mtime();
39
40 memset(rec, 0, sizeof(*rec));
41 if (S_ISDIR(inode->i_mode)) {
42 rec->type = HFS_CDR_DIR;
43 rec->dir.DirID = cpu_to_be32(cnid);
44 rec->dir.CrDat = mtime;
45 rec->dir.MdDat = mtime;
46 rec->dir.BkDat = 0;
47 rec->dir.UsrInfo.frView = cpu_to_be16(0xff);
48 return sizeof(struct hfs_cat_dir);
49 } else {
50 /* init some fields for the file record */
51 rec->type = HFS_CDR_FIL;
52 rec->file.Flags = HFS_FIL_USED | HFS_FIL_THD;
53 if (!(inode->i_mode & S_IWUSR))
54 rec->file.Flags |= HFS_FIL_LOCK;
55 rec->file.FlNum = cpu_to_be32(cnid);
56 rec->file.CrDat = mtime;
57 rec->file.MdDat = mtime;
58 rec->file.BkDat = 0;
59 rec->file.UsrWds.fdType = HFS_SB(inode->i_sb)->s_type;
60 rec->file.UsrWds.fdCreator = HFS_SB(inode->i_sb)->s_creator;
61 return sizeof(struct hfs_cat_file);
62 }
63}
64
65static int hfs_cat_build_thread(hfs_cat_rec *rec, int type,
66 u32 parentid, struct qstr *name)
67{
68 rec->type = type;
69 memset(rec->thread.reserved, 0, sizeof(rec->thread.reserved));
70 rec->thread.ParID = cpu_to_be32(parentid);
71 hfs_triv2mac(&rec->thread.CName, name);
72 return sizeof(struct hfs_cat_thread);
73}
74
75/*
76 * create_entry()
77 *
78 * Add a new file or directory to the catalog B-tree and
79 * return a (struct hfs_cat_entry) for it in '*result'.
80 */
81int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode *inode)
82{
83 struct hfs_find_data fd;
84 struct super_block *sb;
85 union hfs_cat_rec entry;
86 int entry_size;
87 int err;
88
89 dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n", str->name, cnid, inode->i_nlink);
90 if (dir->i_size >= HFS_MAX_VALENCE)
91 return -ENOSPC;
92
93 sb = dir->i_sb;
94 hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
95
96 hfs_cat_build_key(fd.search_key, cnid, NULL);
97 entry_size = hfs_cat_build_thread(&entry, S_ISDIR(inode->i_mode) ?
98 HFS_CDR_THD : HFS_CDR_FTH,
99 dir->i_ino, str);
100 err = hfs_brec_find(&fd);
101 if (err != -ENOENT) {
102 if (!err)
103 err = -EEXIST;
104 goto err2;
105 }
106 err = hfs_brec_insert(&fd, &entry, entry_size);
107 if (err)
108 goto err2;
109
110 hfs_cat_build_key(fd.search_key, dir->i_ino, str);
111 entry_size = hfs_cat_build_record(&entry, cnid, inode);
112 err = hfs_brec_find(&fd);
113 if (err != -ENOENT) {
114 /* panic? */
115 if (!err)
116 err = -EEXIST;
117 goto err1;
118 }
119 err = hfs_brec_insert(&fd, &entry, entry_size);
120 if (err)
121 goto err1;
122
123 dir->i_size++;
124 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
125 mark_inode_dirty(dir);
126 hfs_find_exit(&fd);
127 return 0;
128
129err1:
130 hfs_cat_build_key(fd.search_key, cnid, NULL);
131 if (!hfs_brec_find(&fd))
132 hfs_brec_remove(&fd);
133err2:
134 hfs_find_exit(&fd);
135 return err;
136}
137
138/*
139 * hfs_cat_compare()
140 *
141 * Description:
142 * This is the comparison function used for the catalog B-tree. In
143 * comparing catalog B-tree entries, the parent id is the most
144 * significant field (compared as unsigned ints). The name field is
145 * the least significant (compared in "Macintosh lexical order",
146 * see hfs_strcmp() in string.c)
147 * Input Variable(s):
148 * struct hfs_cat_key *key1: pointer to the first key to compare
149 * struct hfs_cat_key *key2: pointer to the second key to compare
150 * Output Variable(s):
151 * NONE
152 * Returns:
153 * int: negative if key1<key2, positive if key1>key2, and 0 if key1==key2
154 * Preconditions:
155 * key1 and key2 point to "valid" (struct hfs_cat_key)s.
156 * Postconditions:
157 * This function has no side-effects
158 */
159int hfs_cat_keycmp(const btree_key *key1, const btree_key *key2)
160{
161 int retval;
162
163 retval = be32_to_cpu(key1->cat.ParID) - be32_to_cpu(key2->cat.ParID);
164 if (!retval)
165 retval = hfs_strcmp(key1->cat.CName.name, key1->cat.CName.len,
166 key2->cat.CName.name, key2->cat.CName.len);
167
168 return retval;
169}
170
171/* Try to get a catalog entry for given catalog id */
172// move to read_super???
173int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
174 struct hfs_find_data *fd)
175{
176 hfs_cat_rec rec;
177 int res, len, type;
178
179 hfs_cat_build_key(fd->search_key, cnid, NULL);
180 res = hfs_brec_read(fd, &rec, sizeof(rec));
181 if (res)
182 return res;
183
184 type = rec.type;
185 if (type != HFS_CDR_THD && type != HFS_CDR_FTH) {
186 printk("HFS-fs: Found bad thread record in catalog\n");
187 return -EIO;
188 }
189
190 fd->search_key->cat.ParID = rec.thread.ParID;
191 len = fd->search_key->cat.CName.len = rec.thread.CName.len;
192 memcpy(fd->search_key->cat.CName.name, rec.thread.CName.name, len);
193 return hfs_brec_find(fd);
194}
195
196
197/*
198 * hfs_cat_delete()
199 *
200 * Delete the indicated file or directory.
201 * The associated thread is also removed unless ('with_thread'==0).
202 */
203int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str)
204{
205 struct super_block *sb;
206 struct hfs_find_data fd;
207 struct list_head *pos;
208 int res, type;
209
210 dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid);
211 sb = dir->i_sb;
212 hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
213
214 hfs_cat_build_key(fd.search_key, dir->i_ino, str);
215 res = hfs_brec_find(&fd);
216 if (res)
217 goto out;
218
219 type = hfs_bnode_read_u8(fd.bnode, fd.entryoffset);
220 if (type == HFS_CDR_FIL) {
221 struct hfs_cat_file file;
222 hfs_bnode_read(fd.bnode, &file, fd.entryoffset, sizeof(file));
223 if (be32_to_cpu(file.FlNum) == cnid) {
224#if 0
225 hfs_free_fork(sb, &file, HFS_FK_DATA);
226#endif
227 hfs_free_fork(sb, &file, HFS_FK_RSRC);
228 }
229 }
230
231 list_for_each(pos, &HFS_I(dir)->open_dir_list) {
232 struct hfs_readdir_data *rd =
233 list_entry(pos, struct hfs_readdir_data, list);
234 if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0)
235 rd->file->f_pos--;
236 }
237
238 res = hfs_brec_remove(&fd);
239 if (res)
240 goto out;
241
242 hfs_cat_build_key(fd.search_key, cnid, NULL);
243 res = hfs_brec_find(&fd);
244 if (!res) {
245 res = hfs_brec_remove(&fd);
246 if (res)
247 goto out;
248 }
249
250 dir->i_size--;
251 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
252 mark_inode_dirty(dir);
253 res = 0;
254out:
255 hfs_find_exit(&fd);
256
257 return res;
258}
259
260/*
261 * hfs_cat_move()
262 *
263 * Rename a file or directory, possibly to a new directory.
264 * If the destination exists it is removed and a
265 * (struct hfs_cat_entry) for it is returned in '*result'.
266 */
267int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name,
268 struct inode *dst_dir, struct qstr *dst_name)
269{
270 struct super_block *sb;
271 struct hfs_find_data src_fd, dst_fd;
272 union hfs_cat_rec entry;
273 int entry_size, type;
274 int err;
275
276 dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, src_dir->i_ino, src_name->name,
277 dst_dir->i_ino, dst_name->name);
278 sb = src_dir->i_sb;
279 hfs_find_init(HFS_SB(sb)->cat_tree, &src_fd);
280 dst_fd = src_fd;
281
282 /* find the old dir entry and read the data */
283 hfs_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name);
284 err = hfs_brec_find(&src_fd);
285 if (err)
286 goto out;
287
288 hfs_bnode_read(src_fd.bnode, &entry, src_fd.entryoffset,
289 src_fd.entrylength);
290
291 /* create new dir entry with the data from the old entry */
292 hfs_cat_build_key(dst_fd.search_key, dst_dir->i_ino, dst_name);
293 err = hfs_brec_find(&dst_fd);
294 if (err != -ENOENT) {
295 if (!err)
296 err = -EEXIST;
297 goto out;
298 }
299
300 err = hfs_brec_insert(&dst_fd, &entry, src_fd.entrylength);
301 if (err)
302 goto out;
303 dst_dir->i_size++;
304 dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC;
305 mark_inode_dirty(dst_dir);
306
307 /* finally remove the old entry */
308 hfs_cat_build_key(src_fd.search_key, src_dir->i_ino, src_name);
309 err = hfs_brec_find(&src_fd);
310 if (err)
311 goto out;
312 err = hfs_brec_remove(&src_fd);
313 if (err)
314 goto out;
315 src_dir->i_size--;
316 src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC;
317 mark_inode_dirty(src_dir);
318
319 type = entry.type;
320 if (type == HFS_CDR_FIL && !(entry.file.Flags & HFS_FIL_THD))
321 goto out;
322
323 /* remove old thread entry */
324 hfs_cat_build_key(src_fd.search_key, cnid, NULL);
325 err = hfs_brec_find(&src_fd);
326 if (err)
327 goto out;
328 err = hfs_brec_remove(&src_fd);
329 if (err)
330 goto out;
331
332 /* create new thread entry */
333 hfs_cat_build_key(dst_fd.search_key, cnid, NULL);
334 entry_size = hfs_cat_build_thread(&entry, type == HFS_CDR_FIL ? HFS_CDR_FTH : HFS_CDR_THD,
335 dst_dir->i_ino, dst_name);
336 err = hfs_brec_find(&dst_fd);
337 if (err != -ENOENT) {
338 if (!err)
339 err = -EEXIST;
340 goto out;
341 }
342 err = hfs_brec_insert(&dst_fd, &entry, entry_size);
343out:
344 hfs_bnode_put(dst_fd.bnode);
345 hfs_find_exit(&src_fd);
346 return err;
347}
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
new file mode 100644
index 000000000000..c55998262aed
--- /dev/null
+++ b/fs/hfs/dir.c
@@ -0,0 +1,330 @@
1/*
2 * linux/fs/hfs/dir.c
3 *
4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * (C) 2003 Ardis Technologies <roman@ardistech.com>
6 * This file may be distributed under the terms of the GNU General Public License.
7 *
8 * This file contains directory-related functions independent of which
9 * scheme is being used to represent forks.
10 *
11 * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
12 */
13
14#include "hfs_fs.h"
15#include "btree.h"
16
17/*
18 * hfs_lookup()
19 */
20static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry,
21 struct nameidata *nd)
22{
23 hfs_cat_rec rec;
24 struct hfs_find_data fd;
25 struct inode *inode = NULL;
26 int res;
27
28 dentry->d_op = &hfs_dentry_operations;
29
30 hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd);
31 hfs_cat_build_key(fd.search_key, dir->i_ino, &dentry->d_name);
32 res = hfs_brec_read(&fd, &rec, sizeof(rec));
33 if (res) {
34 hfs_find_exit(&fd);
35 if (res == -ENOENT) {
36 /* No such entry */
37 inode = NULL;
38 goto done;
39 }
40 return ERR_PTR(res);
41 }
42 inode = hfs_iget(dir->i_sb, &fd.search_key->cat, &rec);
43 hfs_find_exit(&fd);
44 if (!inode)
45 return ERR_PTR(-EACCES);
46done:
47 d_add(dentry, inode);
48 return NULL;
49}
50
51/*
52 * hfs_readdir
53 */
54static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
55{
56 struct inode *inode = filp->f_dentry->d_inode;
57 struct super_block *sb = inode->i_sb;
58 int len, err;
59 char strbuf[HFS_NAMELEN + 1];
60 union hfs_cat_rec entry;
61 struct hfs_find_data fd;
62 struct hfs_readdir_data *rd;
63 u16 type;
64
65 if (filp->f_pos >= inode->i_size)
66 return 0;
67
68 hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
69 hfs_cat_build_key(fd.search_key, inode->i_ino, NULL);
70 err = hfs_brec_find(&fd);
71 if (err)
72 goto out;
73
74 switch ((u32)filp->f_pos) {
75 case 0:
76 /* This is completely artificial... */
77 if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR))
78 goto out;
79 filp->f_pos++;
80 /* fall through */
81 case 1:
82 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
83 if (entry.type != HFS_CDR_THD) {
84 printk("HFS: bad catalog folder thread\n");
85 err = -EIO;
86 goto out;
87 }
88 //if (fd.entrylength < HFS_MIN_THREAD_SZ) {
89 // printk("HFS: truncated catalog thread\n");
90 // err = -EIO;
91 // goto out;
92 //}
93 if (filldir(dirent, "..", 2, 1,
94 be32_to_cpu(entry.thread.ParID), DT_DIR))
95 goto out;
96 filp->f_pos++;
97 /* fall through */
98 default:
99 if (filp->f_pos >= inode->i_size)
100 goto out;
101 err = hfs_brec_goto(&fd, filp->f_pos - 1);
102 if (err)
103 goto out;
104 }
105
106 for (;;) {
107 if (be32_to_cpu(fd.key->cat.ParID) != inode->i_ino) {
108 printk("HFS: walked past end of dir\n");
109 err = -EIO;
110 goto out;
111 }
112 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
113 type = entry.type;
114 len = hfs_mac2triv(strbuf, &fd.key->cat.CName);
115 if (type == HFS_CDR_DIR) {
116 if (fd.entrylength < sizeof(struct hfs_cat_dir)) {
117 printk("HFS: small dir entry\n");
118 err = -EIO;
119 goto out;
120 }
121 if (filldir(dirent, strbuf, len, filp->f_pos,
122 be32_to_cpu(entry.dir.DirID), DT_DIR))
123 break;
124 } else if (type == HFS_CDR_FIL) {
125 if (fd.entrylength < sizeof(struct hfs_cat_file)) {
126 printk("HFS: small file entry\n");
127 err = -EIO;
128 goto out;
129 }
130 if (filldir(dirent, strbuf, len, filp->f_pos,
131 be32_to_cpu(entry.file.FlNum), DT_REG))
132 break;
133 } else {
134 printk("HFS: bad catalog entry type %d\n", type);
135 err = -EIO;
136 goto out;
137 }
138 filp->f_pos++;
139 if (filp->f_pos >= inode->i_size)
140 goto out;
141 err = hfs_brec_goto(&fd, 1);
142 if (err)
143 goto out;
144 }
145 rd = filp->private_data;
146 if (!rd) {
147 rd = kmalloc(sizeof(struct hfs_readdir_data), GFP_KERNEL);
148 if (!rd) {
149 err = -ENOMEM;
150 goto out;
151 }
152 filp->private_data = rd;
153 rd->file = filp;
154 list_add(&rd->list, &HFS_I(inode)->open_dir_list);
155 }
156 memcpy(&rd->key, &fd.key, sizeof(struct hfs_cat_key));
157out:
158 hfs_find_exit(&fd);
159 return err;
160}
161
162static int hfs_dir_release(struct inode *inode, struct file *file)
163{
164 struct hfs_readdir_data *rd = file->private_data;
165 if (rd) {
166 list_del(&rd->list);
167 kfree(rd);
168 }
169 return 0;
170}
171
172/*
173 * hfs_create()
174 *
175 * This is the create() entry in the inode_operations structure for
176 * regular HFS directories. The purpose is to create a new file in
177 * a directory and return a corresponding inode, given the inode for
178 * the directory and the name (and its length) of the new file.
179 */
180static int hfs_create(struct inode *dir, struct dentry *dentry, int mode,
181 struct nameidata *nd)
182{
183 struct inode *inode;
184 int res;
185
186 inode = hfs_new_inode(dir, &dentry->d_name, mode);
187 if (!inode)
188 return -ENOSPC;
189
190 res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode);
191 if (res) {
192 inode->i_nlink = 0;
193 hfs_delete_inode(inode);
194 iput(inode);
195 return res;
196 }
197 d_instantiate(dentry, inode);
198 mark_inode_dirty(inode);
199 return 0;
200}
201
202/*
203 * hfs_mkdir()
204 *
205 * This is the mkdir() entry in the inode_operations structure for
206 * regular HFS directories. The purpose is to create a new directory
207 * in a directory, given the inode for the parent directory and the
208 * name (and its length) of the new directory.
209 */
210static int hfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
211{
212 struct inode *inode;
213 int res;
214
215 inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode);
216 if (!inode)
217 return -ENOSPC;
218
219 res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode);
220 if (res) {
221 inode->i_nlink = 0;
222 hfs_delete_inode(inode);
223 iput(inode);
224 return res;
225 }
226 d_instantiate(dentry, inode);
227 mark_inode_dirty(inode);
228 return 0;
229}
230
231/*
232 * hfs_unlink()
233 *
234 * This is the unlink() entry in the inode_operations structure for
235 * regular HFS directories. The purpose is to delete an existing
236 * file, given the inode for the parent directory and the name
237 * (and its length) of the existing file.
238 */
239static int hfs_unlink(struct inode *dir, struct dentry *dentry)
240{
241 struct inode *inode;
242 int res;
243
244 inode = dentry->d_inode;
245 res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
246 if (res)
247 return res;
248
249 inode->i_nlink--;
250 hfs_delete_inode(inode);
251 inode->i_ctime = CURRENT_TIME_SEC;
252 mark_inode_dirty(inode);
253
254 return res;
255}
256
257/*
258 * hfs_rmdir()
259 *
260 * This is the rmdir() entry in the inode_operations structure for
261 * regular HFS directories. The purpose is to delete an existing
262 * directory, given the inode for the parent directory and the name
263 * (and its length) of the existing directory.
264 */
265static int hfs_rmdir(struct inode *dir, struct dentry *dentry)
266{
267 struct inode *inode;
268 int res;
269
270 inode = dentry->d_inode;
271 if (inode->i_size != 2)
272 return -ENOTEMPTY;
273 res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
274 if (res)
275 return res;
276 inode->i_nlink = 0;
277 inode->i_ctime = CURRENT_TIME_SEC;
278 hfs_delete_inode(inode);
279 mark_inode_dirty(inode);
280 return 0;
281}
282
283/*
284 * hfs_rename()
285 *
286 * This is the rename() entry in the inode_operations structure for
287 * regular HFS directories. The purpose is to rename an existing
288 * file or directory, given the inode for the current directory and
289 * the name (and its length) of the existing file/directory and the
290 * inode for the new directory and the name (and its length) of the
291 * new file/directory.
292 * XXX: how do you handle must_be dir?
293 */
294static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
295 struct inode *new_dir, struct dentry *new_dentry)
296{
297 int res;
298
299 /* Unlink destination if it already exists */
300 if (new_dentry->d_inode) {
301 res = hfs_unlink(new_dir, new_dentry);
302 if (res)
303 return res;
304 }
305
306 res = hfs_cat_move(old_dentry->d_inode->i_ino,
307 old_dir, &old_dentry->d_name,
308 new_dir, &new_dentry->d_name);
309 if (!res)
310 hfs_cat_build_key((btree_key *)&HFS_I(old_dentry->d_inode)->cat_key,
311 new_dir->i_ino, &new_dentry->d_name);
312 return res;
313}
314
315struct file_operations hfs_dir_operations = {
316 .read = generic_read_dir,
317 .readdir = hfs_readdir,
318 .llseek = generic_file_llseek,
319 .release = hfs_dir_release,
320};
321
322struct inode_operations hfs_dir_inode_operations = {
323 .create = hfs_create,
324 .lookup = hfs_lookup,
325 .unlink = hfs_unlink,
326 .mkdir = hfs_mkdir,
327 .rmdir = hfs_rmdir,
328 .rename = hfs_rename,
329 .setattr = hfs_inode_setattr,
330};
diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c
new file mode 100644
index 000000000000..cbc8510ad222
--- /dev/null
+++ b/fs/hfs/extent.c
@@ -0,0 +1,527 @@
1/*
2 * linux/fs/hfs/extent.c
3 *
4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * (C) 2003 Ardis Technologies <roman@ardistech.com>
6 * This file may be distributed under the terms of the GNU General Public License.
7 *
8 * This file contains the functions related to the extents B-tree.
9 */
10
11#include <linux/pagemap.h>
12
13#include "hfs_fs.h"
14#include "btree.h"
15
16/*================ File-local functions ================*/
17
18/*
19 * build_key
20 */
21static void hfs_ext_build_key(hfs_btree_key *key, u32 cnid, u16 block, u8 type)
22{
23 key->key_len = 7;
24 key->ext.FkType = type;
25 key->ext.FNum = cpu_to_be32(cnid);
26 key->ext.FABN = cpu_to_be16(block);
27}
28
29/*
30 * hfs_ext_compare()
31 *
32 * Description:
33 * This is the comparison function used for the extents B-tree. In
34 * comparing extent B-tree entries, the file id is the most
35 * significant field (compared as unsigned ints); the fork type is
36 * the second most significant field (compared as unsigned chars);
37 * and the allocation block number field is the least significant
38 * (compared as unsigned ints).
39 * Input Variable(s):
40 * struct hfs_ext_key *key1: pointer to the first key to compare
41 * struct hfs_ext_key *key2: pointer to the second key to compare
42 * Output Variable(s):
43 * NONE
44 * Returns:
45 * int: negative if key1<key2, positive if key1>key2, and 0 if key1==key2
46 * Preconditions:
47 * key1 and key2 point to "valid" (struct hfs_ext_key)s.
48 * Postconditions:
49 * This function has no side-effects */
50int hfs_ext_keycmp(const btree_key *key1, const btree_key *key2)
51{
52 __be32 fnum1, fnum2;
53 __be16 block1, block2;
54
55 fnum1 = key1->ext.FNum;
56 fnum2 = key2->ext.FNum;
57 if (fnum1 != fnum2)
58 return be32_to_cpu(fnum1) < be32_to_cpu(fnum2) ? -1 : 1;
59 if (key1->ext.FkType != key2->ext.FkType)
60 return key1->ext.FkType < key2->ext.FkType ? -1 : 1;
61
62 block1 = key1->ext.FABN;
63 block2 = key2->ext.FABN;
64 if (block1 == block2)
65 return 0;
66 return be16_to_cpu(block1) < be16_to_cpu(block2) ? -1 : 1;
67}
68
69/*
70 * hfs_ext_find_block
71 *
72 * Find a block within an extent record
73 */
74static u16 hfs_ext_find_block(struct hfs_extent *ext, u16 off)
75{
76 int i;
77 u16 count;
78
79 for (i = 0; i < 3; ext++, i++) {
80 count = be16_to_cpu(ext->count);
81 if (off < count)
82 return be16_to_cpu(ext->block) + off;
83 off -= count;
84 }
85 /* panic? */
86 return 0;
87}
88
89static int hfs_ext_block_count(struct hfs_extent *ext)
90{
91 int i;
92 u16 count = 0;
93
94 for (i = 0; i < 3; ext++, i++)
95 count += be16_to_cpu(ext->count);
96 return count;
97}
98
99static u16 hfs_ext_lastblock(struct hfs_extent *ext)
100{
101 int i;
102
103 ext += 2;
104 for (i = 0; i < 2; ext--, i++)
105 if (ext->count)
106 break;
107 return be16_to_cpu(ext->block) + be16_to_cpu(ext->count);
108}
109
110static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd)
111{
112 int res;
113
114 hfs_ext_build_key(fd->search_key, inode->i_ino, HFS_I(inode)->cached_start,
115 HFS_IS_RSRC(inode) ? HFS_FK_RSRC : HFS_FK_DATA);
116 res = hfs_brec_find(fd);
117 if (HFS_I(inode)->flags & HFS_FLG_EXT_NEW) {
118 if (res != -ENOENT)
119 return;
120 hfs_brec_insert(fd, HFS_I(inode)->cached_extents, sizeof(hfs_extent_rec));
121 HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW);
122 } else {
123 if (res)
124 return;
125 hfs_bnode_write(fd->bnode, HFS_I(inode)->cached_extents, fd->entryoffset, fd->entrylength);
126 HFS_I(inode)->flags &= ~HFS_FLG_EXT_DIRTY;
127 }
128}
129
130void hfs_ext_write_extent(struct inode *inode)
131{
132 struct hfs_find_data fd;
133
134 if (HFS_I(inode)->flags & HFS_FLG_EXT_DIRTY) {
135 hfs_find_init(HFS_SB(inode->i_sb)->ext_tree, &fd);
136 __hfs_ext_write_extent(inode, &fd);
137 hfs_find_exit(&fd);
138 }
139}
140
141static inline int __hfs_ext_read_extent(struct hfs_find_data *fd, struct hfs_extent *extent,
142 u32 cnid, u32 block, u8 type)
143{
144 int res;
145
146 hfs_ext_build_key(fd->search_key, cnid, block, type);
147 fd->key->ext.FNum = 0;
148 res = hfs_brec_find(fd);
149 if (res && res != -ENOENT)
150 return res;
151 if (fd->key->ext.FNum != fd->search_key->ext.FNum ||
152 fd->key->ext.FkType != fd->search_key->ext.FkType)
153 return -ENOENT;
154 if (fd->entrylength != sizeof(hfs_extent_rec))
155 return -EIO;
156 hfs_bnode_read(fd->bnode, extent, fd->entryoffset, sizeof(hfs_extent_rec));
157 return 0;
158}
159
160static inline int __hfs_ext_cache_extent(struct hfs_find_data *fd, struct inode *inode, u32 block)
161{
162 int res;
163
164 if (HFS_I(inode)->flags & HFS_FLG_EXT_DIRTY)
165 __hfs_ext_write_extent(inode, fd);
166
167 res = __hfs_ext_read_extent(fd, HFS_I(inode)->cached_extents, inode->i_ino,
168 block, HFS_IS_RSRC(inode) ? HFS_FK_RSRC : HFS_FK_DATA);
169 if (!res) {
170 HFS_I(inode)->cached_start = be16_to_cpu(fd->key->ext.FABN);
171 HFS_I(inode)->cached_blocks = hfs_ext_block_count(HFS_I(inode)->cached_extents);
172 } else {
173 HFS_I(inode)->cached_start = HFS_I(inode)->cached_blocks = 0;
174 HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW);
175 }
176 return res;
177}
178
179static int hfs_ext_read_extent(struct inode *inode, u16 block)
180{
181 struct hfs_find_data fd;
182 int res;
183
184 if (block >= HFS_I(inode)->cached_start &&
185 block < HFS_I(inode)->cached_start + HFS_I(inode)->cached_blocks)
186 return 0;
187
188 hfs_find_init(HFS_SB(inode->i_sb)->ext_tree, &fd);
189 res = __hfs_ext_cache_extent(&fd, inode, block);
190 hfs_find_exit(&fd);
191 return res;
192}
193
194static void hfs_dump_extent(struct hfs_extent *extent)
195{
196 int i;
197
198 dprint(DBG_EXTENT, " ");
199 for (i = 0; i < 3; i++)
200 dprint(DBG_EXTENT, " %u:%u", be16_to_cpu(extent[i].block),
201 be16_to_cpu(extent[i].count));
202 dprint(DBG_EXTENT, "\n");
203}
204
205static int hfs_add_extent(struct hfs_extent *extent, u16 offset,
206 u16 alloc_block, u16 block_count)
207{
208 u16 count, start;
209 int i;
210
211 hfs_dump_extent(extent);
212 for (i = 0; i < 3; extent++, i++) {
213 count = be16_to_cpu(extent->count);
214 if (offset == count) {
215 start = be16_to_cpu(extent->block);
216 if (alloc_block != start + count) {
217 if (++i >= 3)
218 return -ENOSPC;
219 extent++;
220 extent->block = cpu_to_be16(alloc_block);
221 } else
222 block_count += count;
223 extent->count = cpu_to_be16(block_count);
224 return 0;
225 } else if (offset < count)
226 break;
227 offset -= count;
228 }
229 /* panic? */
230 return -EIO;
231}
232
233static int hfs_free_extents(struct super_block *sb, struct hfs_extent *extent,
234 u16 offset, u16 block_nr)
235{
236 u16 count, start;
237 int i;
238
239 hfs_dump_extent(extent);
240 for (i = 0; i < 3; extent++, i++) {
241 count = be16_to_cpu(extent->count);
242 if (offset == count)
243 goto found;
244 else if (offset < count)
245 break;
246 offset -= count;
247 }
248 /* panic? */
249 return -EIO;
250found:
251 for (;;) {
252 start = be16_to_cpu(extent->block);
253 if (count <= block_nr) {
254 hfs_clear_vbm_bits(sb, start, count);
255 extent->block = 0;
256 extent->count = 0;
257 block_nr -= count;
258 } else {
259 count -= block_nr;
260 hfs_clear_vbm_bits(sb, start + count, block_nr);
261 extent->count = cpu_to_be16(count);
262 block_nr = 0;
263 }
264 if (!block_nr || !i)
265 return 0;
266 i--;
267 extent--;
268 count = be16_to_cpu(extent->count);
269 }
270}
271
272int hfs_free_fork(struct super_block *sb, struct hfs_cat_file *file, int type)
273{
274 struct hfs_find_data fd;
275 u32 total_blocks, blocks, start;
276 u32 cnid = be32_to_cpu(file->FlNum);
277 struct hfs_extent *extent;
278 int res, i;
279
280 if (type == HFS_FK_DATA) {
281 total_blocks = be32_to_cpu(file->PyLen);
282 extent = file->ExtRec;
283 } else {
284 total_blocks = be32_to_cpu(file->RPyLen);
285 extent = file->RExtRec;
286 }
287 total_blocks /= HFS_SB(sb)->alloc_blksz;
288 if (!total_blocks)
289 return 0;
290
291 blocks = 0;
292 for (i = 0; i < 3; extent++, i++)
293 blocks += be16_to_cpu(extent[i].count);
294
295 res = hfs_free_extents(sb, extent, blocks, blocks);
296 if (res)
297 return res;
298 if (total_blocks == blocks)
299 return 0;
300
301 hfs_find_init(HFS_SB(sb)->ext_tree, &fd);
302 do {
303 res = __hfs_ext_read_extent(&fd, extent, cnid, total_blocks, type);
304 if (res)
305 break;
306 start = be16_to_cpu(fd.key->ext.FABN);
307 hfs_free_extents(sb, extent, total_blocks - start, total_blocks);
308 hfs_brec_remove(&fd);
309 total_blocks = start;
310 } while (total_blocks > blocks);
311 hfs_find_exit(&fd);
312
313 return res;
314}
315
316/*
317 * hfs_get_block
318 */
319int hfs_get_block(struct inode *inode, sector_t block,
320 struct buffer_head *bh_result, int create)
321{
322 struct super_block *sb;
323 u16 dblock, ablock;
324 int res;
325
326 sb = inode->i_sb;
327 /* Convert inode block to disk allocation block */
328 ablock = (u32)block / HFS_SB(sb)->fs_div;
329
330 if (block >= HFS_I(inode)->fs_blocks) {
331 if (block > HFS_I(inode)->fs_blocks || !create)
332 return -EIO;
333 if (ablock >= HFS_I(inode)->alloc_blocks) {
334 res = hfs_extend_file(inode);
335 if (res)
336 return res;
337 }
338 } else
339 create = 0;
340
341 if (ablock < HFS_I(inode)->first_blocks) {
342 dblock = hfs_ext_find_block(HFS_I(inode)->first_extents, ablock);
343 goto done;
344 }
345
346 down(&HFS_I(inode)->extents_lock);
347 res = hfs_ext_read_extent(inode, ablock);
348 if (!res)
349 dblock = hfs_ext_find_block(HFS_I(inode)->cached_extents,
350 ablock - HFS_I(inode)->cached_start);
351 else {
352 up(&HFS_I(inode)->extents_lock);
353 return -EIO;
354 }
355 up(&HFS_I(inode)->extents_lock);
356
357done:
358 map_bh(bh_result, sb, HFS_SB(sb)->fs_start +
359 dblock * HFS_SB(sb)->fs_div +
360 (u32)block % HFS_SB(sb)->fs_div);
361
362 if (create) {
363 set_buffer_new(bh_result);
364 HFS_I(inode)->phys_size += sb->s_blocksize;
365 HFS_I(inode)->fs_blocks++;
366 inode_add_bytes(inode, sb->s_blocksize);
367 mark_inode_dirty(inode);
368 }
369 return 0;
370}
371
372int hfs_extend_file(struct inode *inode)
373{
374 struct super_block *sb = inode->i_sb;
375 u32 start, len, goal;
376 int res;
377
378 down(&HFS_I(inode)->extents_lock);
379 if (HFS_I(inode)->alloc_blocks == HFS_I(inode)->first_blocks)
380 goal = hfs_ext_lastblock(HFS_I(inode)->first_extents);
381 else {
382 res = hfs_ext_read_extent(inode, HFS_I(inode)->alloc_blocks);
383 if (res)
384 goto out;
385 goal = hfs_ext_lastblock(HFS_I(inode)->cached_extents);
386 }
387
388 len = HFS_I(inode)->clump_blocks;
389 start = hfs_vbm_search_free(sb, goal, &len);
390 if (!len) {
391 res = -ENOSPC;
392 goto out;
393 }
394
395 dprint(DBG_EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len);
396 if (HFS_I(inode)->alloc_blocks == HFS_I(inode)->first_blocks) {
397 if (!HFS_I(inode)->first_blocks) {
398 dprint(DBG_EXTENT, "first extents\n");
399 /* no extents yet */
400 HFS_I(inode)->first_extents[0].block = cpu_to_be16(start);
401 HFS_I(inode)->first_extents[0].count = cpu_to_be16(len);
402 res = 0;
403 } else {
404 /* try to append to extents in inode */
405 res = hfs_add_extent(HFS_I(inode)->first_extents,
406 HFS_I(inode)->alloc_blocks,
407 start, len);
408 if (res == -ENOSPC)
409 goto insert_extent;
410 }
411 if (!res) {
412 hfs_dump_extent(HFS_I(inode)->first_extents);
413 HFS_I(inode)->first_blocks += len;
414 }
415 } else {
416 res = hfs_add_extent(HFS_I(inode)->cached_extents,
417 HFS_I(inode)->alloc_blocks -
418 HFS_I(inode)->cached_start,
419 start, len);
420 if (!res) {
421 hfs_dump_extent(HFS_I(inode)->cached_extents);
422 HFS_I(inode)->flags |= HFS_FLG_EXT_DIRTY;
423 HFS_I(inode)->cached_blocks += len;
424 } else if (res == -ENOSPC)
425 goto insert_extent;
426 }
427out:
428 up(&HFS_I(inode)->extents_lock);
429 if (!res) {
430 HFS_I(inode)->alloc_blocks += len;
431 mark_inode_dirty(inode);
432 if (inode->i_ino < HFS_FIRSTUSER_CNID)
433 set_bit(HFS_FLG_ALT_MDB_DIRTY, &HFS_SB(sb)->flags);
434 set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
435 sb->s_dirt = 1;
436 }
437 return res;
438
439insert_extent:
440 dprint(DBG_EXTENT, "insert new extent\n");
441 hfs_ext_write_extent(inode);
442
443 memset(HFS_I(inode)->cached_extents, 0, sizeof(hfs_extent_rec));
444 HFS_I(inode)->cached_extents[0].block = cpu_to_be16(start);
445 HFS_I(inode)->cached_extents[0].count = cpu_to_be16(len);
446 hfs_dump_extent(HFS_I(inode)->cached_extents);
447 HFS_I(inode)->flags |= HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW;
448 HFS_I(inode)->cached_start = HFS_I(inode)->alloc_blocks;
449 HFS_I(inode)->cached_blocks = len;
450
451 res = 0;
452 goto out;
453}
454
455void hfs_file_truncate(struct inode *inode)
456{
457 struct super_block *sb = inode->i_sb;
458 struct hfs_find_data fd;
459 u16 blk_cnt, alloc_cnt, start;
460 u32 size;
461 int res;
462
463 dprint(DBG_INODE, "truncate: %lu, %Lu -> %Lu\n", inode->i_ino,
464 (long long)HFS_I(inode)->phys_size, inode->i_size);
465 if (inode->i_size > HFS_I(inode)->phys_size) {
466 struct address_space *mapping = inode->i_mapping;
467 struct page *page;
468 int res;
469
470 size = inode->i_size - 1;
471 page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT);
472 if (!page)
473 return;
474 size &= PAGE_CACHE_SIZE - 1;
475 size++;
476 res = mapping->a_ops->prepare_write(NULL, page, size, size);
477 if (!res)
478 res = mapping->a_ops->commit_write(NULL, page, size, size);
479 if (res)
480 inode->i_size = HFS_I(inode)->phys_size;
481 unlock_page(page);
482 page_cache_release(page);
483 mark_inode_dirty(inode);
484 return;
485 }
486 size = inode->i_size + HFS_SB(sb)->alloc_blksz - 1;
487 blk_cnt = size / HFS_SB(sb)->alloc_blksz;
488 alloc_cnt = HFS_I(inode)->alloc_blocks;
489 if (blk_cnt == alloc_cnt)
490 goto out;
491
492 down(&HFS_I(inode)->extents_lock);
493 hfs_find_init(HFS_SB(sb)->ext_tree, &fd);
494 while (1) {
495 if (alloc_cnt == HFS_I(inode)->first_blocks) {
496 hfs_free_extents(sb, HFS_I(inode)->first_extents,
497 alloc_cnt, alloc_cnt - blk_cnt);
498 hfs_dump_extent(HFS_I(inode)->first_extents);
499 HFS_I(inode)->first_blocks = blk_cnt;
500 break;
501 }
502 res = __hfs_ext_cache_extent(&fd, inode, alloc_cnt);
503 if (res)
504 break;
505 start = HFS_I(inode)->cached_start;
506 hfs_free_extents(sb, HFS_I(inode)->cached_extents,
507 alloc_cnt - start, alloc_cnt - blk_cnt);
508 hfs_dump_extent(HFS_I(inode)->cached_extents);
509 if (blk_cnt > start) {
510 HFS_I(inode)->flags |= HFS_FLG_EXT_DIRTY;
511 break;
512 }
513 alloc_cnt = start;
514 HFS_I(inode)->cached_start = HFS_I(inode)->cached_blocks = 0;
515 HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW);
516 hfs_brec_remove(&fd);
517 }
518 hfs_find_exit(&fd);
519 up(&HFS_I(inode)->extents_lock);
520
521 HFS_I(inode)->alloc_blocks = blk_cnt;
522out:
523 HFS_I(inode)->phys_size = inode->i_size;
524 HFS_I(inode)->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
525 inode_set_bytes(inode, HFS_I(inode)->fs_blocks << sb->s_blocksize_bits);
526 mark_inode_dirty(inode);
527}
diff --git a/fs/hfs/hfs.h b/fs/hfs/hfs.h
new file mode 100644
index 000000000000..df6b33adee3b
--- /dev/null
+++ b/fs/hfs/hfs.h
@@ -0,0 +1,287 @@
1/*
2 * linux/fs/hfs/hfs.h
3 *
4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * (C) 2003 Ardis Technologies <roman@ardistech.com>
6 * This file may be distributed under the terms of the GNU General Public License.
7 */
8
9#ifndef _HFS_H
10#define _HFS_H
11
12/* offsets to various blocks */
13#define HFS_DD_BLK 0 /* Driver Descriptor block */
14#define HFS_PMAP_BLK 1 /* First block of partition map */
15#define HFS_MDB_BLK 2 /* Block (w/i partition) of MDB */
16
17/* magic numbers for various disk blocks */
18#define HFS_DRVR_DESC_MAGIC 0x4552 /* "ER": driver descriptor map */
19#define HFS_OLD_PMAP_MAGIC 0x5453 /* "TS": old-type partition map */
20#define HFS_NEW_PMAP_MAGIC 0x504D /* "PM": new-type partition map */
21#define HFS_SUPER_MAGIC 0x4244 /* "BD": HFS MDB (super block) */
22#define HFS_MFS_SUPER_MAGIC 0xD2D7 /* MFS MDB (super block) */
23
24/* various FIXED size parameters */
25#define HFS_SECTOR_SIZE 512 /* size of an HFS sector */
26#define HFS_SECTOR_SIZE_BITS 9 /* log_2(HFS_SECTOR_SIZE) */
27#define HFS_NAMELEN 31 /* maximum length of an HFS filename */
28#define HFS_MAX_VALENCE 32767U
29
30/* Meanings of the drAtrb field of the MDB,
31 * Reference: _Inside Macintosh: Files_ p. 2-61
32 */
33#define HFS_SB_ATTRIB_HLOCK (1 << 7)
34#define HFS_SB_ATTRIB_UNMNT (1 << 8)
35#define HFS_SB_ATTRIB_SPARED (1 << 9)
36#define HFS_SB_ATTRIB_INCNSTNT (1 << 11)
37#define HFS_SB_ATTRIB_SLOCK (1 << 15)
38
39/* Some special File ID numbers */
40#define HFS_POR_CNID 1 /* Parent Of the Root */
41#define HFS_ROOT_CNID 2 /* ROOT directory */
42#define HFS_EXT_CNID 3 /* EXTents B-tree */
43#define HFS_CAT_CNID 4 /* CATalog B-tree */
44#define HFS_BAD_CNID 5 /* BAD blocks file */
45#define HFS_ALLOC_CNID 6 /* ALLOCation file (HFS+) */
46#define HFS_START_CNID 7 /* STARTup file (HFS+) */
47#define HFS_ATTR_CNID 8 /* ATTRibutes file (HFS+) */
48#define HFS_EXCH_CNID 15 /* ExchangeFiles temp id */
49#define HFS_FIRSTUSER_CNID 16
50
51/* values for hfs_cat_rec.cdrType */
52#define HFS_CDR_DIR 0x01 /* folder (directory) */
53#define HFS_CDR_FIL 0x02 /* file */
54#define HFS_CDR_THD 0x03 /* folder (directory) thread */
55#define HFS_CDR_FTH 0x04 /* file thread */
56
57/* legal values for hfs_ext_key.FkType and hfs_file.fork */
58#define HFS_FK_DATA 0x00
59#define HFS_FK_RSRC 0xFF
60
61/* bits in hfs_fil_entry.Flags */
62#define HFS_FIL_LOCK 0x01 /* locked */
63#define HFS_FIL_THD 0x02 /* file thread */
64#define HFS_FIL_DOPEN 0x04 /* data fork open */
65#define HFS_FIL_ROPEN 0x08 /* resource fork open */
66#define HFS_FIL_DIR 0x10 /* directory (always clear) */
67#define HFS_FIL_NOCOPY 0x40 /* copy-protected file */
68#define HFS_FIL_USED 0x80 /* open */
69
70/* bits in hfs_dir_entry.Flags. dirflags is 16 bits. */
71#define HFS_DIR_LOCK 0x01 /* locked */
72#define HFS_DIR_THD 0x02 /* directory thread */
73#define HFS_DIR_INEXPFOLDER 0x04 /* in a shared area */
74#define HFS_DIR_MOUNTED 0x08 /* mounted */
75#define HFS_DIR_DIR 0x10 /* directory (always set) */
76#define HFS_DIR_EXPFOLDER 0x20 /* share point */
77
78/* bits hfs_finfo.fdFlags */
79#define HFS_FLG_INITED 0x0100
80#define HFS_FLG_LOCKED 0x1000
81#define HFS_FLG_INVISIBLE 0x4000
82
83/*======== HFS structures as they appear on the disk ========*/
84
85#define __packed __attribute__ ((packed))
86
87/* Pascal-style string of up to 31 characters */
88struct hfs_name {
89 u8 len;
90 u8 name[HFS_NAMELEN];
91} __packed;
92
93struct hfs_point {
94 __be16 v;
95 __be16 h;
96} __packed;
97
98struct hfs_rect {
99 __be16 top;
100 __be16 left;
101 __be16 bottom;
102 __be16 right;
103} __packed;
104
105struct hfs_finfo {
106 __be32 fdType;
107 __be32 fdCreator;
108 __be16 fdFlags;
109 struct hfs_point fdLocation;
110 __be16 fdFldr;
111} __packed;
112
113struct hfs_fxinfo {
114 __be16 fdIconID;
115 u8 fdUnused[8];
116 __be16 fdComment;
117 __be32 fdPutAway;
118} __packed;
119
120struct hfs_dinfo {
121 struct hfs_rect frRect;
122 __be16 frFlags;
123 struct hfs_point frLocation;
124 __be16 frView;
125} __packed;
126
127struct hfs_dxinfo {
128 struct hfs_point frScroll;
129 __be32 frOpenChain;
130 __be16 frUnused;
131 __be16 frComment;
132 __be32 frPutAway;
133} __packed;
134
135union hfs_finder_info {
136 struct {
137 struct hfs_finfo finfo;
138 struct hfs_fxinfo fxinfo;
139 } file;
140 struct {
141 struct hfs_dinfo dinfo;
142 struct hfs_dxinfo dxinfo;
143 } dir;
144} __packed;
145
146/* Cast to a pointer to a generic bkey */
147#define HFS_BKEY(X) (((void)((X)->KeyLen)), ((struct hfs_bkey *)(X)))
148
149/* The key used in the catalog b-tree: */
150struct hfs_cat_key {
151 u8 key_len; /* number of bytes in the key */
152 u8 reserved; /* padding */
153 __be32 ParID; /* CNID of the parent dir */
154 struct hfs_name CName; /* The filename of the entry */
155} __packed;
156
157/* The key used in the extents b-tree: */
158struct hfs_ext_key {
159 u8 key_len; /* number of bytes in the key */
160 u8 FkType; /* HFS_FK_{DATA,RSRC} */
161 __be32 FNum; /* The File ID of the file */
162 __be16 FABN; /* allocation blocks number*/
163} __packed;
164
165typedef union hfs_btree_key {
166 u8 key_len; /* number of bytes in the key */
167 struct hfs_cat_key cat;
168 struct hfs_ext_key ext;
169} hfs_btree_key;
170
171typedef union hfs_btree_key btree_key;
172
173struct hfs_extent {
174 __be16 block;
175 __be16 count;
176};
177typedef struct hfs_extent hfs_extent_rec[3];
178
179/* The catalog record for a file */
180struct hfs_cat_file {
181 s8 type; /* The type of entry */
182 u8 reserved;
183 u8 Flags; /* Flags such as read-only */
184 s8 Typ; /* file version number = 0 */
185 struct hfs_finfo UsrWds; /* data used by the Finder */
186 __be32 FlNum; /* The CNID */
187 __be16 StBlk; /* obsolete */
188 __be32 LgLen; /* The logical EOF of the data fork*/
189 __be32 PyLen; /* The physical EOF of the data fork */
190 __be16 RStBlk; /* obsolete */
191 __be32 RLgLen; /* The logical EOF of the rsrc fork */
192 __be32 RPyLen; /* The physical EOF of the rsrc fork */
193 __be32 CrDat; /* The creation date */
194 __be32 MdDat; /* The modified date */
195 __be32 BkDat; /* The last backup date */
196 struct hfs_fxinfo FndrInfo; /* more data for the Finder */
197 __be16 ClpSize; /* number of bytes to allocate
198 when extending files */
199 hfs_extent_rec ExtRec; /* first extent record
200 for the data fork */
201 hfs_extent_rec RExtRec; /* first extent record
202 for the resource fork */
203 u32 Resrv; /* reserved by Apple */
204} __packed;
205
206/* the catalog record for a directory */
207struct hfs_cat_dir {
208 s8 type; /* The type of entry */
209 u8 reserved;
210 __be16 Flags; /* flags */
211 __be16 Val; /* Valence: number of files and
212 dirs in the directory */
213 __be32 DirID; /* The CNID */
214 __be32 CrDat; /* The creation date */
215 __be32 MdDat; /* The modification date */
216 __be32 BkDat; /* The last backup date */
217 struct hfs_dinfo UsrInfo; /* data used by the Finder */
218 struct hfs_dxinfo FndrInfo; /* more data used by Finder */
219 u8 Resrv[16]; /* reserved by Apple */
220} __packed;
221
222/* the catalog record for a thread */
223struct hfs_cat_thread {
224 s8 type; /* The type of entry */
225 u8 reserved[9]; /* reserved by Apple */
226 __be32 ParID; /* CNID of parent directory */
227 struct hfs_name CName; /* The name of this entry */
228} __packed;
229
230/* A catalog tree record */
231typedef union hfs_cat_rec {
232 s8 type; /* The type of entry */
233 struct hfs_cat_file file;
234 struct hfs_cat_dir dir;
235 struct hfs_cat_thread thread;
236} hfs_cat_rec;
237
238struct hfs_mdb {
239 __be16 drSigWord; /* Signature word indicating fs type */
240 __be32 drCrDate; /* fs creation date/time */
241 __be32 drLsMod; /* fs modification date/time */
242 __be16 drAtrb; /* fs attributes */
243 __be16 drNmFls; /* number of files in root directory */
244 __be16 drVBMSt; /* location (in 512-byte blocks)
245 of the volume bitmap */
246 __be16 drAllocPtr; /* location (in allocation blocks)
247 to begin next allocation search */
248 __be16 drNmAlBlks; /* number of allocation blocks */
249 __be32 drAlBlkSiz; /* bytes in an allocation block */
250 __be32 drClpSiz; /* clumpsize, the number of bytes to
251 allocate when extending a file */
252 __be16 drAlBlSt; /* location (in 512-byte blocks)
253 of the first allocation block */
254 __be32 drNxtCNID; /* CNID to assign to the next
255 file or directory created */
256 __be16 drFreeBks; /* number of free allocation blocks */
257 u8 drVN[28]; /* the volume label */
258 __be32 drVolBkUp; /* fs backup date/time */
259 __be16 drVSeqNum; /* backup sequence number */
260 __be32 drWrCnt; /* fs write count */
261 __be32 drXTClpSiz; /* clumpsize for the extents B-tree */
262 __be32 drCTClpSiz; /* clumpsize for the catalog B-tree */
263 __be16 drNmRtDirs; /* number of directories in
264 the root directory */
265 __be32 drFilCnt; /* number of files in the fs */
266 __be32 drDirCnt; /* number of directories in the fs */
267 u8 drFndrInfo[32]; /* data used by the Finder */
268 __be16 drEmbedSigWord; /* embedded volume signature */
269 __be32 drEmbedExtent; /* starting block number (xdrStABN)
270 and number of allocation blocks
271 (xdrNumABlks) occupied by embedded
272 volume */
273 __be32 drXTFlSize; /* bytes in the extents B-tree */
274 hfs_extent_rec drXTExtRec; /* extents B-tree's first 3 extents */
275 __be32 drCTFlSize; /* bytes in the catalog B-tree */
276 hfs_extent_rec drCTExtRec; /* catalog B-tree's first 3 extents */
277} __packed;
278
279/*======== Data structures kept in memory ========*/
280
281struct hfs_readdir_data {
282 struct list_head list;
283 struct file *file;
284 struct hfs_cat_key key;
285};
286
287#endif
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
new file mode 100644
index 000000000000..0dc8ef8e14de
--- /dev/null
+++ b/fs/hfs/hfs_fs.h
@@ -0,0 +1,286 @@
1/*
2 * linux/fs/hfs/hfs_fs.h
3 *
4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * (C) 2003 Ardis Technologies <roman@ardistech.com>
6 * This file may be distributed under the terms of the GNU General Public License.
7 */
8
9#ifndef _LINUX_HFS_FS_H
10#define _LINUX_HFS_FS_H
11
12#include <linux/version.h>
13#include <linux/slab.h>
14#include <linux/types.h>
15#include <linux/buffer_head.h>
16#include <linux/fs.h>
17
18#include <asm/byteorder.h>
19#include <asm/uaccess.h>
20
21#include "hfs.h"
22
23#define DBG_BNODE_REFS 0x00000001
24#define DBG_BNODE_MOD 0x00000002
25#define DBG_CAT_MOD 0x00000004
26#define DBG_INODE 0x00000008
27#define DBG_SUPER 0x00000010
28#define DBG_EXTENT 0x00000020
29#define DBG_BITMAP 0x00000040
30
31//#define DBG_MASK (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD|DBG_CAT_MOD|DBG_BITMAP)
32//#define DBG_MASK (DBG_BNODE_MOD|DBG_CAT_MOD|DBG_INODE)
33//#define DBG_MASK (DBG_CAT_MOD|DBG_BNODE_REFS|DBG_INODE|DBG_EXTENT)
34#define DBG_MASK (0)
35
36#define dprint(flg, fmt, args...) \
37 if (flg & DBG_MASK) printk(fmt , ## args)
38
39#define hfs_warn(format, args...) printk(KERN_WARNING format , ## args)
40#define hfs_error(format, args...) printk(KERN_ERR format , ## args)
41
42/*
43 * struct hfs_inode_info
44 *
45 * The HFS-specific part of a Linux (struct inode)
46 */
47struct hfs_inode_info {
48 atomic_t opencnt;
49
50 unsigned int flags;
51
52 /* to deal with localtime ugliness */
53 int tz_secondswest;
54
55 struct hfs_cat_key cat_key;
56
57 struct list_head open_dir_list;
58 struct inode *rsrc_inode;
59
60 struct semaphore extents_lock;
61
62 u16 alloc_blocks, clump_blocks;
63 sector_t fs_blocks;
64 /* Allocation extents from catlog record or volume header */
65 hfs_extent_rec first_extents;
66 u16 first_blocks;
67 hfs_extent_rec cached_extents;
68 u16 cached_start, cached_blocks;
69
70 loff_t phys_size;
71 struct inode vfs_inode;
72};
73
74#define HFS_FLG_RSRC 0x0001
75#define HFS_FLG_EXT_DIRTY 0x0002
76#define HFS_FLG_EXT_NEW 0x0004
77
78#define HFS_IS_RSRC(inode) (HFS_I(inode)->flags & HFS_FLG_RSRC)
79
80/*
81 * struct hfs_sb_info
82 *
83 * The HFS-specific part of a Linux (struct super_block)
84 */
85struct hfs_sb_info {
86 struct buffer_head *mdb_bh; /* The hfs_buffer
87 holding the real
88 superblock (aka VIB
89 or MDB) */
90 struct hfs_mdb *mdb;
91 struct buffer_head *alt_mdb_bh; /* The hfs_buffer holding
92 the alternate superblock */
93 struct hfs_mdb *alt_mdb;
94 __be32 *bitmap; /* The page holding the
95 allocation bitmap */
96 struct hfs_btree *ext_tree; /* Information about
97 the extents b-tree */
98 struct hfs_btree *cat_tree; /* Information about
99 the catalog b-tree */
100 u32 file_count; /* The number of
101 regular files in
102 the filesystem */
103 u32 folder_count; /* The number of
104 directories in the
105 filesystem */
106 u32 next_id; /* The next available
107 file id number */
108 u32 clumpablks; /* The number of allocation
109 blocks to try to add when
110 extending a file */
111 u32 fs_start; /* The first 512-byte
112 block represented
113 in the bitmap */
114 u32 part_start;
115 u16 root_files; /* The number of
116 regular
117 (non-directory)
118 files in the root
119 directory */
120 u16 root_dirs; /* The number of
121 directories in the
122 root directory */
123 u16 fs_ablocks; /* The number of
124 allocation blocks
125 in the filesystem */
126 u16 free_ablocks; /* the number of unused
127 allocation blocks
128 in the filesystem */
129 u32 alloc_blksz; /* The size of an
130 "allocation block" */
131 int s_quiet; /* Silent failure when
132 changing owner or mode? */
133 __be32 s_type; /* Type for new files */
134 __be32 s_creator; /* Creator for new files */
135 umode_t s_file_umask; /* The umask applied to the
136 permissions on all files */
137 umode_t s_dir_umask; /* The umask applied to the
138 permissions on all dirs */
139 uid_t s_uid; /* The uid of all files */
140 gid_t s_gid; /* The gid of all files */
141
142 int session, part;
143
144 struct semaphore bitmap_lock;
145
146 unsigned long flags;
147
148 u16 blockoffset;
149
150 int fs_div;
151
152 struct hlist_head rsrc_inodes;
153};
154
155#define HFS_FLG_BITMAP_DIRTY 0
156#define HFS_FLG_MDB_DIRTY 1
157#define HFS_FLG_ALT_MDB_DIRTY 2
158
159/* bitmap.c */
160extern u32 hfs_vbm_search_free(struct super_block *, u32, u32 *);
161extern int hfs_clear_vbm_bits(struct super_block *, u16, u16);
162
163/* catalog.c */
164extern int hfs_cat_keycmp(const btree_key *, const btree_key *);
165struct hfs_find_data;
166extern int hfs_cat_find_brec(struct super_block *, u32, struct hfs_find_data *);
167extern int hfs_cat_create(u32, struct inode *, struct qstr *, struct inode *);
168extern int hfs_cat_delete(u32, struct inode *, struct qstr *);
169extern int hfs_cat_move(u32, struct inode *, struct qstr *,
170 struct inode *, struct qstr *);
171extern void hfs_cat_build_key(btree_key *, u32, struct qstr *);
172
173/* dir.c */
174extern struct file_operations hfs_dir_operations;
175extern struct inode_operations hfs_dir_inode_operations;
176
177/* extent.c */
178extern int hfs_ext_keycmp(const btree_key *, const btree_key *);
179extern int hfs_free_fork(struct super_block *, struct hfs_cat_file *, int);
180extern void hfs_ext_write_extent(struct inode *);
181extern int hfs_extend_file(struct inode *);
182extern void hfs_file_truncate(struct inode *);
183
184extern int hfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
185
186/* inode.c */
187extern struct address_space_operations hfs_aops;
188extern struct address_space_operations hfs_btree_aops;
189
190extern struct inode *hfs_new_inode(struct inode *, struct qstr *, int);
191extern void hfs_inode_write_fork(struct inode *, struct hfs_extent *, __be32 *, __be32 *);
192extern int hfs_write_inode(struct inode *, int);
193extern int hfs_inode_setattr(struct dentry *, struct iattr *);
194extern void hfs_inode_read_fork(struct inode *inode, struct hfs_extent *ext,
195 __be32 log_size, __be32 phys_size, u32 clump_size);
196extern struct inode *hfs_iget(struct super_block *, struct hfs_cat_key *, hfs_cat_rec *);
197extern void hfs_clear_inode(struct inode *);
198extern void hfs_delete_inode(struct inode *);
199
200/* attr.c */
201extern int hfs_setxattr(struct dentry *dentry, const char *name,
202 const void *value, size_t size, int flags);
203extern ssize_t hfs_getxattr(struct dentry *dentry, const char *name,
204 void *value, size_t size);
205extern ssize_t hfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
206
207/* mdb.c */
208extern int hfs_mdb_get(struct super_block *);
209extern void hfs_mdb_commit(struct super_block *);
210extern void hfs_mdb_close(struct super_block *);
211extern void hfs_mdb_put(struct super_block *);
212
213/* part_tbl.c */
214extern int hfs_part_find(struct super_block *, sector_t *, sector_t *);
215
216/* string.c */
217extern struct dentry_operations hfs_dentry_operations;
218
219extern int hfs_hash_dentry(struct dentry *, struct qstr *);
220extern int hfs_strcmp(const unsigned char *, unsigned int,
221 const unsigned char *, unsigned int);
222extern int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
223
224/* trans.c */
225extern void hfs_triv2mac(struct hfs_name *, struct qstr *);
226extern int hfs_mac2triv(char *, const struct hfs_name *);
227
228extern struct timezone sys_tz;
229
230/*
231 * There are two time systems. Both are based on seconds since
232 * a particular time/date.
233 * Unix: unsigned lil-endian since 00:00 GMT, Jan. 1, 1970
234 * mac: unsigned big-endian since 00:00 GMT, Jan. 1, 1904
235 *
236 */
237#define __hfs_u_to_mtime(sec) cpu_to_be32(sec + 2082844800U - sys_tz.tz_minuteswest * 60)
238#define __hfs_m_to_utime(sec) (be32_to_cpu(sec) - 2082844800U + sys_tz.tz_minuteswest * 60)
239
240#define HFS_I(inode) (list_entry(inode, struct hfs_inode_info, vfs_inode))
241#define HFS_SB(sb) ((struct hfs_sb_info *)(sb)->s_fs_info)
242
243#define hfs_m_to_utime(time) (struct timespec){ .tv_sec = __hfs_m_to_utime(time) }
244#define hfs_u_to_mtime(time) __hfs_u_to_mtime((time).tv_sec)
245#define hfs_mtime() __hfs_u_to_mtime(get_seconds())
246
247static inline const char *hfs_mdb_name(struct super_block *sb)
248{
249 return sb->s_id;
250}
251
252static inline void hfs_bitmap_dirty(struct super_block *sb)
253{
254 set_bit(HFS_FLG_BITMAP_DIRTY, &HFS_SB(sb)->flags);
255 sb->s_dirt = 1;
256}
257
258static inline void hfs_buffer_sync(struct buffer_head *bh)
259{
260 while (buffer_locked(bh)) {
261 wait_on_buffer(bh);
262 }
263 if (buffer_dirty(bh)) {
264 ll_rw_block(WRITE, 1, &bh);
265 wait_on_buffer(bh);
266 }
267}
268
269#define sb_bread512(sb, sec, data) ({ \
270 struct buffer_head *__bh; \
271 sector_t __block; \
272 loff_t __start; \
273 int __offset; \
274 \
275 __start = (loff_t)(sec) << HFS_SECTOR_SIZE_BITS;\
276 __block = __start >> (sb)->s_blocksize_bits; \
277 __offset = __start & ((sb)->s_blocksize - 1); \
278 __bh = sb_bread((sb), __block); \
279 if (likely(__bh != NULL)) \
280 data = (void *)(__bh->b_data + __offset);\
281 else \
282 data = NULL; \
283 __bh; \
284})
285
286#endif
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
new file mode 100644
index 000000000000..751912326094
--- /dev/null
+++ b/fs/hfs/inode.c
@@ -0,0 +1,636 @@
1/*
2 * linux/fs/hfs/inode.c
3 *
4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * (C) 2003 Ardis Technologies <roman@ardistech.com>
6 * This file may be distributed under the terms of the GNU General Public License.
7 *
8 * This file contains inode-related functions which do not depend on
9 * which scheme is being used to represent forks.
10 *
11 * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
12 */
13
14#include <linux/pagemap.h>
15#include <linux/version.h>
16#include <linux/mpage.h>
17
18#include "hfs_fs.h"
19#include "btree.h"
20
21static struct file_operations hfs_file_operations;
22static struct inode_operations hfs_file_inode_operations;
23
24/*================ Variable-like macros ================*/
25
26#define HFS_VALID_MODE_BITS (S_IFREG | S_IFDIR | S_IRWXUGO)
27
28static int hfs_writepage(struct page *page, struct writeback_control *wbc)
29{
30 return block_write_full_page(page, hfs_get_block, wbc);
31}
32
33static int hfs_readpage(struct file *file, struct page *page)
34{
35 return block_read_full_page(page, hfs_get_block);
36}
37
38static int hfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
39{
40 return cont_prepare_write(page, from, to, hfs_get_block,
41 &HFS_I(page->mapping->host)->phys_size);
42}
43
44static sector_t hfs_bmap(struct address_space *mapping, sector_t block)
45{
46 return generic_block_bmap(mapping, block, hfs_get_block);
47}
48
49static int hfs_releasepage(struct page *page, int mask)
50{
51 struct inode *inode = page->mapping->host;
52 struct super_block *sb = inode->i_sb;
53 struct hfs_btree *tree;
54 struct hfs_bnode *node;
55 u32 nidx;
56 int i, res = 1;
57
58 switch (inode->i_ino) {
59 case HFS_EXT_CNID:
60 tree = HFS_SB(sb)->ext_tree;
61 break;
62 case HFS_CAT_CNID:
63 tree = HFS_SB(sb)->cat_tree;
64 break;
65 default:
66 BUG();
67 return 0;
68 }
69 if (tree->node_size >= PAGE_CACHE_SIZE) {
70 nidx = page->index >> (tree->node_size_shift - PAGE_CACHE_SHIFT);
71 spin_lock(&tree->hash_lock);
72 node = hfs_bnode_findhash(tree, nidx);
73 if (!node)
74 ;
75 else if (atomic_read(&node->refcnt))
76 res = 0;
77 if (res && node) {
78 hfs_bnode_unhash(node);
79 hfs_bnode_free(node);
80 }
81 spin_unlock(&tree->hash_lock);
82 } else {
83 nidx = page->index << (PAGE_CACHE_SHIFT - tree->node_size_shift);
84 i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift);
85 spin_lock(&tree->hash_lock);
86 do {
87 node = hfs_bnode_findhash(tree, nidx++);
88 if (!node)
89 continue;
90 if (atomic_read(&node->refcnt)) {
91 res = 0;
92 break;
93 }
94 hfs_bnode_unhash(node);
95 hfs_bnode_free(node);
96 } while (--i && nidx < tree->node_count);
97 spin_unlock(&tree->hash_lock);
98 }
99 //printk("releasepage: %lu,%x = %d\n", page->index, mask, res);
100 return res ? try_to_free_buffers(page) : 0;
101}
102
103static int hfs_get_blocks(struct inode *inode, sector_t iblock, unsigned long max_blocks,
104 struct buffer_head *bh_result, int create)
105{
106 int ret;
107
108 ret = hfs_get_block(inode, iblock, bh_result, create);
109 if (!ret)
110 bh_result->b_size = (1 << inode->i_blkbits);
111 return ret;
112}
113
114static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb,
115 const struct iovec *iov, loff_t offset, unsigned long nr_segs)
116{
117 struct file *file = iocb->ki_filp;
118 struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
119
120 return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
121 offset, nr_segs, hfs_get_blocks, NULL);
122}
123
124static int hfs_writepages(struct address_space *mapping,
125 struct writeback_control *wbc)
126{
127 return mpage_writepages(mapping, wbc, hfs_get_block);
128}
129
130struct address_space_operations hfs_btree_aops = {
131 .readpage = hfs_readpage,
132 .writepage = hfs_writepage,
133 .sync_page = block_sync_page,
134 .prepare_write = hfs_prepare_write,
135 .commit_write = generic_commit_write,
136 .bmap = hfs_bmap,
137 .releasepage = hfs_releasepage,
138};
139
140struct address_space_operations hfs_aops = {
141 .readpage = hfs_readpage,
142 .writepage = hfs_writepage,
143 .sync_page = block_sync_page,
144 .prepare_write = hfs_prepare_write,
145 .commit_write = generic_commit_write,
146 .bmap = hfs_bmap,
147 .direct_IO = hfs_direct_IO,
148 .writepages = hfs_writepages,
149};
150
151/*
152 * hfs_new_inode
153 */
154struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, int mode)
155{
156 struct super_block *sb = dir->i_sb;
157 struct inode *inode = new_inode(sb);
158 if (!inode)
159 return NULL;
160
161 init_MUTEX(&HFS_I(inode)->extents_lock);
162 INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list);
163 hfs_cat_build_key((btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name);
164 inode->i_ino = HFS_SB(sb)->next_id++;
165 inode->i_mode = mode;
166 inode->i_uid = current->fsuid;
167 inode->i_gid = current->fsgid;
168 inode->i_nlink = 1;
169 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
170 inode->i_blksize = HFS_SB(sb)->alloc_blksz;
171 HFS_I(inode)->flags = 0;
172 HFS_I(inode)->rsrc_inode = NULL;
173 HFS_I(inode)->fs_blocks = 0;
174 if (S_ISDIR(mode)) {
175 inode->i_size = 2;
176 HFS_SB(sb)->folder_count++;
177 if (dir->i_ino == HFS_ROOT_CNID)
178 HFS_SB(sb)->root_dirs++;
179 inode->i_op = &hfs_dir_inode_operations;
180 inode->i_fop = &hfs_dir_operations;
181 inode->i_mode |= S_IRWXUGO;
182 inode->i_mode &= ~HFS_SB(inode->i_sb)->s_dir_umask;
183 } else if (S_ISREG(mode)) {
184 HFS_I(inode)->clump_blocks = HFS_SB(sb)->clumpablks;
185 HFS_SB(sb)->file_count++;
186 if (dir->i_ino == HFS_ROOT_CNID)
187 HFS_SB(sb)->root_files++;
188 inode->i_op = &hfs_file_inode_operations;
189 inode->i_fop = &hfs_file_operations;
190 inode->i_mapping->a_ops = &hfs_aops;
191 inode->i_mode |= S_IRUGO|S_IXUGO;
192 if (mode & S_IWUSR)
193 inode->i_mode |= S_IWUGO;
194 inode->i_mode &= ~HFS_SB(inode->i_sb)->s_file_umask;
195 HFS_I(inode)->phys_size = 0;
196 HFS_I(inode)->alloc_blocks = 0;
197 HFS_I(inode)->first_blocks = 0;
198 HFS_I(inode)->cached_start = 0;
199 HFS_I(inode)->cached_blocks = 0;
200 memset(HFS_I(inode)->first_extents, 0, sizeof(hfs_extent_rec));
201 memset(HFS_I(inode)->cached_extents, 0, sizeof(hfs_extent_rec));
202 }
203 insert_inode_hash(inode);
204 mark_inode_dirty(inode);
205 set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
206 sb->s_dirt = 1;
207
208 return inode;
209}
210
211void hfs_delete_inode(struct inode *inode)
212{
213 struct super_block *sb = inode->i_sb;
214
215 dprint(DBG_INODE, "delete_inode: %lu\n", inode->i_ino);
216 if (S_ISDIR(inode->i_mode)) {
217 HFS_SB(sb)->folder_count--;
218 if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID))
219 HFS_SB(sb)->root_dirs--;
220 set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
221 sb->s_dirt = 1;
222 return;
223 }
224 HFS_SB(sb)->file_count--;
225 if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID))
226 HFS_SB(sb)->root_files--;
227 if (S_ISREG(inode->i_mode)) {
228 if (!inode->i_nlink) {
229 inode->i_size = 0;
230 hfs_file_truncate(inode);
231 }
232 }
233 set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
234 sb->s_dirt = 1;
235}
236
237void hfs_inode_read_fork(struct inode *inode, struct hfs_extent *ext,
238 __be32 __log_size, __be32 phys_size, u32 clump_size)
239{
240 struct super_block *sb = inode->i_sb;
241 u32 log_size = be32_to_cpu(__log_size);
242 u16 count;
243 int i;
244
245 memcpy(HFS_I(inode)->first_extents, ext, sizeof(hfs_extent_rec));
246 for (count = 0, i = 0; i < 3; i++)
247 count += be16_to_cpu(ext[i].count);
248 HFS_I(inode)->first_blocks = count;
249
250 inode->i_size = HFS_I(inode)->phys_size = log_size;
251 HFS_I(inode)->fs_blocks = (log_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
252 inode_set_bytes(inode, HFS_I(inode)->fs_blocks << sb->s_blocksize_bits);
253 HFS_I(inode)->alloc_blocks = be32_to_cpu(phys_size) /
254 HFS_SB(sb)->alloc_blksz;
255 HFS_I(inode)->clump_blocks = clump_size / HFS_SB(sb)->alloc_blksz;
256 if (!HFS_I(inode)->clump_blocks)
257 HFS_I(inode)->clump_blocks = HFS_SB(sb)->clumpablks;
258}
259
260struct hfs_iget_data {
261 struct hfs_cat_key *key;
262 hfs_cat_rec *rec;
263};
264
265static int hfs_test_inode(struct inode *inode, void *data)
266{
267 struct hfs_iget_data *idata = data;
268 hfs_cat_rec *rec;
269
270 rec = idata->rec;
271 switch (rec->type) {
272 case HFS_CDR_DIR:
273 return inode->i_ino == be32_to_cpu(rec->dir.DirID);
274 case HFS_CDR_FIL:
275 return inode->i_ino == be32_to_cpu(rec->file.FlNum);
276 default:
277 BUG();
278 return 1;
279 }
280}
281
282/*
283 * hfs_read_inode
284 */
285static int hfs_read_inode(struct inode *inode, void *data)
286{
287 struct hfs_iget_data *idata = data;
288 struct hfs_sb_info *hsb = HFS_SB(inode->i_sb);
289 hfs_cat_rec *rec;
290
291 HFS_I(inode)->flags = 0;
292 HFS_I(inode)->rsrc_inode = NULL;
293 init_MUTEX(&HFS_I(inode)->extents_lock);
294 INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list);
295
296 /* Initialize the inode */
297 inode->i_uid = hsb->s_uid;
298 inode->i_gid = hsb->s_gid;
299 inode->i_nlink = 1;
300 inode->i_blksize = HFS_SB(inode->i_sb)->alloc_blksz;
301
302 if (idata->key)
303 HFS_I(inode)->cat_key = *idata->key;
304 else
305 HFS_I(inode)->flags |= HFS_FLG_RSRC;
306 HFS_I(inode)->tz_secondswest = sys_tz.tz_minuteswest * 60;
307
308 rec = idata->rec;
309 switch (rec->type) {
310 case HFS_CDR_FIL:
311 if (!HFS_IS_RSRC(inode)) {
312 hfs_inode_read_fork(inode, rec->file.ExtRec, rec->file.LgLen,
313 rec->file.PyLen, be16_to_cpu(rec->file.ClpSize));
314 } else {
315 hfs_inode_read_fork(inode, rec->file.RExtRec, rec->file.RLgLen,
316 rec->file.RPyLen, be16_to_cpu(rec->file.ClpSize));
317 }
318
319 inode->i_ino = be32_to_cpu(rec->file.FlNum);
320 inode->i_mode = S_IRUGO | S_IXUGO;
321 if (!(rec->file.Flags & HFS_FIL_LOCK))
322 inode->i_mode |= S_IWUGO;
323 inode->i_mode &= ~hsb->s_file_umask;
324 inode->i_mode |= S_IFREG;
325 inode->i_ctime = inode->i_atime = inode->i_mtime =
326 hfs_m_to_utime(rec->file.MdDat);
327 inode->i_op = &hfs_file_inode_operations;
328 inode->i_fop = &hfs_file_operations;
329 inode->i_mapping->a_ops = &hfs_aops;
330 break;
331 case HFS_CDR_DIR:
332 inode->i_ino = be32_to_cpu(rec->dir.DirID);
333 inode->i_size = be16_to_cpu(rec->dir.Val) + 2;
334 HFS_I(inode)->fs_blocks = 0;
335 inode->i_mode = S_IFDIR | (S_IRWXUGO & ~hsb->s_dir_umask);
336 inode->i_ctime = inode->i_atime = inode->i_mtime =
337 hfs_m_to_utime(rec->dir.MdDat);
338 inode->i_op = &hfs_dir_inode_operations;
339 inode->i_fop = &hfs_dir_operations;
340 break;
341 default:
342 make_bad_inode(inode);
343 }
344 return 0;
345}
346
347/*
348 * __hfs_iget()
349 *
350 * Given the MDB for a HFS filesystem, a 'key' and an 'entry' in
351 * the catalog B-tree and the 'type' of the desired file return the
352 * inode for that file/directory or NULL. Note that 'type' indicates
353 * whether we want the actual file or directory, or the corresponding
354 * metadata (AppleDouble header file or CAP metadata file).
355 */
356struct inode *hfs_iget(struct super_block *sb, struct hfs_cat_key *key, hfs_cat_rec *rec)
357{
358 struct hfs_iget_data data = { key, rec };
359 struct inode *inode;
360 u32 cnid;
361
362 switch (rec->type) {
363 case HFS_CDR_DIR:
364 cnid = be32_to_cpu(rec->dir.DirID);
365 break;
366 case HFS_CDR_FIL:
367 cnid = be32_to_cpu(rec->file.FlNum);
368 break;
369 default:
370 return NULL;
371 }
372 inode = iget5_locked(sb, cnid, hfs_test_inode, hfs_read_inode, &data);
373 if (inode && (inode->i_state & I_NEW))
374 unlock_new_inode(inode);
375 return inode;
376}
377
378void hfs_inode_write_fork(struct inode *inode, struct hfs_extent *ext,
379 __be32 *log_size, __be32 *phys_size)
380{
381 memcpy(ext, HFS_I(inode)->first_extents, sizeof(hfs_extent_rec));
382
383 if (log_size)
384 *log_size = cpu_to_be32(inode->i_size);
385 if (phys_size)
386 *phys_size = cpu_to_be32(HFS_I(inode)->alloc_blocks *
387 HFS_SB(inode->i_sb)->alloc_blksz);
388}
389
390int hfs_write_inode(struct inode *inode, int unused)
391{
392 struct inode *main_inode = inode;
393 struct hfs_find_data fd;
394 hfs_cat_rec rec;
395
396 dprint(DBG_INODE, "hfs_write_inode: %lu\n", inode->i_ino);
397 hfs_ext_write_extent(inode);
398
399 if (inode->i_ino < HFS_FIRSTUSER_CNID) {
400 switch (inode->i_ino) {
401 case HFS_ROOT_CNID:
402 break;
403 case HFS_EXT_CNID:
404 hfs_btree_write(HFS_SB(inode->i_sb)->ext_tree);
405 return 0;
406 case HFS_CAT_CNID:
407 hfs_btree_write(HFS_SB(inode->i_sb)->cat_tree);
408 return 0;
409 default:
410 BUG();
411 return -EIO;
412 }
413 }
414
415 if (HFS_IS_RSRC(inode))
416 main_inode = HFS_I(inode)->rsrc_inode;
417
418 if (!main_inode->i_nlink)
419 return 0;
420
421 if (hfs_find_init(HFS_SB(main_inode->i_sb)->cat_tree, &fd))
422 /* panic? */
423 return -EIO;
424
425 fd.search_key->cat = HFS_I(main_inode)->cat_key;
426 if (hfs_brec_find(&fd))
427 /* panic? */
428 goto out;
429
430 if (S_ISDIR(main_inode->i_mode)) {
431 if (fd.entrylength < sizeof(struct hfs_cat_dir))
432 /* panic? */;
433 hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
434 sizeof(struct hfs_cat_dir));
435 if (rec.type != HFS_CDR_DIR ||
436 be32_to_cpu(rec.dir.DirID) != inode->i_ino) {
437 }
438
439 rec.dir.MdDat = hfs_u_to_mtime(inode->i_mtime);
440 rec.dir.Val = cpu_to_be16(inode->i_size - 2);
441
442 hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
443 sizeof(struct hfs_cat_dir));
444 } else if (HFS_IS_RSRC(inode)) {
445 hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
446 sizeof(struct hfs_cat_file));
447 hfs_inode_write_fork(inode, rec.file.RExtRec,
448 &rec.file.RLgLen, &rec.file.RPyLen);
449 hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
450 sizeof(struct hfs_cat_file));
451 } else {
452 if (fd.entrylength < sizeof(struct hfs_cat_file))
453 /* panic? */;
454 hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
455 sizeof(struct hfs_cat_file));
456 if (rec.type != HFS_CDR_FIL ||
457 be32_to_cpu(rec.file.FlNum) != inode->i_ino) {
458 }
459
460 if (inode->i_mode & S_IWUSR)
461 rec.file.Flags &= ~HFS_FIL_LOCK;
462 else
463 rec.file.Flags |= HFS_FIL_LOCK;
464 hfs_inode_write_fork(inode, rec.file.ExtRec, &rec.file.LgLen, &rec.file.PyLen);
465 rec.file.MdDat = hfs_u_to_mtime(inode->i_mtime);
466
467 hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
468 sizeof(struct hfs_cat_file));
469 }
470out:
471 hfs_find_exit(&fd);
472 return 0;
473}
474
475static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
476 struct nameidata *nd)
477{
478 struct inode *inode = NULL;
479 hfs_cat_rec rec;
480 struct hfs_find_data fd;
481 int res;
482
483 if (HFS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc"))
484 goto out;
485
486 inode = HFS_I(dir)->rsrc_inode;
487 if (inode)
488 goto out;
489
490 inode = new_inode(dir->i_sb);
491 if (!inode)
492 return ERR_PTR(-ENOMEM);
493
494 hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd);
495 fd.search_key->cat = HFS_I(dir)->cat_key;
496 res = hfs_brec_read(&fd, &rec, sizeof(rec));
497 if (!res) {
498 struct hfs_iget_data idata = { NULL, &rec };
499 hfs_read_inode(inode, &idata);
500 }
501 hfs_find_exit(&fd);
502 if (res) {
503 iput(inode);
504 return ERR_PTR(res);
505 }
506 HFS_I(inode)->rsrc_inode = dir;
507 HFS_I(dir)->rsrc_inode = inode;
508 igrab(dir);
509 hlist_add_head(&inode->i_hash, &HFS_SB(dir->i_sb)->rsrc_inodes);
510 mark_inode_dirty(inode);
511out:
512 d_add(dentry, inode);
513 return NULL;
514}
515
516void hfs_clear_inode(struct inode *inode)
517{
518 if (HFS_IS_RSRC(inode) && HFS_I(inode)->rsrc_inode) {
519 HFS_I(HFS_I(inode)->rsrc_inode)->rsrc_inode = NULL;
520 iput(HFS_I(inode)->rsrc_inode);
521 }
522}
523
524static int hfs_permission(struct inode *inode, int mask,
525 struct nameidata *nd)
526{
527 if (S_ISREG(inode->i_mode) && mask & MAY_EXEC)
528 return 0;
529 return generic_permission(inode, mask, NULL);
530}
531
532static int hfs_file_open(struct inode *inode, struct file *file)
533{
534 if (HFS_IS_RSRC(inode))
535 inode = HFS_I(inode)->rsrc_inode;
536 if (atomic_read(&file->f_count) != 1)
537 return 0;
538 atomic_inc(&HFS_I(inode)->opencnt);
539 return 0;
540}
541
542static int hfs_file_release(struct inode *inode, struct file *file)
543{
544 //struct super_block *sb = inode->i_sb;
545
546 if (HFS_IS_RSRC(inode))
547 inode = HFS_I(inode)->rsrc_inode;
548 if (atomic_read(&file->f_count) != 0)
549 return 0;
550 if (atomic_dec_and_test(&HFS_I(inode)->opencnt)) {
551 down(&inode->i_sem);
552 hfs_file_truncate(inode);
553 //if (inode->i_flags & S_DEAD) {
554 // hfs_delete_cat(inode->i_ino, HFSPLUS_SB(sb).hidden_dir, NULL);
555 // hfs_delete_inode(inode);
556 //}
557 up(&inode->i_sem);
558 }
559 return 0;
560}
561
562/*
563 * hfs_notify_change()
564 *
565 * Based very closely on fs/msdos/inode.c by Werner Almesberger
566 *
567 * This is the notify_change() field in the super_operations structure
568 * for HFS file systems. The purpose is to take that changes made to
569 * an inode and apply then in a filesystem-dependent manner. In this
570 * case the process has a few of tasks to do:
571 * 1) prevent changes to the i_uid and i_gid fields.
572 * 2) map file permissions to the closest allowable permissions
573 * 3) Since multiple Linux files can share the same on-disk inode under
574 * HFS (for instance the data and resource forks of a file) a change
575 * to permissions must be applied to all other in-core inodes which
576 * correspond to the same HFS file.
577 */
578
579int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr)
580{
581 struct inode *inode = dentry->d_inode;
582 struct hfs_sb_info *hsb = HFS_SB(inode->i_sb);
583 int error;
584
585 error = inode_change_ok(inode, attr); /* basic permission checks */
586 if (error)
587 return error;
588
589 /* no uig/gid changes and limit which mode bits can be set */
590 if (((attr->ia_valid & ATTR_UID) &&
591 (attr->ia_uid != hsb->s_uid)) ||
592 ((attr->ia_valid & ATTR_GID) &&
593 (attr->ia_gid != hsb->s_gid)) ||
594 ((attr->ia_valid & ATTR_MODE) &&
595 ((S_ISDIR(inode->i_mode) &&
596 (attr->ia_mode != inode->i_mode)) ||
597 (attr->ia_mode & ~HFS_VALID_MODE_BITS)))) {
598 return hsb->s_quiet ? 0 : error;
599 }
600
601 if (attr->ia_valid & ATTR_MODE) {
602 /* Only the 'w' bits can ever change and only all together. */
603 if (attr->ia_mode & S_IWUSR)
604 attr->ia_mode = inode->i_mode | S_IWUGO;
605 else
606 attr->ia_mode = inode->i_mode & ~S_IWUGO;
607 attr->ia_mode &= S_ISDIR(inode->i_mode) ? ~hsb->s_dir_umask: ~hsb->s_file_umask;
608 }
609 error = inode_setattr(inode, attr);
610 if (error)
611 return error;
612
613 return 0;
614}
615
616
617static struct file_operations hfs_file_operations = {
618 .llseek = generic_file_llseek,
619 .read = generic_file_read,
620 .write = generic_file_write,
621 .mmap = generic_file_mmap,
622 .sendfile = generic_file_sendfile,
623 .fsync = file_fsync,
624 .open = hfs_file_open,
625 .release = hfs_file_release,
626};
627
628static struct inode_operations hfs_file_inode_operations = {
629 .lookup = hfs_file_lookup,
630 .truncate = hfs_file_truncate,
631 .setattr = hfs_inode_setattr,
632 .permission = hfs_permission,
633 .setxattr = hfs_setxattr,
634 .getxattr = hfs_getxattr,
635 .listxattr = hfs_listxattr,
636};
diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c
new file mode 100644
index 000000000000..4efb640c4d0c
--- /dev/null
+++ b/fs/hfs/mdb.c
@@ -0,0 +1,343 @@
1/*
2 * linux/fs/hfs/mdb.c
3 *
4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * (C) 2003 Ardis Technologies <roman@ardistech.com>
6 * This file may be distributed under the terms of the GNU General Public License.
7 *
8 * This file contains functions for reading/writing the MDB.
9 */
10
11#include <linux/cdrom.h>
12#include <linux/genhd.h>
13
14#include "hfs_fs.h"
15#include "btree.h"
16
17/*================ File-local data types ================*/
18
19/*
20 * The HFS Master Directory Block (MDB).
21 *
22 * Also known as the Volume Information Block (VIB), this structure is
23 * the HFS equivalent of a superblock.
24 *
25 * Reference: _Inside Macintosh: Files_ pages 2-59 through 2-62
26 *
27 * modified for HFS Extended
28 */
29
30static int hfs_get_last_session(struct super_block *sb,
31 sector_t *start, sector_t *size)
32{
33 struct cdrom_multisession ms_info;
34 struct cdrom_tocentry te;
35 int res;
36
37 /* default values */
38 *start = 0;
39 *size = sb->s_bdev->bd_inode->i_size >> 9;
40
41 if (HFS_SB(sb)->session >= 0) {
42 te.cdte_track = HFS_SB(sb)->session;
43 te.cdte_format = CDROM_LBA;
44 res = ioctl_by_bdev(sb->s_bdev, CDROMREADTOCENTRY, (unsigned long)&te);
45 if (!res && (te.cdte_ctrl & CDROM_DATA_TRACK) == 4) {
46 *start = (sector_t)te.cdte_addr.lba << 2;
47 return 0;
48 }
49 printk(KERN_ERR "HFS: Invalid session number or type of track\n");
50 return -EINVAL;
51 }
52 ms_info.addr_format = CDROM_LBA;
53 res = ioctl_by_bdev(sb->s_bdev, CDROMMULTISESSION, (unsigned long)&ms_info);
54 if (!res && ms_info.xa_flag)
55 *start = (sector_t)ms_info.addr.lba << 2;
56 return 0;
57}
58
59/*
60 * hfs_mdb_get()
61 *
62 * Build the in-core MDB for a filesystem, including
63 * the B-trees and the volume bitmap.
64 */
65int hfs_mdb_get(struct super_block *sb)
66{
67 struct buffer_head *bh;
68 struct hfs_mdb *mdb, *mdb2;
69 unsigned int block;
70 char *ptr;
71 int off2, len, size, sect;
72 sector_t part_start, part_size;
73 loff_t off;
74 __be16 attrib;
75
76 /* set the device driver to 512-byte blocks */
77 size = sb_min_blocksize(sb, HFS_SECTOR_SIZE);
78 if (!size)
79 return -EINVAL;
80
81 if (hfs_get_last_session(sb, &part_start, &part_size))
82 return -EINVAL;
83 while (1) {
84 /* See if this is an HFS filesystem */
85 bh = sb_bread512(sb, part_start + HFS_MDB_BLK, mdb);
86 if (!bh)
87 goto out;
88
89 if (mdb->drSigWord == cpu_to_be16(HFS_SUPER_MAGIC))
90 break;
91 brelse(bh);
92
93 /* check for a partition block
94 * (should do this only for cdrom/loop though)
95 */
96 if (hfs_part_find(sb, &part_start, &part_size))
97 goto out;
98 }
99
100 HFS_SB(sb)->alloc_blksz = size = be32_to_cpu(mdb->drAlBlkSiz);
101 if (!size || (size & (HFS_SECTOR_SIZE - 1))) {
102 hfs_warn("hfs_fs: bad allocation block size %d\n", size);
103 goto out_bh;
104 }
105
106 size = min(HFS_SB(sb)->alloc_blksz, (u32)PAGE_SIZE);
107 /* size must be a multiple of 512 */
108 while (size & (size - 1))
109 size -= HFS_SECTOR_SIZE;
110 sect = be16_to_cpu(mdb->drAlBlSt) + part_start;
111 /* align block size to first sector */
112 while (sect & ((size - 1) >> HFS_SECTOR_SIZE_BITS))
113 size >>= 1;
114 /* align block size to weird alloc size */
115 while (HFS_SB(sb)->alloc_blksz & (size - 1))
116 size >>= 1;
117 brelse(bh);
118 if (!sb_set_blocksize(sb, size)) {
119 printk("hfs_fs: unable to set blocksize to %u\n", size);
120 goto out;
121 }
122
123 bh = sb_bread512(sb, part_start + HFS_MDB_BLK, mdb);
124 if (!bh)
125 goto out;
126 if (mdb->drSigWord != cpu_to_be16(HFS_SUPER_MAGIC))
127 goto out_bh;
128
129 HFS_SB(sb)->mdb_bh = bh;
130 HFS_SB(sb)->mdb = mdb;
131
132 /* These parameters are read from the MDB, and never written */
133 HFS_SB(sb)->part_start = part_start;
134 HFS_SB(sb)->fs_ablocks = be16_to_cpu(mdb->drNmAlBlks);
135 HFS_SB(sb)->fs_div = HFS_SB(sb)->alloc_blksz >> sb->s_blocksize_bits;
136 HFS_SB(sb)->clumpablks = be32_to_cpu(mdb->drClpSiz) /
137 HFS_SB(sb)->alloc_blksz;
138 if (!HFS_SB(sb)->clumpablks)
139 HFS_SB(sb)->clumpablks = 1;
140 HFS_SB(sb)->fs_start = (be16_to_cpu(mdb->drAlBlSt) + part_start) >>
141 (sb->s_blocksize_bits - HFS_SECTOR_SIZE_BITS);
142
143 /* These parameters are read from and written to the MDB */
144 HFS_SB(sb)->free_ablocks = be16_to_cpu(mdb->drFreeBks);
145 HFS_SB(sb)->next_id = be32_to_cpu(mdb->drNxtCNID);
146 HFS_SB(sb)->root_files = be16_to_cpu(mdb->drNmFls);
147 HFS_SB(sb)->root_dirs = be16_to_cpu(mdb->drNmRtDirs);
148 HFS_SB(sb)->file_count = be32_to_cpu(mdb->drFilCnt);
149 HFS_SB(sb)->folder_count = be32_to_cpu(mdb->drDirCnt);
150
151 /* TRY to get the alternate (backup) MDB. */
152 sect = part_start + part_size - 2;
153 bh = sb_bread512(sb, sect, mdb2);
154 if (bh) {
155 if (mdb2->drSigWord == cpu_to_be16(HFS_SUPER_MAGIC)) {
156 HFS_SB(sb)->alt_mdb_bh = bh;
157 HFS_SB(sb)->alt_mdb = mdb2;
158 } else
159 brelse(bh);
160 }
161
162 if (!HFS_SB(sb)->alt_mdb) {
163 hfs_warn("hfs_fs: unable to locate alternate MDB\n");
164 hfs_warn("hfs_fs: continuing without an alternate MDB\n");
165 }
166
167 HFS_SB(sb)->bitmap = (__be32 *)__get_free_pages(GFP_KERNEL, PAGE_SIZE < 8192 ? 1 : 0);
168 if (!HFS_SB(sb)->bitmap)
169 goto out;
170
171 /* read in the bitmap */
172 block = be16_to_cpu(mdb->drVBMSt) + part_start;
173 off = (loff_t)block << HFS_SECTOR_SIZE_BITS;
174 size = (HFS_SB(sb)->fs_ablocks + 8) / 8;
175 ptr = (u8 *)HFS_SB(sb)->bitmap;
176 while (size) {
177 bh = sb_bread(sb, off >> sb->s_blocksize_bits);
178 if (!bh) {
179 hfs_warn("hfs_fs: unable to read volume bitmap\n");
180 goto out;
181 }
182 off2 = off & (sb->s_blocksize - 1);
183 len = min((int)sb->s_blocksize - off2, size);
184 memcpy(ptr, bh->b_data + off2, len);
185 brelse(bh);
186 ptr += len;
187 off += len;
188 size -= len;
189 }
190
191 HFS_SB(sb)->ext_tree = hfs_btree_open(sb, HFS_EXT_CNID, hfs_ext_keycmp);
192 if (!HFS_SB(sb)->ext_tree) {
193 hfs_warn("hfs_fs: unable to open extent tree\n");
194 goto out;
195 }
196 HFS_SB(sb)->cat_tree = hfs_btree_open(sb, HFS_CAT_CNID, hfs_cat_keycmp);
197 if (!HFS_SB(sb)->cat_tree) {
198 hfs_warn("hfs_fs: unable to open catalog tree\n");
199 goto out;
200 }
201
202 attrib = mdb->drAtrb;
203 if (!(attrib & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) {
204 hfs_warn("HFS-fs warning: Filesystem was not cleanly unmounted, "
205 "running fsck.hfs is recommended. mounting read-only.\n");
206 sb->s_flags |= MS_RDONLY;
207 }
208 if ((attrib & cpu_to_be16(HFS_SB_ATTRIB_SLOCK))) {
209 hfs_warn("HFS-fs: Filesystem is marked locked, mounting read-only.\n");
210 sb->s_flags |= MS_RDONLY;
211 }
212 if (!(sb->s_flags & MS_RDONLY)) {
213 /* Mark the volume uncleanly unmounted in case we crash */
214 attrib &= cpu_to_be16(~HFS_SB_ATTRIB_UNMNT);
215 attrib |= cpu_to_be16(HFS_SB_ATTRIB_INCNSTNT);
216 mdb->drAtrb = attrib;
217 mdb->drWrCnt = cpu_to_be32(be32_to_cpu(mdb->drWrCnt) + 1);
218 mdb->drLsMod = hfs_mtime();
219
220 mark_buffer_dirty(HFS_SB(sb)->mdb_bh);
221 hfs_buffer_sync(HFS_SB(sb)->mdb_bh);
222 }
223
224 return 0;
225
226out_bh:
227 brelse(bh);
228out:
229 hfs_mdb_put(sb);
230 return -EIO;
231}
232
233/*
234 * hfs_mdb_commit()
235 *
236 * Description:
237 * This updates the MDB on disk (look also at hfs_write_super()).
238 * It does not check, if the superblock has been modified, or
239 * if the filesystem has been mounted read-only. It is mainly
240 * called by hfs_write_super() and hfs_btree_extend().
241 * Input Variable(s):
242 * struct hfs_mdb *mdb: Pointer to the hfs MDB
243 * int backup;
244 * Output Variable(s):
245 * NONE
246 * Returns:
247 * void
248 * Preconditions:
249 * 'mdb' points to a "valid" (struct hfs_mdb).
250 * Postconditions:
251 * The HFS MDB and on disk will be updated, by copying the possibly
252 * modified fields from the in memory MDB (in native byte order) to
253 * the disk block buffer.
254 * If 'backup' is non-zero then the alternate MDB is also written
255 * and the function doesn't return until it is actually on disk.
256 */
257void hfs_mdb_commit(struct super_block *sb)
258{
259 struct hfs_mdb *mdb = HFS_SB(sb)->mdb;
260
261 if (test_and_clear_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags)) {
262 /* These parameters may have been modified, so write them back */
263 mdb->drLsMod = hfs_mtime();
264 mdb->drFreeBks = cpu_to_be16(HFS_SB(sb)->free_ablocks);
265 mdb->drNxtCNID = cpu_to_be32(HFS_SB(sb)->next_id);
266 mdb->drNmFls = cpu_to_be16(HFS_SB(sb)->root_files);
267 mdb->drNmRtDirs = cpu_to_be16(HFS_SB(sb)->root_dirs);
268 mdb->drFilCnt = cpu_to_be32(HFS_SB(sb)->file_count);
269 mdb->drDirCnt = cpu_to_be32(HFS_SB(sb)->folder_count);
270
271 /* write MDB to disk */
272 mark_buffer_dirty(HFS_SB(sb)->mdb_bh);
273 }
274
275 /* write the backup MDB, not returning until it is written.
276 * we only do this when either the catalog or extents overflow
277 * files grow. */
278 if (test_and_clear_bit(HFS_FLG_ALT_MDB_DIRTY, &HFS_SB(sb)->flags) &&
279 HFS_SB(sb)->alt_mdb) {
280 hfs_inode_write_fork(HFS_SB(sb)->ext_tree->inode, mdb->drXTExtRec,
281 &mdb->drXTFlSize, NULL);
282 hfs_inode_write_fork(HFS_SB(sb)->cat_tree->inode, mdb->drCTExtRec,
283 &mdb->drCTFlSize, NULL);
284 memcpy(HFS_SB(sb)->alt_mdb, HFS_SB(sb)->mdb, HFS_SECTOR_SIZE);
285 HFS_SB(sb)->alt_mdb->drAtrb |= cpu_to_be16(HFS_SB_ATTRIB_UNMNT);
286 HFS_SB(sb)->alt_mdb->drAtrb &= cpu_to_be16(~HFS_SB_ATTRIB_INCNSTNT);
287 mark_buffer_dirty(HFS_SB(sb)->alt_mdb_bh);
288 hfs_buffer_sync(HFS_SB(sb)->alt_mdb_bh);
289 }
290
291 if (test_and_clear_bit(HFS_FLG_BITMAP_DIRTY, &HFS_SB(sb)->flags)) {
292 struct buffer_head *bh;
293 sector_t block;
294 char *ptr;
295 int off, size, len;
296
297 block = be16_to_cpu(HFS_SB(sb)->mdb->drVBMSt) + HFS_SB(sb)->part_start;
298 off = (block << HFS_SECTOR_SIZE_BITS) & (sb->s_blocksize - 1);
299 block >>= sb->s_blocksize_bits - HFS_SECTOR_SIZE_BITS;
300 size = (HFS_SB(sb)->fs_ablocks + 7) / 8;
301 ptr = (u8 *)HFS_SB(sb)->bitmap;
302 while (size) {
303 bh = sb_bread(sb, block);
304 if (!bh) {
305 hfs_warn("hfs_fs: unable to read volume bitmap\n");
306 break;
307 }
308 len = min((int)sb->s_blocksize - off, size);
309 memcpy(bh->b_data + off, ptr, len);
310 mark_buffer_dirty(bh);
311 brelse(bh);
312 block++;
313 off = 0;
314 ptr += len;
315 size -= len;
316 }
317 }
318}
319
320void hfs_mdb_close(struct super_block *sb)
321{
322 /* update volume attributes */
323 if (sb->s_flags & MS_RDONLY)
324 return;
325 HFS_SB(sb)->mdb->drAtrb |= cpu_to_be16(HFS_SB_ATTRIB_UNMNT);
326 HFS_SB(sb)->mdb->drAtrb &= cpu_to_be16(~HFS_SB_ATTRIB_INCNSTNT);
327 mark_buffer_dirty(HFS_SB(sb)->mdb_bh);
328}
329
330/*
331 * hfs_mdb_put()
332 *
333 * Release the resources associated with the in-core MDB. */
334void hfs_mdb_put(struct super_block *sb)
335{
336 /* free the B-trees */
337 hfs_btree_close(HFS_SB(sb)->ext_tree);
338 hfs_btree_close(HFS_SB(sb)->cat_tree);
339
340 /* free the buffers holding the primary and alternate MDBs */
341 brelse(HFS_SB(sb)->mdb_bh);
342 brelse(HFS_SB(sb)->alt_mdb_bh);
343}
diff --git a/fs/hfs/part_tbl.c b/fs/hfs/part_tbl.c
new file mode 100644
index 000000000000..36add537d153
--- /dev/null
+++ b/fs/hfs/part_tbl.c
@@ -0,0 +1,117 @@
1/*
2 * linux/fs/hfs/part_tbl.c
3 *
4 * Copyright (C) 1996-1997 Paul H. Hargrove
5 * (C) 2003 Ardis Technologies <roman@ardistech.com>
6 * This file may be distributed under the terms of the GNU General Public License.
7 *
8 * Original code to handle the new style Mac partition table based on
9 * a patch contributed by Holger Schemel (aeglos@valinor.owl.de).
10 */
11
12#include "hfs_fs.h"
13
14/*
15 * The new style Mac partition map
16 *
17 * For each partition on the media there is a physical block (512-byte
18 * block) containing one of these structures. These blocks are
19 * contiguous starting at block 1.
20 */
21struct new_pmap {
22 __be16 pmSig; /* signature */
23 __be16 reSigPad; /* padding */
24 __be32 pmMapBlkCnt; /* partition blocks count */
25 __be32 pmPyPartStart; /* physical block start of partition */
26 __be32 pmPartBlkCnt; /* physical block count of partition */
27 u8 pmPartName[32]; /* (null terminated?) string
28 giving the name of this
29 partition */
30 u8 pmPartType[32]; /* (null terminated?) string
31 giving the type of this
32 partition */
33 /* a bunch more stuff we don't need */
34} __packed;
35
36/*
37 * The old style Mac partition map
38 *
39 * The partition map consists for a 2-byte signature followed by an
40 * array of these structures. The map is terminated with an all-zero
41 * one of these.
42 */
43struct old_pmap {
44 __be16 pdSig; /* Signature bytes */
45 struct old_pmap_entry {
46 __be32 pdStart;
47 __be32 pdSize;
48 __be32 pdFSID;
49 } pdEntry[42];
50} __packed;
51
52/*
53 * hfs_part_find()
54 *
55 * Parse the partition map looking for the
56 * start and length of the 'part'th HFS partition.
57 */
58int hfs_part_find(struct super_block *sb,
59 sector_t *part_start, sector_t *part_size)
60{
61 struct buffer_head *bh;
62 __be16 *data;
63 int i, size, res;
64
65 res = -ENOENT;
66 bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK, data);
67 if (!bh)
68 return -EIO;
69
70 switch (be16_to_cpu(*data)) {
71 case HFS_OLD_PMAP_MAGIC:
72 {
73 struct old_pmap *pm;
74 struct old_pmap_entry *p;
75
76 pm = (struct old_pmap *)bh->b_data;
77 p = pm->pdEntry;
78 size = 42;
79 for (i = 0; i < size; p++, i++) {
80 if (p->pdStart && p->pdSize &&
81 p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
82 (HFS_SB(sb)->part < 0 || HFS_SB(sb)->part == i)) {
83 *part_start += be32_to_cpu(p->pdStart);
84 *part_size = be32_to_cpu(p->pdSize);
85 res = 0;
86 }
87 }
88 break;
89 }
90 case HFS_NEW_PMAP_MAGIC:
91 {
92 struct new_pmap *pm;
93
94 pm = (struct new_pmap *)bh->b_data;
95 size = be32_to_cpu(pm->pmMapBlkCnt);
96 for (i = 0; i < size;) {
97 if (!memcmp(pm->pmPartType,"Apple_HFS", 9) &&
98 (HFS_SB(sb)->part < 0 || HFS_SB(sb)->part == i)) {
99 *part_start += be32_to_cpu(pm->pmPyPartStart);
100 *part_size = be32_to_cpu(pm->pmPartBlkCnt);
101 res = 0;
102 break;
103 }
104 brelse(bh);
105 bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK + ++i, pm);
106 if (!bh)
107 return -EIO;
108 if (pm->pmSig != cpu_to_be16(HFS_NEW_PMAP_MAGIC))
109 break;
110 }
111 break;
112 }
113 }
114 brelse(bh);
115
116 return res;
117}
diff --git a/fs/hfs/string.c b/fs/hfs/string.c
new file mode 100644
index 000000000000..927a5af79428
--- /dev/null
+++ b/fs/hfs/string.c
@@ -0,0 +1,115 @@
1/*
2 * linux/fs/hfs/string.c
3 *
4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * (C) 2003 Ardis Technologies <roman@ardistech.com>
6 * This file may be distributed under the terms of the GNU General Public License.
7 *
8 * This file contains the string comparison function for the
9 * Macintosh character set.
10 *
11 * The code in this file is derived from code which is copyright
12 * 1986, 1989, 1990 by Abacus Research and Development, Inc. (ARDI)
13 * It is used here by the permission of ARDI's president Cliff Matthews.
14 */
15
16#include "hfs_fs.h"
17#include <linux/dcache.h>
18
19/*================ File-local variables ================*/
20
21/*
22 * unsigned char caseorder[]
23 *
24 * Defines the lexical ordering of characters on the Macintosh
25 *
26 * Composition of the 'casefold' and 'order' tables from ARDI's code
27 * with the entry for 0x20 changed to match that for 0xCA to remove
28 * special case for those two characters.
29 */
30static unsigned char caseorder[256] = {
31 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
32 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
33 0x20,0x22,0x23,0x28,0x29,0x2A,0x2B,0x2C,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36,
34 0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
35 0x47,0x48,0x57,0x59,0x5D,0x5F,0x66,0x68,0x6A,0x6C,0x72,0x74,0x76,0x78,0x7A,0x7E,
36 0x8C,0x8E,0x90,0x92,0x95,0x97,0x9E,0xA0,0xA2,0xA4,0xA7,0xA9,0xAA,0xAB,0xAC,0xAD,
37 0x4E,0x48,0x57,0x59,0x5D,0x5F,0x66,0x68,0x6A,0x6C,0x72,0x74,0x76,0x78,0x7A,0x7E,
38 0x8C,0x8E,0x90,0x92,0x95,0x97,0x9E,0xA0,0xA2,0xA4,0xA7,0xAF,0xB0,0xB1,0xB2,0xB3,
39 0x4A,0x4C,0x5A,0x60,0x7B,0x7F,0x98,0x4F,0x49,0x51,0x4A,0x4B,0x4C,0x5A,0x60,0x63,
40 0x64,0x65,0x6E,0x6F,0x70,0x71,0x7B,0x84,0x85,0x86,0x7F,0x80,0x9A,0x9B,0x9C,0x98,
41 0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0x94,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0x4D,0x81,
42 0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0x55,0x8A,0xCC,0x4D,0x81,
43 0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0x26,0x27,0xD4,0x20,0x49,0x4B,0x80,0x82,0x82,
44 0xD5,0xD6,0x24,0x25,0x2D,0x2E,0xD7,0xD8,0xA6,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
45 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
46 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
47};
48
49/*================ Global functions ================*/
50
51/*
52 * Hash a string to an integer in a case-independent way
53 */
54int hfs_hash_dentry(struct dentry *dentry, struct qstr *this)
55{
56 const unsigned char *name = this->name;
57 unsigned int hash, len = this->len;
58
59 if (len > HFS_NAMELEN)
60 len = HFS_NAMELEN;
61
62 hash = init_name_hash();
63 for (; len; len--)
64 hash = partial_name_hash(caseorder[*name++], hash);
65 this->hash = end_name_hash(hash);
66 return 0;
67}
68
69/*
70 * Compare two strings in the HFS filename character ordering
71 * Returns positive, negative, or zero, not just 0 or (+/-)1
72 *
73 * Equivalent to ARDI's call:
74 * ROMlib_RelString(s1+1, s2+1, true, false, (s1[0]<<16) | s2[0])
75 */
76int hfs_strcmp(const unsigned char *s1, unsigned int len1,
77 const unsigned char *s2, unsigned int len2)
78{
79 int len, tmp;
80
81 len = (len1 > len2) ? len2 : len1;
82
83 while (len--) {
84 tmp = (int)caseorder[*(s1++)] - (int)caseorder[*(s2++)];
85 if (tmp)
86 return tmp;
87 }
88 return len1 - len2;
89}
90
91/*
92 * Test for equality of two strings in the HFS filename character ordering.
93 * return 1 on failure and 0 on success
94 */
95int hfs_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2)
96{
97 const unsigned char *n1, *n2;
98 int len;
99
100 len = s1->len;
101 if (len >= HFS_NAMELEN) {
102 if (s2->len < HFS_NAMELEN)
103 return 1;
104 len = HFS_NAMELEN;
105 } else if (len != s2->len)
106 return 1;
107
108 n1 = s1->name;
109 n2 = s2->name;
110 while (len--) {
111 if (caseorder[*n1++] != caseorder[*n2++])
112 return 1;
113 }
114 return 0;
115}
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
new file mode 100644
index 000000000000..1e2c193134cc
--- /dev/null
+++ b/fs/hfs/super.c
@@ -0,0 +1,395 @@
1/*
2 * linux/fs/hfs/super.c
3 *
4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * (C) 2003 Ardis Technologies <roman@ardistech.com>
6 * This file may be distributed under the terms of the GNU General Public License.
7 *
8 * This file contains hfs_read_super(), some of the super_ops and
9 * init_module() and cleanup_module(). The remaining super_ops are in
10 * inode.c since they deal with inodes.
11 *
12 * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
13 */
14
15#include <linux/config.h>
16#include <linux/module.h>
17#include <linux/blkdev.h>
18#include <linux/init.h>
19#include <linux/parser.h>
20#include <linux/vfs.h>
21
22#include "hfs_fs.h"
23#include "btree.h"
24
25static kmem_cache_t *hfs_inode_cachep;
26
27MODULE_LICENSE("GPL");
28
29/*
30 * hfs_write_super()
31 *
32 * Description:
33 * This function is called by the VFS only. When the filesystem
34 * is mounted r/w it updates the MDB on disk.
35 * Input Variable(s):
36 * struct super_block *sb: Pointer to the hfs superblock
37 * Output Variable(s):
38 * NONE
39 * Returns:
40 * void
41 * Preconditions:
42 * 'sb' points to a "valid" (struct super_block).
43 * Postconditions:
44 * The MDB is marked 'unsuccessfully unmounted' by clearing bit 8 of drAtrb
45 * (hfs_put_super() must set this flag!). Some MDB fields are updated
46 * and the MDB buffer is written to disk by calling hfs_mdb_commit().
47 */
48static void hfs_write_super(struct super_block *sb)
49{
50 sb->s_dirt = 0;
51 if (sb->s_flags & MS_RDONLY)
52 return;
53 /* sync everything to the buffers */
54 hfs_mdb_commit(sb);
55}
56
57/*
58 * hfs_put_super()
59 *
60 * This is the put_super() entry in the super_operations structure for
61 * HFS filesystems. The purpose is to release the resources
62 * associated with the superblock sb.
63 */
64static void hfs_put_super(struct super_block *sb)
65{
66 hfs_mdb_close(sb);
67 /* release the MDB's resources */
68 hfs_mdb_put(sb);
69}
70
71/*
72 * hfs_statfs()
73 *
74 * This is the statfs() entry in the super_operations structure for
75 * HFS filesystems. The purpose is to return various data about the
76 * filesystem.
77 *
78 * changed f_files/f_ffree to reflect the fs_ablock/free_ablocks.
79 */
80static int hfs_statfs(struct super_block *sb, struct kstatfs *buf)
81{
82 buf->f_type = HFS_SUPER_MAGIC;
83 buf->f_bsize = sb->s_blocksize;
84 buf->f_blocks = (u32)HFS_SB(sb)->fs_ablocks * HFS_SB(sb)->fs_div;
85 buf->f_bfree = (u32)HFS_SB(sb)->free_ablocks * HFS_SB(sb)->fs_div;
86 buf->f_bavail = buf->f_bfree;
87 buf->f_files = HFS_SB(sb)->fs_ablocks;
88 buf->f_ffree = HFS_SB(sb)->free_ablocks;
89 buf->f_namelen = HFS_NAMELEN;
90
91 return 0;
92}
93
94static int hfs_remount(struct super_block *sb, int *flags, char *data)
95{
96 *flags |= MS_NODIRATIME;
97 if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
98 return 0;
99 if (!(*flags & MS_RDONLY)) {
100 if (!(HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) {
101 printk("HFS-fs warning: Filesystem was not cleanly unmounted, "
102 "running fsck.hfs is recommended. leaving read-only.\n");
103 sb->s_flags |= MS_RDONLY;
104 *flags |= MS_RDONLY;
105 } else if (HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_SLOCK)) {
106 printk("HFS-fs: Filesystem is marked locked, leaving read-only.\n");
107 sb->s_flags |= MS_RDONLY;
108 *flags |= MS_RDONLY;
109 }
110 }
111 return 0;
112}
113
114static struct inode *hfs_alloc_inode(struct super_block *sb)
115{
116 struct hfs_inode_info *i;
117
118 i = kmem_cache_alloc(hfs_inode_cachep, SLAB_KERNEL);
119 return i ? &i->vfs_inode : NULL;
120}
121
122static void hfs_destroy_inode(struct inode *inode)
123{
124 kmem_cache_free(hfs_inode_cachep, HFS_I(inode));
125}
126
127static struct super_operations hfs_super_operations = {
128 .alloc_inode = hfs_alloc_inode,
129 .destroy_inode = hfs_destroy_inode,
130 .write_inode = hfs_write_inode,
131 .clear_inode = hfs_clear_inode,
132 .put_super = hfs_put_super,
133 .write_super = hfs_write_super,
134 .statfs = hfs_statfs,
135 .remount_fs = hfs_remount,
136};
137
138enum {
139 opt_uid, opt_gid, opt_umask, opt_file_umask, opt_dir_umask,
140 opt_part, opt_session, opt_type, opt_creator, opt_quiet,
141 opt_err
142};
143
144static match_table_t tokens = {
145 { opt_uid, "uid=%u" },
146 { opt_gid, "gid=%u" },
147 { opt_umask, "umask=%o" },
148 { opt_file_umask, "file_umask=%o" },
149 { opt_dir_umask, "dir_umask=%o" },
150 { opt_part, "part=%u" },
151 { opt_session, "session=%u" },
152 { opt_type, "type=%s" },
153 { opt_creator, "creator=%s" },
154 { opt_quiet, "quiet" },
155 { opt_err, NULL }
156};
157
158static inline int match_fourchar(substring_t *arg, u32 *result)
159{
160 if (arg->to - arg->from != 4)
161 return -EINVAL;
162 memcpy(result, arg->from, 4);
163 return 0;
164}
165
166/*
167 * parse_options()
168 *
169 * adapted from linux/fs/msdos/inode.c written 1992,93 by Werner Almesberger
170 * This function is called by hfs_read_super() to parse the mount options.
171 */
172static int parse_options(char *options, struct hfs_sb_info *hsb)
173{
174 char *p;
175 substring_t args[MAX_OPT_ARGS];
176 int tmp, token;
177
178 /* initialize the sb with defaults */
179 hsb->s_uid = current->uid;
180 hsb->s_gid = current->gid;
181 hsb->s_file_umask = 0133;
182 hsb->s_dir_umask = 0022;
183 hsb->s_type = hsb->s_creator = cpu_to_be32(0x3f3f3f3f); /* == '????' */
184 hsb->s_quiet = 0;
185 hsb->part = -1;
186 hsb->session = -1;
187
188 if (!options)
189 return 1;
190
191 while ((p = strsep(&options, ",")) != NULL) {
192 if (!*p)
193 continue;
194
195 token = match_token(p, tokens, args);
196 switch (token) {
197 case opt_uid:
198 if (match_int(&args[0], &tmp)) {
199 printk("HFS: uid requires an argument\n");
200 return 0;
201 }
202 hsb->s_uid = (uid_t)tmp;
203 break;
204 case opt_gid:
205 if (match_int(&args[0], &tmp)) {
206 printk("HFS: gid requires an argument\n");
207 return 0;
208 }
209 hsb->s_gid = (gid_t)tmp;
210 break;
211 case opt_umask:
212 if (match_octal(&args[0], &tmp)) {
213 printk("HFS: umask requires a value\n");
214 return 0;
215 }
216 hsb->s_file_umask = (umode_t)tmp;
217 hsb->s_dir_umask = (umode_t)tmp;
218 break;
219 case opt_file_umask:
220 if (match_octal(&args[0], &tmp)) {
221 printk("HFS: file_umask requires a value\n");
222 return 0;
223 }
224 hsb->s_file_umask = (umode_t)tmp;
225 break;
226 case opt_dir_umask:
227 if (match_octal(&args[0], &tmp)) {
228 printk("HFS: dir_umask requires a value\n");
229 return 0;
230 }
231 hsb->s_dir_umask = (umode_t)tmp;
232 break;
233 case opt_part:
234 if (match_int(&args[0], &hsb->part)) {
235 printk("HFS: part requires an argument\n");
236 return 0;
237 }
238 break;
239 case opt_session:
240 if (match_int(&args[0], &hsb->session)) {
241 printk("HFS: session requires an argument\n");
242 return 0;
243 }
244 break;
245 case opt_type:
246 if (match_fourchar(&args[0], &hsb->s_type)) {
247 printk("HFS+-fs: type requires a 4 character value\n");
248 return 0;
249 }
250 break;
251 case opt_creator:
252 if (match_fourchar(&args[0], &hsb->s_creator)) {
253 printk("HFS+-fs: creator requires a 4 character value\n");
254 return 0;
255 }
256 break;
257 case opt_quiet:
258 hsb->s_quiet = 1;
259 break;
260 default:
261 return 0;
262 }
263 }
264
265 hsb->s_dir_umask &= 0777;
266 hsb->s_file_umask &= 0577;
267
268 return 1;
269}
270
271/*
272 * hfs_read_super()
273 *
274 * This is the function that is responsible for mounting an HFS
275 * filesystem. It performs all the tasks necessary to get enough data
276 * from the disk to read the root inode. This includes parsing the
277 * mount options, dealing with Macintosh partitions, reading the
278 * superblock and the allocation bitmap blocks, calling
279 * hfs_btree_init() to get the necessary data about the extents and
280 * catalog B-trees and, finally, reading the root inode into memory.
281 */
282static int hfs_fill_super(struct super_block *sb, void *data, int silent)
283{
284 struct hfs_sb_info *sbi;
285 struct hfs_find_data fd;
286 hfs_cat_rec rec;
287 struct inode *root_inode;
288 int res;
289
290 sbi = kmalloc(sizeof(struct hfs_sb_info), GFP_KERNEL);
291 if (!sbi)
292 return -ENOMEM;
293 sb->s_fs_info = sbi;
294 memset(sbi, 0, sizeof(struct hfs_sb_info));
295 INIT_HLIST_HEAD(&sbi->rsrc_inodes);
296
297 res = -EINVAL;
298 if (!parse_options((char *)data, sbi)) {
299 hfs_warn("hfs_fs: unable to parse mount options.\n");
300 goto bail3;
301 }
302
303 sb->s_op = &hfs_super_operations;
304 sb->s_flags |= MS_NODIRATIME;
305 init_MUTEX(&sbi->bitmap_lock);
306
307 res = hfs_mdb_get(sb);
308 if (res) {
309 if (!silent)
310 hfs_warn("VFS: Can't find a HFS filesystem on dev %s.\n",
311 hfs_mdb_name(sb));
312 res = -EINVAL;
313 goto bail2;
314 }
315
316 /* try to get the root inode */
317 hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
318 res = hfs_cat_find_brec(sb, HFS_ROOT_CNID, &fd);
319 if (!res)
320 hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, fd.entrylength);
321 if (res) {
322 hfs_find_exit(&fd);
323 goto bail_no_root;
324 }
325 root_inode = hfs_iget(sb, &fd.search_key->cat, &rec);
326 hfs_find_exit(&fd);
327 if (!root_inode)
328 goto bail_no_root;
329
330 sb->s_root = d_alloc_root(root_inode);
331 if (!sb->s_root)
332 goto bail_iput;
333
334 sb->s_root->d_op = &hfs_dentry_operations;
335
336 /* everything's okay */
337 return 0;
338
339bail_iput:
340 iput(root_inode);
341bail_no_root:
342 hfs_warn("hfs_fs: get root inode failed.\n");
343 hfs_mdb_put(sb);
344bail2:
345bail3:
346 kfree(sbi);
347 return res;
348}
349
350static struct super_block *hfs_get_sb(struct file_system_type *fs_type,
351 int flags, const char *dev_name, void *data)
352{
353 return get_sb_bdev(fs_type, flags, dev_name, data, hfs_fill_super);
354}
355
356static struct file_system_type hfs_fs_type = {
357 .owner = THIS_MODULE,
358 .name = "hfs",
359 .get_sb = hfs_get_sb,
360 .kill_sb = kill_block_super,
361 .fs_flags = FS_REQUIRES_DEV,
362};
363
364static void hfs_init_once(void *p, kmem_cache_t *cachep, unsigned long flags)
365{
366 struct hfs_inode_info *i = p;
367
368 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR)
369 inode_init_once(&i->vfs_inode);
370}
371
372static int __init init_hfs_fs(void)
373{
374 int err;
375
376 hfs_inode_cachep = kmem_cache_create("hfs_inode_cache",
377 sizeof(struct hfs_inode_info), 0, SLAB_HWCACHE_ALIGN,
378 hfs_init_once, NULL);
379 if (!hfs_inode_cachep)
380 return -ENOMEM;
381 err = register_filesystem(&hfs_fs_type);
382 if (err)
383 kmem_cache_destroy(hfs_inode_cachep);
384 return err;
385}
386
387static void __exit exit_hfs_fs(void)
388{
389 unregister_filesystem(&hfs_fs_type);
390 if (kmem_cache_destroy(hfs_inode_cachep))
391 printk(KERN_INFO "hfs_inode_cache: not all structures were freed\n");
392}
393
394module_init(init_hfs_fs)
395module_exit(exit_hfs_fs)
diff --git a/fs/hfs/sysdep.c b/fs/hfs/sysdep.c
new file mode 100644
index 000000000000..5bf89ec01cd4
--- /dev/null
+++ b/fs/hfs/sysdep.c
@@ -0,0 +1,40 @@
1/*
2 * linux/fs/hfs/sysdep.c
3 *
4 * Copyright (C) 1996 Paul H. Hargrove
5 * (C) 2003 Ardis Technologies <roman@ardistech.com>
6 * This file may be distributed under the terms of the GNU General Public License.
7 *
8 * This file contains the code to do various system dependent things.
9 */
10
11#include "hfs_fs.h"
12
13/* dentry case-handling: just lowercase everything */
14
15static int hfs_revalidate_dentry(struct dentry *dentry, struct nameidata *nd)
16{
17 struct inode *inode = dentry->d_inode;
18 int diff;
19
20 if(!inode)
21 return 1;
22
23 /* fix up inode on a timezone change */
24 diff = sys_tz.tz_minuteswest * 60 - HFS_I(inode)->tz_secondswest;
25 if (diff) {
26 inode->i_ctime.tv_sec += diff;
27 inode->i_atime.tv_sec += diff;
28 inode->i_mtime.tv_sec += diff;
29 HFS_I(inode)->tz_secondswest += diff;
30 }
31 return 1;
32}
33
34struct dentry_operations hfs_dentry_operations =
35{
36 .d_revalidate = hfs_revalidate_dentry,
37 .d_hash = hfs_hash_dentry,
38 .d_compare = hfs_compare_dentry,
39};
40
diff --git a/fs/hfs/trans.c b/fs/hfs/trans.c
new file mode 100644
index 000000000000..fb9720abbadd
--- /dev/null
+++ b/fs/hfs/trans.c
@@ -0,0 +1,72 @@
1/*
2 * linux/fs/hfs/trans.c
3 *
4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * This file may be distributed under the terms of the GNU General Public License.
6 *
7 * This file contains routines for converting between the Macintosh
8 * character set and various other encodings. This includes dealing
9 * with ':' vs. '/' as the path-element separator.
10 */
11
12#include "hfs_fs.h"
13
14/*================ Global functions ================*/
15
16/*
17 * hfs_mac2triv()
18 *
19 * Given a 'Pascal String' (a string preceded by a length byte) in
20 * the Macintosh character set produce the corresponding filename using
21 * the 'trivial' name-mangling scheme, returning the length of the
22 * mangled filename. Note that the output string is not NULL
23 * terminated.
24 *
25 * The name-mangling works as follows:
26 * The character '/', which is illegal in Linux filenames is replaced
27 * by ':' which never appears in HFS filenames. All other characters
28 * are passed unchanged from input to output.
29 */
30int hfs_mac2triv(char *out, const struct hfs_name *in)
31{
32 const char *p;
33 char c;
34 int i, len;
35
36 len = in->len;
37 p = in->name;
38 for (i = 0; i < len; i++) {
39 c = *p++;
40 *out++ = c == '/' ? ':' : c;
41 }
42 return i;
43}
44
45/*
46 * hfs_triv2mac()
47 *
48 * Given an ASCII string (not null-terminated) and its length,
49 * generate the corresponding filename in the Macintosh character set
50 * using the 'trivial' name-mangling scheme, returning the length of
51 * the mangled filename. Note that the output string is not NULL
52 * terminated.
53 *
54 * This routine is a inverse to hfs_mac2triv().
55 * A ':' is replaced by a '/'.
56 */
57void hfs_triv2mac(struct hfs_name *out, struct qstr *in)
58{
59 const char *src;
60 char *dst, c;
61 int i, len;
62
63 out->len = len = min((unsigned int)HFS_NAMELEN, in->len);
64 src = in->name;
65 dst = out->name;
66 for (i = 0; i < len; i++) {
67 c = *src++;
68 *dst++ = c == ':' ? '/' : c;
69 }
70 for (; i < HFS_NAMELEN; i++)
71 *dst++ = 0;
72}