~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/hfs/dir.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * linux/fs/hfs/dir.c
  3  *
  4  * Copyright (C) 1995-1997  Paul H. Hargrove
  5  * This file may be distributed under the terms of the GNU Public License.
  6  *
  7  * This file contains directory-related functions independent of which
  8  * scheme is being used to represent forks.
  9  *
 10  * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
 11  *
 12  * "XXX" in a comment is a note to myself to consider changing something.
 13  *
 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.
 17  */
 18 
 19 #include "hfs.h"
 20 #include <linux/hfs_fs_sb.h>
 21 #include <linux/hfs_fs_i.h>
 22 #include <linux/hfs_fs.h>
 23 
 24 /*================ File-local functions ================*/
 25 
 26 /*
 27  * build_key()
 28  *
 29  * Build a key for a file by the given name in the given directory.
 30  * If the name matches one of the reserved names returns 1 otherwise 0.
 31  */
 32 static int build_key(struct hfs_cat_key *key, struct inode *dir,
 33                      const char *name, int len)
 34 {
 35         struct hfs_name cname;
 36         const struct hfs_name *reserved;
 37 
 38         /* mangle the name */
 39         hfs_nameout(dir, &cname, name, len);
 40 
 41         /* check against reserved names */
 42         reserved = HFS_SB(dir->i_sb)->s_reserved1;
 43         while (reserved->Len) {
 44                 if (hfs_streq(reserved->Name, reserved->Len, 
 45                               cname.Name, cname.Len)) {
 46                         return 1;
 47                 }
 48                 ++reserved;
 49         }
 50 
 51         /* check against the names reserved only in the root directory */
 52         if (HFS_I(dir)->entry->cnid == htonl(HFS_ROOT_CNID)) {
 53                 reserved = HFS_SB(dir->i_sb)->s_reserved2;
 54                 while (reserved->Len) {
 55                         if (hfs_streq(reserved->Name, reserved->Len,
 56                                       cname.Name, cname.Len)) {
 57                                 return 1;
 58                         }
 59                         ++reserved;
 60                 }
 61         }
 62 
 63         /* build the key */
 64         hfs_cat_build_key(HFS_I(dir)->entry->cnid, &cname, key);
 65 
 66         return 0;
 67 }
 68 
 69 /*
 70  * update_dirs_plus()
 71  *
 72  * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and
 73  * 'i_version' of the inodes associated with a directory that has
 74  * had a file ('is_dir'==0) or directory ('is_dir'!=0) added to it.
 75  */
 76 static inline void update_dirs_plus(struct hfs_cat_entry *dir, int is_dir)
 77 {
 78         int i;
 79 
 80         for (i = 0; i < 4; ++i) {
 81                 struct dentry *de = dir->sys_entry[i];
 82                 if (de) {
 83                         struct inode *tmp = de->d_inode;
 84                         if (S_ISDIR(tmp->i_mode)) {
 85                                 if (is_dir &&
 86                                     (i == HFS_ITYPE_TO_INT(HFS_ITYPE_NORM))) {
 87                                         /* In "normal" directory only */
 88                                         ++(tmp->i_nlink);
 89                                 }
 90                                 tmp->i_size += HFS_I(tmp)->dir_size;
 91                                 tmp->i_version = ++event;
 92                         }
 93                         tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;
 94                         mark_inode_dirty(tmp);
 95                 }
 96         }
 97 }
 98 
 99 /*
100  * update_dirs_minus()
101  *
102  * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and
103  * 'i_version' of the inodes associated with a directory that has
104  * had a file ('is_dir'==0) or directory ('is_dir'!=0) removed.
105  */
106 static inline void update_dirs_minus(struct hfs_cat_entry *dir, int is_dir)
107 {
108         int i;
109 
110         for (i = 0; i < 4; ++i) {
111                 struct dentry *de = dir->sys_entry[i];
112                 if (de) {
113                         struct inode *tmp = de->d_inode;
114                         if (S_ISDIR(tmp->i_mode)) {
115                                 if (is_dir &&
116                                     (i == HFS_ITYPE_TO_INT(HFS_ITYPE_NORM))) {
117                                         /* In "normal" directory only */
118                                         --(tmp->i_nlink);
119                                 }
120                                 tmp->i_size -= HFS_I(tmp)->dir_size;
121                                 tmp->i_version = ++event;
122                         }
123                         tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;
124                         mark_inode_dirty(tmp);
125                 }
126         }
127 }
128 
129 /*
130  * mark_inodes_deleted()
131  *
132  * Update inodes associated with a deleted entry to reflect its deletion.
133  * Well, we really just drop the dentry.
134  *
135  * XXX: we should be using delete_inode for some of this stuff.
136  */
137 static inline void mark_inodes_deleted(struct hfs_cat_entry *entry, 
138                                        struct dentry *dentry)
139 {
140         struct dentry *de;
141         struct inode *tmp;
142         int i;
143 
144         for (i = 0; i < 4; ++i) {
145                 if ((de = entry->sys_entry[i]) && (dentry != de)) {
146                       dget(de);
147                       tmp = de->d_inode;
148                       tmp->i_nlink = 0;
149                       tmp->i_ctime = CURRENT_TIME;
150                       mark_inode_dirty(tmp);
151                       d_delete(de);
152                       dput(de);
153                 }
154         }
155 }
156 
157 /*================ Global functions ================*/
158 
159 /*
160  * hfs_create()
161  *
162  * This is the create() entry in the inode_operations structure for
163  * regular HFS directories.  The purpose is to create a new file in
164  * a directory and return a corresponding inode, given the inode for
165  * the directory and the name (and its length) of the new file.
166  */
167 int hfs_create(struct inode * dir, struct dentry *dentry, int mode)
168 {
169         struct hfs_cat_entry *entry = HFS_I(dir)->entry;
170         struct hfs_cat_entry *new;
171         struct hfs_cat_key key;
172         struct inode *inode;
173         int error;
174 
175         /* build the key, checking against reserved names */
176         if (build_key(&key, dir, dentry->d_name.name, dentry->d_name.len)) 
177                 return -EEXIST;
178 
179         if ((error = hfs_cat_create(entry, &key, 
180                                (mode & S_IWUSR) ? 0 : HFS_FIL_LOCK,
181                                HFS_SB(dir->i_sb)->s_type,
182                                HFS_SB(dir->i_sb)->s_creator, &new)))
183                 return error;
184 
185         /* create an inode for the new file. back out if we run
186          * into trouble. */
187         new->count++; /* hfs_iget() eats one */
188         if (!(inode = hfs_iget(new, HFS_I(dir)->file_type, dentry))) {
189                 hfs_cat_delete(entry, new, 1);
190                 hfs_cat_put(new);
191                 return -EIO;
192         }
193 
194         hfs_cat_put(new);
195         update_dirs_plus(entry, 0);
196         /* toss any relevant negative dentries */
197         if (HFS_I(dir)->d_drop_op)
198                 HFS_I(dir)->d_drop_op(dentry, HFS_I(dir)->file_type);
199         mark_inode_dirty(inode);
200         d_instantiate(dentry, inode);
201         return 0;
202 }
203 
204 /*
205  * hfs_mkdir()
206  *
207  * This is the mkdir() entry in the inode_operations structure for
208  * regular HFS directories.  The purpose is to create a new directory
209  * in a directory, given the inode for the parent directory and the
210  * name (and its length) of the new directory.
211  */
212 int hfs_mkdir(struct inode * parent, struct dentry *dentry, int mode)
213 {
214         struct hfs_cat_entry *entry = HFS_I(parent)->entry;
215         struct hfs_cat_entry *new;
216         struct hfs_cat_key key;
217         struct inode *inode;
218         int error;
219 
220         /* build the key, checking against reserved names */
221         if (build_key(&key, parent, dentry->d_name.name, 
222                       dentry->d_name.len)) 
223                 return -EEXIST;
224 
225         /* try to create the directory */
226         if ((error = hfs_cat_mkdir(entry, &key, &new)))
227                 return error;
228 
229         /* back out if we run into trouble */
230         new->count++; /* hfs_iget eats one */
231         if (!(inode = hfs_iget(new, HFS_I(parent)->file_type, dentry))) {
232                 hfs_cat_delete(entry, new, 1);
233                 hfs_cat_put(new);
234                 return -EIO;
235         }
236 
237         hfs_cat_put(new);
238         update_dirs_plus(entry, 1);
239         mark_inode_dirty(inode);
240         d_instantiate(dentry, inode);
241         return 0;
242 }
243 
244 /*
245  * hfs_unlink()
246  *
247  * This is the unlink() entry in the inode_operations structure for
248  * regular HFS directories.  The purpose is to delete an existing
249  * file, given the inode for the parent directory and the name
250  * (and its length) of the existing file.
251  */
252 int hfs_unlink(struct inode * dir, struct dentry *dentry)
253 {
254         struct hfs_cat_entry *entry = HFS_I(dir)->entry;
255         struct hfs_cat_entry *victim = NULL;
256         struct hfs_cat_key key;
257         int error;
258 
259         if (build_key(&key, dir, dentry->d_name.name,
260                       dentry->d_name.len)) 
261                 return -EPERM;
262 
263         if (!(victim = hfs_cat_get(entry->mdb, &key))) 
264                 return -ENOENT;
265 
266         error = -EPERM;
267         if (victim->type != HFS_CDR_FIL)
268                 goto hfs_unlink_put;
269 
270         if (!(error = hfs_cat_delete(entry, victim, 1))) {
271                 struct inode *inode = dentry->d_inode;
272 
273                 mark_inodes_deleted(victim, dentry);
274                 inode->i_nlink--; 
275                 inode->i_ctime = CURRENT_TIME;
276                 mark_inode_dirty(inode);
277                 update_dirs_minus(entry, 0);
278         }
279 
280 hfs_unlink_put:
281         hfs_cat_put(victim);    /* Note that hfs_cat_put(NULL) is safe. */
282         return error;
283 }
284 
285 /*
286  * hfs_rmdir()
287  *
288  * This is the rmdir() entry in the inode_operations structure for
289  * regular HFS directories.  The purpose is to delete an existing
290  * directory, given the inode for the parent directory and the name
291  * (and its length) of the existing directory.
292  */
293 int hfs_rmdir(struct inode * parent, struct dentry *dentry)
294 {
295         struct hfs_cat_entry *entry = HFS_I(parent)->entry;
296         struct hfs_cat_entry *victim = NULL;
297         struct inode *inode = dentry->d_inode;
298         struct hfs_cat_key key;
299         int error;
300 
301         if (build_key(&key, parent, dentry->d_name.name,
302                       dentry->d_name.len))
303                 return -EPERM;
304 
305         if (!(victim = hfs_cat_get(entry->mdb, &key)))
306                 return -ENOENT;
307 
308         error = -ENOTDIR;
309         if (victim->type != HFS_CDR_DIR) 
310                 goto hfs_rmdir_put;
311 
312         error = -EBUSY;
313         if (!d_unhashed(dentry))
314                 goto hfs_rmdir_put;
315 
316         /* we only have to worry about 2 and 3 for mount points */
317         if (victim->sys_entry[2] && d_mountpoint(victim->sys_entry[2]))
318                 goto hfs_rmdir_put;
319         if (victim->sys_entry[3] && d_mountpoint(victim->sys_entry[3])) 
320                 goto hfs_rmdir_put;
321 
322         
323         if ((error = hfs_cat_delete(entry, victim, 1)))
324                 goto hfs_rmdir_put;
325 
326         mark_inodes_deleted(victim, dentry);
327         inode->i_nlink = 0;
328         inode->i_ctime = CURRENT_TIME;
329         mark_inode_dirty(inode);
330         update_dirs_minus(entry, 1);
331          
332 hfs_rmdir_put:
333         hfs_cat_put(victim);    /* Note that hfs_cat_put(NULL) is safe. */
334         return error;
335 }
336 
337 /*
338  * hfs_rename()
339  *
340  * This is the rename() entry in the inode_operations structure for
341  * regular HFS directories.  The purpose is to rename an existing
342  * file or directory, given the inode for the current directory and
343  * the name (and its length) of the existing file/directory and the
344  * inode for the new directory and the name (and its length) of the
345  * new file/directory.
346  * XXX: how do you handle must_be dir?
347  */
348 int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
349                struct inode *new_dir, struct dentry *new_dentry)
350 {
351         struct hfs_cat_entry *old_parent = HFS_I(old_dir)->entry;
352         struct hfs_cat_entry *new_parent = HFS_I(new_dir)->entry;
353         struct hfs_cat_entry *victim = NULL;
354         struct hfs_cat_entry *deleted;
355         struct hfs_cat_key key;
356         int error;
357 
358         if (build_key(&key, old_dir, old_dentry->d_name.name,
359                       old_dentry->d_name.len) ||
360             (HFS_ITYPE(old_dir->i_ino) != HFS_ITYPE(new_dir->i_ino))) 
361                 return -EPERM;
362 
363         if (!(victim = hfs_cat_get(old_parent->mdb, &key))) 
364                 return -ENOENT;
365 
366         error = -EPERM;
367         if (build_key(&key, new_dir, new_dentry->d_name.name,
368                              new_dentry->d_name.len)) 
369                 goto hfs_rename_put;
370 
371         if (!(error = hfs_cat_move(old_parent, new_parent,
372                                    victim, &key, &deleted))) {
373                 int is_dir = (victim->type == HFS_CDR_DIR);
374                 
375                 /* drop the old dentries */
376                 mark_inodes_deleted(victim, old_dentry);
377                 update_dirs_minus(old_parent, is_dir);
378                 if (deleted) {
379                         mark_inodes_deleted(deleted, new_dentry);
380                         hfs_cat_put(deleted);
381                 } else {
382                         /* no existing inodes. just drop negative dentries */
383                         if (HFS_I(new_dir)->d_drop_op) 
384                                 HFS_I(new_dir)->d_drop_op(new_dentry, 
385                                           HFS_I(new_dir)->file_type);
386                         update_dirs_plus(new_parent, is_dir);
387                 }
388         
389         }
390 
391 hfs_rename_put:
392         hfs_cat_put(victim);    /* Note that hfs_cat_put(NULL) is safe. */
393         return error;
394 }
395 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.