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 struct file_operations hfs_nat_dir_operations
= {
66 read
: generic_read_dir
,
71 struct inode_operations hfs_nat_ndir_inode_operations
= {
78 setattr
: hfs_notify_change
,
81 struct inode_operations hfs_nat_hdir_inode_operations
= {
84 unlink
: nat_hdr_unlink
,
85 rename
: nat_hdr_rename
,
86 setattr
: hfs_notify_change
,
89 /*================ File-local functions ================*/
94 * This is the lookup() entry in the inode_operations structure for
95 * HFS directories in the Netatalk scheme. The purpose is to generate
96 * the inode corresponding to an entry in a directory, given the inode
97 * for the directory and the name (and its length) of the entry.
99 static struct dentry
*nat_lookup(struct inode
* dir
, struct dentry
*dentry
)
102 struct hfs_name cname
;
103 struct hfs_cat_entry
*entry
;
104 struct hfs_cat_key key
;
105 struct inode
*inode
= NULL
;
107 dentry
->d_op
= &hfs_dentry_operations
;
108 entry
= HFS_I(dir
)->entry
;
109 dtype
= HFS_ITYPE(dir
->i_ino
);
111 /* Perform name-mangling */
112 hfs_nameout(dir
, &cname
, dentry
->d_name
.name
, dentry
->d_name
.len
);
114 /* no need to check for "." or ".." */
116 /* Check for ".AppleDouble" if in a normal directory,
117 and for ".Parent" in ".AppleDouble". */
118 if (dtype
==HFS_NAT_NDIR
) {
119 /* Check for ".AppleDouble" */
120 if (hfs_streq(cname
.Name
, cname
.Len
,
121 DOT_APPLEDOUBLE
->Name
, DOT_APPLEDOUBLE_LEN
)) {
122 ++entry
->count
; /* __hfs_iget() eats one */
123 inode
= hfs_iget(entry
, HFS_NAT_HDIR
, dentry
);
126 } else if (dtype
==HFS_NAT_HDIR
) {
127 if (hfs_streq(cname
.Name
, cname
.Len
,
128 DOT_PARENT
->Name
, DOT_PARENT_LEN
)) {
129 ++entry
->count
; /* __hfs_iget() eats one */
130 inode
= hfs_iget(entry
, HFS_NAT_HDR
, dentry
);
134 if ((entry
->cnid
== htonl(HFS_ROOT_CNID
)) &&
135 hfs_streq(cname
.Name
, cname
.Len
,
136 ROOTINFO
->Name
, ROOTINFO_LEN
)) {
137 ++entry
->count
; /* __hfs_iget() eats one */
138 inode
= hfs_iget(entry
, HFS_NAT_HDR
, dentry
);
143 /* Do an hfs_iget() on the mangled name. */
144 hfs_cat_build_key(entry
->cnid
, &cname
, &key
);
145 inode
= hfs_iget(hfs_cat_get(entry
->mdb
, &key
),
146 HFS_I(dir
)->file_type
, dentry
);
148 /* Don't return a header file for a directory other than .Parent */
149 if (inode
&& (dtype
== HFS_NAT_HDIR
) &&
150 (HFS_I(inode
)->entry
!= entry
) &&
151 (HFS_I(inode
)->entry
->type
== HFS_CDR_DIR
)) {
152 iput(inode
); /* this does an hfs_cat_put */
157 d_add(dentry
, inode
);
164 * This is the readdir() entry in the file_operations structure for
165 * HFS directories in the netatalk scheme. The purpose is to
166 * enumerate the entries in a directory, given the inode of the
167 * directory and a struct file which indicates the location in the
168 * directory. The struct file is updated so that the next call with
169 * the same dir and filp will produce the next directory entry. The
170 * entries are returned in dirent, which is "filled-in" by calling
171 * filldir(). This allows the same readdir() function be used for
172 * different dirent formats. We try to read in as many entries as we
173 * can before filldir() refuses to take any more.
175 * Note that the Netatalk format doesn't have the problem with
176 * metadata for covered directories that exists in the other formats,
177 * since the metadata is contained within the directory.
179 static int nat_readdir(struct file
* filp
,
180 void * dirent
, filldir_t filldir
)
184 struct hfs_brec brec
;
185 struct hfs_cat_entry
*entry
;
186 struct inode
*dir
= filp
->f_dentry
->d_inode
;
188 entry
= HFS_I(dir
)->entry
;
189 type
= HFS_ITYPE(dir
->i_ino
);
190 skip_dirs
= (type
== HFS_NAT_HDIR
);
192 if (filp
->f_pos
== 0) {
193 /* Entry 0 is for "." */
194 if (filldir(dirent
, DOT
->Name
, DOT_LEN
, 0, dir
->i_ino
,
201 if (filp
->f_pos
== 1) {
202 /* Entry 1 is for ".." */
205 if (type
== HFS_NAT_NDIR
) {
206 cnid
= hfs_get_nl(entry
->key
.ParID
);
211 if (filldir(dirent
, DOT_DOT
->Name
,
212 DOT_DOT_LEN
, 1, ntohl(cnid
), DT_DIR
)) {
218 if (filp
->f_pos
< (dir
->i_size
- 2)) {
222 if (hfs_cat_open(entry
, &brec
) ||
223 hfs_cat_next(entry
, &brec
, filp
->f_pos
- 2, &cnid
, &type
)) {
226 while (filp
->f_pos
< (dir
->i_size
- 2)) {
227 if (hfs_cat_next(entry
, &brec
, 1, &cnid
, &type
)) {
230 if (!skip_dirs
|| (type
!= HFS_CDR_DIR
)) {
233 unsigned char tmp_name
[HFS_NAMEMAX
];
235 ino
= ntohl(cnid
) | HFS_I(dir
)->file_type
;
236 len
= hfs_namein(dir
, tmp_name
,
237 &((struct hfs_cat_key
*)brec
.key
)->CName
);
238 if (filldir(dirent
, tmp_name
, len
,
239 filp
->f_pos
, ino
, DT_UNKNOWN
)) {
240 hfs_cat_close(entry
, &brec
);
246 hfs_cat_close(entry
, &brec
);
249 if (filp
->f_pos
== (dir
->i_size
- 2)) {
250 if (type
== HFS_NAT_NDIR
) {
251 /* In normal dirs entry 2 is for ".AppleDouble" */
252 if (filldir(dirent
, DOT_APPLEDOUBLE
->Name
,
253 DOT_APPLEDOUBLE_LEN
, filp
->f_pos
,
254 ntohl(entry
->cnid
) | HFS_NAT_HDIR
,
258 } else if (type
== HFS_NAT_HDIR
) {
259 /* In .AppleDouble entry 2 is for ".Parent" */
260 if (filldir(dirent
, DOT_PARENT
->Name
,
261 DOT_PARENT_LEN
, filp
->f_pos
,
262 ntohl(entry
->cnid
) | HFS_NAT_HDR
,
270 if (filp
->f_pos
== (dir
->i_size
- 1)) {
271 /* handle ROOT/.AppleDouble/RootInfo as the last entry. */
272 if ((entry
->cnid
== htonl(HFS_ROOT_CNID
)) &&
273 (type
== HFS_NAT_HDIR
)) {
274 if (filldir(dirent
, ROOTINFO
->Name
,
275 ROOTINFO_LEN
, filp
->f_pos
,
276 ntohl(entry
->cnid
) | HFS_NAT_HDR
,
287 /* due to the dcache caching negative dentries for non-existent files,
288 * we need to drop those entries when a file silently gets created.
289 * as far as i can tell, the calls that need to do this are the file
290 * related calls (create, rename, and mknod). the directory calls
291 * should be immune. the relevant calls in dir.c call drop_dentry
292 * upon successful completion. */
293 void hfs_nat_drop_dentry(struct dentry
*dentry
, const ino_t type
)
298 case HFS_NAT_HDR
: /* given .AppleDouble/name */
300 de
= hfs_lookup_dentry(dentry
->d_parent
->d_parent
,
301 dentry
->d_name
.name
, dentry
->d_name
.len
);
309 case HFS_NAT_DATA
: /* given name */
310 /* look for .AppleDouble/name */
311 hfs_drop_special(dentry
->d_parent
, DOT_APPLEDOUBLE
, dentry
);
320 * This is the rmdir() entry in the inode_operations structure for
321 * Netatalk directories. The purpose is to delete an existing
322 * directory, given the inode for the parent directory and the name
323 * (and its length) of the existing directory.
325 * We handle .AppleDouble and call hfs_rmdir() for all other cases.
327 static int nat_rmdir(struct inode
*parent
, struct dentry
*dentry
)
329 struct hfs_cat_entry
*entry
= HFS_I(parent
)->entry
;
330 struct hfs_name cname
;
333 hfs_nameout(parent
, &cname
, dentry
->d_name
.name
, dentry
->d_name
.len
);
334 if (hfs_streq(cname
.Name
, cname
.Len
,
335 DOT_APPLEDOUBLE
->Name
, DOT_APPLEDOUBLE_LEN
)) {
336 if (!HFS_SB(parent
->i_sb
)->s_afpd
) {
337 /* Not in AFPD compatibility mode */
339 } else if (entry
->u
.dir
.files
|| entry
->u
.dir
.dirs
) {
340 /* AFPD compatible, but the directory is not empty */
343 /* AFPD compatible, so pretend to succeed */
347 error
= hfs_rmdir(parent
, dentry
);
355 * This is the unlink() entry in the inode_operations structure for
356 * Netatalk .AppleDouble directories. The purpose is to delete an
357 * existing file, given the inode for the parent directory and the name
358 * (and its length) of the existing file.
360 * WE DON'T ACTUALLY DELETE HEADER THE FILE.
361 * In non-afpd-compatible mode:
363 * In afpd-compatible mode:
364 * We return success if the file exists or is .Parent.
365 * Otherwise we return -ENOENT.
367 static int nat_hdr_unlink(struct inode
*dir
, struct dentry
*dentry
)
369 struct hfs_cat_entry
*entry
= HFS_I(dir
)->entry
;
372 if (!HFS_SB(dir
->i_sb
)->s_afpd
) {
373 /* Not in AFPD compatibility mode */
376 struct hfs_name cname
;
378 hfs_nameout(dir
, &cname
, dentry
->d_name
.name
,
380 if (!hfs_streq(cname
.Name
, cname
.Len
,
381 DOT_PARENT
->Name
, DOT_PARENT_LEN
)) {
382 struct hfs_cat_entry
*victim
;
383 struct hfs_cat_key key
;
385 hfs_cat_build_key(entry
->cnid
, &cname
, &key
);
386 victim
= hfs_cat_get(entry
->mdb
, &key
);
389 /* pretend to succeed */
402 * This is the rename() entry in the inode_operations structure for
403 * Netatalk header directories. The purpose is to rename an existing
404 * file given the inode for the current directory and the name
405 * (and its length) of the existing file and the inode for the new
406 * directory and the name (and its length) of the new file/directory.
408 * WE NEVER MOVE ANYTHING.
409 * In non-afpd-compatible mode:
411 * In afpd-compatible mode:
412 * If the source header doesn't exist, we return -ENOENT.
413 * If the destination is not a header directory we return -EPERM.
414 * We return success if the destination is also a header directory
415 * and the header exists or is ".Parent".
417 static int nat_hdr_rename(struct inode
*old_dir
, struct dentry
*old_dentry
,
418 struct inode
*new_dir
, struct dentry
*new_dentry
)
420 struct hfs_cat_entry
*entry
= HFS_I(old_dir
)->entry
;
423 if (!HFS_SB(old_dir
->i_sb
)->s_afpd
) {
424 /* Not in AFPD compatibility mode */
427 struct hfs_name cname
;
429 hfs_nameout(old_dir
, &cname
, old_dentry
->d_name
.name
,
430 old_dentry
->d_name
.len
);
431 if (!hfs_streq(cname
.Name
, cname
.Len
,
432 DOT_PARENT
->Name
, DOT_PARENT_LEN
)) {
433 struct hfs_cat_entry
*victim
;
434 struct hfs_cat_key key
;
436 hfs_cat_build_key(entry
->cnid
, &cname
, &key
);
437 victim
= hfs_cat_get(entry
->mdb
, &key
);
440 /* pretend to succeed */
447 if (!error
&& (HFS_ITYPE(new_dir
->i_ino
) != HFS_NAT_HDIR
)) {