]> err.no Git - linux-2.6/blobdiff - fs/inotify.c
Merge branch 'master'
[linux-2.6] / fs / inotify.c
index 2fd97ef547ffcac2b35a3bcee5a37667b8e51ef4..2fecb7af4a77d6316171f0e25a40fd9027a71647 100644 (file)
@@ -176,6 +176,7 @@ static inline void put_inotify_dev(struct inotify_device *dev)
        if (atomic_dec_and_test(&dev->count)) {
                atomic_dec(&dev->user->inotify_devs);
                free_uid(dev->user);
+               idr_destroy(&dev->idr);
                kfree(dev);
        }
 }
@@ -363,15 +364,16 @@ static int inotify_dev_get_wd(struct inotify_device *dev,
 /*
  * find_inode - resolve a user-given path to a specific inode and return a nd
  */
-static int find_inode(const char __user *dirname, struct nameidata *nd)
+static int find_inode(const char __user *dirname, struct nameidata *nd,
+                     unsigned flags)
 {
        int error;
 
-       error = __user_walk(dirname, LOOKUP_FOLLOW, nd);
+       error = __user_walk(dirname, flags, nd);
        if (error)
                return error;
        /* you can only watch an inode if you have read permissions on it */
-       error = permission(nd->dentry->d_inode, MAY_READ, NULL);
+       error = vfs_permission(nd, MAY_READ);
        if (error) 
                path_release(nd);
        return error;
@@ -931,6 +933,8 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
        struct nameidata nd;
        struct file *filp;
        int ret, fput_needed;
+       int mask_add = 0;
+       unsigned flags = 0;
 
        filp = fget_light(fd, &fput_needed);
        if (unlikely(!filp))
@@ -942,7 +946,12 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
                goto fput_and_out;
        }
 
-       ret = find_inode(path, &nd);
+       if (!(mask & IN_DONT_FOLLOW))
+               flags |= LOOKUP_FOLLOW;
+       if (mask & IN_ONLYDIR)
+               flags |= LOOKUP_DIRECTORY;
+
+       ret = find_inode(path, &nd, flags);
        if (unlikely(ret))
                goto fput_and_out;
 
@@ -953,6 +962,9 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
        down(&inode->inotify_sem);
        down(&dev->sem);
 
+       if (mask & IN_MASK_ADD)
+               mask_add = 1;
+
        /* don't let user-space set invalid bits: we don't want flags set */
        mask &= IN_ALL_EVENTS;
        if (unlikely(!mask)) {
@@ -966,7 +978,10 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
         */
        old = inode_find_dev(inode, dev);
        if (unlikely(old)) {
-               old->mask = mask;
+               if (mask_add)
+                       old->mask |= mask;
+               else
+                       old->mask = mask;
                ret = old->wd;
                goto out;
        }