VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / fs / cifs / dir.c
index 85cccbb..91567f6 100644 (file)
@@ -101,6 +101,7 @@ cifs_bp_rename_retry:
        return full_path;
 }
 
+/* Note: caller must free return buffer */
 char *
 build_wildcard_path_from_dentry(struct dentry *direntry)
 {
@@ -108,18 +109,28 @@ build_wildcard_path_from_dentry(struct dentry *direntry)
        int namelen = 0;
        char *full_path;
 
+       if(direntry == NULL)
+               return NULL;  /* not much we can do if dentry is freed and
+               we need to reopen the file after it was closed implicitly
+               when the server crashed */
+
+cifs_bwp_rename_retry:
        for (temp = direntry; !IS_ROOT(temp);) {
                namelen += (1 + temp->d_name.len);
                temp = temp->d_parent;
+               if(temp == NULL) {
+                       cERROR(1,("corrupt dentry"));
+                       return NULL;
+               }
        }
-       namelen += 3;           /* allow for trailing null and wildcard (slash and *) */
-       full_path = kmalloc(namelen, GFP_KERNEL);
-       namelen--;
-       full_path[namelen] = 0; /* trailing null */
-       namelen--;
-       full_path[namelen] = '*';
-       namelen--;
+
+       full_path = kmalloc(namelen+3, GFP_KERNEL);
+       if(full_path == NULL)
+               return full_path;
+
        full_path[namelen] = '\\';
+       full_path[namelen+1] = '*';
+       full_path[namelen+2] = 0;  /* trailing null */
 
        for (temp = direntry; !IS_ROOT(temp);) {
                namelen -= 1 + temp->d_name.len;
@@ -129,13 +140,26 @@ build_wildcard_path_from_dentry(struct dentry *direntry)
                        full_path[namelen] = '\\';
                        strncpy(full_path + namelen + 1, temp->d_name.name,
                                temp->d_name.len);
+                       cFYI(0, (" name: %s ", full_path + namelen));
                }
                temp = temp->d_parent;
+               if(temp == NULL) {
+                       cERROR(1,("corrupt dentry"));
+                       kfree(full_path);
+                       return NULL;
+               }
        }
-       if (namelen != 0)
+       if (namelen != 0) {
                cERROR(1,
                       ("We did not end path lookup where we expected namelen is %d",
                        namelen));
+               /* presumably this is only possible if we were racing with a rename 
+               of one of the parent directories  (we can not lock the dentries
+               above us to prevent this, but retrying should be harmless) */
+               kfree(full_path);
+               namelen = 0;
+               goto cifs_bwp_rename_retry;
+       }
 
        return full_path;
 }
@@ -219,11 +243,19 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                then we now have to set the mode if possible */
                if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
                        (oplock & CIFS_CREATE_ACTION))
-                       CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
+                       if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+                               CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
+                                       (__u64)current->euid,
+                                       (__u64)current->egid,
+                                       0 /* dev */,
+                                       cifs_sb->local_nls);
+                       } else {
+                               CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
                                        (__u64)-1,
                                        (__u64)-1,
                                        0 /* dev */,
                                        cifs_sb->local_nls);
+                       }
                else {
                        /* BB implement via Windows security descriptors */
                        /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
@@ -233,10 +265,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
        /* BB server might mask mode so we have to query for Unix case*/
                if (pTcon->ses->capabilities & CAP_UNIX)
                        rc = cifs_get_inode_info_unix(&newinode, full_path,
-                                                inode->i_sb);
+                                                inode->i_sb,xid);
                else {
                        rc = cifs_get_inode_info(&newinode, full_path,
-                                                buf, inode->i_sb);
+                                                buf, inode->i_sb,xid);
                        if(newinode)
                                newinode->i_mode = mode;
                }
@@ -324,12 +356,19 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
                rc = -ENOMEM;
        
        if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) {
-               rc = CIFSSMBUnixSetPerms(xid, pTcon,
-                       full_path, mode, current->euid, current->egid,
-                       device_number, cifs_sb->local_nls);
+               if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+                       rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
+                               mode,(__u64)current->euid,(__u64)current->egid,
+                               device_number, cifs_sb->local_nls);
+               } else {
+                       rc = CIFSSMBUnixSetPerms(xid, pTcon,
+                               full_path, mode, (__u64)-1, (__u64)-1,
+                               device_number, cifs_sb->local_nls);
+               }
+
                if(!rc) {
                        rc = cifs_get_inode_info_unix(&newinode, full_path,
-                                               inode->i_sb);
+                                               inode->i_sb,xid);
                        direntry->d_op = &cifs_dentry_ops;
                        if(rc == 0)
                                d_instantiate(direntry, newinode);
@@ -389,10 +428,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
 
        if (pTcon->ses->capabilities & CAP_UNIX)
                rc = cifs_get_inode_info_unix(&newInode, full_path,
-                                             parent_dir_inode->i_sb);
+                                             parent_dir_inode->i_sb,xid);
        else
                rc = cifs_get_inode_info(&newInode, full_path, NULL,
-                                        parent_dir_inode->i_sb);
+                                        parent_dir_inode->i_sb,xid);
 
        if ((rc == 0) && (newInode != NULL)) {
                direntry->d_op = &cifs_dentry_ops;
@@ -431,9 +470,16 @@ cifs_dir_open(struct inode *inode, struct file *file)
        cifs_sb = CIFS_SB(inode->i_sb);
        pTcon = cifs_sb->tcon;
 
-       full_path = build_wildcard_path_from_dentry(file->f_dentry);
+       if(file->f_dentry) {
+               down(&file->f_dentry->d_sb->s_vfs_rename_sem);
+               full_path = build_wildcard_path_from_dentry(file->f_dentry);
+               up(&file->f_dentry->d_sb->s_vfs_rename_sem);
+       } else {
+               FreeXid(xid);
+               return -EIO;
+       }
 
-       cFYI(1, (" inode = 0x%p and full path is %s", inode, full_path));
+       cFYI(1, ("inode = 0x%p and full path is %s", inode, full_path));
 
        if (full_path)
                kfree(full_path);