cifs: convert cifs_get_inode_info and non-posix readdir to use cifs_iget
cifs: convert cifs_get_inode_info and non-posix readdir to use cifs_iget Rather than allocating an inode and filling it out, have cifs_get_inode_info fill out a cifs_fattr and call cifs_iget. This means a pretty hefty reorganization of cifs_get_inode_info. For the readdir codepath, add a couple of new functions for filling out cifs_fattr's from different FindFile response infolevels. Finally, remove cifs_new_inode since there are no more callers. Signed-off-by: Jeff Layton <jlayton@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
parent
b77863bfa1
commit
0b8f18e358
5 changed files with 249 additions and 526 deletions
|
@ -327,7 +327,7 @@ static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
|
||||||
|
|
||||||
static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
||||||
struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
|
struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
|
||||||
struct inode *inode)
|
struct cifs_fattr *fattr)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int num_aces = 0;
|
int num_aces = 0;
|
||||||
|
@ -340,7 +340,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
||||||
if (!pdacl) {
|
if (!pdacl) {
|
||||||
/* no DACL in the security descriptor, set
|
/* no DACL in the security descriptor, set
|
||||||
all the permissions for user/group/other */
|
all the permissions for user/group/other */
|
||||||
inode->i_mode |= S_IRWXUGO;
|
fattr->cf_mode |= S_IRWXUGO;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,7 +357,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
||||||
/* reset rwx permissions for user/group/other.
|
/* reset rwx permissions for user/group/other.
|
||||||
Also, if num_aces is 0 i.e. DACL has no ACEs,
|
Also, if num_aces is 0 i.e. DACL has no ACEs,
|
||||||
user/group/other have no permissions */
|
user/group/other have no permissions */
|
||||||
inode->i_mode &= ~(S_IRWXUGO);
|
fattr->cf_mode &= ~(S_IRWXUGO);
|
||||||
|
|
||||||
acl_base = (char *)pdacl;
|
acl_base = (char *)pdacl;
|
||||||
acl_size = sizeof(struct cifs_acl);
|
acl_size = sizeof(struct cifs_acl);
|
||||||
|
@ -379,17 +379,17 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
||||||
if (compare_sids(&(ppace[i]->sid), pownersid))
|
if (compare_sids(&(ppace[i]->sid), pownersid))
|
||||||
access_flags_to_mode(ppace[i]->access_req,
|
access_flags_to_mode(ppace[i]->access_req,
|
||||||
ppace[i]->type,
|
ppace[i]->type,
|
||||||
&(inode->i_mode),
|
&fattr->cf_mode,
|
||||||
&user_mask);
|
&user_mask);
|
||||||
if (compare_sids(&(ppace[i]->sid), pgrpsid))
|
if (compare_sids(&(ppace[i]->sid), pgrpsid))
|
||||||
access_flags_to_mode(ppace[i]->access_req,
|
access_flags_to_mode(ppace[i]->access_req,
|
||||||
ppace[i]->type,
|
ppace[i]->type,
|
||||||
&(inode->i_mode),
|
&fattr->cf_mode,
|
||||||
&group_mask);
|
&group_mask);
|
||||||
if (compare_sids(&(ppace[i]->sid), &sid_everyone))
|
if (compare_sids(&(ppace[i]->sid), &sid_everyone))
|
||||||
access_flags_to_mode(ppace[i]->access_req,
|
access_flags_to_mode(ppace[i]->access_req,
|
||||||
ppace[i]->type,
|
ppace[i]->type,
|
||||||
&(inode->i_mode),
|
&fattr->cf_mode,
|
||||||
&other_mask);
|
&other_mask);
|
||||||
|
|
||||||
/* memcpy((void *)(&(cifscred->aces[i])),
|
/* memcpy((void *)(&(cifscred->aces[i])),
|
||||||
|
@ -464,7 +464,7 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
|
||||||
|
|
||||||
/* Convert CIFS ACL to POSIX form */
|
/* Convert CIFS ACL to POSIX form */
|
||||||
static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
|
static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
|
||||||
struct inode *inode)
|
struct cifs_fattr *fattr)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
|
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
|
||||||
|
@ -472,7 +472,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
|
||||||
char *end_of_acl = ((char *)pntsd) + acl_len;
|
char *end_of_acl = ((char *)pntsd) + acl_len;
|
||||||
__u32 dacloffset;
|
__u32 dacloffset;
|
||||||
|
|
||||||
if ((inode == NULL) || (pntsd == NULL))
|
if (pntsd == NULL)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
||||||
|
@ -497,7 +497,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
|
||||||
|
|
||||||
if (dacloffset)
|
if (dacloffset)
|
||||||
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
|
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
|
||||||
group_sid_ptr, inode);
|
group_sid_ptr, fattr);
|
||||||
else
|
else
|
||||||
cFYI(1, ("no ACL")); /* BB grant all or default perms? */
|
cFYI(1, ("no ACL")); /* BB grant all or default perms? */
|
||||||
|
|
||||||
|
@ -508,7 +508,6 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
|
||||||
memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
|
memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
|
||||||
sizeof(struct cifs_sid)); */
|
sizeof(struct cifs_sid)); */
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -671,8 +670,9 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
|
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
|
||||||
void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
|
void
|
||||||
const char *path, const __u16 *pfid)
|
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
||||||
|
struct inode *inode, const char *path, const __u16 *pfid)
|
||||||
{
|
{
|
||||||
struct cifs_ntsd *pntsd = NULL;
|
struct cifs_ntsd *pntsd = NULL;
|
||||||
u32 acllen = 0;
|
u32 acllen = 0;
|
||||||
|
@ -687,7 +687,7 @@ void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
|
||||||
|
|
||||||
/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
|
/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
|
||||||
if (pntsd)
|
if (pntsd)
|
||||||
rc = parse_sec_desc(pntsd, acllen, inode);
|
rc = parse_sec_desc(pntsd, acllen, fattr);
|
||||||
if (rc)
|
if (rc)
|
||||||
cFYI(1, ("parse sec desc failed rc = %d", rc));
|
cFYI(1, ("parse sec desc failed rc = %d", rc));
|
||||||
|
|
||||||
|
|
|
@ -479,6 +479,8 @@ struct dfs_info3_param {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CIFS_FATTR_DFS_REFERRAL 0x1
|
#define CIFS_FATTR_DFS_REFERRAL 0x1
|
||||||
|
#define CIFS_FATTR_DELETE_PENDING 0x2
|
||||||
|
#define CIFS_FATTR_NEED_REVAL 0x4
|
||||||
|
|
||||||
struct cifs_fattr {
|
struct cifs_fattr {
|
||||||
u32 cf_flags;
|
u32 cf_flags;
|
||||||
|
|
|
@ -102,7 +102,6 @@ extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
|
||||||
FILE_UNIX_BASIC_INFO *info,
|
FILE_UNIX_BASIC_INFO *info,
|
||||||
struct cifs_sb_info *cifs_sb);
|
struct cifs_sb_info *cifs_sb);
|
||||||
extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr);
|
extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr);
|
||||||
extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum);
|
|
||||||
extern struct inode *cifs_iget(struct super_block *sb,
|
extern struct inode *cifs_iget(struct super_block *sb,
|
||||||
struct cifs_fattr *fattr);
|
struct cifs_fattr *fattr);
|
||||||
|
|
||||||
|
@ -113,8 +112,9 @@ extern int cifs_get_inode_info(struct inode **pinode,
|
||||||
extern int cifs_get_inode_info_unix(struct inode **pinode,
|
extern int cifs_get_inode_info_unix(struct inode **pinode,
|
||||||
const unsigned char *search_path,
|
const unsigned char *search_path,
|
||||||
struct super_block *sb, int xid);
|
struct super_block *sb, int xid);
|
||||||
extern void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
|
extern void cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
|
||||||
const char *path, const __u16 *pfid);
|
struct cifs_fattr *fattr, struct inode *inode,
|
||||||
|
const char *path, const __u16 *pfid);
|
||||||
extern int mode_to_acl(struct inode *inode, const char *path, __u64);
|
extern int mode_to_acl(struct inode *inode, const char *path, __u64);
|
||||||
|
|
||||||
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
|
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
|
||||||
|
|
397
fs/cifs/inode.c
397
fs/cifs/inode.c
|
@ -82,23 +82,34 @@ void
|
||||||
cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
||||||
{
|
{
|
||||||
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
|
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
|
||||||
unsigned long now = jiffies;
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||||
|
unsigned long oldtime = cifs_i->time;
|
||||||
|
|
||||||
inode->i_atime = fattr->cf_atime;
|
inode->i_atime = fattr->cf_atime;
|
||||||
inode->i_mtime = fattr->cf_mtime;
|
inode->i_mtime = fattr->cf_mtime;
|
||||||
inode->i_ctime = fattr->cf_ctime;
|
inode->i_ctime = fattr->cf_ctime;
|
||||||
inode->i_mode = fattr->cf_mode;
|
|
||||||
inode->i_rdev = fattr->cf_rdev;
|
inode->i_rdev = fattr->cf_rdev;
|
||||||
inode->i_nlink = fattr->cf_nlink;
|
inode->i_nlink = fattr->cf_nlink;
|
||||||
inode->i_uid = fattr->cf_uid;
|
inode->i_uid = fattr->cf_uid;
|
||||||
inode->i_gid = fattr->cf_gid;
|
inode->i_gid = fattr->cf_gid;
|
||||||
|
|
||||||
|
/* if dynperm is set, don't clobber existing mode */
|
||||||
|
if (inode->i_state & I_NEW ||
|
||||||
|
!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
|
||||||
|
inode->i_mode = fattr->cf_mode;
|
||||||
|
|
||||||
cifs_i->cifsAttrs = fattr->cf_cifsattrs;
|
cifs_i->cifsAttrs = fattr->cf_cifsattrs;
|
||||||
cifs_i->uniqueid = fattr->cf_uniqueid;
|
cifs_i->uniqueid = fattr->cf_uniqueid;
|
||||||
|
|
||||||
|
if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
|
||||||
|
cifs_i->time = 0;
|
||||||
|
else
|
||||||
|
cifs_i->time = jiffies;
|
||||||
|
|
||||||
cFYI(1, ("inode 0x%p old_time=%ld new_time=%ld", inode,
|
cFYI(1, ("inode 0x%p old_time=%ld new_time=%ld", inode,
|
||||||
cifs_i->time, now));
|
oldtime, cifs_i->time));
|
||||||
cifs_i->time = now;
|
|
||||||
|
cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Can't safely change the file size here if the client is writing to
|
* Can't safely change the file size here if the client is writing to
|
||||||
|
@ -219,49 +230,6 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
|
||||||
fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
|
fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* cifs_new inode - create new inode, initialize, and hash it
|
|
||||||
* @sb - pointer to superblock
|
|
||||||
* @inum - if valid pointer and serverino is enabled, replace i_ino with val
|
|
||||||
*
|
|
||||||
* Create a new inode, initialize it for CIFS and hash it. Returns the new
|
|
||||||
* inode or NULL if one couldn't be allocated.
|
|
||||||
*
|
|
||||||
* If the share isn't mounted with "serverino" or inum is a NULL pointer then
|
|
||||||
* we'll just use the inode number assigned by new_inode(). Note that this can
|
|
||||||
* mean i_ino collisions since the i_ino assigned by new_inode is not
|
|
||||||
* guaranteed to be unique.
|
|
||||||
*/
|
|
||||||
struct inode *
|
|
||||||
cifs_new_inode(struct super_block *sb, __u64 *inum)
|
|
||||||
{
|
|
||||||
struct inode *inode;
|
|
||||||
|
|
||||||
inode = new_inode(sb);
|
|
||||||
if (inode == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* BB: Is i_ino == 0 legal? Here, we assume that it is. If it isn't we
|
|
||||||
* stop passing inum as ptr. Are there sanity checks we can use to
|
|
||||||
* ensure that the server is really filling in that field? Also,
|
|
||||||
* if serverino is disabled, perhaps we should be using iunique()?
|
|
||||||
*/
|
|
||||||
if (inum && (CIFS_SB(sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
|
|
||||||
inode->i_ino = (unsigned long) *inum;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* must set this here instead of cifs_alloc_inode since VFS will
|
|
||||||
* clobber i_flags
|
|
||||||
*/
|
|
||||||
if (sb->s_flags & MS_NOATIME)
|
|
||||||
inode->i_flags |= S_NOATIME | S_NOCMTIME;
|
|
||||||
|
|
||||||
insert_inode_hash(inode);
|
|
||||||
|
|
||||||
return inode;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cifs_get_inode_info_unix(struct inode **pinode,
|
int cifs_get_inode_info_unix(struct inode **pinode,
|
||||||
const unsigned char *full_path,
|
const unsigned char *full_path,
|
||||||
struct super_block *sb, int xid)
|
struct super_block *sb, int xid)
|
||||||
|
@ -302,9 +270,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decode_sfu_inode(struct inode *inode, __u64 size,
|
static int
|
||||||
const unsigned char *path,
|
cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
|
||||||
struct cifs_sb_info *cifs_sb, int xid)
|
struct cifs_sb_info *cifs_sb, int xid)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
int oplock = 0;
|
int oplock = 0;
|
||||||
|
@ -316,10 +284,15 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
|
||||||
|
|
||||||
pbuf = buf;
|
pbuf = buf;
|
||||||
|
|
||||||
if (size == 0) {
|
fattr->cf_mode &= ~S_IFMT;
|
||||||
inode->i_mode |= S_IFIFO;
|
|
||||||
|
if (fattr->cf_eof == 0) {
|
||||||
|
fattr->cf_mode |= S_IFIFO;
|
||||||
|
fattr->cf_dtype = DT_FIFO;
|
||||||
return 0;
|
return 0;
|
||||||
} else if (size < 8) {
|
} else if (fattr->cf_eof < 8) {
|
||||||
|
fattr->cf_mode |= S_IFREG;
|
||||||
|
fattr->cf_dtype = DT_REG;
|
||||||
return -EINVAL; /* EOPNOTSUPP? */
|
return -EINVAL; /* EOPNOTSUPP? */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,42 +304,46 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
int buf_type = CIFS_NO_BUFFER;
|
int buf_type = CIFS_NO_BUFFER;
|
||||||
/* Read header */
|
/* Read header */
|
||||||
rc = CIFSSMBRead(xid, pTcon,
|
rc = CIFSSMBRead(xid, pTcon, netfid,
|
||||||
netfid,
|
|
||||||
24 /* length */, 0 /* offset */,
|
24 /* length */, 0 /* offset */,
|
||||||
&bytes_read, &pbuf, &buf_type);
|
&bytes_read, &pbuf, &buf_type);
|
||||||
if ((rc == 0) && (bytes_read >= 8)) {
|
if ((rc == 0) && (bytes_read >= 8)) {
|
||||||
if (memcmp("IntxBLK", pbuf, 8) == 0) {
|
if (memcmp("IntxBLK", pbuf, 8) == 0) {
|
||||||
cFYI(1, ("Block device"));
|
cFYI(1, ("Block device"));
|
||||||
inode->i_mode |= S_IFBLK;
|
fattr->cf_mode |= S_IFBLK;
|
||||||
|
fattr->cf_dtype = DT_BLK;
|
||||||
if (bytes_read == 24) {
|
if (bytes_read == 24) {
|
||||||
/* we have enough to decode dev num */
|
/* we have enough to decode dev num */
|
||||||
__u64 mjr; /* major */
|
__u64 mjr; /* major */
|
||||||
__u64 mnr; /* minor */
|
__u64 mnr; /* minor */
|
||||||
mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
|
mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
|
||||||
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
|
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
|
||||||
inode->i_rdev = MKDEV(mjr, mnr);
|
fattr->cf_rdev = MKDEV(mjr, mnr);
|
||||||
}
|
}
|
||||||
} else if (memcmp("IntxCHR", pbuf, 8) == 0) {
|
} else if (memcmp("IntxCHR", pbuf, 8) == 0) {
|
||||||
cFYI(1, ("Char device"));
|
cFYI(1, ("Char device"));
|
||||||
inode->i_mode |= S_IFCHR;
|
fattr->cf_mode |= S_IFCHR;
|
||||||
|
fattr->cf_dtype = DT_CHR;
|
||||||
if (bytes_read == 24) {
|
if (bytes_read == 24) {
|
||||||
/* we have enough to decode dev num */
|
/* we have enough to decode dev num */
|
||||||
__u64 mjr; /* major */
|
__u64 mjr; /* major */
|
||||||
__u64 mnr; /* minor */
|
__u64 mnr; /* minor */
|
||||||
mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
|
mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
|
||||||
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
|
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
|
||||||
inode->i_rdev = MKDEV(mjr, mnr);
|
fattr->cf_rdev = MKDEV(mjr, mnr);
|
||||||
}
|
}
|
||||||
} else if (memcmp("IntxLNK", pbuf, 7) == 0) {
|
} else if (memcmp("IntxLNK", pbuf, 7) == 0) {
|
||||||
cFYI(1, ("Symlink"));
|
cFYI(1, ("Symlink"));
|
||||||
inode->i_mode |= S_IFLNK;
|
fattr->cf_mode |= S_IFLNK;
|
||||||
|
fattr->cf_dtype = DT_LNK;
|
||||||
} else {
|
} else {
|
||||||
inode->i_mode |= S_IFREG; /* file? */
|
fattr->cf_mode |= S_IFREG; /* file? */
|
||||||
|
fattr->cf_dtype = DT_REG;
|
||||||
rc = -EOPNOTSUPP;
|
rc = -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
inode->i_mode |= S_IFREG; /* then it is a file */
|
fattr->cf_mode |= S_IFREG; /* then it is a file */
|
||||||
|
fattr->cf_dtype = DT_REG;
|
||||||
rc = -EOPNOTSUPP; /* or some unknown SFU type */
|
rc = -EOPNOTSUPP; /* or some unknown SFU type */
|
||||||
}
|
}
|
||||||
CIFSSMBClose(xid, pTcon, netfid);
|
CIFSSMBClose(xid, pTcon, netfid);
|
||||||
|
@ -376,9 +353,13 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
|
||||||
|
|
||||||
#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
|
#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
|
||||||
|
|
||||||
static int get_sfu_mode(struct inode *inode,
|
/*
|
||||||
const unsigned char *path,
|
* Fetch mode bits as provided by SFU.
|
||||||
struct cifs_sb_info *cifs_sb, int xid)
|
*
|
||||||
|
* FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ?
|
||||||
|
*/
|
||||||
|
static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
|
||||||
|
struct cifs_sb_info *cifs_sb, int xid)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_CIFS_XATTR
|
#ifdef CONFIG_CIFS_XATTR
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
|
@ -386,68 +367,80 @@ static int get_sfu_mode(struct inode *inode,
|
||||||
__u32 mode;
|
__u32 mode;
|
||||||
|
|
||||||
rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
|
rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
|
||||||
ea_value, 4 /* size of buf */, cifs_sb->local_nls,
|
ea_value, 4 /* size of buf */, cifs_sb->local_nls,
|
||||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
cifs_sb->mnt_cifs_flags &
|
||||||
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return (int)rc;
|
return (int)rc;
|
||||||
else if (rc > 3) {
|
else if (rc > 3) {
|
||||||
mode = le32_to_cpu(*((__le32 *)ea_value));
|
mode = le32_to_cpu(*((__le32 *)ea_value));
|
||||||
inode->i_mode &= ~SFBITS_MASK;
|
fattr->cf_mode &= ~SFBITS_MASK;
|
||||||
cFYI(1, ("special bits 0%o org mode 0%o", mode, inode->i_mode));
|
cFYI(1, ("special bits 0%o org mode 0%o", mode,
|
||||||
inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode;
|
fattr->cf_mode));
|
||||||
|
fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode;
|
||||||
cFYI(1, ("special mode bits 0%o", mode));
|
cFYI(1, ("special mode bits 0%o", mode));
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
#else
|
#else
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
|
||||||
* Needed to setup inode data for the directory which is the
|
void
|
||||||
* junction to the new submount (ie to setup the fake directory
|
cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
|
||||||
* which represents a DFS referral)
|
struct cifs_sb_info *cifs_sb, bool adjust_tz)
|
||||||
*/
|
|
||||||
static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat,
|
|
||||||
struct super_block *sb)
|
|
||||||
{
|
{
|
||||||
memset(pfnd_dat, 0, sizeof(FILE_ALL_INFO));
|
memset(fattr, 0, sizeof(*fattr));
|
||||||
|
fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
|
||||||
|
if (info->DeletePending)
|
||||||
|
fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;
|
||||||
|
|
||||||
/* __le64 pfnd_dat->AllocationSize = cpu_to_le64(0);
|
if (info->LastAccessTime)
|
||||||
__le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
|
fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
|
||||||
__u8 pfnd_dat->DeletePending = 0;
|
else
|
||||||
__u8 pfnd_data->Directory = 0;
|
fattr->cf_atime = CURRENT_TIME;
|
||||||
__le32 pfnd_dat->EASize = 0;
|
|
||||||
__u64 pfnd_dat->IndexNumber = 0;
|
fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
|
||||||
__u64 pfnd_dat->IndexNumber1 = 0; */
|
fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
|
||||||
pfnd_dat->CreationTime =
|
|
||||||
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
|
if (adjust_tz) {
|
||||||
pfnd_dat->LastAccessTime =
|
fattr->cf_ctime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
|
||||||
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
|
fattr->cf_mtime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
|
||||||
pfnd_dat->LastWriteTime =
|
}
|
||||||
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
|
|
||||||
pfnd_dat->ChangeTime =
|
fattr->cf_eof = le64_to_cpu(info->EndOfFile);
|
||||||
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
|
fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
|
||||||
pfnd_dat->Attributes = cpu_to_le32(ATTR_DIRECTORY);
|
|
||||||
pfnd_dat->NumberOfLinks = cpu_to_le32(2);
|
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
|
||||||
|
fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
|
||||||
|
fattr->cf_dtype = DT_DIR;
|
||||||
|
} else {
|
||||||
|
fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
|
||||||
|
fattr->cf_dtype = DT_REG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clear write bits if ATTR_READONLY is set */
|
||||||
|
if (fattr->cf_cifsattrs & ATTR_READONLY)
|
||||||
|
fattr->cf_mode &= ~(S_IWUGO);
|
||||||
|
|
||||||
|
fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
|
||||||
|
|
||||||
|
fattr->cf_uid = cifs_sb->mnt_uid;
|
||||||
|
fattr->cf_gid = cifs_sb->mnt_gid;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cifs_get_inode_info(struct inode **pinode,
|
int cifs_get_inode_info(struct inode **pinode,
|
||||||
const unsigned char *full_path, FILE_ALL_INFO *pfindData,
|
const unsigned char *full_path, FILE_ALL_INFO *pfindData,
|
||||||
struct super_block *sb, int xid, const __u16 *pfid)
|
struct super_block *sb, int xid, const __u16 *pfid)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0, tmprc;
|
||||||
__u32 attr;
|
|
||||||
struct cifsInodeInfo *cifsInfo;
|
|
||||||
struct cifsTconInfo *pTcon;
|
struct cifsTconInfo *pTcon;
|
||||||
struct inode *inode;
|
|
||||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
bool adjustTZ = false;
|
bool adjustTZ = false;
|
||||||
bool is_dfs_referral = false;
|
struct cifs_fattr fattr;
|
||||||
umode_t default_mode;
|
|
||||||
|
|
||||||
pTcon = cifs_sb->tcon;
|
pTcon = cifs_sb->tcon;
|
||||||
cFYI(1, ("Getting info on %s", full_path));
|
cFYI(1, ("Getting info on %s", full_path));
|
||||||
|
@ -482,164 +475,83 @@ int cifs_get_inode_info(struct inode **pinode,
|
||||||
adjustTZ = true;
|
adjustTZ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
|
|
||||||
if (rc == -EREMOTE) {
|
if (!rc) {
|
||||||
is_dfs_referral = true;
|
cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData,
|
||||||
fill_fake_finddata(pfindData, sb);
|
cifs_sb, adjustTZ);
|
||||||
|
} else if (rc == -EREMOTE) {
|
||||||
|
cifs_create_dfs_fattr(&fattr, sb);
|
||||||
rc = 0;
|
rc = 0;
|
||||||
} else if (rc)
|
} else {
|
||||||
goto cgii_exit;
|
goto cgii_exit;
|
||||||
|
}
|
||||||
|
|
||||||
attr = le32_to_cpu(pfindData->Attributes);
|
/*
|
||||||
|
* If an inode wasn't passed in, then get the inode number
|
||||||
/* get new inode */
|
*
|
||||||
|
* Is an i_ino of zero legal? Can we use that to check if the server
|
||||||
|
* supports returning inode numbers? Are there other sanity checks we
|
||||||
|
* can use to ensure that the server is really filling in that field?
|
||||||
|
*
|
||||||
|
* We can not use the IndexNumber field by default from Windows or
|
||||||
|
* Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA
|
||||||
|
* CIFS spec claims that this value is unique within the scope of a
|
||||||
|
* share, and the windows docs hint that it's actually unique
|
||||||
|
* per-machine.
|
||||||
|
*
|
||||||
|
* 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 (*pinode == NULL) {
|
if (*pinode == NULL) {
|
||||||
__u64 inode_num;
|
|
||||||
__u64 *pinum = &inode_num;
|
|
||||||
|
|
||||||
/* Is an i_ino of zero legal? Can we use that to check
|
|
||||||
if the server supports returning inode numbers? Are
|
|
||||||
there other sanity checks we can use to ensure that
|
|
||||||
the server is really filling in that field? */
|
|
||||||
|
|
||||||
/* We can not use the IndexNumber field by default from
|
|
||||||
Windows or Samba (in ALL_INFO buf) but we can request
|
|
||||||
it explicitly. It may not be unique presumably if
|
|
||||||
the server has multiple devices mounted under one share */
|
|
||||||
|
|
||||||
/* 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) {
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
|
||||||
int rc1 = 0;
|
int rc1 = 0;
|
||||||
|
|
||||||
rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
|
rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
|
||||||
full_path, pinum,
|
full_path, &fattr.cf_uniqueid,
|
||||||
cifs_sb->local_nls,
|
cifs_sb->local_nls,
|
||||||
cifs_sb->mnt_cifs_flags &
|
cifs_sb->mnt_cifs_flags &
|
||||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
if (rc1) {
|
if (rc1) {
|
||||||
cFYI(1, ("GetSrvInodeNum rc %d", rc1));
|
|
||||||
pinum = NULL;
|
|
||||||
/* BB EOPNOSUPP disable SERVER_INUM? */
|
/* BB EOPNOSUPP disable SERVER_INUM? */
|
||||||
|
cFYI(1, ("GetSrvInodeNum rc %d", rc1));
|
||||||
|
fattr.cf_uniqueid = iunique(sb, ROOT_I);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pinum = NULL;
|
fattr.cf_uniqueid = iunique(sb, ROOT_I);
|
||||||
}
|
}
|
||||||
|
|
||||||
*pinode = cifs_new_inode(sb, pinum);
|
|
||||||
if (*pinode == NULL) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto cgii_exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inode = *pinode;
|
|
||||||
cifsInfo = CIFS_I(inode);
|
|
||||||
cifsInfo->cifsAttrs = attr;
|
|
||||||
cifsInfo->delete_pending = pfindData->DeletePending ? true : false;
|
|
||||||
cFYI(1, ("Old time %ld", cifsInfo->time));
|
|
||||||
cifsInfo->time = jiffies;
|
|
||||||
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
|
|
||||||
will match rather than setting to:
|
|
||||||
(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
|
|
||||||
|
|
||||||
/* Linux can not store file creation time so ignore it */
|
|
||||||
if (pfindData->LastAccessTime)
|
|
||||||
inode->i_atime = cifs_NTtimeToUnix(pfindData->LastAccessTime);
|
|
||||||
else /* do not need to use current_fs_time - time not stored */
|
|
||||||
inode->i_atime = CURRENT_TIME;
|
|
||||||
inode->i_mtime = cifs_NTtimeToUnix(pfindData->LastWriteTime);
|
|
||||||
inode->i_ctime = cifs_NTtimeToUnix(pfindData->ChangeTime);
|
|
||||||
cFYI(DBG2, ("Attributes came in as 0x%x", attr));
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get default inode mode */
|
|
||||||
if (attr & ATTR_DIRECTORY)
|
|
||||||
default_mode = cifs_sb->mnt_dir_mode;
|
|
||||||
else
|
|
||||||
default_mode = cifs_sb->mnt_file_mode;
|
|
||||||
|
|
||||||
/* set permission bits */
|
|
||||||
if (atomic_read(&cifsInfo->inUse) == 0 ||
|
|
||||||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
|
|
||||||
inode->i_mode = default_mode;
|
|
||||||
else {
|
|
||||||
/* just reenable write bits if !ATTR_READONLY */
|
|
||||||
if ((inode->i_mode & S_IWUGO) == 0 &&
|
|
||||||
(attr & ATTR_READONLY) == 0)
|
|
||||||
inode->i_mode |= (S_IWUGO & default_mode);
|
|
||||||
|
|
||||||
inode->i_mode &= ~S_IFMT;
|
|
||||||
}
|
|
||||||
/* clear write bits if ATTR_READONLY is set */
|
|
||||||
if (attr & ATTR_READONLY)
|
|
||||||
inode->i_mode &= ~S_IWUGO;
|
|
||||||
|
|
||||||
/* set inode type */
|
|
||||||
if ((attr & ATTR_SYSTEM) &&
|
|
||||||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
|
|
||||||
/* no need to fix endianness on 0 */
|
|
||||||
if (pfindData->EndOfFile == 0)
|
|
||||||
inode->i_mode |= S_IFIFO;
|
|
||||||
else if (decode_sfu_inode(inode,
|
|
||||||
le64_to_cpu(pfindData->EndOfFile),
|
|
||||||
full_path, cifs_sb, xid))
|
|
||||||
cFYI(1, ("unknown SFU file type\n"));
|
|
||||||
} else {
|
} else {
|
||||||
if (attr & ATTR_DIRECTORY)
|
fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid;
|
||||||
inode->i_mode |= S_IFDIR;
|
|
||||||
else
|
|
||||||
inode->i_mode |= S_IFREG;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cifsInfo->server_eof = le64_to_cpu(pfindData->EndOfFile);
|
/* query for SFU type info if supported and needed */
|
||||||
spin_lock(&inode->i_lock);
|
if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
|
||||||
if (is_size_safe_to_change(cifsInfo, cifsInfo->server_eof)) {
|
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
|
||||||
/* can not safely shrink the file size here if the
|
tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
|
||||||
client is writing to it due to potential races */
|
if (tmprc)
|
||||||
i_size_write(inode, cifsInfo->server_eof);
|
cFYI(1, ("cifs_sfu_type failed: %d", tmprc));
|
||||||
|
|
||||||
/* 512 bytes (2**9) is the fake blocksize that must be
|
|
||||||
used for this calculation */
|
|
||||||
inode->i_blocks = (512 - 1 + le64_to_cpu(
|
|
||||||
pfindData->AllocationSize)) >> 9;
|
|
||||||
}
|
}
|
||||||
spin_unlock(&inode->i_lock);
|
|
||||||
|
|
||||||
inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
|
|
||||||
|
|
||||||
/* BB fill in uid and gid here? with help from winbind?
|
|
||||||
or retrieve from NTFS stream extended attribute */
|
|
||||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||||
/* fill in 0777 bits from ACL */
|
/* fill in 0777 bits from ACL */
|
||||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
||||||
cFYI(1, ("Getting mode bits from ACL"));
|
cFYI(1, ("Getting mode bits from ACL"));
|
||||||
acl_to_uid_mode(cifs_sb, inode, full_path, pfid);
|
cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
|
|
||||||
/* fill in remaining high mode bits e.g. SUID, VTX */
|
/* fill in remaining high mode bits e.g. SUID, VTX */
|
||||||
get_sfu_mode(inode, full_path, cifs_sb, xid);
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
|
||||||
} else if (atomic_read(&cifsInfo->inUse) == 0) {
|
cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
|
||||||
inode->i_uid = cifs_sb->mnt_uid;
|
|
||||||
inode->i_gid = cifs_sb->mnt_gid;
|
if (!*pinode) {
|
||||||
/* set so we do not keep refreshing these fields with
|
*pinode = cifs_iget(sb, &fattr);
|
||||||
bad data after user has changed them in memory */
|
if (!*pinode)
|
||||||
atomic_set(&cifsInfo->inUse, 1);
|
rc = -ENOMEM;
|
||||||
|
} else {
|
||||||
|
cifs_fattr_to_inode(*pinode, &fattr);
|
||||||
}
|
}
|
||||||
|
|
||||||
cifs_set_ops(inode, is_dfs_referral);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cgii_exit:
|
cgii_exit:
|
||||||
kfree(buf);
|
kfree(buf);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -753,21 +665,14 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
xid = GetXid();
|
xid = GetXid();
|
||||||
if (cifs_sb->tcon->unix_ext) {
|
if (cifs_sb->tcon->unix_ext)
|
||||||
rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
|
rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
|
||||||
if (!inode)
|
else
|
||||||
return ERR_PTR(-ENOMEM);
|
rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
|
||||||
} else {
|
|
||||||
inode = iget_locked(sb, ino);
|
|
||||||
if (!inode)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
if (!(inode->i_state & I_NEW))
|
|
||||||
return inode;
|
|
||||||
|
|
||||||
rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb,
|
|
||||||
xid, NULL);
|
xid, NULL);
|
||||||
unlock_new_inode(inode);
|
|
||||||
}
|
if (!inode)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
if (rc && cifs_sb->tcon->ipc) {
|
if (rc && cifs_sb->tcon->ipc) {
|
||||||
cFYI(1, ("ipc connection - fake read inode"));
|
cFYI(1, ("ipc connection - fake read inode"));
|
||||||
|
|
|
@ -112,239 +112,74 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
|
||||||
return dentry;
|
return dentry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns 1 if new inode created, 2 if both dentry and inode were */
|
static void
|
||||||
/* Might check in the future if inode number changed so we can rehash inode */
|
cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
|
||||||
static int
|
|
||||||
construct_dentry(struct qstr *qstring, struct file *file,
|
|
||||||
struct inode **ptmp_inode, struct dentry **pnew_dentry,
|
|
||||||
__u64 *inum)
|
|
||||||
{
|
{
|
||||||
struct dentry *tmp_dentry = NULL;
|
fattr->cf_uid = cifs_sb->mnt_uid;
|
||||||
struct super_block *sb = file->f_path.dentry->d_sb;
|
fattr->cf_gid = cifs_sb->mnt_gid;
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
cFYI(1, ("For %s", qstring->name));
|
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
|
||||||
|
fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
|
||||||
tmp_dentry = d_lookup(file->f_path.dentry, qstring);
|
fattr->cf_dtype = DT_DIR;
|
||||||
if (tmp_dentry) {
|
|
||||||
/* BB: overwrite old name? i.e. tmp_dentry->d_name and
|
|
||||||
* tmp_dentry->d_name.len??
|
|
||||||
*/
|
|
||||||
cFYI(0, ("existing dentry with inode 0x%p",
|
|
||||||
tmp_dentry->d_inode));
|
|
||||||
*ptmp_inode = tmp_dentry->d_inode;
|
|
||||||
if (*ptmp_inode == NULL) {
|
|
||||||
*ptmp_inode = cifs_new_inode(sb, inum);
|
|
||||||
if (*ptmp_inode == NULL)
|
|
||||||
return rc;
|
|
||||||
rc = 1;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
tmp_dentry = d_alloc(file->f_path.dentry, qstring);
|
fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
|
||||||
if (tmp_dentry == NULL) {
|
fattr->cf_dtype = DT_REG;
|
||||||
cERROR(1, ("Failed allocating dentry"));
|
|
||||||
*ptmp_inode = NULL;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CIFS_SB(sb)->tcon->nocase)
|
|
||||||
tmp_dentry->d_op = &cifs_ci_dentry_ops;
|
|
||||||
else
|
|
||||||
tmp_dentry->d_op = &cifs_dentry_ops;
|
|
||||||
|
|
||||||
*ptmp_inode = cifs_new_inode(sb, inum);
|
|
||||||
if (*ptmp_inode == NULL)
|
|
||||||
return rc;
|
|
||||||
rc = 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp_dentry->d_time = jiffies;
|
if (fattr->cf_cifsattrs & ATTR_READONLY)
|
||||||
*pnew_dentry = tmp_dentry;
|
fattr->cf_mode &= ~S_IWUGO;
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL &&
|
||||||
char *buf, unsigned int *pobject_type, int isNewInode)
|
fattr->cf_cifsattrs & ATTR_SYSTEM) {
|
||||||
{
|
if (fattr->cf_eof == 0) {
|
||||||
loff_t local_size;
|
fattr->cf_mode &= ~S_IFMT;
|
||||||
struct timespec local_mtime;
|
fattr->cf_mode |= S_IFIFO;
|
||||||
|
fattr->cf_dtype = DT_FIFO;
|
||||||
struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
|
|
||||||
struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
|
|
||||||
__u32 attr;
|
|
||||||
__u64 allocation_size;
|
|
||||||
__u64 end_of_file;
|
|
||||||
umode_t default_mode;
|
|
||||||
|
|
||||||
/* save mtime and size */
|
|
||||||
local_mtime = tmp_inode->i_mtime;
|
|
||||||
local_size = tmp_inode->i_size;
|
|
||||||
|
|
||||||
if (new_buf_type) {
|
|
||||||
FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;
|
|
||||||
|
|
||||||
attr = le32_to_cpu(pfindData->ExtFileAttributes);
|
|
||||||
allocation_size = le64_to_cpu(pfindData->AllocationSize);
|
|
||||||
end_of_file = le64_to_cpu(pfindData->EndOfFile);
|
|
||||||
tmp_inode->i_atime =
|
|
||||||
cifs_NTtimeToUnix(pfindData->LastAccessTime);
|
|
||||||
tmp_inode->i_mtime =
|
|
||||||
cifs_NTtimeToUnix(pfindData->LastWriteTime);
|
|
||||||
tmp_inode->i_ctime =
|
|
||||||
cifs_NTtimeToUnix(pfindData->ChangeTime);
|
|
||||||
} else { /* legacy, OS2 and DOS style */
|
|
||||||
int offset = cifs_sb->tcon->ses->server->timeAdj;
|
|
||||||
FIND_FILE_STANDARD_INFO *pfindData =
|
|
||||||
(FIND_FILE_STANDARD_INFO *)buf;
|
|
||||||
|
|
||||||
tmp_inode->i_mtime = cnvrtDosUnixTm(pfindData->LastWriteDate,
|
|
||||||
pfindData->LastWriteTime,
|
|
||||||
offset);
|
|
||||||
tmp_inode->i_atime = cnvrtDosUnixTm(pfindData->LastAccessDate,
|
|
||||||
pfindData->LastAccessTime,
|
|
||||||
offset);
|
|
||||||
tmp_inode->i_ctime = cnvrtDosUnixTm(pfindData->LastWriteDate,
|
|
||||||
pfindData->LastWriteTime,
|
|
||||||
offset);
|
|
||||||
attr = le16_to_cpu(pfindData->Attributes);
|
|
||||||
allocation_size = le32_to_cpu(pfindData->AllocationSize);
|
|
||||||
end_of_file = le32_to_cpu(pfindData->DataSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Linux can not store file creation time unfortunately so ignore it */
|
|
||||||
|
|
||||||
cifsInfo->cifsAttrs = attr;
|
|
||||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
|
||||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
|
||||||
/* get more accurate mode via ACL - so force inode refresh */
|
|
||||||
cifsInfo->time = 0;
|
|
||||||
} else
|
|
||||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
|
||||||
cifsInfo->time = jiffies;
|
|
||||||
|
|
||||||
/* treat dos attribute of read-only as read-only mode bit e.g. 555? */
|
|
||||||
/* 2767 perms - indicate mandatory locking */
|
|
||||||
/* BB fill in uid and gid here? with help from winbind?
|
|
||||||
or retrieve from NTFS stream extended attribute */
|
|
||||||
if (atomic_read(&cifsInfo->inUse) == 0) {
|
|
||||||
tmp_inode->i_uid = cifs_sb->mnt_uid;
|
|
||||||
tmp_inode->i_gid = cifs_sb->mnt_gid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attr & ATTR_DIRECTORY)
|
|
||||||
default_mode = cifs_sb->mnt_dir_mode;
|
|
||||||
else
|
|
||||||
default_mode = cifs_sb->mnt_file_mode;
|
|
||||||
|
|
||||||
/* set initial permissions */
|
|
||||||
if ((atomic_read(&cifsInfo->inUse) == 0) ||
|
|
||||||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
|
|
||||||
tmp_inode->i_mode = default_mode;
|
|
||||||
else {
|
|
||||||
/* just reenable write bits if !ATTR_READONLY */
|
|
||||||
if ((tmp_inode->i_mode & S_IWUGO) == 0 &&
|
|
||||||
(attr & ATTR_READONLY) == 0)
|
|
||||||
tmp_inode->i_mode |= (S_IWUGO & default_mode);
|
|
||||||
|
|
||||||
tmp_inode->i_mode &= ~S_IFMT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clear write bits if ATTR_READONLY is set */
|
|
||||||
if (attr & ATTR_READONLY)
|
|
||||||
tmp_inode->i_mode &= ~S_IWUGO;
|
|
||||||
|
|
||||||
/* set inode type */
|
|
||||||
if ((attr & ATTR_SYSTEM) &&
|
|
||||||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
|
|
||||||
if (end_of_file == 0) {
|
|
||||||
tmp_inode->i_mode |= S_IFIFO;
|
|
||||||
*pobject_type = DT_FIFO;
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* trying to get the type can be slow, so just call
|
* trying to get the type and mode via SFU can be slow,
|
||||||
* this a regular file for now, and mark for reval
|
* so just call those regular files for now, and mark
|
||||||
|
* for reval
|
||||||
*/
|
*/
|
||||||
tmp_inode->i_mode |= S_IFREG;
|
fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
|
||||||
*pobject_type = DT_REG;
|
|
||||||
cifsInfo->time = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (attr & ATTR_DIRECTORY) {
|
|
||||||
tmp_inode->i_mode |= S_IFDIR;
|
|
||||||
*pobject_type = DT_DIR;
|
|
||||||
} else {
|
|
||||||
tmp_inode->i_mode |= S_IFREG;
|
|
||||||
*pobject_type = DT_REG;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* can not fill in nlink here as in qpathinfo version and Unx search */
|
void
|
||||||
if (atomic_read(&cifsInfo->inUse) == 0)
|
cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
|
||||||
atomic_set(&cifsInfo->inUse, 1);
|
struct cifs_sb_info *cifs_sb)
|
||||||
|
{
|
||||||
|
memset(fattr, 0, sizeof(*fattr));
|
||||||
|
fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes);
|
||||||
|
fattr->cf_eof = le64_to_cpu(info->EndOfFile);
|
||||||
|
fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
|
||||||
|
fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
|
||||||
|
fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
|
||||||
|
fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
|
||||||
|
|
||||||
cifsInfo->server_eof = end_of_file;
|
cifs_fill_common_info(fattr, cifs_sb);
|
||||||
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 */
|
void
|
||||||
/* for this calculation, even though the reported blocksize is larger */
|
cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info,
|
||||||
tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9;
|
struct cifs_sb_info *cifs_sb)
|
||||||
}
|
{
|
||||||
spin_unlock(&tmp_inode->i_lock);
|
int offset = cifs_sb->tcon->ses->server->timeAdj;
|
||||||
|
|
||||||
if (allocation_size < end_of_file)
|
memset(fattr, 0, sizeof(*fattr));
|
||||||
cFYI(1, ("May be sparse file, allocation less than file size"));
|
fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate,
|
||||||
cFYI(1, ("File Size %ld and blocks %llu",
|
info->LastAccessTime, offset);
|
||||||
(unsigned long)tmp_inode->i_size,
|
fattr->cf_ctime = cnvrtDosUnixTm(info->LastWriteDate,
|
||||||
(unsigned long long)tmp_inode->i_blocks));
|
info->LastWriteTime, offset);
|
||||||
if (S_ISREG(tmp_inode->i_mode)) {
|
fattr->cf_mtime = cnvrtDosUnixTm(info->LastWriteDate,
|
||||||
cFYI(1, ("File inode"));
|
info->LastWriteTime, offset);
|
||||||
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) &&
|
fattr->cf_cifsattrs = le16_to_cpu(info->Attributes);
|
||||||
(cifs_sb->tcon->ses->server->maxBuf <
|
fattr->cf_bytes = le32_to_cpu(info->AllocationSize);
|
||||||
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
|
fattr->cf_eof = le32_to_cpu(info->DataSize);
|
||||||
tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
|
|
||||||
else
|
|
||||||
tmp_inode->i_data.a_ops = &cifs_addr_ops;
|
|
||||||
|
|
||||||
if (isNewInode)
|
cifs_fill_common_info(fattr, cifs_sb);
|
||||||
return; /* No sense invalidating pages for new inode
|
|
||||||
since 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;
|
|
||||||
} else {
|
|
||||||
cFYI(1, ("Init special inode"));
|
|
||||||
init_special_inode(tmp_inode, tmp_inode->i_mode,
|
|
||||||
tmp_inode->i_rdev);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BB eventually need to add the following helper function to
|
/* BB eventually need to add the following helper function to
|
||||||
|
@ -846,11 +681,10 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct qstr qstring;
|
struct qstr qstring;
|
||||||
struct cifsFileInfo *pCifsF;
|
struct cifsFileInfo *pCifsF;
|
||||||
unsigned int obj_type;
|
u64 inum;
|
||||||
__u64 inum;
|
|
||||||
ino_t ino;
|
ino_t ino;
|
||||||
|
struct super_block *sb;
|
||||||
struct cifs_sb_info *cifs_sb;
|
struct cifs_sb_info *cifs_sb;
|
||||||
struct inode *tmp_inode;
|
|
||||||
struct dentry *tmp_dentry;
|
struct dentry *tmp_dentry;
|
||||||
struct cifs_fattr fattr;
|
struct cifs_fattr fattr;
|
||||||
|
|
||||||
|
@ -870,71 +704,53 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
sb = file->f_path.dentry->d_sb;
|
||||||
|
cifs_sb = CIFS_SB(sb);
|
||||||
|
|
||||||
qstring.name = scratch_buf;
|
qstring.name = scratch_buf;
|
||||||
rc = cifs_get_name_from_search_buf(&qstring, pfindEntry,
|
rc = cifs_get_name_from_search_buf(&qstring, pfindEntry,
|
||||||
pCifsF->srch_inf.info_level,
|
pCifsF->srch_inf.info_level,
|
||||||
pCifsF->srch_inf.unicode, cifs_sb,
|
pCifsF->srch_inf.unicode, cifs_sb,
|
||||||
max_len,
|
max_len, &inum /* returned */);
|
||||||
&inum /* returned */);
|
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* only these two infolevels return valid inode numbers */
|
if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
|
||||||
if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
|
|
||||||
cifs_unix_basic_to_fattr(&fattr,
|
cifs_unix_basic_to_fattr(&fattr,
|
||||||
&((FILE_UNIX_INFO *) pfindEntry)->basic,
|
&((FILE_UNIX_INFO *) pfindEntry)->basic,
|
||||||
cifs_sb);
|
cifs_sb);
|
||||||
tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring,
|
else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
|
||||||
&fattr);
|
cifs_std_info_to_fattr(&fattr, (FIND_FILE_STANDARD_INFO *)
|
||||||
obj_type = fattr.cf_dtype;
|
pfindEntry, cifs_sb);
|
||||||
ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
|
else
|
||||||
} else {
|
cifs_dir_info_to_fattr(&fattr, (FILE_DIRECTORY_INFO *)
|
||||||
if (pCifsF->srch_inf.info_level ==
|
pfindEntry, cifs_sb);
|
||||||
SMB_FIND_FILE_ID_FULL_DIR_INFO)
|
|
||||||
rc = construct_dentry(&qstring, file, &tmp_inode,
|
|
||||||
&tmp_dentry, &inum);
|
|
||||||
else
|
|
||||||
rc = construct_dentry(&qstring, file, &tmp_inode,
|
|
||||||
&tmp_dentry, NULL);
|
|
||||||
|
|
||||||
if ((tmp_inode == NULL) || (tmp_dentry == NULL)) {
|
/* FIXME: make _to_fattr functions fill this out */
|
||||||
rc = -ENOMEM;
|
if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO)
|
||||||
goto out;
|
fattr.cf_uniqueid = inum;
|
||||||
}
|
else
|
||||||
|
fattr.cf_uniqueid = iunique(sb, ROOT_I);
|
||||||
|
|
||||||
/* we pass in rc below, indicating whether it is a new inode,
|
ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
|
||||||
* so we can figure out whether to invalidate the inode cached
|
tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr);
|
||||||
* data if the file has changed
|
|
||||||
*/
|
|
||||||
if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
|
|
||||||
fill_in_inode(tmp_inode, 0, pfindEntry, &obj_type, rc);
|
|
||||||
else
|
|
||||||
fill_in_inode(tmp_inode, 1, pfindEntry, &obj_type, rc);
|
|
||||||
|
|
||||||
/* new inode - needs to be tied to dentry */
|
|
||||||
if (rc) {
|
|
||||||
d_instantiate(tmp_dentry, tmp_inode);
|
|
||||||
if (rc == 2)
|
|
||||||
d_rehash(tmp_dentry);
|
|
||||||
}
|
|
||||||
|
|
||||||
ino = cifs_uniqueid_to_ino_t(tmp_inode->i_ino);
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
|
rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
|
||||||
ino, obj_type);
|
ino, fattr.cf_dtype);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we can not return filldir errors to the caller since they are
|
||||||
|
* "normal" when the stat blocksize is too small - we return remapped
|
||||||
|
* error instead
|
||||||
|
*
|
||||||
|
* FIXME: This looks bogus. filldir returns -EOVERFLOW in the above
|
||||||
|
* case already. Why should we be clobbering other errors from it?
|
||||||
|
*/
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cFYI(1, ("filldir rc = %d", rc));
|
cFYI(1, ("filldir rc = %d", rc));
|
||||||
/* we can not return filldir errors to the caller
|
|
||||||
since they are "normal" when the stat blocksize
|
|
||||||
is too small - we return remapped error instead */
|
|
||||||
rc = -EOVERFLOW;
|
rc = -EOVERFLOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
dput(tmp_dentry);
|
dput(tmp_dentry);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue