nfsd: nfsd should drop CAP_MKNOD for non-root
[safe/jmp/linux-2.6] / fs / cifs / link.c
index 8e25996..63f6440 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/link.c
  *
 /*
  *   fs/cifs/link.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2003
+ *   Copyright (C) International Business Machines  Corp., 2002,2008
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -50,47 +50,49 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
 
        fromName = build_path_from_dentry(old_file);
        toName = build_path_from_dentry(direntry);
 
        fromName = build_path_from_dentry(old_file);
        toName = build_path_from_dentry(direntry);
-       if((fromName == NULL) || (toName == NULL)) {
+       if ((fromName == NULL) || (toName == NULL)) {
                rc = -ENOMEM;
                goto cifs_hl_exit;
        }
 
                rc = -ENOMEM;
                goto cifs_hl_exit;
        }
 
-       if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)
+/*     if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)*/
+       if (pTcon->unix_ext)
                rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
                rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
-                                           cifs_sb_target->local_nls, 
+                                           cifs_sb_target->local_nls,
                                            cifs_sb_target->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
        else {
                rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
                                            cifs_sb_target->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
        else {
                rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
-                                       cifs_sb_target->local_nls, 
+                                       cifs_sb_target->local_nls,
                                        cifs_sb_target->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
                                        cifs_sb_target->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
-               if((rc == -EIO) || (rc == -EINVAL))
-                       rc = -EOPNOTSUPP;  
+               if ((rc == -EIO) || (rc == -EINVAL))
+                       rc = -EOPNOTSUPP;
        }
 
        d_drop(direntry);       /* force new lookup from server of target */
 
        /* if source file is cached (oplocked) revalidate will not go to server
           until the file is closed or oplock broken so update nlinks locally */
        }
 
        d_drop(direntry);       /* force new lookup from server of target */
 
        /* if source file is cached (oplocked) revalidate will not go to server
           until the file is closed or oplock broken so update nlinks locally */
-       if(old_file->d_inode) {
+       if (old_file->d_inode) {
                cifsInode = CIFS_I(old_file->d_inode);
                cifsInode = CIFS_I(old_file->d_inode);
-               if(rc == 0) {
+               if (rc == 0) {
                        old_file->d_inode->i_nlink++;
                        old_file->d_inode->i_nlink++;
-                       old_file->d_inode->i_ctime = CURRENT_TIME;
+/* BB should we make this contingent on superblock flag NOATIME? */
+/*                     old_file->d_inode->i_ctime = CURRENT_TIME;*/
                        /* parent dir timestamps will update from srv
                        within a second, would it really be worth it
                        to set the parent dir cifs inode time to zero
                        to force revalidate (faster) for it too? */
                }
                        /* parent dir timestamps will update from srv
                        within a second, would it really be worth it
                        to set the parent dir cifs inode time to zero
                        to force revalidate (faster) for it too? */
                }
-               /* if not oplocked will force revalidate to get info 
+               /* if not oplocked will force revalidate to get info
                   on source file from srv */
                cifsInode->time = 0;
 
                   on source file from srv */
                cifsInode->time = 0;
 
-                /* Will update parent dir timestamps from srv within a second.
+               /* Will update parent dir timestamps from srv within a second.
                   Would it really be worth it to set the parent dir (cifs
                   inode) time field to zero to force revalidate on parent
                   Would it really be worth it to set the parent dir (cifs
                   inode) time field to zero to force revalidate on parent
-                  directory faster ie 
+                  directory faster ie
                        CIFS_I(inode)->time = 0;  */
        }
 
                        CIFS_I(inode)->time = 0;  */
        }
 
@@ -108,7 +110,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
        int rc = -EACCES;
        int xid;
        char *full_path = NULL;
        int rc = -EACCES;
        int xid;
        char *full_path = NULL;
-       char * target_path = ERR_PTR(-ENOMEM);
+       char *target_path = ERR_PTR(-ENOMEM);
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
 
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
 
@@ -128,13 +130,19 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
                goto out;
        }
 
                goto out;
        }
 
-/* BB add read reparse point symlink code and Unix extensions symlink code here BB */
+       /* We could change this to:
+               if (pTcon->unix_ext)
+          but there does not seem any point in refusing to
+          get symlink info if we can, even if unix extensions
+          turned off for this mount */
+
        if (pTcon->ses->capabilities & CAP_UNIX)
                rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
                                             target_path,
                                             PATH_MAX-1,
                                             cifs_sb->local_nls);
        else {
        if (pTcon->ses->capabilities & CAP_UNIX)
                rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
                                             target_path,
                                             PATH_MAX-1,
                                             cifs_sb->local_nls);
        else {
+               /* BB add read reparse point symlink code here */
                /* rc = CIFSSMBQueryReparseLinkInfo */
                /* BB Add code to Query ReparsePoint info */
                /* BB Add MAC style xsymlink check here if enabled */
                /* rc = CIFSSMBQueryReparseLinkInfo */
                /* BB Add code to Query ReparsePoint info */
                /* BB Add MAC style xsymlink check here if enabled */
@@ -175,7 +183,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
 
        full_path = build_path_from_dentry(direntry);
 
 
        full_path = build_path_from_dentry(direntry);
 
-       if(full_path == NULL) {
+       if (full_path == NULL) {
                FreeXid(xid);
                return -ENOMEM;
        }
                FreeXid(xid);
                return -ENOMEM;
        }
@@ -184,19 +192,20 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
        cFYI(1, ("symname is %s", symname));
 
        /* BB what if DFS and this volume is on different share? BB */
        cFYI(1, ("symname is %s", symname));
 
        /* BB what if DFS and this volume is on different share? BB */
-       if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+       if (pTcon->unix_ext)
                rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
                                           cifs_sb->local_nls);
        /* else
                rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
                                           cifs_sb->local_nls);
        /* else
-          rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,cifs_sb_target->local_nls); */
+          rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
+                                       cifs_sb_target->local_nls); */
 
        if (rc == 0) {
 
        if (rc == 0) {
-               if (pTcon->ses->capabilities & CAP_UNIX)
+               if (pTcon->unix_ext)
                        rc = cifs_get_inode_info_unix(&newinode, full_path,
                        rc = cifs_get_inode_info_unix(&newinode, full_path,
-                                                     inode->i_sb,xid);
+                                                     inode->i_sb, xid);
                else
                        rc = cifs_get_inode_info(&newinode, full_path, NULL,
                else
                        rc = cifs_get_inode_info(&newinode, full_path, NULL,
-                                                inode->i_sb,xid);
+                                                inode->i_sb, xid, NULL);
 
                if (rc != 0) {
                        cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
 
                if (rc != 0) {
                        cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
@@ -221,14 +230,11 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
        struct inode *inode = direntry->d_inode;
        int rc = -EACCES;
        int xid;
        struct inode *inode = direntry->d_inode;
        int rc = -EACCES;
        int xid;
-       int oplock = FALSE;
+       int oplock = 0;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
        char *full_path = NULL;
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
        char *full_path = NULL;
-       char *tmp_path =  NULL;
-       char * tmpbuffer;
-       unsigned char * referrals = NULL;
-       int num_referrals = 0;
+       char *tmpbuffer;
        int len;
        __u16 fid;
 
        int len;
        __u16 fid;
 
@@ -236,13 +242,13 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
        cifs_sb = CIFS_SB(inode->i_sb);
        pTcon = cifs_sb->tcon;
 
        cifs_sb = CIFS_SB(inode->i_sb);
        pTcon = cifs_sb->tcon;
 
-/* BB would it be safe against deadlock to grab this sem 
+/* BB would it be safe against deadlock to grab this sem
       even though rename itself grabs the sem and calls lookup? */
 /*       mutex_lock(&inode->i_sb->s_vfs_rename_mutex);*/
        full_path = build_path_from_dentry(direntry);
 /*       mutex_unlock(&inode->i_sb->s_vfs_rename_mutex);*/
 
       even though rename itself grabs the sem and calls lookup? */
 /*       mutex_lock(&inode->i_sb->s_vfs_rename_mutex);*/
        full_path = build_path_from_dentry(direntry);
 /*       mutex_unlock(&inode->i_sb->s_vfs_rename_mutex);*/
 
-       if(full_path == NULL) {
+       if (full_path == NULL) {
                FreeXid(xid);
                return -ENOMEM;
        }
                FreeXid(xid);
                return -ENOMEM;
        }
@@ -250,71 +256,47 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
        cFYI(1,
             ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d",
              full_path, inode, pBuffer, buflen));
        cFYI(1,
             ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d",
              full_path, inode, pBuffer, buflen));
-       if(buflen > PATH_MAX)
+       if (buflen > PATH_MAX)
                len = PATH_MAX;
        else
                len = buflen;
                len = PATH_MAX;
        else
                len = buflen;
-       tmpbuffer = kmalloc(len,GFP_KERNEL);   
-       if(tmpbuffer == NULL) {
+       tmpbuffer = kmalloc(len, GFP_KERNEL);
+       if (tmpbuffer == NULL) {
                kfree(full_path);
                FreeXid(xid);
                return -ENOMEM;
        }
 
                kfree(full_path);
                FreeXid(xid);
                return -ENOMEM;
        }
 
-/* BB add read reparse point symlink code and Unix extensions symlink code here BB */
+/* BB add read reparse point symlink code and
+       Unix extensions symlink code here BB */
+/* We could disable this based on pTcon->unix_ext flag instead ... but why? */
        if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
                rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
                                tmpbuffer,
                                len - 1,
                                cifs_sb->local_nls);
        else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
        if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
                rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
                                tmpbuffer,
                                len - 1,
                                cifs_sb->local_nls);
        else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
-               cERROR(1,("SFU style symlinks not implemented yet"));
+               cERROR(1, ("SFU style symlinks not implemented yet"));
                /* add open and read as in fs/cifs/inode.c */
                /* add open and read as in fs/cifs/inode.c */
-       
        } else {
                rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
        } else {
                rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
-                               OPEN_REPARSE_POINT,&fid, &oplock, NULL, 
-                               cifs_sb->local_nls, 
-                               cifs_sb->mnt_cifs_flags & 
+                               OPEN_REPARSE_POINT, &fid, &oplock, NULL,
+                               cifs_sb->local_nls,
+                               cifs_sb->mnt_cifs_flags &
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
-               if(!rc) {
+               if (!rc) {
                        rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
                                tmpbuffer,
                        rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
                                tmpbuffer,
-                               len - 1, 
+                               len - 1,
                                fid,
                                cifs_sb->local_nls);
                                fid,
                                cifs_sb->local_nls);
-                       if(CIFSSMBClose(xid, pTcon, fid)) {
-                               cFYI(1,("Error closing junction point (open for ioctl)"));
-                       }
-                       if(rc == -EIO) {
-                               /* Query if DFS Junction */
-                               tmp_path =
-                                       kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
-                                               GFP_KERNEL);
-                               if (tmp_path) {
-                                       strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
-                                       strncat(tmp_path, full_path, MAX_PATHCONF);
-                                       rc = get_dfs_path(xid, pTcon->ses, tmp_path,
-                                               cifs_sb->local_nls,
-                                               &num_referrals, &referrals,
-                                               cifs_sb->mnt_cifs_flags &
-                                                   CIFS_MOUNT_MAP_SPECIAL_CHR);
-                                       cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc));
-                                       if((num_referrals == 0) && (rc == 0))
-                                               rc = -EACCES;
-                                       else {
-                                               cFYI(1,("num referral: %d",num_referrals));
-                                               if(referrals) {
-                                                       cFYI(1,("referral string: %s",referrals));
-                                                       strncpy(tmpbuffer, referrals, len-1);                            
-                                               }
-                                       }
-                                       kfree(referrals);
-                                       kfree(tmp_path);
-}
-                               /* BB add code like else decode referrals then memcpy to
-                                 tmpbuffer and free referrals string array BB */
+                       if (CIFSSMBClose(xid, pTcon, fid)) {
+                               cFYI(1, ("Error closing junction point "
+                                        "(open for ioctl)"));
                        }
                        }
+                       /* If it is a DFS junction earlier we would have gotten
+                          PATH_NOT_COVERED returned from server so we do
+                          not need to request the DFS info here */
                }
        }
        /* BB Anything else to do to handle recursive links? */
                }
        }
        /* BB Anything else to do to handle recursive links? */