Import 2.3.1pre2
[davej-history.git] / fs / hfs / dir.c
blob6d111009634ef6dd11f398229cadbc24bc059617
1 /*
2 * linux/fs/hfs/dir.c
4 * Copyright (C) 1995-1997 Paul H. Hargrove
5 * This file may be distributed under the terms of the GNU Public License.
7 * This file contains directory-related functions independent of which
8 * scheme is being used to represent forks.
10 * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
12 * "XXX" in a comment is a note to myself to consider changing something.
14 * In function preconditions the term "valid" applied to a pointer to
15 * a structure means that the pointer is non-NULL and the structure it
16 * points to has all fields initialized to consistent values.
19 #include "hfs.h"
20 #include <linux/hfs_fs_sb.h>
21 #include <linux/hfs_fs_i.h>
22 #include <linux/hfs_fs.h>
24 /*================ File-local functions ================*/
27 * build_key()
29 * Build a key for a file by the given name in the given directory.
30 * If the name matches one of the reserved names returns 1 otherwise 0.
32 static int build_key(struct hfs_cat_key *key, struct inode *dir,
33 const char *name, int len)
35 struct hfs_name cname;
36 const struct hfs_name *reserved;
38 /* mangle the name */
39 hfs_nameout(dir, &cname, name, len);
41 /* check against reserved names */
42 reserved = HFS_SB(dir->i_sb)->s_reserved1;
43 while (reserved->Len) {
44 if (hfs_streq(reserved->Name, reserved->Len,
45 cname.Name, cname.Len)) {
46 return 1;
48 ++reserved;
51 /* check against the names reserved only in the root directory */
52 if (HFS_I(dir)->entry->cnid == htonl(HFS_ROOT_CNID)) {
53 reserved = HFS_SB(dir->i_sb)->s_reserved2;
54 while (reserved->Len) {
55 if (hfs_streq(reserved->Name, reserved->Len,
56 cname.Name, cname.Len)) {
57 return 1;
59 ++reserved;
63 /* build the key */
64 hfs_cat_build_key(HFS_I(dir)->entry->cnid, &cname, key);
66 return 0;
70 * update_dirs_plus()
72 * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and
73 * 'i_version' of the inodes associated with a directory that has
74 * had a file ('is_dir'==0) or directory ('is_dir'!=0) added to it.
76 static inline void update_dirs_plus(struct hfs_cat_entry *dir, int is_dir)
78 int i;
80 for (i = 0; i < 4; ++i) {
81 struct dentry *de = dir->sys_entry[i];
82 if (de) {
83 struct inode *tmp = de->d_inode;
84 if (S_ISDIR(tmp->i_mode)) {
85 if (is_dir &&
86 (i == HFS_ITYPE_TO_INT(HFS_ITYPE_NORM))) {
87 /* In "normal" directory only */
88 ++(tmp->i_nlink);
90 tmp->i_size += HFS_I(tmp)->dir_size;
91 tmp->i_version = ++event;
93 tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;
94 mark_inode_dirty(tmp);
100 * update_dirs_minus()
102 * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and
103 * 'i_version' of the inodes associated with a directory that has
104 * had a file ('is_dir'==0) or directory ('is_dir'!=0) removed.
106 static inline void update_dirs_minus(struct hfs_cat_entry *dir, int is_dir)
108 int i;
110 for (i = 0; i < 4; ++i) {
111 struct dentry *de = dir->sys_entry[i];
112 if (de) {
113 struct inode *tmp = de->d_inode;
114 if (S_ISDIR(tmp->i_mode)) {
115 if (is_dir &&
116 (i == HFS_ITYPE_TO_INT(HFS_ITYPE_NORM))) {
117 /* In "normal" directory only */
118 --(tmp->i_nlink);
120 tmp->i_size -= HFS_I(tmp)->dir_size;
121 tmp->i_version = ++event;
123 tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;
124 mark_inode_dirty(tmp);
130 * mark_inodes_deleted()
132 * Update inodes associated with a deleted entry to reflect its deletion.
133 * Well, we really just drop the dentry.
135 * XXX: we should be using delete_inode for some of this stuff.
137 static inline void mark_inodes_deleted(struct hfs_cat_entry *entry,
138 struct dentry *dentry)
140 struct dentry *de;
141 struct inode *tmp;
142 int i;
144 for (i = 0; i < 4; ++i) {
145 if ((de = entry->sys_entry[i]) && (dentry != de)) {
146 dget(de);
147 tmp = de->d_inode;
148 tmp->i_nlink = 0;
149 tmp->i_ctime = CURRENT_TIME;
150 mark_inode_dirty(tmp);
151 d_delete(de);
152 dput(de);
157 /*================ Global functions ================*/
160 * hfs_dir_read()
162 * This is the read() entry in the file_operations structure for HFS
163 * directories. It simply returns an error code, since reading is not
164 * supported.
166 hfs_rwret_t hfs_dir_read(struct file * filp, char *buf,
167 hfs_rwarg_t count, loff_t *ppos)
169 return -EISDIR;
173 * hfs_create()
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.
180 int hfs_create(struct inode * dir, struct dentry *dentry, int mode)
182 struct hfs_cat_entry *entry = HFS_I(dir)->entry;
183 struct hfs_cat_entry *new;
184 struct hfs_cat_key key;
185 struct inode *inode;
186 int error;
188 /* build the key, checking against reserved names */
189 if (build_key(&key, dir, dentry->d_name.name, dentry->d_name.len))
190 return -EEXIST;
192 if ((error = hfs_cat_create(entry, &key,
193 (mode & S_IWUSR) ? 0 : HFS_FIL_LOCK,
194 HFS_SB(dir->i_sb)->s_type,
195 HFS_SB(dir->i_sb)->s_creator, &new)))
196 return error;
198 /* create an inode for the new file. back out if we run
199 * into trouble. */
200 new->count++; /* hfs_iget() eats one */
201 if (!(inode = hfs_iget(new, HFS_I(dir)->file_type, dentry))) {
202 hfs_cat_delete(entry, new, 1);
203 hfs_cat_put(new);
204 return -EIO;
207 hfs_cat_put(new);
208 update_dirs_plus(entry, 0);
209 /* toss any relevant negative dentries */
210 if (HFS_I(dir)->d_drop_op)
211 HFS_I(dir)->d_drop_op(dentry, HFS_I(dir)->file_type);
212 mark_inode_dirty(inode);
213 d_instantiate(dentry, inode);
214 return 0;
218 * hfs_mkdir()
220 * This is the mkdir() entry in the inode_operations structure for
221 * regular HFS directories. The purpose is to create a new directory
222 * in a directory, given the inode for the parent directory and the
223 * name (and its length) of the new directory.
225 int hfs_mkdir(struct inode * parent, struct dentry *dentry, int mode)
227 struct hfs_cat_entry *entry = HFS_I(parent)->entry;
228 struct hfs_cat_entry *new;
229 struct hfs_cat_key key;
230 struct inode *inode;
231 int error;
233 /* build the key, checking against reserved names */
234 if (build_key(&key, parent, dentry->d_name.name,
235 dentry->d_name.len))
236 return -EEXIST;
238 /* try to create the directory */
239 if ((error = hfs_cat_mkdir(entry, &key, &new)))
240 return error;
242 /* back out if we run into trouble */
243 new->count++; /* hfs_iget eats one */
244 if (!(inode = hfs_iget(new, HFS_I(parent)->file_type, dentry))) {
245 hfs_cat_delete(entry, new, 1);
246 hfs_cat_put(new);
247 return -EIO;
250 hfs_cat_put(new);
251 update_dirs_plus(entry, 1);
252 mark_inode_dirty(inode);
253 d_instantiate(dentry, inode);
254 return 0;
258 * hfs_unlink()
260 * This is the unlink() entry in the inode_operations structure for
261 * regular HFS directories. The purpose is to delete an existing
262 * file, given the inode for the parent directory and the name
263 * (and its length) of the existing file.
265 int hfs_unlink(struct inode * dir, struct dentry *dentry)
267 struct hfs_cat_entry *entry = HFS_I(dir)->entry;
268 struct hfs_cat_entry *victim = NULL;
269 struct hfs_cat_key key;
270 int error;
272 if (build_key(&key, dir, dentry->d_name.name,
273 dentry->d_name.len))
274 return -EPERM;
276 if (!(victim = hfs_cat_get(entry->mdb, &key)))
277 return -ENOENT;
279 error = -EPERM;
280 if (victim->type != HFS_CDR_FIL)
281 goto hfs_unlink_put;
283 if (!(error = hfs_cat_delete(entry, victim, 1))) {
284 struct inode *inode = dentry->d_inode;
286 mark_inodes_deleted(victim, dentry);
287 inode->i_nlink--;
288 inode->i_ctime = CURRENT_TIME;
289 mark_inode_dirty(inode);
290 d_delete(dentry);
291 update_dirs_minus(entry, 0);
294 hfs_unlink_put:
295 hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */
296 return error;
300 * hfs_rmdir()
302 * This is the rmdir() entry in the inode_operations structure for
303 * regular HFS directories. The purpose is to delete an existing
304 * directory, given the inode for the parent directory and the name
305 * (and its length) of the existing directory.
307 int hfs_rmdir(struct inode * parent, struct dentry *dentry)
309 struct hfs_cat_entry *entry = HFS_I(parent)->entry;
310 struct hfs_cat_entry *victim = NULL;
311 struct inode *inode = dentry->d_inode;
312 struct hfs_cat_key key;
313 int error;
315 if (build_key(&key, parent, dentry->d_name.name,
316 dentry->d_name.len))
317 return -EPERM;
319 if (!(victim = hfs_cat_get(entry->mdb, &key)))
320 return -ENOENT;
322 error = -ENOTDIR;
323 if (victim->type != HFS_CDR_DIR)
324 goto hfs_rmdir_put;
326 error = -EBUSY;
327 if (!list_empty(&dentry->d_hash))
328 goto hfs_rmdir_put;
330 if (/* we only have to worry about 2 and 3 for mount points */
331 (victim->sys_entry[2] &&
332 (victim->sys_entry[2]->d_mounts !=
333 victim->sys_entry[2]->d_covers)) ||
334 (victim->sys_entry[3] &&
335 (victim->sys_entry[3]->d_mounts !=
336 victim->sys_entry[3]->d_covers))
338 goto hfs_rmdir_put;
341 if ((error = hfs_cat_delete(entry, victim, 1)))
342 goto hfs_rmdir_put;
344 mark_inodes_deleted(victim, dentry);
345 inode->i_nlink = 0;
346 inode->i_ctime = CURRENT_TIME;
347 mark_inode_dirty(inode);
348 d_delete(dentry);
349 update_dirs_minus(entry, 1);
351 hfs_rmdir_put:
352 hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */
353 return error;
357 * hfs_rename()
359 * This is the rename() entry in the inode_operations structure for
360 * regular HFS directories. The purpose is to rename an existing
361 * file or directory, given the inode for the current directory and
362 * the name (and its length) of the existing file/directory and the
363 * inode for the new directory and the name (and its length) of the
364 * new file/directory.
365 * XXX: how do you handle must_be dir?
367 int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
368 struct inode *new_dir, struct dentry *new_dentry)
370 struct hfs_cat_entry *old_parent = HFS_I(old_dir)->entry;
371 struct hfs_cat_entry *new_parent = HFS_I(new_dir)->entry;
372 struct hfs_cat_entry *victim = NULL;
373 struct hfs_cat_entry *deleted;
374 struct hfs_cat_key key;
375 int error;
377 if (build_key(&key, old_dir, old_dentry->d_name.name,
378 old_dentry->d_name.len) ||
379 (HFS_ITYPE(old_dir->i_ino) != HFS_ITYPE(new_dir->i_ino)))
380 return -EPERM;
382 if (!(victim = hfs_cat_get(old_parent->mdb, &key)))
383 return -ENOENT;
385 error = -EPERM;
386 if (build_key(&key, new_dir, new_dentry->d_name.name,
387 new_dentry->d_name.len))
388 goto hfs_rename_put;
390 if (!(error = hfs_cat_move(old_parent, new_parent,
391 victim, &key, &deleted))) {
392 int is_dir = (victim->type == HFS_CDR_DIR);
394 /* drop the old dentries */
395 mark_inodes_deleted(victim, old_dentry);
396 update_dirs_minus(old_parent, is_dir);
397 if (deleted) {
398 mark_inodes_deleted(deleted, new_dentry);
399 hfs_cat_put(deleted);
400 } else {
401 /* no existing inodes. just drop negative dentries */
402 if (HFS_I(new_dir)->d_drop_op)
403 HFS_I(new_dir)->d_drop_op(new_dentry,
404 HFS_I(new_dir)->file_type);
405 update_dirs_plus(new_parent, is_dir);
410 hfs_rename_put:
411 hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */
412 return error;