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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [reiserfs/] [xattr_acl.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
#include <linux/capability.h>
2
#include <linux/fs.h>
3
#include <linux/posix_acl.h>
4
#include <linux/reiserfs_fs.h>
5
#include <linux/errno.h>
6
#include <linux/pagemap.h>
7
#include <linux/xattr.h>
8
#include <linux/posix_acl_xattr.h>
9
#include <linux/reiserfs_xattr.h>
10
#include <linux/reiserfs_acl.h>
11
#include <asm/uaccess.h>
12
 
13
static int reiserfs_set_acl(struct inode *inode, int type,
14
                            struct posix_acl *acl);
15
 
16
static int
17
xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
18
{
19
        struct posix_acl *acl;
20
        int error;
21
 
22
        if (!reiserfs_posixacl(inode->i_sb))
23
                return -EOPNOTSUPP;
24
        if (!is_owner_or_cap(inode))
25
                return -EPERM;
26
 
27
        if (value) {
28
                acl = posix_acl_from_xattr(value, size);
29
                if (IS_ERR(acl)) {
30
                        return PTR_ERR(acl);
31
                } else if (acl) {
32
                        error = posix_acl_valid(acl);
33
                        if (error)
34
                                goto release_and_out;
35
                }
36
        } else
37
                acl = NULL;
38
 
39
        error = reiserfs_set_acl(inode, type, acl);
40
 
41
      release_and_out:
42
        posix_acl_release(acl);
43
        return error;
44
}
45
 
46
static int
47
xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
48
{
49
        struct posix_acl *acl;
50
        int error;
51
 
52
        if (!reiserfs_posixacl(inode->i_sb))
53
                return -EOPNOTSUPP;
54
 
55
        acl = reiserfs_get_acl(inode, type);
56
        if (IS_ERR(acl))
57
                return PTR_ERR(acl);
58
        if (acl == NULL)
59
                return -ENODATA;
60
        error = posix_acl_to_xattr(acl, buffer, size);
61
        posix_acl_release(acl);
62
 
63
        return error;
64
}
65
 
66
/*
67
 * Convert from filesystem to in-memory representation.
68
 */
69
static struct posix_acl *posix_acl_from_disk(const void *value, size_t size)
70
{
71
        const char *end = (char *)value + size;
72
        int n, count;
73
        struct posix_acl *acl;
74
 
75
        if (!value)
76
                return NULL;
77
        if (size < sizeof(reiserfs_acl_header))
78
                return ERR_PTR(-EINVAL);
79
        if (((reiserfs_acl_header *) value)->a_version !=
80
            cpu_to_le32(REISERFS_ACL_VERSION))
81
                return ERR_PTR(-EINVAL);
82
        value = (char *)value + sizeof(reiserfs_acl_header);
83
        count = reiserfs_acl_count(size);
84
        if (count < 0)
85
                return ERR_PTR(-EINVAL);
86
        if (count == 0)
87
                return NULL;
88
        acl = posix_acl_alloc(count, GFP_NOFS);
89
        if (!acl)
90
                return ERR_PTR(-ENOMEM);
91
        for (n = 0; n < count; n++) {
92
                reiserfs_acl_entry *entry = (reiserfs_acl_entry *) value;
93
                if ((char *)value + sizeof(reiserfs_acl_entry_short) > end)
94
                        goto fail;
95
                acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);
96
                acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
97
                switch (acl->a_entries[n].e_tag) {
98
                case ACL_USER_OBJ:
99
                case ACL_GROUP_OBJ:
100
                case ACL_MASK:
101
                case ACL_OTHER:
102
                        value = (char *)value +
103
                            sizeof(reiserfs_acl_entry_short);
104
                        acl->a_entries[n].e_id = ACL_UNDEFINED_ID;
105
                        break;
106
 
107
                case ACL_USER:
108
                case ACL_GROUP:
109
                        value = (char *)value + sizeof(reiserfs_acl_entry);
110
                        if ((char *)value > end)
111
                                goto fail;
112
                        acl->a_entries[n].e_id = le32_to_cpu(entry->e_id);
113
                        break;
114
 
115
                default:
116
                        goto fail;
117
                }
118
        }
119
        if (value != end)
120
                goto fail;
121
        return acl;
122
 
123
      fail:
124
        posix_acl_release(acl);
125
        return ERR_PTR(-EINVAL);
126
}
127
 
128
/*
129
 * Convert from in-memory to filesystem representation.
130
 */
131
static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size)
132
{
133
        reiserfs_acl_header *ext_acl;
134
        char *e;
135
        int n;
136
 
137
        *size = reiserfs_acl_size(acl->a_count);
138
        ext_acl = kmalloc(sizeof(reiserfs_acl_header) +
139
                                                  acl->a_count *
140
                                                  sizeof(reiserfs_acl_entry),
141
                                                  GFP_NOFS);
142
        if (!ext_acl)
143
                return ERR_PTR(-ENOMEM);
144
        ext_acl->a_version = cpu_to_le32(REISERFS_ACL_VERSION);
145
        e = (char *)ext_acl + sizeof(reiserfs_acl_header);
146
        for (n = 0; n < acl->a_count; n++) {
147
                reiserfs_acl_entry *entry = (reiserfs_acl_entry *) e;
148
                entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag);
149
                entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
150
                switch (acl->a_entries[n].e_tag) {
151
                case ACL_USER:
152
                case ACL_GROUP:
153
                        entry->e_id = cpu_to_le32(acl->a_entries[n].e_id);
154
                        e += sizeof(reiserfs_acl_entry);
155
                        break;
156
 
157
                case ACL_USER_OBJ:
158
                case ACL_GROUP_OBJ:
159
                case ACL_MASK:
160
                case ACL_OTHER:
161
                        e += sizeof(reiserfs_acl_entry_short);
162
                        break;
163
 
164
                default:
165
                        goto fail;
166
                }
167
        }
168
        return (char *)ext_acl;
169
 
170
      fail:
171
        kfree(ext_acl);
172
        return ERR_PTR(-EINVAL);
173
}
174
 
175
/*
176
 * Inode operation get_posix_acl().
177
 *
178
 * inode->i_mutex: down
179
 * BKL held [before 2.5.x]
180
 */
181
struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
182
{
183
        char *name, *value;
184
        struct posix_acl *acl, **p_acl;
185
        int size;
186
        int retval;
187
        struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
188
 
189
        switch (type) {
190
        case ACL_TYPE_ACCESS:
191
                name = POSIX_ACL_XATTR_ACCESS;
192
                p_acl = &reiserfs_i->i_acl_access;
193
                break;
194
        case ACL_TYPE_DEFAULT:
195
                name = POSIX_ACL_XATTR_DEFAULT;
196
                p_acl = &reiserfs_i->i_acl_default;
197
                break;
198
        default:
199
                return ERR_PTR(-EINVAL);
200
        }
201
 
202
        if (IS_ERR(*p_acl)) {
203
                if (PTR_ERR(*p_acl) == -ENODATA)
204
                        return NULL;
205
        } else if (*p_acl != NULL)
206
                return posix_acl_dup(*p_acl);
207
 
208
        size = reiserfs_xattr_get(inode, name, NULL, 0);
209
        if (size < 0) {
210
                if (size == -ENODATA || size == -ENOSYS) {
211
                        *p_acl = ERR_PTR(-ENODATA);
212
                        return NULL;
213
                }
214
                return ERR_PTR(size);
215
        }
216
 
217
        value = kmalloc(size, GFP_NOFS);
218
        if (!value)
219
                return ERR_PTR(-ENOMEM);
220
 
221
        retval = reiserfs_xattr_get(inode, name, value, size);
222
        if (retval == -ENODATA || retval == -ENOSYS) {
223
                /* This shouldn't actually happen as it should have
224
                   been caught above.. but just in case */
225
                acl = NULL;
226
                *p_acl = ERR_PTR(-ENODATA);
227
        } else if (retval < 0) {
228
                acl = ERR_PTR(retval);
229
        } else {
230
                acl = posix_acl_from_disk(value, retval);
231
                if (!IS_ERR(acl))
232
                        *p_acl = posix_acl_dup(acl);
233
        }
234
 
235
        kfree(value);
236
        return acl;
237
}
238
 
239
/*
240
 * Inode operation set_posix_acl().
241
 *
242
 * inode->i_mutex: down
243
 * BKL held [before 2.5.x]
244
 */
245
static int
246
reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
247
{
248
        char *name;
249
        void *value = NULL;
250
        struct posix_acl **p_acl;
251
        size_t size;
252
        int error;
253
        struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
254
 
255
        if (S_ISLNK(inode->i_mode))
256
                return -EOPNOTSUPP;
257
 
258
        switch (type) {
259
        case ACL_TYPE_ACCESS:
260
                name = POSIX_ACL_XATTR_ACCESS;
261
                p_acl = &reiserfs_i->i_acl_access;
262
                if (acl) {
263
                        mode_t mode = inode->i_mode;
264
                        error = posix_acl_equiv_mode(acl, &mode);
265
                        if (error < 0)
266
                                return error;
267
                        else {
268
                                inode->i_mode = mode;
269
                                if (error == 0)
270
                                        acl = NULL;
271
                        }
272
                }
273
                break;
274
        case ACL_TYPE_DEFAULT:
275
                name = POSIX_ACL_XATTR_DEFAULT;
276
                p_acl = &reiserfs_i->i_acl_default;
277
                if (!S_ISDIR(inode->i_mode))
278
                        return acl ? -EACCES : 0;
279
                break;
280
        default:
281
                return -EINVAL;
282
        }
283
 
284
        if (acl) {
285
                value = posix_acl_to_disk(acl, &size);
286
                if (IS_ERR(value))
287
                        return (int)PTR_ERR(value);
288
                error = reiserfs_xattr_set(inode, name, value, size, 0);
289
        } else {
290
                error = reiserfs_xattr_del(inode, name);
291
                if (error == -ENODATA) {
292
                        /* This may seem odd here, but it means that the ACL was set
293
                         * with a value representable with mode bits. If there was
294
                         * an ACL before, reiserfs_xattr_del already dirtied the inode.
295
                         */
296
                        mark_inode_dirty(inode);
297
                        error = 0;
298
                }
299
        }
300
 
301
        kfree(value);
302
 
303
        if (!error) {
304
                /* Release the old one */
305
                if (!IS_ERR(*p_acl) && *p_acl)
306
                        posix_acl_release(*p_acl);
307
 
308
                if (acl == NULL)
309
                        *p_acl = ERR_PTR(-ENODATA);
310
                else
311
                        *p_acl = posix_acl_dup(acl);
312
        }
313
 
314
        return error;
315
}
316
 
317
/* dir->i_mutex: locked,
318
 * inode is new and not released into the wild yet */
319
int
320
reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
321
                             struct inode *inode)
322
{
323
        struct posix_acl *acl;
324
        int err = 0;
325
 
326
        /* ACLs only get applied to files and directories */
327
        if (S_ISLNK(inode->i_mode))
328
                return 0;
329
 
330
        /* ACLs can only be used on "new" objects, so if it's an old object
331
         * there is nothing to inherit from */
332
        if (get_inode_sd_version(dir) == STAT_DATA_V1)
333
                goto apply_umask;
334
 
335
        /* Don't apply ACLs to objects in the .reiserfs_priv tree.. This
336
         * would be useless since permissions are ignored, and a pain because
337
         * it introduces locking cycles */
338
        if (is_reiserfs_priv_object(dir)) {
339
                reiserfs_mark_inode_private(inode);
340
                goto apply_umask;
341
        }
342
 
343
        acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT);
344
        if (IS_ERR(acl)) {
345
                if (PTR_ERR(acl) == -ENODATA)
346
                        goto apply_umask;
347
                return PTR_ERR(acl);
348
        }
349
 
350
        if (acl) {
351
                struct posix_acl *acl_copy;
352
                mode_t mode = inode->i_mode;
353
                int need_acl;
354
 
355
                /* Copy the default ACL to the default ACL of a new directory */
356
                if (S_ISDIR(inode->i_mode)) {
357
                        err = reiserfs_set_acl(inode, ACL_TYPE_DEFAULT, acl);
358
                        if (err)
359
                                goto cleanup;
360
                }
361
 
362
                /* Now we reconcile the new ACL and the mode,
363
                   potentially modifying both */
364
                acl_copy = posix_acl_clone(acl, GFP_NOFS);
365
                if (!acl_copy) {
366
                        err = -ENOMEM;
367
                        goto cleanup;
368
                }
369
 
370
                need_acl = posix_acl_create_masq(acl_copy, &mode);
371
                if (need_acl >= 0) {
372
                        if (mode != inode->i_mode) {
373
                                inode->i_mode = mode;
374
                        }
375
 
376
                        /* If we need an ACL.. */
377
                        if (need_acl > 0) {
378
                                err =
379
                                    reiserfs_set_acl(inode, ACL_TYPE_ACCESS,
380
                                                     acl_copy);
381
                                if (err)
382
                                        goto cleanup_copy;
383
                        }
384
                }
385
              cleanup_copy:
386
                posix_acl_release(acl_copy);
387
              cleanup:
388
                posix_acl_release(acl);
389
        } else {
390
              apply_umask:
391
                /* no ACL, apply umask */
392
                inode->i_mode &= ~current->fs->umask;
393
        }
394
 
395
        return err;
396
}
397
 
398
/* Looks up and caches the result of the default ACL.
399
 * We do this so that we don't need to carry the xattr_sem into
400
 * reiserfs_new_inode if we don't need to */
401
int reiserfs_cache_default_acl(struct inode *inode)
402
{
403
        int ret = 0;
404
        if (reiserfs_posixacl(inode->i_sb) && !is_reiserfs_priv_object(inode)) {
405
                struct posix_acl *acl;
406
                reiserfs_read_lock_xattr_i(inode);
407
                reiserfs_read_lock_xattrs(inode->i_sb);
408
                acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT);
409
                reiserfs_read_unlock_xattrs(inode->i_sb);
410
                reiserfs_read_unlock_xattr_i(inode);
411
                ret = (acl && !IS_ERR(acl));
412
                if (ret)
413
                        posix_acl_release(acl);
414
        }
415
 
416
        return ret;
417
}
418
 
419
int reiserfs_acl_chmod(struct inode *inode)
420
{
421
        struct posix_acl *acl, *clone;
422
        int error;
423
 
424
        if (S_ISLNK(inode->i_mode))
425
                return -EOPNOTSUPP;
426
 
427
        if (get_inode_sd_version(inode) == STAT_DATA_V1 ||
428
            !reiserfs_posixacl(inode->i_sb)) {
429
                return 0;
430
        }
431
 
432
        reiserfs_read_lock_xattrs(inode->i_sb);
433
        acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
434
        reiserfs_read_unlock_xattrs(inode->i_sb);
435
        if (!acl)
436
                return 0;
437
        if (IS_ERR(acl))
438
                return PTR_ERR(acl);
439
        clone = posix_acl_clone(acl, GFP_NOFS);
440
        posix_acl_release(acl);
441
        if (!clone)
442
                return -ENOMEM;
443
        error = posix_acl_chmod_masq(clone, inode->i_mode);
444
        if (!error) {
445
                int lock = !has_xattr_dir(inode);
446
                reiserfs_write_lock_xattr_i(inode);
447
                if (lock)
448
                        reiserfs_write_lock_xattrs(inode->i_sb);
449
                else
450
                        reiserfs_read_lock_xattrs(inode->i_sb);
451
                error = reiserfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
452
                if (lock)
453
                        reiserfs_write_unlock_xattrs(inode->i_sb);
454
                else
455
                        reiserfs_read_unlock_xattrs(inode->i_sb);
456
                reiserfs_write_unlock_xattr_i(inode);
457
        }
458
        posix_acl_release(clone);
459
        return error;
460
}
461
 
462
static int
463
posix_acl_access_get(struct inode *inode, const char *name,
464
                     void *buffer, size_t size)
465
{
466
        if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
467
                return -EINVAL;
468
        return xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
469
}
470
 
471
static int
472
posix_acl_access_set(struct inode *inode, const char *name,
473
                     const void *value, size_t size, int flags)
474
{
475
        if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
476
                return -EINVAL;
477
        return xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
478
}
479
 
480
static int posix_acl_access_del(struct inode *inode, const char *name)
481
{
482
        struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
483
        struct posix_acl **acl = &reiserfs_i->i_acl_access;
484
        if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
485
                return -EINVAL;
486
        if (!IS_ERR(*acl) && *acl) {
487
                posix_acl_release(*acl);
488
                *acl = ERR_PTR(-ENODATA);
489
        }
490
 
491
        return 0;
492
}
493
 
494
static int
495
posix_acl_access_list(struct inode *inode, const char *name, int namelen,
496
                      char *out)
497
{
498
        int len = namelen;
499
        if (!reiserfs_posixacl(inode->i_sb))
500
                return 0;
501
        if (out)
502
                memcpy(out, name, len);
503
 
504
        return len;
505
}
506
 
507
struct reiserfs_xattr_handler posix_acl_access_handler = {
508
        .prefix = POSIX_ACL_XATTR_ACCESS,
509
        .get = posix_acl_access_get,
510
        .set = posix_acl_access_set,
511
        .del = posix_acl_access_del,
512
        .list = posix_acl_access_list,
513
};
514
 
515
static int
516
posix_acl_default_get(struct inode *inode, const char *name,
517
                      void *buffer, size_t size)
518
{
519
        if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
520
                return -EINVAL;
521
        return xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
522
}
523
 
524
static int
525
posix_acl_default_set(struct inode *inode, const char *name,
526
                      const void *value, size_t size, int flags)
527
{
528
        if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
529
                return -EINVAL;
530
        return xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
531
}
532
 
533
static int posix_acl_default_del(struct inode *inode, const char *name)
534
{
535
        struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
536
        struct posix_acl **acl = &reiserfs_i->i_acl_default;
537
        if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
538
                return -EINVAL;
539
        if (!IS_ERR(*acl) && *acl) {
540
                posix_acl_release(*acl);
541
                *acl = ERR_PTR(-ENODATA);
542
        }
543
 
544
        return 0;
545
}
546
 
547
static int
548
posix_acl_default_list(struct inode *inode, const char *name, int namelen,
549
                       char *out)
550
{
551
        int len = namelen;
552
        if (!reiserfs_posixacl(inode->i_sb))
553
                return 0;
554
        if (out)
555
                memcpy(out, name, len);
556
 
557
        return len;
558
}
559
 
560
struct reiserfs_xattr_handler posix_acl_default_handler = {
561
        .prefix = POSIX_ACL_XATTR_DEFAULT,
562
        .get = posix_acl_default_get,
563
        .set = posix_acl_default_set,
564
        .del = posix_acl_default_del,
565
        .list = posix_acl_default_list,
566
};

powered by: WebSVN 2.1.0

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