vserver 1.9.5.x5
[linux-2.6.git] / fs / cifs / inode.c
index c12231b..80ab68c 100644 (file)
@@ -35,9 +35,8 @@ extern int is_size_safe_to_change(struct cifsInodeInfo *);
 int
 cifs_get_inode_info_unix(struct inode **pinode,
                         const unsigned char *search_path,
-                        struct super_block *sb)
+                        struct super_block *sb,int xid)
 {
-       int xid;
        int rc = 0;
        FILE_UNIX_BASIC_INFO findData;
        struct cifsTconInfo *pTcon;
@@ -45,8 +44,6 @@ cifs_get_inode_info_unix(struct inode **pinode,
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        char *tmp_path;
 
-       xid = GetXid();
-
        pTcon = cifs_sb->tcon;
        cFYI(1, (" Getting info on %s ", search_path));
        /* we could have done a find first instead but this returns more info */
@@ -62,7 +59,6 @@ cifs_get_inode_info_unix(struct inode **pinode,
                                    strnlen(search_path, MAX_PATHCONF) + 1,
                                    GFP_KERNEL);
                        if (tmp_path == NULL) {
-                               FreeXid(xid);
                                return -ENOMEM;
                        }
         /* have to skip first of the double backslash of UNC name */
@@ -75,19 +71,31 @@ cifs_get_inode_info_unix(struct inode **pinode,
 
                        /* BB fix up inode etc. */
                } else if (rc) {
-                       FreeXid(xid);
                        return rc;
                }
 
        } else {
                struct cifsInodeInfo *cifsInfo;
+               __u32 type = le32_to_cpu(findData.Type);
+               __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
+               __u64 end_of_file = le64_to_cpu(findData.EndOfFile);
 
                /* get new inode */
                if (*pinode == NULL) {
                        *pinode = new_inode(sb);
+                       if(*pinode == NULL) 
+                               return -ENOMEM;
+                       /* Is an i_ino of zero legal? */
+                       /* Are there sanity checks we can use to ensure that
+                       the server is really filling in that field? */
+                       if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
+                               (*pinode)->i_ino = 
+                                       (unsigned long)findData.UniqueId;
+                       } /* note ino incremented to unique num in new_inode */
+                       insert_inode_hash(*pinode);
                }
+                       
                inode = *pinode;
-
                cifsInfo = CIFS_I(inode);
 
                cFYI(1, (" Old time %ld ", cifsInfo->time));
@@ -103,33 +111,34 @@ cifs_get_inode_info_unix(struct inode **pinode,
                inode->i_ctime =
                    cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
                inode->i_mode = le64_to_cpu(findData.Permissions);
-               findData.Type = le32_to_cpu(findData.Type);
-               if (findData.Type == UNIX_FILE) {
+               if (type == UNIX_FILE) {
                        inode->i_mode |= S_IFREG;
-               } else if (findData.Type == UNIX_SYMLINK) {
+               } else if (type == UNIX_SYMLINK) {
                        inode->i_mode |= S_IFLNK;
-               } else if (findData.Type == UNIX_DIR) {
+               } else if (type == UNIX_DIR) {
                        inode->i_mode |= S_IFDIR;
-               } else if (findData.Type == UNIX_CHARDEV) {
+               } else if (type == UNIX_CHARDEV) {
                        inode->i_mode |= S_IFCHR;
-               } else if (findData.Type == UNIX_BLOCKDEV) {
+                       inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
+                               le64_to_cpu(findData.DevMinor) & MINORMASK);
+               } else if (type == UNIX_BLOCKDEV) {
                        inode->i_mode |= S_IFBLK;
-               } else if (findData.Type == UNIX_FIFO) {
+                       inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
+                               le64_to_cpu(findData.DevMinor) & MINORMASK);
+               } else if (type == UNIX_FIFO) {
                        inode->i_mode |= S_IFIFO;
-               } else if (findData.Type == UNIX_SOCKET) {
+               } else if (type == UNIX_SOCKET) {
                        inode->i_mode |= S_IFSOCK;
                }
                inode->i_uid = le64_to_cpu(findData.Uid);
                inode->i_gid = le64_to_cpu(findData.Gid);
                inode->i_nlink = le64_to_cpu(findData.Nlinks);
-               findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes);
-               findData.EndOfFile = le64_to_cpu(findData.EndOfFile);
 
                if(is_size_safe_to_change(cifsInfo)) {
                /* can not safely change the file size here if the 
                   client is writing to it due to potential races */
 
-                       i_size_write(inode,findData.EndOfFile);
+                       i_size_write(inode, end_of_file);
 /* blksize needs to be multiple of two. So safer to default to blksize
        and blkbits set in superblock so 2**blkbits and blksize will match */
 /*             inode->i_blksize =
@@ -141,14 +150,14 @@ cifs_get_inode_info_unix(struct inode **pinode,
                 
 
 /*             inode->i_blocks = 
-                       (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;*/
+                       (inode->i_blksize - 1 + num_of_bytes) >> inode->i_blkbits;*/
 
                /* 512 bytes (2**9) is the fake blocksize that must be used */
                /* for this calculation */
-                       inode->i_blocks = (512 - 1 + findData.NumOfBytes) >> 9;
+                       inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
                }
 
-               if (findData.NumOfBytes < findData.EndOfFile)
+               if (num_of_bytes < end_of_file)
                        cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file "));
                cFYI(1,
                     ("Size %ld and blocks %ld ",
@@ -172,15 +181,13 @@ cifs_get_inode_info_unix(struct inode **pinode,
                                           inode->i_rdev);
                }
        }
-       FreeXid(xid);
        return rc;
 }
 
 int
 cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, 
-               FILE_ALL_INFO * pfindData, struct super_block *sb)
+               FILE_ALL_INFO * pfindData, struct super_block *sb, int xid)
 {
-       int xid;
        int rc = 0;
        struct cifsTconInfo *pTcon;
        struct inode *inode;
@@ -188,15 +195,12 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
        char *tmp_path;
        char *buf = NULL;
 
-       xid = GetXid();
-
        pTcon = cifs_sb->tcon;
        cFYI(1,("Getting info on %s ", search_path));
 
        if((pfindData == NULL) && (*pinode != NULL)) {
                if(CIFS_I(*pinode)->clientCanCacheRead) {
                        cFYI(1,("No need to revalidate inode sizes on cached file "));
-                       FreeXid(xid);
                        return rc;
                }
        }
@@ -204,6 +208,8 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
        /* if file info not passed in then get it from server */
        if(pfindData == NULL) {
                buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
+               if(buf == NULL)
+                       return -ENOMEM;
                pfindData = (FILE_ALL_INFO *)buf;
        /* could do find first instead but this returns more info */
                rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
@@ -221,7 +227,6 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
                        if (tmp_path == NULL) {
                                if(buf)
                                        kfree(buf);
-                               FreeXid(xid);
                                return -ENOMEM;
                        }
 
@@ -235,21 +240,37 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
                } else if (rc) {
                        if(buf)
                                kfree(buf);
-                       FreeXid(xid);
                        return rc;
                }
        } else {
                struct cifsInodeInfo *cifsInfo;
+               __u32 attr = le32_to_cpu(pfindData->Attributes);
 
                /* get new inode */
                if (*pinode == NULL) {
                        *pinode = new_inode(sb);
-               }
+                       if(*pinode == NULL)
+                               return -ENOMEM;
+                       /* Is an i_ino of zero legal? */
+                       /* Are there sanity checks we can use to ensure that
+                       the server is really filling in that field? */
+
+                       /* We can not use the IndexNumber from either
+                       Windows or Samba as it is frequently set to zero */
+                       /* There may be higher info levels that work but
+                       Are there Windows server or network appliances
+                       for which IndexNumber field is not guaranteed unique? */
+               
+                       /* if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
+                               (*pinode)->i_ino = 
+                                       (unsigned long)pfindData->IndexNumber;
+                       } */ /*NB: ino incremented to unique num in new_inode*/
 
+                       insert_inode_hash(*pinode);
+               }
                inode = *pinode;
                cifsInfo = CIFS_I(inode);
-               pfindData->Attributes = le32_to_cpu(pfindData->Attributes);
-               cifsInfo->cifsAttrs = pfindData->Attributes;
+               cifsInfo->cifsAttrs = attr;
                cFYI(1, (" Old time %ld ", cifsInfo->time));
                cifsInfo->time = jiffies;
                cFYI(1, (" New time %ld ", cifsInfo->time));
@@ -267,17 +288,17 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
                inode->i_ctime =
                    cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
                cFYI(0,
-                    (" Attributes came in as 0x%x ", pfindData->Attributes));
+                    (" Attributes came in as 0x%x ", attr));
 
                /* set default mode. will override for dirs below */
                if(atomic_read(&cifsInfo->inUse) == 0)
                        /* new inode, can safely set these fields */
                        inode->i_mode = cifs_sb->mnt_file_mode;
 
-               if (pfindData->Attributes & ATTR_REPARSE) {
-       /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */
-                       inode->i_mode |= S_IFLNK;
-               } else if (pfindData->Attributes & ATTR_DIRECTORY) {
+/*             if (attr & ATTR_REPARSE)  */
+/*             We no longer handle these as symlinks because we could not */
+/*             follow them due to the absolute path with drive letter */
+               if (attr & ATTR_DIRECTORY) {
        /* override default perms since we do not do byte range locking on dirs */
                        inode->i_mode = cifs_sb->mnt_dir_mode;
                        inode->i_mode |= S_IFDIR;
@@ -296,10 +317,9 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
 
                /* 512 bytes (2**9) is the fake blocksize that must be used */
                /* for this calculation */
-                       inode->i_blocks = (512 - 1 + pfindData->AllocationSize)
+                       inode->i_blocks = (512 - 1 + le64_to_cpu(pfindData->AllocationSize))
                                 >> 9;
                }
-               pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
 
                inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
 
@@ -332,22 +352,23 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
        }
        if(buf)
            kfree(buf);
-       FreeXid(xid);
        return rc;
 }
 
 void
 cifs_read_inode(struct inode *inode)
 {                              /* gets root inode */
-
+       int xid;
        struct cifs_sb_info *cifs_sb;
 
        cifs_sb = CIFS_SB(inode->i_sb);
-
+       xid = GetXid();
        if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
-               cifs_get_inode_info_unix(&inode, "", inode->i_sb);
+               cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid);
        else
-               cifs_get_inode_info(&inode, "", NULL, inode->i_sb);
+               cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid);
+       /* can not call macro FreeXid here since in a void func */
+       _FreeXid(xid);
 }
 
 int
@@ -430,7 +451,7 @@ cifs_unlink(struct inode *inode, struct dentry *direntry)
        cifsInode = CIFS_I(direntry->d_inode);
        cifsInode->time = 0;    /* will force revalidate to get info when needed */
        direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
-           CURRENT_TIME;
+           current_fs_time(inode->i_sb);
        cifsInode = CIFS_I(inode);
        cifsInode->time = 0;    /* force revalidate of dir as well */
 
@@ -473,21 +494,29 @@ cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                inode->i_nlink++;
                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,NULL,
-                                                inode->i_sb);
+                                                inode->i_sb,xid);
 
                direntry->d_op = &cifs_dentry_ops;
                d_instantiate(direntry, newinode);
                if(direntry->d_inode)
                        direntry->d_inode->i_nlink = 2;
-               if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)                
-                       CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
-                               (__u64)-1,  
-                               (__u64)-1,
-                               0 /* dev_t */,
-                               cifs_sb->local_nls);
+               if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+                       if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+                               CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
+                                               (__u64)current->euid,  
+                                               (__u64)current->egid,
+                                               0 /* dev_t */,
+                                               cifs_sb->local_nls);
+                       } else {
+                               CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
+                                               (__u64)-1,  
+                                               (__u64)-1,
+                                               0 /* dev_t */,
+                                               cifs_sb->local_nls);
+                       }
                else { /* BB to be implemented via Windows secrty descriptors*/
                /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
                }
@@ -535,7 +564,7 @@ cifs_rmdir(struct inode *inode, struct dentry *direntry)
        cifsInode = CIFS_I(direntry->d_inode);
        cifsInode->time = 0;    /* force revalidate to go get info when needed */
        direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
-           CURRENT_TIME;
+           current_fs_time(inode->i_sb);
 
        if (full_path)
                kfree(full_path);
@@ -698,7 +727,7 @@ cifs_revalidate(struct dentry *direntry)
 
        if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
                rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
-                                        direntry->d_sb);
+                                        direntry->d_sb,xid);
                if(rc) {
                        cFYI(1,("error on getting revalidate info %d",rc));
 /*                     if(rc != -ENOENT)
@@ -706,7 +735,7 @@ cifs_revalidate(struct dentry *direntry)
                }
        } else {
                rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
-                                   direntry->d_sb);
+                                   direntry->d_sb,xid);
                if(rc) {
                        cFYI(1,("error on getting revalidate info %d",rc));
 /*                     if(rc != -ENOENT)
@@ -943,7 +972,7 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
        } else
                time_buf.ChangeTime = 0;
 
-       if (set_time | time_buf.Attributes) {
+       if (set_time || time_buf.Attributes) {
                /* BB what if setting one attribute fails  
                        (such as size) but time setting works */
                time_buf.CreationTime = 0;      /* do not change */
@@ -951,10 +980,21 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                         via Handle (SetFileInfo) instead of by path */
                rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
                                cifs_sb->local_nls);
+               if(rc == -EOPNOTSUPP) {
+                       cFYI(1,("OS2 level of SetPathInfo not implemented"));
+                       /* Need to convert time_buf into old format, 
+                       but probably better to do that inside the function
+                       below rather than here */
+                       /* Better to return EOPNOTSUPP until function
+                       below is ready */
+                       /* CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
+                       FILE_INFO_STANDARD * data, cifs_sb->local_nls); */
+               }
        }
 
        /* do not  need local check to inode_check_ok since the server does that */
-       inode_setattr(direntry->d_inode, attrs);
+       if (!rc)
+               rc = inode_setattr(direntry->d_inode, attrs);
        if (full_path)
                kfree(full_path);
        FreeXid(xid);