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:
Jeff Layton 2009-07-09 01:46:37 -04:00 committed by Steve French
parent b77863bfa1
commit 0b8f18e358
5 changed files with 249 additions and 526 deletions

View file

@ -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));

View file

@ -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;

View file

@ -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 *,

View file

@ -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"));

View file

@ -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;
} }