File: /usr/src/linux/fs/hfs/dir_cap.c

1     /*
2      * Copyright (C) 1995-1997  Paul H. Hargrove
3      * This file may be distributed under the terms of the GNU General Public License.
4      *
5      * This file contains the inode_operations and file_operations
6      * structures for HFS directories under the CAP scheme.
7      *
8      * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
9      *
10      * The source code distribution of the Columbia AppleTalk Package for
11      * UNIX, version 6.0, (CAP) was used as a specification of the
12      * location and format of files used by CAP's Aufs.  No code from CAP
13      * appears in hfs_fs.  hfs_fs is not a work ``derived'' from CAP in
14      * the sense of intellectual property law.
15      *
16      * "XXX" in a comment is a note to myself to consider changing something.
17      *
18      * In function preconditions the term "valid" applied to a pointer to
19      * a structure means that the pointer is non-NULL and the structure it
20      * points to has all fields initialized to consistent values.
21      */
22     
23     #include "hfs.h"
24     #include <linux/hfs_fs_sb.h>
25     #include <linux/hfs_fs_i.h>
26     #include <linux/hfs_fs.h>
27     
28     /*================ Forward declarations ================*/
29     
30     static struct dentry *cap_lookup(struct inode *, struct dentry *);
31     static int cap_readdir(struct file *, void *, filldir_t);
32     
33     /*================ Global variables ================*/
34     
35     #define DOT_LEN			1
36     #define DOT_DOT_LEN		2
37     #define DOT_RESOURCE_LEN	9
38     #define DOT_FINDERINFO_LEN	11
39     #define DOT_ROOTINFO_LEN	9
40     
41     const struct hfs_name hfs_cap_reserved1[] = {
42     	{DOT_LEN,		"."},
43     	{DOT_DOT_LEN,		".."},
44     	{DOT_RESOURCE_LEN,	".resource"},
45     	{DOT_FINDERINFO_LEN,	".finderinfo"},
46     	{0,			""},
47     };
48     
49     const struct hfs_name hfs_cap_reserved2[] = {
50     	{DOT_ROOTINFO_LEN,	".rootinfo"},
51     	{0,			""},
52     };
53     
54     #define DOT		(&hfs_cap_reserved1[0])
55     #define DOT_DOT		(&hfs_cap_reserved1[1])
56     #define DOT_RESOURCE	(&hfs_cap_reserved1[2])
57     #define DOT_FINDERINFO	(&hfs_cap_reserved1[3])
58     #define DOT_ROOTINFO	(&hfs_cap_reserved2[0])
59     
60     struct file_operations hfs_cap_dir_operations = {
61     	read:		generic_read_dir,
62     	readdir:	cap_readdir,
63     	fsync:		file_fsync,
64     };
65     
66     struct inode_operations hfs_cap_ndir_inode_operations = {
67     	create:		hfs_create,
68     	lookup:		cap_lookup,
69     	unlink:		hfs_unlink,
70     	mkdir:		hfs_mkdir,
71     	rmdir:		hfs_rmdir,
72     	rename:		hfs_rename,
73     	setattr:	hfs_notify_change,
74     };
75     
76     struct inode_operations hfs_cap_fdir_inode_operations = {
77     	lookup:		cap_lookup,
78     	setattr:	hfs_notify_change,
79     };
80     
81     struct inode_operations hfs_cap_rdir_inode_operations = {
82     	create:		hfs_create,
83     	lookup:		cap_lookup,
84     	setattr:	hfs_notify_change,
85     };
86     
87     /*================ File-local functions ================*/
88     
89     /*
90      * cap_lookup()
91      *
92      * This is the lookup() entry in the inode_operations structure for
93      * HFS directories in the CAP scheme.  The purpose is to generate the
94      * inode corresponding to an entry in a directory, given the inode for
95      * the directory and the name (and its length) of the entry.
96      */
97     static struct dentry *cap_lookup(struct inode * dir, struct dentry *dentry)
98     {
99     	ino_t dtype;
100     	struct hfs_name cname;
101     	struct hfs_cat_entry *entry;
102     	struct hfs_cat_key key;
103     	struct inode *inode = NULL;
104     
105     	dentry->d_op = &hfs_dentry_operations;
106     	entry = HFS_I(dir)->entry;
107     	dtype = HFS_ITYPE(dir->i_ino);
108     
109     	/* Perform name-mangling */
110     	hfs_nameout(dir, &cname, dentry->d_name.name, 
111     		    dentry->d_name.len);
112     
113     	/* no need to check for "."  or ".." */
114     
115     	/* Check for special directories if in a normal directory.
116     	   Note that cap_dupdir() does an iput(dir). */
117     	if (dtype==HFS_CAP_NDIR) {
118     		/* Check for ".resource", ".finderinfo" and ".rootinfo" */
119     		if (hfs_streq(cname.Name, cname.Len, 
120     			      DOT_RESOURCE->Name, DOT_RESOURCE_LEN)) {
121     			++entry->count; /* __hfs_iget() eats one */
122     			inode = hfs_iget(entry, HFS_CAP_RDIR, dentry);
123     			goto done;
124     		} else if (hfs_streq(cname.Name, cname.Len, 
125     				     DOT_FINDERINFO->Name, 
126     				     DOT_FINDERINFO_LEN)) {
127     			++entry->count; /* __hfs_iget() eats one */
128     			inode = hfs_iget(entry, HFS_CAP_FDIR, dentry);
129     			goto done;
130     		} else if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
131     			   hfs_streq(cname.Name, cname.Len, 
132     				     DOT_ROOTINFO->Name, DOT_ROOTINFO_LEN)) {
133     			++entry->count; /* __hfs_iget() eats one */
134     			inode = hfs_iget(entry, HFS_CAP_FNDR, dentry);
135     			goto done;
136     		}
137     	}
138     
139     	/* Do an hfs_iget() on the mangled name. */
140     	hfs_cat_build_key(entry->cnid, &cname, &key);
141     	inode = hfs_iget(hfs_cat_get(entry->mdb, &key),
142     			 HFS_I(dir)->file_type, dentry);
143     
144     	/* Don't return a resource fork for a directory */
145     	if (inode && (dtype == HFS_CAP_RDIR) && 
146     	    (HFS_I(inode)->entry->type == HFS_CDR_DIR)) {
147     	        iput(inode); /* this does an hfs_cat_put */
148     		inode = NULL;
149     	}
150     
151     done:
152     	d_add(dentry, inode);
153     	return NULL;
154     }
155     
156     /*
157      * cap_readdir()
158      *
159      * This is the readdir() entry in the file_operations structure for
160      * HFS directories in the CAP scheme.  The purpose is to enumerate the
161      * entries in a directory, given the inode of the directory and a
162      * (struct file *), the 'f_pos' field of which indicates the location
163      * in the directory.  The (struct file *) is updated so that the next
164      * call with the same 'dir' and 'filp' arguments will produce the next
165      * directory entry.  The entries are returned in 'dirent', which is
166      * "filled-in" by calling filldir().  This allows the same readdir()
167      * function be used for different dirent formats.  We try to read in
168      * as many entries as we can before filldir() refuses to take any more.
169      *
170      * XXX: In the future it may be a good idea to consider not generating
171      * metadata files for covered directories since the data doesn't
172      * correspond to the mounted directory.	 However this requires an
173      * iget() for every directory which could be considered an excessive
174      * amount of overhead.	Since the inode for a mount point is always
175      * in-core this is another argument for a call to get an inode if it
176      * is in-core or NULL if it is not.
177      */
178     static int cap_readdir(struct file * filp,
179     		       void * dirent, filldir_t filldir)
180     {
181     	ino_t type;
182     	int skip_dirs;
183     	struct hfs_brec brec;
184             struct hfs_cat_entry *entry;
185     	struct inode *dir = filp->f_dentry->d_inode;
186     
187     	entry = HFS_I(dir)->entry;
188     	type = HFS_ITYPE(dir->i_ino);
189     	skip_dirs = (type == HFS_CAP_RDIR);
190     
191     	if (filp->f_pos == 0) {
192     		/* Entry 0 is for "." */
193     		if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino, DT_DIR)) {
194     			return 0;
195     		}
196     		filp->f_pos = 1;
197     	}
198     
199     	if (filp->f_pos == 1) {
200     		/* Entry 1 is for ".." */
201     		hfs_u32 cnid;
202     
203     		if (type == HFS_CAP_NDIR) {
204     			cnid = hfs_get_nl(entry->key.ParID);
205     		} else {
206     			cnid = entry->cnid;
207     		}
208     
209     		if (filldir(dirent, DOT_DOT->Name,
210     			    DOT_DOT_LEN, 1, ntohl(cnid), DT_DIR)) {
211     			return 0;
212     		}
213     		filp->f_pos = 2;
214     	}
215     
216     	if (filp->f_pos < (dir->i_size - 3)) {
217     		hfs_u32 cnid;
218     		hfs_u8 type;
219     
220     	    	if (hfs_cat_open(entry, &brec) ||
221     	    	    hfs_cat_next(entry, &brec, filp->f_pos - 2, &cnid, &type)) {
222     			return 0;
223     		}
224     		while (filp->f_pos < (dir->i_size - 3)) {
225     			if (hfs_cat_next(entry, &brec, 1, &cnid, &type)) {
226     				return 0;
227     			}
228     			if (!skip_dirs || (type != HFS_CDR_DIR)) {
229     				ino_t ino;
230     				unsigned int len;
231     				unsigned char tmp_name[HFS_NAMEMAX];
232     
233     				ino = ntohl(cnid) | HFS_I(dir)->file_type;
234     				len = hfs_namein(dir, tmp_name,
235     				    &((struct hfs_cat_key *)brec.key)->CName);
236     				if (filldir(dirent, tmp_name, len,
237     					    filp->f_pos, ino, DT_UNKNOWN)) {
238     					hfs_cat_close(entry, &brec);
239     					return 0;
240     				}
241     			}
242     			++filp->f_pos;
243     		}
244     		hfs_cat_close(entry, &brec);
245     	}
246     
247     	if (filp->f_pos == (dir->i_size - 3)) {
248     		if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
249     		    (type == HFS_CAP_NDIR)) {
250     			/* In root dir last-2 entry is for ".rootinfo" */
251     			if (filldir(dirent, DOT_ROOTINFO->Name,
252     				    DOT_ROOTINFO_LEN, filp->f_pos,
253     				    ntohl(entry->cnid) | HFS_CAP_FNDR,
254     				    DT_UNKNOWN)) {
255     				return 0;
256     			}
257     		}
258     		++filp->f_pos;
259     	}
260     
261     	if (filp->f_pos == (dir->i_size - 2)) {
262     		if (type == HFS_CAP_NDIR) {
263     			/* In normal dirs last-1 entry is for ".finderinfo" */
264     			if (filldir(dirent, DOT_FINDERINFO->Name,
265     				    DOT_FINDERINFO_LEN, filp->f_pos,
266     				    ntohl(entry->cnid) | HFS_CAP_FDIR,
267     				    DT_UNKNOWN)) {
268     				return 0;
269     			}
270     		}
271     		++filp->f_pos;
272     	}
273     
274     	if (filp->f_pos == (dir->i_size - 1)) {
275     		if (type == HFS_CAP_NDIR) {
276     			/* In normal dirs last entry is for ".resource" */
277     			if (filldir(dirent, DOT_RESOURCE->Name,
278     				    DOT_RESOURCE_LEN, filp->f_pos,
279     				    ntohl(entry->cnid) | HFS_CAP_RDIR,
280     				    DT_UNKNOWN)) {
281     				return 0;
282     			}
283     		}
284     		++filp->f_pos;
285     	}
286     
287     	return 0;
288     }
289     
290     
291     /* due to the dcache caching negative dentries for non-existent files,
292      * we need to drop those entries when a file silently gets created.
293      * as far as i can tell, the calls that need to do this are the file
294      * related calls (create, rename, and mknod). the directory calls
295      * should be immune. the relevant calls in dir.c call drop_dentry 
296      * upon successful completion. */
297     void hfs_cap_drop_dentry(struct dentry *dentry, const ino_t type)
298     {
299       if (type == HFS_CAP_DATA) { /* given name */
300         hfs_drop_special(dentry->d_parent, DOT_FINDERINFO, dentry);
301         hfs_drop_special(dentry->d_parent, DOT_RESOURCE, dentry);
302       } else {
303         struct dentry *de;
304     
305         /* given {.resource,.finderinfo}/name, look for name */
306         if ((de = hfs_lookup_dentry(dentry->d_parent->d_parent,
307     				dentry->d_name.name, dentry->d_name.len))) {
308           if (!de->d_inode)
309     	d_drop(de);
310           dput(de);
311         }
312         
313         switch (type) {
314         case HFS_CAP_RSRC: /* given .resource/name */
315            /* look for .finderinfo/name */
316           hfs_drop_special(dentry->d_parent->d_parent, DOT_FINDERINFO, 
317     		       dentry);
318           break;
319         case HFS_CAP_FNDR: /* given .finderinfo/name. i don't this 
320     			* happens. */
321           /* look for .resource/name */
322           hfs_drop_special(dentry->d_parent->d_parent, DOT_RESOURCE, 
323     		       dentry);
324           break;
325         }
326       }
327     }
328