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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  linux/fs/sysv/namei.c
3
 *
4
 *  minix/namei.c
5
 *  Copyright (C) 1991, 1992  Linus Torvalds
6
 *
7
 *  coh/namei.c
8
 *  Copyright (C) 1993  Pascal Haible, Bruno Haible
9
 *
10
 *  sysv/namei.c
11
 *  Copyright (C) 1993  Bruno Haible
12
 *  Copyright (C) 1997, 1998  Krzysztof G. Baranowski
13
 */
14
 
15
#include <linux/fs.h>
16
#include <linux/sysv_fs.h>
17
#include <linux/pagemap.h>
18
 
19
static inline void inc_count(struct inode *inode)
20
{
21
        inode->i_nlink++;
22
        mark_inode_dirty(inode);
23
}
24
 
25
static inline void dec_count(struct inode *inode)
26
{
27
        inode->i_nlink--;
28
        mark_inode_dirty(inode);
29
}
30
 
31
static int add_nondir(struct dentry *dentry, struct inode *inode)
32
{
33
        int err = sysv_add_link(dentry, inode);
34
        if (!err) {
35
                d_instantiate(dentry, inode);
36
                return 0;
37
        }
38
        dec_count(inode);
39
        iput(inode);
40
        return err;
41
}
42
 
43
static int sysv_hash(struct dentry *dentry, struct qstr *qstr)
44
{
45
        unsigned long hash;
46
        int i;
47
        const unsigned char *name;
48
 
49
        i = SYSV_NAMELEN;
50
        if (i >= qstr->len)
51
                return 0;
52
        /* Truncate the name in place, avoids having to define a compare
53
           function. */
54
        qstr->len = i;
55
        name = qstr->name;
56
        hash = init_name_hash();
57
        while (i--)
58
                hash = partial_name_hash(*name++, hash);
59
        qstr->hash = end_name_hash(hash);
60
        return 0;
61
}
62
 
63
struct dentry_operations sysv_dentry_operations = {
64
        d_hash:         sysv_hash,
65
};
66
 
67
static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry)
68
{
69
        struct inode * inode = NULL;
70
        ino_t ino;
71
 
72
        dentry->d_op = dir->i_sb->s_root->d_op;
73
        if (dentry->d_name.len > SYSV_NAMELEN)
74
                return ERR_PTR(-ENAMETOOLONG);
75
        ino = sysv_inode_by_name(dentry);
76
 
77
        if (ino) {
78
                inode = iget(dir->i_sb, ino);
79
                if (!inode)
80
                        return ERR_PTR(-EACCES);
81
        }
82
        d_add(dentry, inode);
83
        return NULL;
84
}
85
 
86
static int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
87
{
88
        struct inode * inode = sysv_new_inode(dir, mode);
89
        int err = PTR_ERR(inode);
90
 
91
        if (!IS_ERR(inode)) {
92
                sysv_set_inode(inode, rdev);
93
                mark_inode_dirty(inode);
94
                err = add_nondir(dentry, inode);
95
        }
96
        return err;
97
}
98
 
99
static int sysv_create(struct inode * dir, struct dentry * dentry, int mode)
100
{
101
        return sysv_mknod(dir, dentry, mode, 0);
102
}
103
 
104
static int sysv_symlink(struct inode * dir, struct dentry * dentry,
105
        const char * symname)
106
{
107
        int err = -ENAMETOOLONG;
108
        int l = strlen(symname)+1;
109
        struct inode * inode;
110
 
111
        if (l > dir->i_sb->s_blocksize)
112
                goto out;
113
 
114
        inode = sysv_new_inode(dir, S_IFLNK|0777);
115
        err = PTR_ERR(inode);
116
        if (IS_ERR(inode))
117
                goto out;
118
 
119
        sysv_set_inode(inode, 0);
120
        err = block_symlink(inode, symname, l);
121
        if (err)
122
                goto out_fail;
123
 
124
        mark_inode_dirty(inode);
125
        err = add_nondir(dentry, inode);
126
out:
127
        return err;
128
 
129
out_fail:
130
        dec_count(inode);
131
        iput(inode);
132
        goto out;
133
}
134
 
135
static int sysv_link(struct dentry * old_dentry, struct inode * dir,
136
        struct dentry * dentry)
137
{
138
        struct inode *inode = old_dentry->d_inode;
139
 
140
        if (S_ISDIR(inode->i_mode))
141
                return -EPERM;
142
 
143
        if (inode->i_nlink >= inode->i_sb->sv_link_max)
144
                return -EMLINK;
145
 
146
        inode->i_ctime = CURRENT_TIME;
147
        inc_count(inode);
148
        atomic_inc(&inode->i_count);
149
 
150
        return add_nondir(dentry, inode);
151
}
152
 
153
static int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode)
154
{
155
        struct inode * inode;
156
        int err = -EMLINK;
157
 
158
        if (dir->i_nlink >= dir->i_sb->sv_link_max)
159
                goto out;
160
        inc_count(dir);
161
 
162
        inode = sysv_new_inode(dir, S_IFDIR|mode);
163
        err = PTR_ERR(inode);
164
        if (IS_ERR(inode))
165
                goto out_dir;
166
 
167
        sysv_set_inode(inode, 0);
168
 
169
        inc_count(inode);
170
 
171
        err = sysv_make_empty(inode, dir);
172
        if (err)
173
                goto out_fail;
174
 
175
        err = sysv_add_link(dentry, inode);
176
        if (err)
177
                goto out_fail;
178
 
179
        d_instantiate(dentry, inode);
180
out:
181
        return err;
182
 
183
out_fail:
184
        dec_count(inode);
185
        dec_count(inode);
186
        iput(inode);
187
out_dir:
188
        dec_count(dir);
189
        goto out;
190
}
191
 
192
static int sysv_unlink(struct inode * dir, struct dentry * dentry)
193
{
194
        struct inode * inode = dentry->d_inode;
195
        struct page * page;
196
        struct sysv_dir_entry * de;
197
        int err = -ENOENT;
198
 
199
        de = sysv_find_entry(dentry, &page);
200
        if (!de)
201
                goto out;
202
 
203
        err = sysv_delete_entry (de, page);
204
        if (err)
205
                goto out;
206
 
207
        inode->i_ctime = dir->i_ctime;
208
        dec_count(inode);
209
out:
210
        return err;
211
}
212
 
213
static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
214
{
215
        struct inode *inode = dentry->d_inode;
216
        int err = -ENOTEMPTY;
217
 
218
        if (sysv_empty_dir(inode)) {
219
                err = sysv_unlink(dir, dentry);
220
                if (!err) {
221
                        inode->i_size = 0;
222
                        dec_count(inode);
223
                        dec_count(dir);
224
                }
225
        }
226
        return err;
227
}
228
 
229
/*
230
 * Anybody can rename anything with this: the permission checks are left to the
231
 * higher-level routines.
232
 */
233
static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
234
                  struct inode * new_dir, struct dentry * new_dentry)
235
{
236
        struct inode * old_inode = old_dentry->d_inode;
237
        struct inode * new_inode = new_dentry->d_inode;
238
        struct page * dir_page = NULL;
239
        struct sysv_dir_entry * dir_de = NULL;
240
        struct page * old_page;
241
        struct sysv_dir_entry * old_de;
242
        int err = -ENOENT;
243
 
244
        old_de = sysv_find_entry(old_dentry, &old_page);
245
        if (!old_de)
246
                goto out;
247
 
248
        if (S_ISDIR(old_inode->i_mode)) {
249
                err = -EIO;
250
                dir_de = sysv_dotdot(old_inode, &dir_page);
251
                if (!dir_de)
252
                        goto out_old;
253
        }
254
 
255
        if (new_inode) {
256
                struct page * new_page;
257
                struct sysv_dir_entry * new_de;
258
 
259
                err = -ENOTEMPTY;
260
                if (dir_de && !sysv_empty_dir(new_inode))
261
                        goto out_dir;
262
 
263
                err = -ENOENT;
264
                new_de = sysv_find_entry(new_dentry, &new_page);
265
                if (!new_de)
266
                        goto out_dir;
267
                inc_count(old_inode);
268
                sysv_set_link(new_de, new_page, old_inode);
269
                new_inode->i_ctime = CURRENT_TIME;
270
                if (dir_de)
271
                        new_inode->i_nlink--;
272
                dec_count(new_inode);
273
        } else {
274
                if (dir_de) {
275
                        err = -EMLINK;
276
                        if (new_dir->i_nlink >= new_dir->i_sb->sv_link_max)
277
                                goto out_dir;
278
                }
279
                inc_count(old_inode);
280
                err = sysv_add_link(new_dentry, old_inode);
281
                if (err) {
282
                        dec_count(old_inode);
283
                        goto out_dir;
284
                }
285
                if (dir_de)
286
                        inc_count(new_dir);
287
        }
288
 
289
        sysv_delete_entry(old_de, old_page);
290
        dec_count(old_inode);
291
 
292
        if (dir_de) {
293
                sysv_set_link(dir_de, dir_page, new_dir);
294
                dec_count(old_dir);
295
        }
296
        return 0;
297
 
298
out_dir:
299
        if (dir_de) {
300
                kunmap(dir_page);
301
                page_cache_release(dir_page);
302
        }
303
out_old:
304
        kunmap(old_page);
305
        page_cache_release(old_page);
306
out:
307
        return err;
308
}
309
 
310
/*
311
 * directories can handle most operations...
312
 */
313
struct inode_operations sysv_dir_inode_operations = {
314
        create:         sysv_create,
315
        lookup:         sysv_lookup,
316
        link:           sysv_link,
317
        unlink:         sysv_unlink,
318
        symlink:        sysv_symlink,
319
        mkdir:          sysv_mkdir,
320
        rmdir:          sysv_rmdir,
321
        mknod:          sysv_mknod,
322
        rename:         sysv_rename,
323
};

powered by: WebSVN 2.1.0

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