OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [hfs/] [dir.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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 General 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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.