2 * linux/fs/hfs/dir_dbl.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 the inode_operations and file_operations
8 * structures for HFS directories.
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.
20 #include <linux/hfs_fs_sb.h>
21 #include <linux/hfs_fs_i.h>
22 #include <linux/hfs_fs.h>
24 /*================ Forward declarations ================*/
26 static struct dentry
*dbl_lookup(struct inode
*, struct dentry
*);
27 static int dbl_readdir(struct file
*, void *, filldir_t
);
28 static int dbl_create(struct inode
*, struct dentry
*, int);
29 static int dbl_mkdir(struct inode
*, struct dentry
*, int);
30 static int dbl_unlink(struct inode
*, struct dentry
*);
31 static int dbl_rmdir(struct inode
*, struct dentry
*);
32 static int dbl_rename(struct inode
*, struct dentry
*,
33 struct inode
*, struct dentry
*);
35 /*================ Global variables ================*/
39 #define ROOTINFO_LEN 8
40 #define PCNT_ROOTINFO_LEN 9
42 const struct hfs_name hfs_dbl_reserved1
[] = {
48 const struct hfs_name hfs_dbl_reserved2
[] = {
49 {ROOTINFO_LEN
, "RootInfo"},
50 {PCNT_ROOTINFO_LEN
, "%RootInfo"},
54 #define DOT (&hfs_dbl_reserved1[0])
55 #define DOT_DOT (&hfs_dbl_reserved1[1])
56 #define ROOTINFO (&hfs_dbl_reserved2[0])
57 #define PCNT_ROOTINFO (&hfs_dbl_reserved2[1])
59 static struct file_operations hfs_dbl_dir_operations
= {
60 NULL
, /* lseek - default */
61 hfs_dir_read
, /* read - invalid */
62 NULL
, /* write - bad */
63 dbl_readdir
, /* readdir */
64 NULL
, /* select - default */
65 NULL
, /* ioctl - default */
66 NULL
, /* mmap - none */
67 NULL
, /* no special open code */
69 NULL
, /* no special release code */
70 file_fsync
, /* fsync - default */
71 NULL
, /* fasync - default */
72 NULL
, /* check_media_change - none */
73 NULL
/* revalidate - none */
76 struct inode_operations hfs_dbl_dir_inode_operations
= {
77 &hfs_dbl_dir_operations
,/* default directory file-ops */
78 dbl_create
, /* create */
79 dbl_lookup
, /* lookup */
81 dbl_unlink
, /* unlink */
83 dbl_mkdir
, /* mkdir */
84 dbl_rmdir
, /* rmdir */
86 dbl_rename
, /* rename */
88 NULL
, /* follow_link */
93 NULL
, /* permission */
98 /*================ File-local functions ================*/
103 static int is_hdr(struct inode
*dir
, const char *name
, int len
)
107 if (name
[0] == '%') {
108 struct hfs_cat_entry
*entry
= HFS_I(dir
)->entry
;
109 struct hfs_cat_entry
*victim
;
110 struct hfs_name cname
;
111 struct hfs_cat_key key
;
113 hfs_nameout(dir
, &cname
, name
+1, len
-1);
114 hfs_cat_build_key(entry
->cnid
, &cname
, &key
);
115 if ((victim
= hfs_cat_get(entry
->mdb
, &key
))) {
126 * This is the lookup() entry in the inode_operations structure for
127 * HFS directories in the AppleDouble scheme. The purpose is to
128 * generate the inode corresponding to an entry in a directory, given
129 * the inode for the directory and the name (and its length) of the
132 static struct dentry
*dbl_lookup(struct inode
* dir
, struct dentry
*dentry
)
134 struct hfs_name cname
;
135 struct hfs_cat_entry
*entry
;
136 struct hfs_cat_key key
;
137 struct inode
*inode
= NULL
;
139 dentry
->d_op
= &hfs_dentry_operations
;
140 entry
= HFS_I(dir
)->entry
;
142 /* Perform name-mangling */
143 hfs_nameout(dir
, &cname
, dentry
->d_name
.name
, dentry
->d_name
.len
);
145 /* no need to check for "." or ".." */
147 /* Check for "%RootInfo" if in the root directory. */
148 if ((entry
->cnid
== htonl(HFS_ROOT_CNID
)) &&
149 hfs_streq(cname
.Name
, cname
.Len
,
150 PCNT_ROOTINFO
->Name
, PCNT_ROOTINFO_LEN
)) {
151 ++entry
->count
; /* __hfs_iget() eats one */
152 inode
= hfs_iget(entry
, HFS_DBL_HDR
, dentry
);
156 /* Do an hfs_iget() on the mangled name. */
157 hfs_cat_build_key(entry
->cnid
, &cname
, &key
);
158 inode
= hfs_iget(hfs_cat_get(entry
->mdb
, &key
), HFS_DBL_NORM
, dentry
);
160 /* Try as a header if not found and first character is '%' */
161 if (!inode
&& (dentry
->d_name
.name
[0] == '%')) {
162 hfs_nameout(dir
, &cname
, dentry
->d_name
.name
+1,
163 dentry
->d_name
.len
-1);
164 hfs_cat_build_key(entry
->cnid
, &cname
, &key
);
165 inode
= hfs_iget(hfs_cat_get(entry
->mdb
, &key
),
166 HFS_DBL_HDR
, dentry
);
170 d_add(dentry
, inode
);
177 * This is the readdir() entry in the file_operations structure for
178 * HFS directories in the AppleDouble scheme. The purpose is to
179 * enumerate the entries in a directory, given the inode of the
180 * directory and a (struct file *), the 'f_pos' field of which
181 * indicates the location in the directory. The (struct file *) is
182 * updated so that the next call with the same 'dir' and 'filp'
183 * arguments will produce the next directory entry. The entries are
184 * returned in 'dirent', which is "filled-in" by calling filldir().
185 * This allows the same readdir() function be used for different
186 * formats. We try to read in as many entries as we can before
187 * filldir() refuses to take any more.
189 * XXX: In the future it may be a good idea to consider not generating
190 * metadata files for covered directories since the data doesn't
191 * correspond to the mounted directory. However this requires an
192 * iget() for every directory which could be considered an excessive
193 * amount of overhead. Since the inode for a mount point is always
194 * in-core this is another argument for a call to get an inode if it
195 * is in-core or NULL if it is not.
197 static int dbl_readdir(struct file
* filp
,
198 void * dirent
, filldir_t filldir
)
200 struct hfs_brec brec
;
201 struct hfs_cat_entry
*entry
;
202 struct inode
*dir
= filp
->f_dentry
->d_inode
;
204 if (!dir
|| !dir
->i_sb
|| !S_ISDIR(dir
->i_mode
)) {
208 entry
= HFS_I(dir
)->entry
;
210 if (filp
->f_pos
== 0) {
211 /* Entry 0 is for "." */
212 if (filldir(dirent
, DOT
->Name
, DOT_LEN
, 0, dir
->i_ino
)) {
218 if (filp
->f_pos
== 1) {
219 /* Entry 1 is for ".." */
220 if (filldir(dirent
, DOT_DOT
->Name
, DOT_DOT_LEN
, 1,
221 hfs_get_hl(entry
->key
.ParID
))) {
227 if (filp
->f_pos
< (dir
->i_size
- 1)) {
231 if (hfs_cat_open(entry
, &brec
) ||
232 hfs_cat_next(entry
, &brec
, (filp
->f_pos
- 1) >> 1,
237 while (filp
->f_pos
< (dir
->i_size
- 1)) {
238 unsigned char tmp_name
[HFS_NAMEMAX
+ 1];
240 int is_hdr
= (filp
->f_pos
& 1);
244 ino
= ntohl(cnid
) | HFS_DBL_HDR
;
246 len
= 1 + hfs_namein(dir
, tmp_name
+ 1,
247 &((struct hfs_cat_key
*)brec
.key
)->CName
);
249 if (hfs_cat_next(entry
, &brec
, 1,
254 len
= hfs_namein(dir
, tmp_name
,
255 &((struct hfs_cat_key
*)brec
.key
)->CName
);
258 if (filldir(dirent
, tmp_name
, len
, filp
->f_pos
, ino
)) {
259 hfs_cat_close(entry
, &brec
);
264 hfs_cat_close(entry
, &brec
);
267 if (filp
->f_pos
== (dir
->i_size
- 1)) {
268 if (entry
->cnid
== htonl(HFS_ROOT_CNID
)) {
269 /* In root dir last entry is for "%RootInfo" */
270 if (filldir(dirent
, PCNT_ROOTINFO
->Name
,
271 PCNT_ROOTINFO_LEN
, filp
->f_pos
,
272 ntohl(entry
->cnid
) | HFS_DBL_HDR
)) {
285 * This is the create() entry in the inode_operations structure for
286 * AppleDouble directories. The purpose is to create a new file in
287 * a directory and return a corresponding inode, given the inode for
288 * the directory and the name (and its length) of the new file.
290 static int dbl_create(struct inode
* dir
, struct dentry
*dentry
,
295 if (is_hdr(dir
, dentry
->d_name
.name
, dentry
->d_name
.len
)) {
298 error
= hfs_create(dir
, dentry
, mode
);
306 * This is the mkdir() entry in the inode_operations structure for
307 * AppleDouble directories. The purpose is to create a new directory
308 * in a directory, given the inode for the parent directory and the
309 * name (and its length) of the new directory.
311 static int dbl_mkdir(struct inode
* parent
, struct dentry
*dentry
,
316 if (is_hdr(parent
, dentry
->d_name
.name
, dentry
->d_name
.len
)) {
319 error
= hfs_mkdir(parent
, dentry
, mode
);
327 * This is the unlink() entry in the inode_operations structure for
328 * AppleDouble directories. The purpose is to delete an existing
329 * file, given the inode for the parent directory and the name
330 * (and its length) of the existing file.
332 static int dbl_unlink(struct inode
* dir
, struct dentry
*dentry
)
336 error
= hfs_unlink(dir
, dentry
);
337 if ((error
== -ENOENT
) && is_hdr(dir
, dentry
->d_name
.name
,
338 dentry
->d_name
.len
)) {
347 * This is the rmdir() entry in the inode_operations structure for
348 * AppleDouble directories. The purpose is to delete an existing
349 * directory, given the inode for the parent directory and the name
350 * (and its length) of the existing directory.
352 static int dbl_rmdir(struct inode
* parent
, struct dentry
*dentry
)
356 error
= hfs_rmdir(parent
, dentry
);
357 if ((error
== -ENOENT
) && is_hdr(parent
, dentry
->d_name
.name
,
358 dentry
->d_name
.len
)) {
367 * This is the rename() entry in the inode_operations structure for
368 * AppleDouble directories. The purpose is to rename an existing
369 * file or directory, given the inode for the current directory and
370 * the name (and its length) of the existing file/directory and the
371 * inode for the new directory and the name (and its length) of the
372 * new file/directory.
374 * XXX: how do we handle must_be_dir?
376 static int dbl_rename(struct inode
*old_dir
, struct dentry
*old_dentry
,
377 struct inode
*new_dir
, struct dentry
*new_dentry
)
381 if (is_hdr(new_dir
, new_dentry
->d_name
.name
,
382 new_dentry
->d_name
.len
)) {
385 error
= hfs_rename(old_dir
, old_dentry
,
386 new_dir
, new_dentry
);
387 if ((error
== -ENOENT
) /*&& !must_be_dir*/ &&
388 is_hdr(old_dir
, old_dentry
->d_name
.name
,
389 old_dentry
->d_name
.len
)) {
397 /* due to the dcache caching negative dentries for non-existent files,
398 * we need to drop those entries when a file silently gets created.
399 * as far as i can tell, the calls that need to do this are the file
400 * related calls (create, rename, and mknod). the directory calls
401 * should be immune. the relevant calls in dir.c call drop_dentry
402 * upon successful completion. */
403 void hfs_dbl_drop_dentry(struct dentry
*dentry
, const ino_t type
)
405 unsigned char tmp_name
[HFS_NAMEMAX
+ 1];
406 struct dentry
*de
= NULL
;
410 /* given %name, look for name. i don't think this happens. */
411 de
= hfs_lookup_dentry(dentry
->d_parent
,
412 dentry
->d_name
.name
+ 1, dentry
->d_name
.len
- 1);
415 /* given name, look for %name */
417 strncpy(tmp_name
+ 1, dentry
->d_name
.name
, HFS_NAMELEN
- 1);
418 de
= hfs_lookup_dentry(dentry
->d_parent
,
419 tmp_name
, dentry
->d_name
.len
+ 1);