linux-old/fs/xattr.c
<<
>>
Prefs
   1/*
   2  File: fs/xattr.c
   3
   4  Extended attribute handling.
   5
   6  Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
   7  Copyright (C) 2001 SGI - Silicon Graphics, Inc <linux-xfs@oss.sgi.com>
   8 */
   9#include <linux/fs.h>
  10#include <linux/slab.h>
  11#include <linux/vmalloc.h>
  12#include <linux/smp_lock.h>
  13#include <linux/file.h>
  14#include <linux/xattr.h>
  15#include <asm/uaccess.h>
  16
  17/*
  18 * Extended attribute memory allocation wrappers, originally
  19 * based on the Intermezzo PRESTO_ALLOC/PRESTO_FREE macros.
  20 * The vmalloc use here is very uncommon - extended attributes
  21 * are supposed to be small chunks of metadata, and it is quite
  22 * unusual to have very many extended attributes, so lists tend
  23 * to be quite short as well.  The 64K upper limit is derived
  24 * from the extended attribute size limit used by XFS.
  25 * Intentionally allow zero @size for value/list size requests.
  26 */
  27static void *
  28xattr_alloc(size_t size, size_t limit)
  29{
  30        void *ptr;
  31
  32        if (size > limit)
  33                return ERR_PTR(-E2BIG);
  34
  35        if (!size)      /* size request, no buffer is needed */
  36                return NULL;
  37        else if (size <= PAGE_SIZE)
  38                ptr = kmalloc((unsigned long) size, GFP_KERNEL);
  39        else
  40                ptr = vmalloc((unsigned long) size);
  41        if (!ptr)
  42                return ERR_PTR(-ENOMEM);
  43        return ptr;
  44}
  45
  46static void
  47xattr_free(void *ptr, size_t size)
  48{
  49        if (!size)      /* size request, no buffer was needed */
  50                return;
  51        else if (size <= PAGE_SIZE)
  52                kfree(ptr);
  53        else
  54                vfree(ptr);
  55}
  56
  57/*
  58 * Extended attribute SET operations
  59 */
  60static long
  61setxattr(struct dentry *d, char *name, void *value, size_t size, int flags)
  62{
  63        int error;
  64        void *kvalue;
  65        char kname[XATTR_NAME_MAX + 1];
  66
  67        if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
  68                return -EINVAL;
  69
  70        error = strncpy_from_user(kname, name, sizeof(kname));
  71        if (error == 0 || error == sizeof(kname))
  72                error = -ERANGE;
  73        if (error < 0)
  74                return error;
  75
  76        kvalue = xattr_alloc(size, XATTR_SIZE_MAX);
  77        if (IS_ERR(kvalue))
  78                return PTR_ERR(kvalue);
  79
  80        if (size > 0 && copy_from_user(kvalue, value, size)) {
  81                xattr_free(kvalue, size);
  82                return -EFAULT;
  83        }
  84
  85        error = -EOPNOTSUPP;
  86        if (d->d_inode->i_op && d->d_inode->i_op->setxattr) {
  87                down(&d->d_inode->i_sem);
  88                lock_kernel();
  89                error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags);
  90                unlock_kernel();
  91                up(&d->d_inode->i_sem);
  92        }
  93
  94        xattr_free(kvalue, size);
  95        return error;
  96}
  97
  98asmlinkage long
  99sys_setxattr(char *path, char *name, void *value, size_t size, int flags)
 100{
 101        struct nameidata nd;
 102        int error;
 103
 104        error = user_path_walk(path, &nd);
 105        if (error)
 106                return error;
 107        error = setxattr(nd.dentry, name, value, size, flags);
 108        path_release(&nd);
 109        return error;
 110}
 111
 112asmlinkage long
 113sys_lsetxattr(char *path, char *name, void *value, size_t size, int flags)
 114{
 115        struct nameidata nd;
 116        int error;
 117
 118        error = user_path_walk_link(path, &nd);
 119        if (error)
 120                return error;
 121        error = setxattr(nd.dentry, name, value, size, flags);
 122        path_release(&nd);
 123        return error;
 124}
 125
 126asmlinkage long
 127sys_fsetxattr(int fd, char *name, void *value, size_t size, int flags)
 128{
 129        struct file *f;
 130        int error = -EBADF;
 131
 132        f = fget(fd);
 133        if (!f)
 134                return error;
 135        error = setxattr(f->f_dentry, name, value, size, flags);
 136        fput(f);
 137        return error;
 138}
 139
 140/*
 141 * Extended attribute GET operations
 142 */
 143static ssize_t
 144getxattr(struct dentry *d, char *name, void *value, size_t size)
 145{
 146        ssize_t error;
 147        void *kvalue;
 148        char kname[XATTR_NAME_MAX + 1];
 149
 150        error = strncpy_from_user(kname, name, sizeof(kname));
 151        if (error == 0 || error == sizeof(kname))
 152                error = -ERANGE;
 153        if (error < 0)
 154                return error;
 155
 156        kvalue = xattr_alloc(size, XATTR_SIZE_MAX);
 157        if (IS_ERR(kvalue))
 158                return PTR_ERR(kvalue);
 159
 160        error = -EOPNOTSUPP;
 161        if (d->d_inode->i_op && d->d_inode->i_op->getxattr) {
 162                down(&d->d_inode->i_sem);
 163                lock_kernel();
 164                error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
 165                unlock_kernel();
 166                up(&d->d_inode->i_sem);
 167        }
 168
 169        if (kvalue && error > 0)
 170                if (copy_to_user(value, kvalue, error))
 171                        error = -EFAULT;
 172        xattr_free(kvalue, size);
 173        return error;
 174}
 175
 176asmlinkage ssize_t
 177sys_getxattr(char *path, char *name, void *value, size_t size)
 178{
 179        struct nameidata nd;
 180        ssize_t error;
 181
 182        error = user_path_walk(path, &nd);
 183        if (error)
 184                return error;
 185        error = getxattr(nd.dentry, name, value, size);
 186        path_release(&nd);
 187        return error;
 188}
 189
 190asmlinkage ssize_t
 191sys_lgetxattr(char *path, char *name, void *value, size_t size)
 192{
 193        struct nameidata nd;
 194        ssize_t error;
 195
 196        error = user_path_walk_link(path, &nd);
 197        if (error)
 198                return error;
 199        error = getxattr(nd.dentry, name, value, size);
 200        path_release(&nd);
 201        return error;
 202}
 203
 204asmlinkage ssize_t
 205sys_fgetxattr(int fd, char *name, void *value, size_t size)
 206{
 207        struct file *f;
 208        ssize_t error = -EBADF;
 209
 210        f = fget(fd);
 211        if (!f)
 212                return error;
 213        error = getxattr(f->f_dentry, name, value, size);
 214        fput(f);
 215        return error;
 216}
 217
 218/*
 219 * Extended attribute LIST operations
 220 */
 221static ssize_t
 222listxattr(struct dentry *d, char *list, size_t size)
 223{
 224        ssize_t error;
 225        char *klist;
 226
 227        klist = (char *)xattr_alloc(size, XATTR_LIST_MAX);
 228        if (IS_ERR(klist))
 229                return PTR_ERR(klist);
 230
 231        error = -EOPNOTSUPP;
 232        if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
 233                down(&d->d_inode->i_sem);
 234                lock_kernel();
 235                error = d->d_inode->i_op->listxattr(d, klist, size);
 236                unlock_kernel();
 237                up(&d->d_inode->i_sem);
 238        }
 239
 240        if (klist && error > 0)
 241                if (copy_to_user(list, klist, error))
 242                        error = -EFAULT;
 243        xattr_free(klist, size);
 244        return error;
 245}
 246
 247asmlinkage ssize_t
 248sys_listxattr(char *path, char *list, size_t size)
 249{
 250        struct nameidata nd;
 251        ssize_t error;
 252
 253        error = user_path_walk(path, &nd);
 254        if (error)
 255                return error;
 256        error = listxattr(nd.dentry, list, size);
 257        path_release(&nd);
 258        return error;
 259}
 260
 261asmlinkage ssize_t
 262sys_llistxattr(char *path, char *list, size_t size)
 263{
 264        struct nameidata nd;
 265        ssize_t error;
 266
 267        error = user_path_walk_link(path, &nd);
 268        if (error)
 269                return error;
 270        error = listxattr(nd.dentry, list, size);
 271        path_release(&nd);
 272        return error;
 273}
 274
 275asmlinkage ssize_t
 276sys_flistxattr(int fd, char *list, size_t size)
 277{
 278        struct file *f;
 279        ssize_t error = -EBADF;
 280
 281        f = fget(fd);
 282        if (!f)
 283                return error;
 284        error = listxattr(f->f_dentry, list, size);
 285        fput(f);
 286        return error;
 287}
 288
 289/*
 290 * Extended attribute REMOVE operations
 291 */
 292static long
 293removexattr(struct dentry *d, char *name)
 294{
 295        int error;
 296        char kname[XATTR_NAME_MAX + 1];
 297
 298        error = strncpy_from_user(kname, name, sizeof(kname));
 299        if (error == 0 || error == sizeof(kname))
 300                error = -ERANGE;
 301        if (error < 0)
 302                return error;
 303
 304        error = -EOPNOTSUPP;
 305        if (d->d_inode->i_op && d->d_inode->i_op->removexattr) {
 306                down(&d->d_inode->i_sem);
 307                lock_kernel();
 308                error = d->d_inode->i_op->removexattr(d, kname);
 309                unlock_kernel();
 310                up(&d->d_inode->i_sem);
 311        }
 312        return error;
 313}
 314
 315asmlinkage long
 316sys_removexattr(char *path, char *name)
 317{
 318        struct nameidata nd;
 319        int error;
 320
 321        error = user_path_walk(path, &nd);
 322        if (error)
 323                return error;
 324        error = removexattr(nd.dentry, name);
 325        path_release(&nd);
 326        return error;
 327}
 328
 329asmlinkage long
 330sys_lremovexattr(char *path, char *name)
 331{
 332        struct nameidata nd;
 333        int error;
 334
 335        error = user_path_walk_link(path, &nd);
 336        if (error)
 337                return error;
 338        error = removexattr(nd.dentry, name);
 339        path_release(&nd);
 340        return error;
 341}
 342
 343asmlinkage long
 344sys_fremovexattr(int fd, char *name)
 345{
 346        struct file *f;
 347        int error = -EBADF;
 348
 349        f = fget(fd);
 350        if (!f)
 351                return error;
 352        error = removexattr(f->f_dentry, name);
 353        fput(f);
 354        return error;
 355}
 356
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.