xref: /OK3568_Linux_fs/kernel/fs/hfs/catalog.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  *  linux/fs/hfs/catalog.c
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 1995-1997  Paul H. Hargrove
5*4882a593Smuzhiyun  * (C) 2003 Ardis Technologies <roman@ardistech.com>
6*4882a593Smuzhiyun  * This file may be distributed under the terms of the GNU General Public License.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * This file contains the functions related to the catalog B-tree.
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * Cache code shamelessly stolen from
11*4882a593Smuzhiyun  *     linux/fs/inode.c Copyright (C) 1991, 1992  Linus Torvalds
12*4882a593Smuzhiyun  *     re-shamelessly stolen Copyright (C) 1997 Linus Torvalds
13*4882a593Smuzhiyun  */
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "hfs_fs.h"
16*4882a593Smuzhiyun #include "btree.h"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun /*
19*4882a593Smuzhiyun  * hfs_cat_build_key()
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * Given the ID of the parent and the name build a search key.
22*4882a593Smuzhiyun  */
hfs_cat_build_key(struct super_block * sb,btree_key * key,u32 parent,const struct qstr * name)23*4882a593Smuzhiyun void hfs_cat_build_key(struct super_block *sb, btree_key *key, u32 parent, const struct qstr *name)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun 	key->cat.reserved = 0;
26*4882a593Smuzhiyun 	key->cat.ParID = cpu_to_be32(parent);
27*4882a593Smuzhiyun 	if (name) {
28*4882a593Smuzhiyun 		hfs_asc2mac(sb, &key->cat.CName, name);
29*4882a593Smuzhiyun 		key->key_len = 6 + key->cat.CName.len;
30*4882a593Smuzhiyun 	} else {
31*4882a593Smuzhiyun 		memset(&key->cat.CName, 0, sizeof(struct hfs_name));
32*4882a593Smuzhiyun 		key->key_len = 6;
33*4882a593Smuzhiyun 	}
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun 
hfs_cat_build_record(hfs_cat_rec * rec,u32 cnid,struct inode * inode)36*4882a593Smuzhiyun static int hfs_cat_build_record(hfs_cat_rec *rec, u32 cnid, struct inode *inode)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun 	__be32 mtime = hfs_mtime();
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	memset(rec, 0, sizeof(*rec));
41*4882a593Smuzhiyun 	if (S_ISDIR(inode->i_mode)) {
42*4882a593Smuzhiyun 		rec->type = HFS_CDR_DIR;
43*4882a593Smuzhiyun 		rec->dir.DirID = cpu_to_be32(cnid);
44*4882a593Smuzhiyun 		rec->dir.CrDat = mtime;
45*4882a593Smuzhiyun 		rec->dir.MdDat = mtime;
46*4882a593Smuzhiyun 		rec->dir.BkDat = 0;
47*4882a593Smuzhiyun 		rec->dir.UsrInfo.frView = cpu_to_be16(0xff);
48*4882a593Smuzhiyun 		return sizeof(struct hfs_cat_dir);
49*4882a593Smuzhiyun 	} else {
50*4882a593Smuzhiyun 		/* init some fields for the file record */
51*4882a593Smuzhiyun 		rec->type = HFS_CDR_FIL;
52*4882a593Smuzhiyun 		rec->file.Flags = HFS_FIL_USED | HFS_FIL_THD;
53*4882a593Smuzhiyun 		if (!(inode->i_mode & S_IWUSR))
54*4882a593Smuzhiyun 			rec->file.Flags |= HFS_FIL_LOCK;
55*4882a593Smuzhiyun 		rec->file.FlNum = cpu_to_be32(cnid);
56*4882a593Smuzhiyun 		rec->file.CrDat = mtime;
57*4882a593Smuzhiyun 		rec->file.MdDat = mtime;
58*4882a593Smuzhiyun 		rec->file.BkDat = 0;
59*4882a593Smuzhiyun 		rec->file.UsrWds.fdType = HFS_SB(inode->i_sb)->s_type;
60*4882a593Smuzhiyun 		rec->file.UsrWds.fdCreator = HFS_SB(inode->i_sb)->s_creator;
61*4882a593Smuzhiyun 		return sizeof(struct hfs_cat_file);
62*4882a593Smuzhiyun 	}
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
hfs_cat_build_thread(struct super_block * sb,hfs_cat_rec * rec,int type,u32 parentid,const struct qstr * name)65*4882a593Smuzhiyun static int hfs_cat_build_thread(struct super_block *sb,
66*4882a593Smuzhiyun 				hfs_cat_rec *rec, int type,
67*4882a593Smuzhiyun 				u32 parentid, const struct qstr *name)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	rec->type = type;
70*4882a593Smuzhiyun 	memset(rec->thread.reserved, 0, sizeof(rec->thread.reserved));
71*4882a593Smuzhiyun 	rec->thread.ParID = cpu_to_be32(parentid);
72*4882a593Smuzhiyun 	hfs_asc2mac(sb, &rec->thread.CName, name);
73*4882a593Smuzhiyun 	return sizeof(struct hfs_cat_thread);
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun /*
77*4882a593Smuzhiyun  * create_entry()
78*4882a593Smuzhiyun  *
79*4882a593Smuzhiyun  * Add a new file or directory to the catalog B-tree and
80*4882a593Smuzhiyun  * return a (struct hfs_cat_entry) for it in '*result'.
81*4882a593Smuzhiyun  */
hfs_cat_create(u32 cnid,struct inode * dir,const struct qstr * str,struct inode * inode)82*4882a593Smuzhiyun int hfs_cat_create(u32 cnid, struct inode *dir, const struct qstr *str, struct inode *inode)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	struct hfs_find_data fd;
85*4882a593Smuzhiyun 	struct super_block *sb;
86*4882a593Smuzhiyun 	union hfs_cat_rec entry;
87*4882a593Smuzhiyun 	int entry_size;
88*4882a593Smuzhiyun 	int err;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	hfs_dbg(CAT_MOD, "create_cat: %s,%u(%d)\n",
91*4882a593Smuzhiyun 		str->name, cnid, inode->i_nlink);
92*4882a593Smuzhiyun 	if (dir->i_size >= HFS_MAX_VALENCE)
93*4882a593Smuzhiyun 		return -ENOSPC;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	sb = dir->i_sb;
96*4882a593Smuzhiyun 	err = hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
97*4882a593Smuzhiyun 	if (err)
98*4882a593Smuzhiyun 		return err;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	/*
101*4882a593Smuzhiyun 	 * Fail early and avoid ENOSPC during the btree operations. We may
102*4882a593Smuzhiyun 	 * have to split the root node at most once.
103*4882a593Smuzhiyun 	 */
104*4882a593Smuzhiyun 	err = hfs_bmap_reserve(fd.tree, 2 * fd.tree->depth);
105*4882a593Smuzhiyun 	if (err)
106*4882a593Smuzhiyun 		goto err2;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
109*4882a593Smuzhiyun 	entry_size = hfs_cat_build_thread(sb, &entry, S_ISDIR(inode->i_mode) ?
110*4882a593Smuzhiyun 			HFS_CDR_THD : HFS_CDR_FTH,
111*4882a593Smuzhiyun 			dir->i_ino, str);
112*4882a593Smuzhiyun 	err = hfs_brec_find(&fd);
113*4882a593Smuzhiyun 	if (err != -ENOENT) {
114*4882a593Smuzhiyun 		if (!err)
115*4882a593Smuzhiyun 			err = -EEXIST;
116*4882a593Smuzhiyun 		goto err2;
117*4882a593Smuzhiyun 	}
118*4882a593Smuzhiyun 	err = hfs_brec_insert(&fd, &entry, entry_size);
119*4882a593Smuzhiyun 	if (err)
120*4882a593Smuzhiyun 		goto err2;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str);
123*4882a593Smuzhiyun 	entry_size = hfs_cat_build_record(&entry, cnid, inode);
124*4882a593Smuzhiyun 	err = hfs_brec_find(&fd);
125*4882a593Smuzhiyun 	if (err != -ENOENT) {
126*4882a593Smuzhiyun 		/* panic? */
127*4882a593Smuzhiyun 		if (!err)
128*4882a593Smuzhiyun 			err = -EEXIST;
129*4882a593Smuzhiyun 		goto err1;
130*4882a593Smuzhiyun 	}
131*4882a593Smuzhiyun 	err = hfs_brec_insert(&fd, &entry, entry_size);
132*4882a593Smuzhiyun 	if (err)
133*4882a593Smuzhiyun 		goto err1;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	dir->i_size++;
136*4882a593Smuzhiyun 	dir->i_mtime = dir->i_ctime = current_time(dir);
137*4882a593Smuzhiyun 	mark_inode_dirty(dir);
138*4882a593Smuzhiyun 	hfs_find_exit(&fd);
139*4882a593Smuzhiyun 	return 0;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun err1:
142*4882a593Smuzhiyun 	hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
143*4882a593Smuzhiyun 	if (!hfs_brec_find(&fd))
144*4882a593Smuzhiyun 		hfs_brec_remove(&fd);
145*4882a593Smuzhiyun err2:
146*4882a593Smuzhiyun 	hfs_find_exit(&fd);
147*4882a593Smuzhiyun 	return err;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun /*
151*4882a593Smuzhiyun  * hfs_cat_compare()
152*4882a593Smuzhiyun  *
153*4882a593Smuzhiyun  * Description:
154*4882a593Smuzhiyun  *   This is the comparison function used for the catalog B-tree.  In
155*4882a593Smuzhiyun  *   comparing catalog B-tree entries, the parent id is the most
156*4882a593Smuzhiyun  *   significant field (compared as unsigned ints).  The name field is
157*4882a593Smuzhiyun  *   the least significant (compared in "Macintosh lexical order",
158*4882a593Smuzhiyun  *   see hfs_strcmp() in string.c)
159*4882a593Smuzhiyun  * Input Variable(s):
160*4882a593Smuzhiyun  *   struct hfs_cat_key *key1: pointer to the first key to compare
161*4882a593Smuzhiyun  *   struct hfs_cat_key *key2: pointer to the second key to compare
162*4882a593Smuzhiyun  * Output Variable(s):
163*4882a593Smuzhiyun  *   NONE
164*4882a593Smuzhiyun  * Returns:
165*4882a593Smuzhiyun  *   int: negative if key1<key2, positive if key1>key2, and 0 if key1==key2
166*4882a593Smuzhiyun  * Preconditions:
167*4882a593Smuzhiyun  *   key1 and key2 point to "valid" (struct hfs_cat_key)s.
168*4882a593Smuzhiyun  * Postconditions:
169*4882a593Smuzhiyun  *   This function has no side-effects
170*4882a593Smuzhiyun  */
hfs_cat_keycmp(const btree_key * key1,const btree_key * key2)171*4882a593Smuzhiyun int hfs_cat_keycmp(const btree_key *key1, const btree_key *key2)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	__be32 k1p, k2p;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	k1p = key1->cat.ParID;
176*4882a593Smuzhiyun 	k2p = key2->cat.ParID;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	if (k1p != k2p)
179*4882a593Smuzhiyun 		return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	return hfs_strcmp(key1->cat.CName.name, key1->cat.CName.len,
182*4882a593Smuzhiyun 			  key2->cat.CName.name, key2->cat.CName.len);
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun /* Try to get a catalog entry for given catalog id */
186*4882a593Smuzhiyun // move to read_super???
hfs_cat_find_brec(struct super_block * sb,u32 cnid,struct hfs_find_data * fd)187*4882a593Smuzhiyun int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
188*4882a593Smuzhiyun 		      struct hfs_find_data *fd)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun 	hfs_cat_rec rec;
191*4882a593Smuzhiyun 	int res, len, type;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	hfs_cat_build_key(sb, fd->search_key, cnid, NULL);
194*4882a593Smuzhiyun 	res = hfs_brec_read(fd, &rec, sizeof(rec));
195*4882a593Smuzhiyun 	if (res)
196*4882a593Smuzhiyun 		return res;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	type = rec.type;
199*4882a593Smuzhiyun 	if (type != HFS_CDR_THD && type != HFS_CDR_FTH) {
200*4882a593Smuzhiyun 		pr_err("found bad thread record in catalog\n");
201*4882a593Smuzhiyun 		return -EIO;
202*4882a593Smuzhiyun 	}
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	fd->search_key->cat.ParID = rec.thread.ParID;
205*4882a593Smuzhiyun 	len = fd->search_key->cat.CName.len = rec.thread.CName.len;
206*4882a593Smuzhiyun 	if (len > HFS_NAMELEN) {
207*4882a593Smuzhiyun 		pr_err("bad catalog namelength\n");
208*4882a593Smuzhiyun 		return -EIO;
209*4882a593Smuzhiyun 	}
210*4882a593Smuzhiyun 	memcpy(fd->search_key->cat.CName.name, rec.thread.CName.name, len);
211*4882a593Smuzhiyun 	return hfs_brec_find(fd);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun /*
216*4882a593Smuzhiyun  * hfs_cat_delete()
217*4882a593Smuzhiyun  *
218*4882a593Smuzhiyun  * Delete the indicated file or directory.
219*4882a593Smuzhiyun  * The associated thread is also removed unless ('with_thread'==0).
220*4882a593Smuzhiyun  */
hfs_cat_delete(u32 cnid,struct inode * dir,const struct qstr * str)221*4882a593Smuzhiyun int hfs_cat_delete(u32 cnid, struct inode *dir, const struct qstr *str)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	struct super_block *sb;
224*4882a593Smuzhiyun 	struct hfs_find_data fd;
225*4882a593Smuzhiyun 	struct hfs_readdir_data *rd;
226*4882a593Smuzhiyun 	int res, type;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	hfs_dbg(CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid);
229*4882a593Smuzhiyun 	sb = dir->i_sb;
230*4882a593Smuzhiyun 	res = hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
231*4882a593Smuzhiyun 	if (res)
232*4882a593Smuzhiyun 		return res;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str);
235*4882a593Smuzhiyun 	res = hfs_brec_find(&fd);
236*4882a593Smuzhiyun 	if (res)
237*4882a593Smuzhiyun 		goto out;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	type = hfs_bnode_read_u8(fd.bnode, fd.entryoffset);
240*4882a593Smuzhiyun 	if (type == HFS_CDR_FIL) {
241*4882a593Smuzhiyun 		struct hfs_cat_file file;
242*4882a593Smuzhiyun 		hfs_bnode_read(fd.bnode, &file, fd.entryoffset, sizeof(file));
243*4882a593Smuzhiyun 		if (be32_to_cpu(file.FlNum) == cnid) {
244*4882a593Smuzhiyun #if 0
245*4882a593Smuzhiyun 			hfs_free_fork(sb, &file, HFS_FK_DATA);
246*4882a593Smuzhiyun #endif
247*4882a593Smuzhiyun 			hfs_free_fork(sb, &file, HFS_FK_RSRC);
248*4882a593Smuzhiyun 		}
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	/* we only need to take spinlock for exclusion with ->release() */
252*4882a593Smuzhiyun 	spin_lock(&HFS_I(dir)->open_dir_lock);
253*4882a593Smuzhiyun 	list_for_each_entry(rd, &HFS_I(dir)->open_dir_list, list) {
254*4882a593Smuzhiyun 		if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0)
255*4882a593Smuzhiyun 			rd->file->f_pos--;
256*4882a593Smuzhiyun 	}
257*4882a593Smuzhiyun 	spin_unlock(&HFS_I(dir)->open_dir_lock);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	res = hfs_brec_remove(&fd);
260*4882a593Smuzhiyun 	if (res)
261*4882a593Smuzhiyun 		goto out;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
264*4882a593Smuzhiyun 	res = hfs_brec_find(&fd);
265*4882a593Smuzhiyun 	if (!res) {
266*4882a593Smuzhiyun 		res = hfs_brec_remove(&fd);
267*4882a593Smuzhiyun 		if (res)
268*4882a593Smuzhiyun 			goto out;
269*4882a593Smuzhiyun 	}
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	dir->i_size--;
272*4882a593Smuzhiyun 	dir->i_mtime = dir->i_ctime = current_time(dir);
273*4882a593Smuzhiyun 	mark_inode_dirty(dir);
274*4882a593Smuzhiyun 	res = 0;
275*4882a593Smuzhiyun out:
276*4882a593Smuzhiyun 	hfs_find_exit(&fd);
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	return res;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun /*
282*4882a593Smuzhiyun  * hfs_cat_move()
283*4882a593Smuzhiyun  *
284*4882a593Smuzhiyun  * Rename a file or directory, possibly to a new directory.
285*4882a593Smuzhiyun  * If the destination exists it is removed and a
286*4882a593Smuzhiyun  * (struct hfs_cat_entry) for it is returned in '*result'.
287*4882a593Smuzhiyun  */
hfs_cat_move(u32 cnid,struct inode * src_dir,const struct qstr * src_name,struct inode * dst_dir,const struct qstr * dst_name)288*4882a593Smuzhiyun int hfs_cat_move(u32 cnid, struct inode *src_dir, const struct qstr *src_name,
289*4882a593Smuzhiyun 		 struct inode *dst_dir, const struct qstr *dst_name)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun 	struct super_block *sb;
292*4882a593Smuzhiyun 	struct hfs_find_data src_fd, dst_fd;
293*4882a593Smuzhiyun 	union hfs_cat_rec entry;
294*4882a593Smuzhiyun 	int entry_size, type;
295*4882a593Smuzhiyun 	int err;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	hfs_dbg(CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n",
298*4882a593Smuzhiyun 		cnid, src_dir->i_ino, src_name->name,
299*4882a593Smuzhiyun 		dst_dir->i_ino, dst_name->name);
300*4882a593Smuzhiyun 	sb = src_dir->i_sb;
301*4882a593Smuzhiyun 	err = hfs_find_init(HFS_SB(sb)->cat_tree, &src_fd);
302*4882a593Smuzhiyun 	if (err)
303*4882a593Smuzhiyun 		return err;
304*4882a593Smuzhiyun 	dst_fd = src_fd;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	/*
307*4882a593Smuzhiyun 	 * Fail early and avoid ENOSPC during the btree operations. We may
308*4882a593Smuzhiyun 	 * have to split the root node at most once.
309*4882a593Smuzhiyun 	 */
310*4882a593Smuzhiyun 	err = hfs_bmap_reserve(src_fd.tree, 2 * src_fd.tree->depth);
311*4882a593Smuzhiyun 	if (err)
312*4882a593Smuzhiyun 		goto out;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	/* find the old dir entry and read the data */
315*4882a593Smuzhiyun 	hfs_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
316*4882a593Smuzhiyun 	err = hfs_brec_find(&src_fd);
317*4882a593Smuzhiyun 	if (err)
318*4882a593Smuzhiyun 		goto out;
319*4882a593Smuzhiyun 	if (src_fd.entrylength > sizeof(entry) || src_fd.entrylength < 0) {
320*4882a593Smuzhiyun 		err = -EIO;
321*4882a593Smuzhiyun 		goto out;
322*4882a593Smuzhiyun 	}
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	hfs_bnode_read(src_fd.bnode, &entry, src_fd.entryoffset,
325*4882a593Smuzhiyun 			    src_fd.entrylength);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	/* create new dir entry with the data from the old entry */
328*4882a593Smuzhiyun 	hfs_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name);
329*4882a593Smuzhiyun 	err = hfs_brec_find(&dst_fd);
330*4882a593Smuzhiyun 	if (err != -ENOENT) {
331*4882a593Smuzhiyun 		if (!err)
332*4882a593Smuzhiyun 			err = -EEXIST;
333*4882a593Smuzhiyun 		goto out;
334*4882a593Smuzhiyun 	}
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	err = hfs_brec_insert(&dst_fd, &entry, src_fd.entrylength);
337*4882a593Smuzhiyun 	if (err)
338*4882a593Smuzhiyun 		goto out;
339*4882a593Smuzhiyun 	dst_dir->i_size++;
340*4882a593Smuzhiyun 	dst_dir->i_mtime = dst_dir->i_ctime = current_time(dst_dir);
341*4882a593Smuzhiyun 	mark_inode_dirty(dst_dir);
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	/* finally remove the old entry */
344*4882a593Smuzhiyun 	hfs_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
345*4882a593Smuzhiyun 	err = hfs_brec_find(&src_fd);
346*4882a593Smuzhiyun 	if (err)
347*4882a593Smuzhiyun 		goto out;
348*4882a593Smuzhiyun 	err = hfs_brec_remove(&src_fd);
349*4882a593Smuzhiyun 	if (err)
350*4882a593Smuzhiyun 		goto out;
351*4882a593Smuzhiyun 	src_dir->i_size--;
352*4882a593Smuzhiyun 	src_dir->i_mtime = src_dir->i_ctime = current_time(src_dir);
353*4882a593Smuzhiyun 	mark_inode_dirty(src_dir);
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	type = entry.type;
356*4882a593Smuzhiyun 	if (type == HFS_CDR_FIL && !(entry.file.Flags & HFS_FIL_THD))
357*4882a593Smuzhiyun 		goto out;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	/* remove old thread entry */
360*4882a593Smuzhiyun 	hfs_cat_build_key(sb, src_fd.search_key, cnid, NULL);
361*4882a593Smuzhiyun 	err = hfs_brec_find(&src_fd);
362*4882a593Smuzhiyun 	if (err)
363*4882a593Smuzhiyun 		goto out;
364*4882a593Smuzhiyun 	err = hfs_brec_remove(&src_fd);
365*4882a593Smuzhiyun 	if (err)
366*4882a593Smuzhiyun 		goto out;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	/* create new thread entry */
369*4882a593Smuzhiyun 	hfs_cat_build_key(sb, dst_fd.search_key, cnid, NULL);
370*4882a593Smuzhiyun 	entry_size = hfs_cat_build_thread(sb, &entry, type == HFS_CDR_FIL ? HFS_CDR_FTH : HFS_CDR_THD,
371*4882a593Smuzhiyun 					dst_dir->i_ino, dst_name);
372*4882a593Smuzhiyun 	err = hfs_brec_find(&dst_fd);
373*4882a593Smuzhiyun 	if (err != -ENOENT) {
374*4882a593Smuzhiyun 		if (!err)
375*4882a593Smuzhiyun 			err = -EEXIST;
376*4882a593Smuzhiyun 		goto out;
377*4882a593Smuzhiyun 	}
378*4882a593Smuzhiyun 	err = hfs_brec_insert(&dst_fd, &entry, entry_size);
379*4882a593Smuzhiyun out:
380*4882a593Smuzhiyun 	hfs_bnode_put(dst_fd.bnode);
381*4882a593Smuzhiyun 	hfs_find_exit(&src_fd);
382*4882a593Smuzhiyun 	return err;
383*4882a593Smuzhiyun }
384