2 * linux/fs/hfs/dir_nat.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 * The source code distributions of Netatalk, versions 1.3.3b2 and
13 * 1.4b2, were used as a specification of the location and format of
14 * files used by Netatalk's afpd. No code from Netatalk appears in
15 * hfs_fs. hfs_fs is not a work ``derived'' from Netatalk in the
16 * sense of intellectual property law.
18 * "XXX" in a comment is a note to myself to consider changing something.
20 * In function preconditions the term "valid" applied to a pointer to
21 * a structure means that the pointer is non-NULL and the structure it
22 * points to has all fields initialized to consistent values.
26 #include <linux/hfs_fs_sb.h>
27 #include <linux/hfs_fs_i.h>
28 #include <linux/hfs_fs.h>
30 /*================ Forward declarations ================*/
32 static struct dentry
*nat_lookup(struct inode
*, struct dentry
*);
33 static int nat_readdir(struct file
*, void *, filldir_t
);
34 static int nat_rmdir(struct inode
*, struct dentry
*);
35 static int nat_hdr_unlink(struct inode
*, struct dentry
*);
36 static int nat_hdr_rename(struct inode
*, struct dentry
*,
37 struct inode
*, struct dentry
*);
39 /*================ Global variables ================*/
43 #define DOT_APPLEDOUBLE_LEN 12
44 #define DOT_PARENT_LEN 7
45 #define ROOTINFO_LEN 8
47 const struct hfs_name hfs_nat_reserved1
[] = {
50 {DOT_APPLEDOUBLE_LEN
, ".AppleDouble"},
51 {DOT_PARENT_LEN
, ".Parent"},
55 const struct hfs_name hfs_nat_reserved2
[] = {
56 {ROOTINFO_LEN
, "RootInfo"},
59 #define DOT (&hfs_nat_reserved1[0])
60 #define DOT_DOT (&hfs_nat_reserved1[1])
61 #define DOT_APPLEDOUBLE (&hfs_nat_reserved1[2])
62 #define DOT_PARENT (&hfs_nat_reserved1[3])
63 #define ROOTINFO (&hfs_nat_reserved2[0])
65 static struct file_operations hfs_nat_dir_operations
= {
66 NULL
, /* lseek - default */
67 hfs_dir_read
, /* read - invalid */
68 NULL
, /* write - bad */
69 nat_readdir
, /* readdir */
70 NULL
, /* select - default */
71 NULL
, /* ioctl - default */
72 NULL
, /* mmap - none */
73 NULL
, /* no special open code */
75 NULL
, /* no special release code */
76 file_fsync
, /* fsync - default */
77 NULL
, /* fasync - default */
78 NULL
, /* check_media_change - none */
79 NULL
, /* revalidate - none */
80 NULL
/* lock - none */
83 struct inode_operations hfs_nat_ndir_inode_operations
= {
84 &hfs_nat_dir_operations
,/* default directory file-ops */
85 hfs_create
, /* create */
86 nat_lookup
, /* lookup */
88 hfs_unlink
, /* unlink */
90 hfs_mkdir
, /* mkdir */
91 nat_rmdir
, /* rmdir */
93 hfs_rename
, /* rename */
95 NULL
, /* follow_link */
100 NULL
, /* permission */
102 NULL
, /* updatepage */
103 NULL
/* revalidate */
106 struct inode_operations hfs_nat_hdir_inode_operations
= {
107 &hfs_nat_dir_operations
,/* default directory file-ops */
108 hfs_create
, /* create */
109 nat_lookup
, /* lookup */
111 nat_hdr_unlink
, /* unlink */
116 nat_hdr_rename
, /* rename */
118 NULL
, /* follow_link */
120 NULL
, /* writepage */
123 NULL
, /* permission */
125 NULL
, /* updatepage */
126 NULL
/* revalidate */
129 /*================ File-local functions ================*/
134 * This is the lookup() entry in the inode_operations structure for
135 * HFS directories in the Netatalk scheme. The purpose is to generate
136 * the inode corresponding to an entry in a directory, given the inode
137 * for the directory and the name (and its length) of the entry.
139 static struct dentry
*nat_lookup(struct inode
* dir
, struct dentry
*dentry
)
142 struct hfs_name cname
;
143 struct hfs_cat_entry
*entry
;
144 struct hfs_cat_key key
;
145 struct inode
*inode
= NULL
;
147 dentry
->d_op
= &hfs_dentry_operations
;
148 entry
= HFS_I(dir
)->entry
;
149 dtype
= HFS_ITYPE(dir
->i_ino
);
151 /* Perform name-mangling */
152 hfs_nameout(dir
, &cname
, dentry
->d_name
.name
, dentry
->d_name
.len
);
154 /* no need to check for "." or ".." */
156 /* Check for ".AppleDouble" if in a normal directory,
157 and for ".Parent" in ".AppleDouble". */
158 if (dtype
==HFS_NAT_NDIR
) {
159 /* Check for ".AppleDouble" */
160 if (hfs_streq(cname
.Name
, cname
.Len
,
161 DOT_APPLEDOUBLE
->Name
, DOT_APPLEDOUBLE_LEN
)) {
162 ++entry
->count
; /* __hfs_iget() eats one */
163 inode
= hfs_iget(entry
, HFS_NAT_HDIR
, dentry
);
166 } else if (dtype
==HFS_NAT_HDIR
) {
167 if (hfs_streq(cname
.Name
, cname
.Len
,
168 DOT_PARENT
->Name
, DOT_PARENT_LEN
)) {
169 ++entry
->count
; /* __hfs_iget() eats one */
170 inode
= hfs_iget(entry
, HFS_NAT_HDR
, dentry
);
174 if ((entry
->cnid
== htonl(HFS_ROOT_CNID
)) &&
175 hfs_streq(cname
.Name
, cname
.Len
,
176 ROOTINFO
->Name
, ROOTINFO_LEN
)) {
177 ++entry
->count
; /* __hfs_iget() eats one */
178 inode
= hfs_iget(entry
, HFS_NAT_HDR
, dentry
);
183 /* Do an hfs_iget() on the mangled name. */
184 hfs_cat_build_key(entry
->cnid
, &cname
, &key
);
185 inode
= hfs_iget(hfs_cat_get(entry
->mdb
, &key
),
186 HFS_I(dir
)->file_type
, dentry
);
188 /* Don't return a header file for a directory other than .Parent */
189 if (inode
&& (dtype
== HFS_NAT_HDIR
) &&
190 (HFS_I(inode
)->entry
!= entry
) &&
191 (HFS_I(inode
)->entry
->type
== HFS_CDR_DIR
)) {
192 iput(inode
); /* this does an hfs_cat_put */
197 d_add(dentry
, inode
);
204 * This is the readdir() entry in the file_operations structure for
205 * HFS directories in the netatalk scheme. The purpose is to
206 * enumerate the entries in a directory, given the inode of the
207 * directory and a struct file which indicates the location in the
208 * directory. The struct file is updated so that the next call with
209 * the same dir and filp will produce the next directory entry. The
210 * entries are returned in dirent, which is "filled-in" by calling
211 * filldir(). This allows the same readdir() function be used for
212 * different dirent formats. We try to read in as many entries as we
213 * can before filldir() refuses to take any more.
215 * Note that the Netatalk format doesn't have the problem with
216 * metadata for covered directories that exists in the other formats,
217 * since the metadata is contained within the directory.
219 static int nat_readdir(struct file
* filp
,
220 void * dirent
, filldir_t filldir
)
224 struct hfs_brec brec
;
225 struct hfs_cat_entry
*entry
;
226 struct inode
*dir
= filp
->f_dentry
->d_inode
;
228 if (!dir
|| !dir
->i_sb
|| !S_ISDIR(dir
->i_mode
)) {
232 entry
= HFS_I(dir
)->entry
;
233 type
= HFS_ITYPE(dir
->i_ino
);
234 skip_dirs
= (type
== HFS_NAT_HDIR
);
236 if (filp
->f_pos
== 0) {
237 /* Entry 0 is for "." */
238 if (filldir(dirent
, DOT
->Name
, DOT_LEN
, 0, dir
->i_ino
)) {
244 if (filp
->f_pos
== 1) {
245 /* Entry 1 is for ".." */
248 if (type
== HFS_NAT_NDIR
) {
249 cnid
= hfs_get_nl(entry
->key
.ParID
);
254 if (filldir(dirent
, DOT_DOT
->Name
,
255 DOT_DOT_LEN
, 1, ntohl(cnid
))) {
261 if (filp
->f_pos
< (dir
->i_size
- 2)) {
265 if (hfs_cat_open(entry
, &brec
) ||
266 hfs_cat_next(entry
, &brec
, filp
->f_pos
- 2, &cnid
, &type
)) {
269 while (filp
->f_pos
< (dir
->i_size
- 2)) {
270 if (hfs_cat_next(entry
, &brec
, 1, &cnid
, &type
)) {
273 if (!skip_dirs
|| (type
!= HFS_CDR_DIR
)) {
276 unsigned char tmp_name
[HFS_NAMEMAX
];
278 ino
= ntohl(cnid
) | HFS_I(dir
)->file_type
;
279 len
= hfs_namein(dir
, tmp_name
,
280 &((struct hfs_cat_key
*)brec
.key
)->CName
);
281 if (filldir(dirent
, tmp_name
, len
,
283 hfs_cat_close(entry
, &brec
);
289 hfs_cat_close(entry
, &brec
);
292 if (filp
->f_pos
== (dir
->i_size
- 2)) {
293 if (type
== HFS_NAT_NDIR
) {
294 /* In normal dirs entry 2 is for ".AppleDouble" */
295 if (filldir(dirent
, DOT_APPLEDOUBLE
->Name
,
296 DOT_APPLEDOUBLE_LEN
, filp
->f_pos
,
297 ntohl(entry
->cnid
) | HFS_NAT_HDIR
)) {
300 } else if (type
== HFS_NAT_HDIR
) {
301 /* In .AppleDouble entry 2 is for ".Parent" */
302 if (filldir(dirent
, DOT_PARENT
->Name
,
303 DOT_PARENT_LEN
, filp
->f_pos
,
304 ntohl(entry
->cnid
) | HFS_NAT_HDR
)) {
311 if (filp
->f_pos
== (dir
->i_size
- 1)) {
312 /* handle ROOT/.AppleDouble/RootInfo as the last entry. */
313 if ((entry
->cnid
== htonl(HFS_ROOT_CNID
)) &&
314 (type
== HFS_NAT_HDIR
)) {
315 if (filldir(dirent
, ROOTINFO
->Name
,
316 ROOTINFO_LEN
, filp
->f_pos
,
317 ntohl(entry
->cnid
) | HFS_NAT_HDR
)) {
327 /* due to the dcache caching negative dentries for non-existent files,
328 * we need to drop those entries when a file silently gets created.
329 * as far as i can tell, the calls that need to do this are the file
330 * related calls (create, rename, and mknod). the directory calls
331 * should be immune. the relevant calls in dir.c call drop_dentry
332 * upon successful completion. */
333 void hfs_nat_drop_dentry(struct dentry
*dentry
, const ino_t type
)
338 case HFS_NAT_HDR
: /* given .AppleDouble/name */
340 de
= hfs_lookup_dentry(dentry
->d_parent
->d_parent
,
341 dentry
->d_name
.name
, dentry
->d_name
.len
);
349 case HFS_NAT_DATA
: /* given name */
350 /* look for .AppleDouble/name */
351 hfs_drop_special(dentry
->d_parent
, DOT_APPLEDOUBLE
, dentry
);
360 * This is the rmdir() entry in the inode_operations structure for
361 * Netatalk directories. The purpose is to delete an existing
362 * directory, given the inode for the parent directory and the name
363 * (and its length) of the existing directory.
365 * We handle .AppleDouble and call hfs_rmdir() for all other cases.
367 static int nat_rmdir(struct inode
*parent
, struct dentry
*dentry
)
369 struct hfs_cat_entry
*entry
= HFS_I(parent
)->entry
;
370 struct hfs_name cname
;
373 hfs_nameout(parent
, &cname
, dentry
->d_name
.name
, dentry
->d_name
.len
);
374 if (hfs_streq(cname
.Name
, cname
.Len
,
375 DOT_APPLEDOUBLE
->Name
, DOT_APPLEDOUBLE_LEN
)) {
376 if (!HFS_SB(parent
->i_sb
)->s_afpd
) {
377 /* Not in AFPD compatibility mode */
379 } else if (entry
->u
.dir
.files
|| entry
->u
.dir
.dirs
) {
380 /* AFPD compatible, but the directory is not empty */
383 /* AFPD compatible, so pretend to succeed */
387 error
= hfs_rmdir(parent
, dentry
);
395 * This is the unlink() entry in the inode_operations structure for
396 * Netatalk .AppleDouble directories. The purpose is to delete an
397 * existing file, given the inode for the parent directory and the name
398 * (and its length) of the existing file.
400 * WE DON'T ACTUALLY DELETE HEADER THE FILE.
401 * In non-afpd-compatible mode:
403 * In afpd-compatible mode:
404 * We return success if the file exists or is .Parent.
405 * Otherwise we return -ENOENT.
407 static int nat_hdr_unlink(struct inode
*dir
, struct dentry
*dentry
)
409 struct hfs_cat_entry
*entry
= HFS_I(dir
)->entry
;
412 if (!HFS_SB(dir
->i_sb
)->s_afpd
) {
413 /* Not in AFPD compatibility mode */
416 struct hfs_name cname
;
418 hfs_nameout(dir
, &cname
, dentry
->d_name
.name
,
420 if (!hfs_streq(cname
.Name
, cname
.Len
,
421 DOT_PARENT
->Name
, DOT_PARENT_LEN
)) {
422 struct hfs_cat_entry
*victim
;
423 struct hfs_cat_key key
;
425 hfs_cat_build_key(entry
->cnid
, &cname
, &key
);
426 victim
= hfs_cat_get(entry
->mdb
, &key
);
429 /* pretend to succeed */
442 * This is the rename() entry in the inode_operations structure for
443 * Netatalk header directories. The purpose is to rename an existing
444 * file given the inode for the current directory and the name
445 * (and its length) of the existing file and the inode for the new
446 * directory and the name (and its length) of the new file/directory.
448 * WE NEVER MOVE ANYTHING.
449 * In non-afpd-compatible mode:
451 * In afpd-compatible mode:
452 * If the source header doesn't exist, we return -ENOENT.
453 * If the destination is not a header directory we return -EPERM.
454 * We return success if the destination is also a header directory
455 * and the header exists or is ".Parent".
457 static int nat_hdr_rename(struct inode
*old_dir
, struct dentry
*old_dentry
,
458 struct inode
*new_dir
, struct dentry
*new_dentry
)
460 struct hfs_cat_entry
*entry
= HFS_I(old_dir
)->entry
;
463 if (!HFS_SB(old_dir
->i_sb
)->s_afpd
) {
464 /* Not in AFPD compatibility mode */
467 struct hfs_name cname
;
469 hfs_nameout(old_dir
, &cname
, old_dentry
->d_name
.name
,
470 old_dentry
->d_name
.len
);
471 if (!hfs_streq(cname
.Name
, cname
.Len
,
472 DOT_PARENT
->Name
, DOT_PARENT_LEN
)) {
473 struct hfs_cat_entry
*victim
;
474 struct hfs_cat_key key
;
476 hfs_cat_build_key(entry
->cnid
, &cname
, &key
);
477 victim
= hfs_cat_get(entry
->mdb
, &key
);
480 /* pretend to succeed */
487 if (!error
&& (HFS_ITYPE(new_dir
->i_ino
) != HFS_NAT_HDIR
)) {