|
@@ -41,7 +41,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|
|
char *tmp_path;
|
|
|
|
|
|
pTcon = cifs_sb->tcon;
|
|
|
- cFYI(1, (" Getting info on %s ", search_path));
|
|
|
+ cFYI(1, ("Getting info on %s ", search_path));
|
|
|
/* could have done a find first instead but this returns more info */
|
|
|
rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
|
|
|
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
|
|
@@ -97,9 +97,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|
|
inode = *pinode;
|
|
|
cifsInfo = CIFS_I(inode);
|
|
|
|
|
|
- cFYI(1, (" Old time %ld ", cifsInfo->time));
|
|
|
+ cFYI(1, ("Old time %ld ", cifsInfo->time));
|
|
|
cifsInfo->time = jiffies;
|
|
|
- cFYI(1, (" New time %ld ", cifsInfo->time));
|
|
|
+ cFYI(1, ("New time %ld ", cifsInfo->time));
|
|
|
/* this is ok to set on every inode revalidate */
|
|
|
atomic_set(&cifsInfo->inUse,1);
|
|
|
|
|
@@ -111,6 +111,9 @@ int 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);
|
|
|
+ /* since we set the inode type below we need to mask off
|
|
|
+ to avoid strange results if bits set above */
|
|
|
+ inode->i_mode &= ~S_IFMT;
|
|
|
if (type == UNIX_FILE) {
|
|
|
inode->i_mode |= S_IFREG;
|
|
|
} else if (type == UNIX_SYMLINK) {
|
|
@@ -129,6 +132,10 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|
|
inode->i_mode |= S_IFIFO;
|
|
|
} else if (type == UNIX_SOCKET) {
|
|
|
inode->i_mode |= S_IFSOCK;
|
|
|
+ } else {
|
|
|
+ /* safest to call it a file if we do not know */
|
|
|
+ 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);
|
|
@@ -155,34 +162,39 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|
|
}
|
|
|
|
|
|
if (num_of_bytes < end_of_file)
|
|
|
- cFYI(1, ("allocation size less than end of file "));
|
|
|
+ cFYI(1, ("allocation size less than end of file"));
|
|
|
cFYI(1,
|
|
|
("Size %ld and blocks %ld",
|
|
|
(unsigned long) inode->i_size, inode->i_blocks));
|
|
|
if (S_ISREG(inode->i_mode)) {
|
|
|
- cFYI(1, (" File inode "));
|
|
|
+ cFYI(1, ("File inode"));
|
|
|
inode->i_op = &cifs_file_inode_ops;
|
|
|
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
|
|
|
- inode->i_fop = &cifs_file_direct_ops;
|
|
|
- else
|
|
|
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
|
|
|
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
|
|
+ inode->i_fop =
|
|
|
+ &cifs_file_direct_nobrl_ops;
|
|
|
+ else
|
|
|
+ inode->i_fop = &cifs_file_direct_ops;
|
|
|
+ } 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(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
|
|
- inode->i_fop->lock = NULL;
|
|
|
+
|
|
|
inode->i_data.a_ops = &cifs_addr_ops;
|
|
|
/* check if server can support readpages */
|
|
|
if(pTcon->ses->server->maxBuf <
|
|
|
4096 + MAX_CIFS_HDR_SIZE)
|
|
|
inode->i_data.a_ops->readpages = NULL;
|
|
|
} else if (S_ISDIR(inode->i_mode)) {
|
|
|
- cFYI(1, (" Directory inode"));
|
|
|
+ cFYI(1, ("Directory inode"));
|
|
|
inode->i_op = &cifs_dir_inode_ops;
|
|
|
inode->i_fop = &cifs_dir_ops;
|
|
|
} else if (S_ISLNK(inode->i_mode)) {
|
|
|
- cFYI(1, (" Symbolic Link inode "));
|
|
|
+ cFYI(1, ("Symbolic Link inode"));
|
|
|
inode->i_op = &cifs_symlink_inode_ops;
|
|
|
/* tmp_inode->i_fop = */ /* do not need to set to anything */
|
|
|
} else {
|
|
|
- cFYI(1, (" Init special inode "));
|
|
|
+ cFYI(1, ("Init special inode"));
|
|
|
init_special_inode(inode, inode->i_mode,
|
|
|
inode->i_rdev);
|
|
|
}
|
|
@@ -190,6 +202,111 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+static int decode_sfu_inode(struct inode * inode, __u64 size,
|
|
|
+ const unsigned char *path,
|
|
|
+ struct cifs_sb_info *cifs_sb, int xid)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ int oplock = FALSE;
|
|
|
+ __u16 netfid;
|
|
|
+ struct cifsTconInfo *pTcon = cifs_sb->tcon;
|
|
|
+ char buf[24];
|
|
|
+ unsigned int bytes_read;
|
|
|
+ char * pbuf;
|
|
|
+
|
|
|
+ pbuf = buf;
|
|
|
+
|
|
|
+ if(size == 0) {
|
|
|
+ inode->i_mode |= S_IFIFO;
|
|
|
+ return 0;
|
|
|
+ } else if (size < 8) {
|
|
|
+ return -EINVAL; /* EOPNOTSUPP? */
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
|
|
|
+ CREATE_NOT_DIR, &netfid, &oplock, NULL,
|
|
|
+ cifs_sb->local_nls,
|
|
|
+ cifs_sb->mnt_cifs_flags &
|
|
|
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
|
|
|
+ if (rc==0) {
|
|
|
+ /* Read header */
|
|
|
+ rc = CIFSSMBRead(xid, pTcon,
|
|
|
+ netfid,
|
|
|
+ 24 /* length */, 0 /* offset */,
|
|
|
+ &bytes_read, &pbuf);
|
|
|
+ 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) {
|
|
|
+ /* we have enough to decode dev num */
|
|
|
+ __u64 mjr; /* major */
|
|
|
+ __u64 mnr; /* minor */
|
|
|
+ mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
|
|
|
+ mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
|
|
|
+ inode->i_rdev = MKDEV(mjr, mnr);
|
|
|
+ }
|
|
|
+ } else if(memcmp("IntxCHR", pbuf, 8) == 0) {
|
|
|
+ cFYI(1,("Char device"));
|
|
|
+ inode->i_mode |= S_IFCHR;
|
|
|
+ if(bytes_read == 24) {
|
|
|
+ /* we have enough to decode dev num */
|
|
|
+ __u64 mjr; /* major */
|
|
|
+ __u64 mnr; /* minor */
|
|
|
+ mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
|
|
|
+ mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
|
|
|
+ inode->i_rdev = MKDEV(mjr, mnr);
|
|
|
+ }
|
|
|
+ } else if(memcmp("IntxLNK", pbuf, 7) == 0) {
|
|
|
+ cFYI(1,("Symlink"));
|
|
|
+ inode->i_mode |= S_IFLNK;
|
|
|
+ } else {
|
|
|
+ inode->i_mode |= S_IFREG; /* file? */
|
|
|
+ rc = -EOPNOTSUPP;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ inode->i_mode |= S_IFREG; /* then it is a file */
|
|
|
+ rc = -EOPNOTSUPP; /* or some unknown SFU type */
|
|
|
+ }
|
|
|
+ CIFSSMBClose(xid, pTcon, netfid);
|
|
|
+ }
|
|
|
+ return rc;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
|
|
|
+
|
|
|
+static int get_sfu_uid_mode(struct inode * inode,
|
|
|
+ const unsigned char *path,
|
|
|
+ struct cifs_sb_info *cifs_sb, int xid)
|
|
|
+{
|
|
|
+#ifdef CONFIG_CIFS_XATTR
|
|
|
+ ssize_t rc;
|
|
|
+ char ea_value[4];
|
|
|
+ __u32 mode;
|
|
|
+
|
|
|
+ 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)
|
|
|
+ return (int)rc;
|
|
|
+ else if (rc > 3) {
|
|
|
+ mode = le32_to_cpu(*((__le32 *)ea_value));
|
|
|
+ inode->i_mode &= ~SFBITS_MASK;
|
|
|
+ cFYI(1,("special bits 0%o org mode 0%o", mode, inode->i_mode));
|
|
|
+ inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode;
|
|
|
+ cFYI(1,("special mode bits 0%o", mode));
|
|
|
+ return 0;
|
|
|
+ } else {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+#else
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
int cifs_get_inode_info(struct inode **pinode,
|
|
|
const unsigned char *search_path, FILE_ALL_INFO *pfindData,
|
|
|
struct super_block *sb, int xid)
|
|
@@ -202,7 +319,7 @@ int cifs_get_inode_info(struct inode **pinode,
|
|
|
char *buf = NULL;
|
|
|
|
|
|
pTcon = cifs_sb->tcon;
|
|
|
- cFYI(1,("Getting info on %s ", search_path));
|
|
|
+ cFYI(1,("Getting info on %s", search_path));
|
|
|
|
|
|
if ((pfindData == NULL) && (*pinode != NULL)) {
|
|
|
if (CIFS_I(*pinode)->clientCanCacheRead) {
|
|
@@ -303,9 +420,9 @@ int cifs_get_inode_info(struct inode **pinode,
|
|
|
inode = *pinode;
|
|
|
cifsInfo = CIFS_I(inode);
|
|
|
cifsInfo->cifsAttrs = attr;
|
|
|
- cFYI(1, (" Old time %ld ", cifsInfo->time));
|
|
|
+ cFYI(1, ("Old time %ld ", cifsInfo->time));
|
|
|
cifsInfo->time = jiffies;
|
|
|
- cFYI(1, (" New time %ld ", cifsInfo->time));
|
|
|
+ cFYI(1, ("New time %ld ", cifsInfo->time));
|
|
|
|
|
|
/* blksize needs to be multiple of two. So safer to default to
|
|
|
blksize and blkbits set in superblock so 2**blkbits and blksize
|
|
@@ -319,13 +436,15 @@ int cifs_get_inode_info(struct inode **pinode,
|
|
|
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
|
|
|
inode->i_ctime =
|
|
|
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
|
|
|
- cFYI(0, (" Attributes came in as 0x%x ", attr));
|
|
|
+ cFYI(0, ("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;
|
|
|
-
|
|
|
+ else /* since we set the inode type below we need to mask off
|
|
|
+ to avoid strange results if type changes and both get orred in */
|
|
|
+ inode->i_mode &= ~S_IFMT;
|
|
|
/* 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 */
|
|
@@ -340,10 +459,16 @@ int cifs_get_inode_info(struct inode **pinode,
|
|
|
(pfindData->EndOfFile == 0)) {
|
|
|
inode->i_mode = cifs_sb->mnt_file_mode;
|
|
|
inode->i_mode |= S_IFIFO;
|
|
|
-/* BB Finish for SFU style symlinks and devies */
|
|
|
-/* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
|
|
|
- (cifsInfo->cifsAttrs & ATTR_SYSTEM) && ) */
|
|
|
-
|
|
|
+/* BB Finish for SFU style symlinks and devices */
|
|
|
+ } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
|
|
|
+ (cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
|
|
|
+ if (decode_sfu_inode(inode,
|
|
|
+ le64_to_cpu(pfindData->EndOfFile),
|
|
|
+ search_path,
|
|
|
+ cifs_sb, xid)) {
|
|
|
+ cFYI(1,("Unrecognized sfu inode type"));
|
|
|
+ }
|
|
|
+ cFYI(1,("sfu mode 0%o",inode->i_mode));
|
|
|
} else {
|
|
|
inode->i_mode |= S_IFREG;
|
|
|
/* treat the dos attribute of read-only as read-only
|
|
@@ -368,7 +493,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 (atomic_read(&cifsInfo->inUse) == 0) {
|
|
|
+ if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
|
|
|
+ /* fill in uid, gid, mode from server ACL */
|
|
|
+ get_sfu_uid_mode(inode, search_path, cifs_sb, xid);
|
|
|
+ } else if (atomic_read(&cifsInfo->inUse) == 0) {
|
|
|
inode->i_uid = cifs_sb->mnt_uid;
|
|
|
inode->i_gid = cifs_sb->mnt_gid;
|
|
|
/* set so we do not keep refreshing these fields with
|
|
@@ -377,24 +505,29 @@ int cifs_get_inode_info(struct inode **pinode,
|
|
|
}
|
|
|
|
|
|
if (S_ISREG(inode->i_mode)) {
|
|
|
- cFYI(1, (" File inode "));
|
|
|
+ cFYI(1, ("File inode"));
|
|
|
inode->i_op = &cifs_file_inode_ops;
|
|
|
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
|
|
|
- inode->i_fop = &cifs_file_direct_ops;
|
|
|
- else
|
|
|
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
|
|
|
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
|
|
+ inode->i_fop =
|
|
|
+ &cifs_file_direct_nobrl_ops;
|
|
|
+ else
|
|
|
+ inode->i_fop = &cifs_file_direct_ops;
|
|
|
+ } 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(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
|
|
- inode->i_fop->lock = NULL;
|
|
|
+
|
|
|
inode->i_data.a_ops = &cifs_addr_ops;
|
|
|
if(pTcon->ses->server->maxBuf <
|
|
|
4096 + MAX_CIFS_HDR_SIZE)
|
|
|
inode->i_data.a_ops->readpages = NULL;
|
|
|
} else if (S_ISDIR(inode->i_mode)) {
|
|
|
- cFYI(1, (" Directory inode "));
|
|
|
+ cFYI(1, ("Directory inode"));
|
|
|
inode->i_op = &cifs_dir_inode_ops;
|
|
|
inode->i_fop = &cifs_dir_ops;
|
|
|
} else if (S_ISLNK(inode->i_mode)) {
|
|
|
- cFYI(1, (" Symbolic Link inode "));
|
|
|
+ cFYI(1, ("Symbolic Link inode"));
|
|
|
inode->i_op = &cifs_symlink_inode_ops;
|
|
|
} else {
|
|
|
init_special_inode(inode, inode->i_mode,
|
|
@@ -431,7 +564,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
|
|
|
struct cifsInodeInfo *cifsInode;
|
|
|
FILE_BASIC_INFO *pinfo_buf;
|
|
|
|
|
|
- cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
|
|
|
+ cFYI(1, ("cifs_unlink, inode = 0x%p with ", inode));
|
|
|
|
|
|
xid = GetXid();
|
|
|
|
|
@@ -651,7 +784,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
|
|
|
char *full_path = NULL;
|
|
|
struct cifsInodeInfo *cifsInode;
|
|
|
|
|
|
- cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
|
|
|
+ cFYI(1, ("cifs_rmdir, inode = 0x%p with ", inode));
|
|
|
|
|
|
xid = GetXid();
|
|
|
|
|
@@ -970,7 +1103,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|
|
|
|
|
xid = GetXid();
|
|
|
|
|
|
- cFYI(1, (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
|
|
|
+ cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x ",
|
|
|
direntry->d_name.name, attrs->ia_valid));
|
|
|
cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
|
|
|
pTcon = cifs_sb->tcon;
|
|
@@ -1086,6 +1219,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|
|
cifs_sb->mnt_cifs_flags &
|
|
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
|
|
else if (attrs->ia_valid & ATTR_MODE) {
|
|
|
+ rc = 0;
|
|
|
if ((mode & S_IWUGO) == 0) /* not writeable */ {
|
|
|
if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
|
|
|
time_buf.Attributes =
|