]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/cifs/inode.c
[CIFS] whitespace fixes
[linux-2.6-omap-h63xx.git] / fs / cifs / inode.c
index f414526e476ab85221dbb79be24c64bf34fa76cd..f0ff12b3f398fcd09bae2f39934263b803bdb1e1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/inode.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2005
+ *   Copyright (C) International Business Machines  Corp., 2002,2007
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -90,7 +90,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                                (*pinode)->i_ino =
                                        (unsigned long)findData.UniqueId;
                        } /* note ino incremented to unique num in new_inode */
-                       if(sb->s_flags & MS_NOATIME)
+                       if (sb->s_flags & MS_NOATIME)
                                (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
                                
                        insert_inode_hash(*pinode);
@@ -139,8 +139,17 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                        inode->i_mode |= S_IFREG;
                        cFYI(1,("unknown type %d",type));
                }
-               inode->i_uid = le64_to_cpu(findData.Uid);
-               inode->i_gid = le64_to_cpu(findData.Gid);
+               
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+                       inode->i_uid = cifs_sb->mnt_uid;
+               else
+                       inode->i_uid = le64_to_cpu(findData.Uid);
+
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+                       inode->i_gid = cifs_sb->mnt_gid;
+               else
+                       inode->i_gid = le64_to_cpu(findData.Gid);
+                       
                inode->i_nlink = le64_to_cpu(findData.Nlinks);
 
                spin_lock(&inode->i_lock);
@@ -178,13 +187,13 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                                                &cifs_file_direct_nobrl_ops;
                                else
                                        inode->i_fop = &cifs_file_direct_ops;
-                       } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+                       } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
                                inode->i_fop = &cifs_file_nobrl_ops;
                        else /* not direct, send byte range locks */ 
                                inode->i_fop = &cifs_file_ops;
 
                        /* check if server can support readpages */
-                       if(pTcon->ses->server->maxBuf < 
+                       if (pTcon->ses->server->maxBuf < 
                            PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
                                inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
                        else
@@ -220,7 +229,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
 
        pbuf = buf;
 
-       if(size == 0) {
+       if (size == 0) {
                inode->i_mode |= S_IFIFO;
                return 0;
        } else if (size < 8) {
@@ -239,11 +248,11 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
                                 netfid,
                                 24 /* length */, 0 /* offset */,
                                 &bytes_read, &pbuf, &buf_type);
-               if((rc == 0) && (bytes_read >= 8)) {
-                       if(memcmp("IntxBLK", pbuf, 8) == 0) {
+               if ((rc == 0) && (bytes_read >= 8)) {
+                       if (memcmp("IntxBLK", pbuf, 8) == 0) {
                                cFYI(1,("Block device"));
                                inode->i_mode |= S_IFBLK;
-                               if(bytes_read == 24) {
+                               if (bytes_read == 24) {
                                        /* we have enough to decode dev num */
                                        __u64 mjr; /* major */
                                        __u64 mnr; /* minor */
@@ -251,10 +260,10 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
                                        mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
                                        inode->i_rdev = MKDEV(mjr, mnr);
                                }
-                       } else if(memcmp("IntxCHR", pbuf, 8) == 0) {
+                       } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
                                cFYI(1,("Char device"));
                                inode->i_mode |= S_IFCHR;
-                               if(bytes_read == 24) {
+                               if (bytes_read == 24) {
                                        /* we have enough to decode dev num */
                                        __u64 mjr; /* major */
                                        __u64 mnr; /* minor */
@@ -262,7 +271,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
                                        mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
                                        inode->i_rdev = MKDEV(mjr, mnr);
                                 }
-                       } else if(memcmp("IntxLNK", pbuf, 7) == 0) {
+                       } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
                                cFYI(1,("Symlink"));
                                inode->i_mode |= S_IFLNK;
                        } else {
@@ -293,7 +302,7 @@ static int get_sfu_uid_mode(struct inode * inode,
        rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
                        ea_value, 4 /* size of buf */, cifs_sb->local_nls,
                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-       if(rc < 0)
+       if (rc < 0)
                return (int)rc;
        else if (rc > 3) {
                mode = le32_to_cpu(*((__le32 *)ea_value));
@@ -348,7 +357,7 @@ int cifs_get_inode_info(struct inode **pinode,
                /* BB optimize code so we do not make the above call
                when server claims no NT SMB support and the above call
                failed at least once - set flag in tcon or mount */
-               if((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
+               if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
                        rc = SMBQueryInformation(xid, pTcon, search_path,
                                        pfindData, cifs_sb->local_nls, 
                                        cifs_sb->mnt_cifs_flags &
@@ -425,7 +434,7 @@ int cifs_get_inode_info(struct inode **pinode,
                                } else /* do we need cast or hash to ino? */
                                        (*pinode)->i_ino = inode_num;
                        } /* else ino incremented to unique num in new_inode*/
-                       if(sb->s_flags & MS_NOATIME)
+                       if (sb->s_flags & MS_NOATIME)
                                (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
                        insert_inode_hash(*pinode);
                }
@@ -442,7 +451,7 @@ int cifs_get_inode_info(struct inode **pinode,
                (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
 
                /* Linux can not store file creation time so ignore it */
-               if(pfindData->LastAccessTime)
+               if (pfindData->LastAccessTime)
                        inode->i_atime = cifs_NTtimeToUnix
                                (le64_to_cpu(pfindData->LastAccessTime));
                else /* do not need to use current_fs_time - time not stored */
@@ -452,7 +461,7 @@ int cifs_get_inode_info(struct inode **pinode,
                inode->i_ctime =
                    cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
                cFYI(0, ("Attributes came in as 0x%x", attr));
-               if(adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
+               if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
                        inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
                        inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
                }
@@ -521,8 +530,10 @@ int cifs_get_inode_info(struct inode **pinode,
 
                /* BB fill in uid and gid here? with help from winbind? 
                   or retrieve from NTFS stream extended attribute */
-               if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
                        /* fill in uid, gid, mode from server ACL */
+                       /* BB FIXME this should also take into account the
+                        * default uid specified on mount if present */
                        get_sfu_uid_mode(inode, search_path, cifs_sb, xid);
                } else if (atomic_read(&cifsInfo->inUse) == 0) {
                        inode->i_uid = cifs_sb->mnt_uid;
@@ -541,12 +552,12 @@ int cifs_get_inode_info(struct inode **pinode,
                                                &cifs_file_direct_nobrl_ops;
                                else
                                        inode->i_fop = &cifs_file_direct_ops;
-                       } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+                       } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
                                inode->i_fop = &cifs_file_nobrl_ops;
                        else /* not direct, send byte range locks */
                                inode->i_fop = &cifs_file_ops;
 
-                       if(pTcon->ses->server->maxBuf < 
+                       if (pTcon->ses->server->maxBuf < 
                             PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
                                inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
                        else
@@ -597,7 +608,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
 
        xid = GetXid();
 
-       if(inode)
+       if (inode)
                cifs_sb = CIFS_SB(inode->i_sb);
        else
                cifs_sb = CIFS_SB(direntry->d_sb);
@@ -723,7 +734,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
                                           when needed */
                direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
        }
-       if(inode) {
+       if (inode) {
                inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
                cifsInode = CIFS_I(inode);
                cifsInode->time = 0;    /* force revalidate of dir as well */
@@ -734,6 +745,136 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
        return rc;
 }
 
+static void posix_fill_in_inode(struct inode *tmp_inode,
+       FILE_UNIX_BASIC_INFO *pData, int *pobject_type, int isNewInode)
+{
+       loff_t local_size;
+       struct timespec local_mtime;
+
+       struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
+       struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
+
+       __u32 type = le32_to_cpu(pData->Type);
+       __u64 num_of_bytes = le64_to_cpu(pData->NumOfBytes);
+       __u64 end_of_file = le64_to_cpu(pData->EndOfFile);
+       cifsInfo->time = jiffies;
+       atomic_inc(&cifsInfo->inUse);
+
+       /* save mtime and size */
+       local_mtime = tmp_inode->i_mtime;
+       local_size  = tmp_inode->i_size;
+
+       tmp_inode->i_atime =
+           cifs_NTtimeToUnix(le64_to_cpu(pData->LastAccessTime));
+       tmp_inode->i_mtime =
+           cifs_NTtimeToUnix(le64_to_cpu(pData->LastModificationTime));
+       tmp_inode->i_ctime =
+           cifs_NTtimeToUnix(le64_to_cpu(pData->LastStatusChange));
+
+       tmp_inode->i_mode = le64_to_cpu(pData->Permissions);
+       /* since we set the inode type below we need to mask off type
+           to avoid strange results if bits above were corrupt */
+        tmp_inode->i_mode &= ~S_IFMT;
+       if (type == UNIX_FILE) {
+               *pobject_type = DT_REG;
+               tmp_inode->i_mode |= S_IFREG;
+       } else if (type == UNIX_SYMLINK) {
+               *pobject_type = DT_LNK;
+               tmp_inode->i_mode |= S_IFLNK;
+       } else if (type == UNIX_DIR) {
+               *pobject_type = DT_DIR;
+               tmp_inode->i_mode |= S_IFDIR;
+       } else if (type == UNIX_CHARDEV) {
+               *pobject_type = DT_CHR;
+               tmp_inode->i_mode |= S_IFCHR;
+               tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
+                               le64_to_cpu(pData->DevMinor) & MINORMASK);
+       } else if (type == UNIX_BLOCKDEV) {
+               *pobject_type = DT_BLK;
+               tmp_inode->i_mode |= S_IFBLK;
+               tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
+                               le64_to_cpu(pData->DevMinor) & MINORMASK);
+       } else if (type == UNIX_FIFO) {
+               *pobject_type = DT_FIFO;
+               tmp_inode->i_mode |= S_IFIFO;
+       } else if (type == UNIX_SOCKET) {
+               *pobject_type = DT_SOCK;
+               tmp_inode->i_mode |= S_IFSOCK;
+       } else {
+               /* safest to just call it a file */
+               *pobject_type = DT_REG;
+               tmp_inode->i_mode |= S_IFREG;
+               cFYI(1,("unknown inode type %d",type)); 
+       }
+
+#ifdef CONFIG_CIFS_DEBUG2
+       cFYI(1,("object type: %d", type));
+#endif
+       tmp_inode->i_uid = le64_to_cpu(pData->Uid);
+       tmp_inode->i_gid = le64_to_cpu(pData->Gid);
+       tmp_inode->i_nlink = le64_to_cpu(pData->Nlinks);
+
+       spin_lock(&tmp_inode->i_lock);
+       if (is_size_safe_to_change(cifsInfo, end_of_file)) {
+               /* can not safely change the file size here if the 
+               client is writing to it due to potential races */
+               i_size_write(tmp_inode, end_of_file);
+
+       /* 512 bytes (2**9) is the fake blocksize that must be used */
+       /* for this calculation, not the real blocksize */
+               tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
+       }
+       spin_unlock(&tmp_inode->i_lock);
+
+       if (S_ISREG(tmp_inode->i_mode)) {
+               cFYI(1, ("File inode"));
+               tmp_inode->i_op = &cifs_file_inode_ops;
+
+               if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+                       if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+                               tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
+                       else
+                               tmp_inode->i_fop = &cifs_file_direct_ops;
+               
+               } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+                       tmp_inode->i_fop = &cifs_file_nobrl_ops;
+               else
+                       tmp_inode->i_fop = &cifs_file_ops;
+
+               if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
+                  (cifs_sb->tcon->ses->server->maxBuf < 
+                       PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
+                       tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+               else
+                       tmp_inode->i_data.a_ops = &cifs_addr_ops;
+
+               if(isNewInode)
+                       return; /* No sense invalidating pages for new inode since we
+                                          have not started caching readahead file data yet */
+
+               if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
+                       (local_size == tmp_inode->i_size)) {
+                       cFYI(1, ("inode exists but unchanged"));
+               } else {
+                       /* file may have changed on server */
+                       cFYI(1, ("invalidate inode, readdir detected change"));
+                       invalidate_remote_inode(tmp_inode);
+               }
+       } else if (S_ISDIR(tmp_inode->i_mode)) {
+               cFYI(1, ("Directory inode"));
+               tmp_inode->i_op = &cifs_dir_inode_ops;
+               tmp_inode->i_fop = &cifs_dir_ops;
+       } else if (S_ISLNK(tmp_inode->i_mode)) {
+               cFYI(1, ("Symbolic Link inode"));
+               tmp_inode->i_op = &cifs_symlink_inode_ops;
+/* tmp_inode->i_fop = *//* do not need to set to anything */
+       } else {
+               cFYI(1, ("Special inode")); 
+               init_special_inode(tmp_inode, tmp_inode->i_mode,
+                                  tmp_inode->i_rdev);
+       }       
+}
+
 int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
 {
        int rc = 0;
@@ -755,6 +896,71 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                FreeXid(xid);
                return -ENOMEM;
        }
+       
+       if((pTcon->ses->capabilities & CAP_UNIX) && 
+               (CIFS_UNIX_POSIX_PATH_OPS_CAP & 
+                       le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
+               u32 oplock = 0;
+               FILE_UNIX_BASIC_INFO * pInfo = 
+                       kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
+               if(pInfo == NULL) {
+                       rc = -ENOMEM;
+                       goto mkdir_out;
+               }
+                       
+               rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
+                               mode, NULL /* netfid */, pInfo, &oplock,
+                               full_path, cifs_sb->local_nls, 
+                               cifs_sb->mnt_cifs_flags & 
+                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+               if (rc) {
+                       cFYI(1, ("posix mkdir returned 0x%x", rc));
+                       d_drop(direntry);
+               } else {
+                       int obj_type;
+                       if (pInfo->Type == -1) /* no return info - go query */
+                               goto mkdir_get_info; 
+/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */
+                       inc_nlink(inode);
+                       if (pTcon->nocase)
+                               direntry->d_op = &cifs_ci_dentry_ops;
+                       else
+                               direntry->d_op = &cifs_dentry_ops;
+
+                       newinode = new_inode(inode->i_sb);
+                       if (newinode == NULL)
+                               goto mkdir_get_info;
+                       /* 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) {
+                               newinode->i_ino =
+                                       (unsigned long)pInfo->UniqueId;
+                       } /* note ino incremented to unique num in new_inode */
+                       if(inode->i_sb->s_flags & MS_NOATIME)
+                               newinode->i_flags |= S_NOATIME | S_NOCMTIME;
+                       newinode->i_nlink = 2;
+
+                       insert_inode_hash(newinode);
+                       d_instantiate(direntry, newinode);
+
+                       /* we already checked in POSIXCreate whether
+                          frame was long enough */
+                       posix_fill_in_inode(direntry->d_inode,
+                                       pInfo, &obj_type, 1 /* NewInode */);
+#ifdef CONFIG_CIFS_DEBUG2
+                       cFYI(1,("instantiated dentry %p %s to inode %p",
+                               direntry, direntry->d_name.name, newinode));
+
+                       if(newinode->i_nlink != 2)
+                               cFYI(1,("unexpected number of links %d",
+                                       newinode->i_nlink));
+#endif
+               }
+               kfree(pInfo);
+               goto mkdir_out;
+       }       
+       
        /* BB add setting the equivalent of mode via CreateX w/ACLs */
        rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
                          cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -762,6 +968,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                cFYI(1, ("cifs_mkdir returned 0x%x", rc));
                d_drop(direntry);
        } else {
+mkdir_get_info:                
                inc_nlink(inode);
                if (pTcon->ses->capabilities & CAP_UNIX)
                        rc = cifs_get_inode_info_unix(&newinode, full_path,
@@ -775,9 +982,12 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                else
                        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)
+                /* setting nlink not necessary except in cases where we
+                 * failed to get it from the server or was set bogus */ 
+               if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
+                               direntry->d_inode->i_nlink = 2; 
+               if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
+                       mode &= ~current->fs->umask;
                        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
                                CIFSSMBUnixSetPerms(xid, pTcon, full_path,
                                                    mode,
@@ -795,7 +1005,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                                                    cifs_sb->mnt_cifs_flags & 
                                                    CIFS_MOUNT_MAP_SPECIAL_CHR);
                        }
-               else {
+               else {
                        /* BB to be implemented via Windows secrty descriptors
                           eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
                                                 -1, -1, local_nls); */
@@ -812,6 +1022,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                        }
                }
        }
+mkdir_out:     
        kfree(full_path);
        FreeXid(xid);
        return rc;
@@ -1339,17 +1550,17 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                                        cpu_to_le32(cifsInode->cifsAttrs |
                                                    ATTR_READONLY);
                        }
-               } else if ((mode & S_IWUGO) == S_IWUGO) {
-                       if (cifsInode->cifsAttrs & ATTR_READONLY) {
-                               set_dosattr = TRUE;
-                               time_buf.Attributes =
-                                       cpu_to_le32(cifsInode->cifsAttrs &
-                                                   (~ATTR_READONLY));
-                               /* Windows ignores set to zero */
-                               if(time_buf.Attributes == 0)
-                                       time_buf.Attributes |= 
-                                               cpu_to_le32(ATTR_NORMAL);
-                       }
+               } else if (cifsInode->cifsAttrs & ATTR_READONLY) {
+                       /* If file is readonly on server, we would
+                       not be able to write to it - so if any write
+                       bit is enabled for user or group or other we
+                       need to at least try to remove r/o dos attr */
+                       set_dosattr = TRUE;
+                       time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs &
+                                           (~ATTR_READONLY));
+                       /* Windows ignores set to zero */
+                       if(time_buf.Attributes == 0)
+                               time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
                }
                /* BB to be implemented -
                   via Windows security descriptors or streams */