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_mknod(struct inode
*, struct dentry
*, int, int);
31 static int dbl_unlink(struct inode
*, struct dentry
*);
32 static int dbl_rmdir(struct inode
*, struct dentry
*);
33 static int dbl_rename(struct inode
*, struct dentry
*,
34 struct inode
*, struct dentry
*);
36 /*================ Global variables ================*/
40 #define ROOTINFO_LEN 8
41 #define PCNT_ROOTINFO_LEN 9
43 const struct hfs_name hfs_dbl_reserved1
[] = {
49 const struct hfs_name hfs_dbl_reserved2
[] = {
50 {ROOTINFO_LEN
, "RootInfo"},
51 {PCNT_ROOTINFO_LEN
, "%RootInfo"},
55 #define DOT (&hfs_dbl_reserved1[0])
56 #define DOT_DOT (&hfs_dbl_reserved1[1])
57 #define ROOTINFO (&hfs_dbl_reserved2[0])
58 #define PCNT_ROOTINFO (&hfs_dbl_reserved2[1])
60 static struct file_operations hfs_dbl_dir_operations
= {
61 NULL
, /* lseek - default */
62 hfs_dir_read
, /* read - invalid */
63 NULL
, /* write - bad */
64 dbl_readdir
, /* readdir */
65 NULL
, /* select - default */
66 NULL
, /* ioctl - default */
67 NULL
, /* mmap - none */
68 NULL
, /* no special open code */
70 NULL
, /* no special release code */
71 file_fsync
, /* fsync - default */
72 NULL
, /* fasync - default */
73 NULL
, /* check_media_change - none */
74 NULL
/* revalidate - none */
77 struct inode_operations hfs_dbl_dir_inode_operations
= {
78 &hfs_dbl_dir_operations
,/* default directory file-ops */
79 dbl_create
, /* create */
80 dbl_lookup
, /* lookup */
82 dbl_unlink
, /* unlink */
84 dbl_mkdir
, /* mkdir */
85 dbl_rmdir
, /* rmdir */
86 dbl_mknod
, /* mknod */
87 dbl_rename
, /* rename */
89 NULL
, /* follow_link */
94 NULL
, /* permission */
99 /*================ File-local functions ================*/
104 static int is_hdr(struct inode
*dir
, const char *name
, int len
)
108 if (name
[0] == '%') {
109 struct hfs_cat_entry
*entry
= HFS_I(dir
)->entry
;
110 struct hfs_cat_entry
*victim
;
111 struct hfs_name cname
;
112 struct hfs_cat_key key
;
114 hfs_nameout(dir
, &cname
, name
+1, len
-1);
115 hfs_cat_build_key(entry
->cnid
, &cname
, &key
);
116 if ((victim
= hfs_cat_get(entry
->mdb
, &key
))) {
127 * This is the lookup() entry in the inode_operations structure for
128 * HFS directories in the AppleDouble scheme. The purpose is to
129 * generate the inode corresponding to an entry in a directory, given
130 * the inode for the directory and the name (and its length) of the
133 static struct dentry
*dbl_lookup(struct inode
* dir
, struct dentry
*dentry
)
135 struct hfs_name cname
;
136 struct hfs_cat_entry
*entry
;
137 struct hfs_cat_key key
;
138 struct inode
*inode
= NULL
;
140 dentry
->d_op
= &hfs_dentry_operations
;
141 entry
= HFS_I(dir
)->entry
;
143 /* Perform name-mangling */
144 hfs_nameout(dir
, &cname
, dentry
->d_name
.name
, dentry
->d_name
.len
);
146 /* no need to check for "." or ".." */
148 /* Check for "%RootInfo" if in the root directory. */
149 if ((entry
->cnid
== htonl(HFS_ROOT_CNID
)) &&
150 hfs_streq(cname
.Name
, cname
.Len
,
151 PCNT_ROOTINFO
->Name
, PCNT_ROOTINFO_LEN
)) {
152 ++entry
->count
; /* __hfs_iget() eats one */
153 inode
= hfs_iget(entry
, HFS_DBL_HDR
, dentry
);
157 /* Do an hfs_iget() on the mangled name. */
158 hfs_cat_build_key(entry
->cnid
, &cname
, &key
);
159 inode
= hfs_iget(hfs_cat_get(entry
->mdb
, &key
), HFS_DBL_NORM
, dentry
);
161 /* Try as a header if not found and first character is '%' */
162 if (!inode
&& (dentry
->d_name
.name
[0] == '%')) {
163 hfs_nameout(dir
, &cname
, dentry
->d_name
.name
+1,
164 dentry
->d_name
.len
-1);
165 hfs_cat_build_key(entry
->cnid
, &cname
, &key
);
166 inode
= hfs_iget(hfs_cat_get(entry
->mdb
, &key
),
167 HFS_DBL_HDR
, dentry
);
171 d_add(dentry
, inode
);
178 * This is the readdir() entry in the file_operations structure for
179 * HFS directories in the AppleDouble scheme. The purpose is to
180 * enumerate the entries in a directory, given the inode of the
181 * directory and a (struct file *), the 'f_pos' field of which
182 * indicates the location in the directory. The (struct file *) is
183 * updated so that the next call with the same 'dir' and 'filp'
184 * arguments will produce the next directory entry. The entries are
185 * returned in 'dirent', which is "filled-in" by calling filldir().
186 * This allows the same readdir() function be used for different
187 * formats. We try to read in as many entries as we can before
188 * filldir() refuses to take any more.
190 * XXX: In the future it may be a good idea to consider not generating
191 * metadata files for covered directories since the data doesn't
192 * correspond to the mounted directory. However this requires an
193 * iget() for every directory which could be considered an excessive
194 * amount of overhead. Since the inode for a mount point is always
195 * in-core this is another argument for a call to get an inode if it
196 * is in-core or NULL if it is not.
198 static int dbl_readdir(struct file
* filp
,
199 void * dirent
, filldir_t filldir
)
201 struct hfs_brec brec
;
202 struct hfs_cat_entry
*entry
;
203 struct inode
*dir
= filp
->f_dentry
->d_inode
;
205 if (!dir
|| !dir
->i_sb
|| !S_ISDIR(dir
->i_mode
)) {
209 entry
= HFS_I(dir
)->entry
;
211 if (filp
->f_pos
== 0) {
212 /* Entry 0 is for "." */
213 if (filldir(dirent
, DOT
->Name
, DOT_LEN
, 0, dir
->i_ino
)) {
219 if (filp
->f_pos
== 1) {
220 /* Entry 1 is for ".." */
221 if (filldir(dirent
, DOT_DOT
->Name
, DOT_DOT_LEN
, 1,
222 hfs_get_hl(entry
->key
.ParID
))) {
228 if (filp
->f_pos
< (dir
->i_size
- 1)) {
232 if (hfs_cat_open(entry
, &brec
) ||
233 hfs_cat_next(entry
, &brec
, (filp
->f_pos
- 1) >> 1,
238 while (filp
->f_pos
< (dir
->i_size
- 1)) {
239 unsigned char tmp_name
[HFS_NAMEMAX
+ 1];
241 int is_hdr
= (filp
->f_pos
& 1);
245 ino
= ntohl(cnid
) | HFS_DBL_HDR
;
247 len
= 1 + hfs_namein(dir
, tmp_name
+ 1,
248 &((struct hfs_cat_key
*)brec
.key
)->CName
);
250 if (hfs_cat_next(entry
, &brec
, 1,
255 len
= hfs_namein(dir
, tmp_name
,
256 &((struct hfs_cat_key
*)brec
.key
)->CName
);
259 if (filldir(dirent
, tmp_name
, len
, filp
->f_pos
, ino
)) {
260 hfs_cat_close(entry
, &brec
);
265 hfs_cat_close(entry
, &brec
);
268 if (filp
->f_pos
== (dir
->i_size
- 1)) {
269 if (entry
->cnid
== htonl(HFS_ROOT_CNID
)) {
270 /* In root dir last entry is for "%RootInfo" */
271 if (filldir(dirent
, PCNT_ROOTINFO
->Name
,
272 PCNT_ROOTINFO_LEN
, filp
->f_pos
,
273 ntohl(entry
->cnid
) | HFS_DBL_HDR
)) {
286 * This is the create() entry in the inode_operations structure for
287 * AppleDouble directories. The purpose is to create a new file in
288 * a directory and return a corresponding inode, given the inode for
289 * the directory and the name (and its length) of the new file.
291 static int dbl_create(struct inode
* dir
, struct dentry
*dentry
,
296 if (is_hdr(dir
, dentry
->d_name
.name
, dentry
->d_name
.len
)) {
299 error
= hfs_create(dir
, dentry
, mode
);
307 * This is the mkdir() entry in the inode_operations structure for
308 * AppleDouble directories. The purpose is to create a new directory
309 * in a directory, given the inode for the parent directory and the
310 * name (and its length) of the new directory.
312 static int dbl_mkdir(struct inode
* parent
, struct dentry
*dentry
,
317 if (is_hdr(parent
, dentry
->d_name
.name
, dentry
->d_name
.len
)) {
320 error
= hfs_mkdir(parent
, dentry
, mode
);
328 * This is the mknod() entry in the inode_operations structure for
329 * regular HFS directories. The purpose is to create a new entry
330 * in a directory, given the inode for the parent directory and the
331 * name (and its length) and the mode of the new entry (and the device
332 * number if the entry is to be a device special file).
334 static int dbl_mknod(struct inode
*dir
, struct dentry
*dentry
,
339 if (is_hdr(dir
, dentry
->d_name
.name
, dentry
->d_name
.len
)) {
342 error
= hfs_mknod(dir
, dentry
, mode
, rdev
);
350 * This is the unlink() entry in the inode_operations structure for
351 * AppleDouble directories. The purpose is to delete an existing
352 * file, given the inode for the parent directory and the name
353 * (and its length) of the existing file.
355 static int dbl_unlink(struct inode
* dir
, struct dentry
*dentry
)
359 error
= hfs_unlink(dir
, dentry
);
360 if ((error
== -ENOENT
) && is_hdr(dir
, dentry
->d_name
.name
,
361 dentry
->d_name
.len
)) {
370 * This is the rmdir() entry in the inode_operations structure for
371 * AppleDouble directories. The purpose is to delete an existing
372 * directory, given the inode for the parent directory and the name
373 * (and its length) of the existing directory.
375 static int dbl_rmdir(struct inode
* parent
, struct dentry
*dentry
)
379 error
= hfs_rmdir(parent
, dentry
);
380 if ((error
== -ENOENT
) && is_hdr(parent
, dentry
->d_name
.name
,
381 dentry
->d_name
.len
)) {
390 * This is the rename() entry in the inode_operations structure for
391 * AppleDouble directories. The purpose is to rename an existing
392 * file or directory, given the inode for the current directory and
393 * the name (and its length) of the existing file/directory and the
394 * inode for the new directory and the name (and its length) of the
395 * new file/directory.
397 * XXX: how do we handle must_be_dir?
399 static int dbl_rename(struct inode
*old_dir
, struct dentry
*old_dentry
,
400 struct inode
*new_dir
, struct dentry
*new_dentry
)
404 if (is_hdr(new_dir
, new_dentry
->d_name
.name
,
405 new_dentry
->d_name
.len
)) {
408 error
= hfs_rename(old_dir
, old_dentry
,
409 new_dir
, new_dentry
);
410 if ((error
== -ENOENT
) /*&& !must_be_dir*/ &&
411 is_hdr(old_dir
, old_dentry
->d_name
.name
,
412 old_dentry
->d_name
.len
)) {
420 /* due to the dcache caching negative dentries for non-existent files,
421 * we need to drop those entries when a file silently gets created.
422 * as far as i can tell, the calls that need to do this are the file
423 * related calls (create, rename, and mknod). the directory calls
424 * should be immune. the relevant calls in dir.c call drop_dentry
425 * upon successful completion. */
426 void hfs_dbl_drop_dentry(struct dentry
*dentry
, const ino_t type
)
428 unsigned char tmp_name
[HFS_NAMEMAX
+ 1];
429 struct dentry
*de
= NULL
;
433 /* given %name, look for name. i don't think this happens. */
434 de
= hfs_lookup_dentry(dentry
->d_parent
,
435 dentry
->d_name
.name
+ 1, dentry
->d_name
.len
- 1);
438 /* given name, look for %name */
440 strncpy(tmp_name
+ 1, dentry
->d_name
.name
, HFS_NAMELEN
- 1);
441 de
= hfs_lookup_dentry(dentry
->d_parent
,
442 tmp_name
, dentry
->d_name
.len
+ 1);