Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: cifs: when ATTR_READONLY is set, only clear write bits on non-directories cifs: remove cifsInodeInfo->inUse counter cifs: convert cifs_get_inode_info and non-posix readdir to use cifs_iget [CIFS] update cifs version number cifs: add and use CIFSSMBUnixSetFileInfo for setattr calls cifs: make a separate function for filling out FILE_UNIX_BASIC_INFO cifs: rename CIFSSMBUnixSetInfo to CIFSSMBUnixSetPathInfo cifs: add pid of initiating process to spnego upcall info cifs: fix regression with O_EXCL creates and optimize away lookup cifs: add new cifs_iget function and convert unix codepath to use it
This commit is contained in:
commit
c2cc49a2f8
@ -5,7 +5,11 @@ client generated ones by default (mount option "serverino" turned
|
||||
on by default if server supports it). Add forceuid and forcegid
|
||||
mount options (so that when negotiating unix extensions specifying
|
||||
which uid mounted does not immediately force the server's reported
|
||||
uids to be overridden). Add support for scope moutn parm.
|
||||
uids to be overridden). Add support for scope mount parm. Improve
|
||||
hard link detection to use same inode for both. Do not set
|
||||
read-only dos attribute on directories (for chmod) since Windows
|
||||
explorer special cases this attribute bit for directories for
|
||||
a different purpose.
|
||||
|
||||
Version 1.58
|
||||
------------
|
||||
|
@ -86,6 +86,9 @@ struct key_type cifs_spnego_key_type = {
|
||||
/* strlen of ";user=" */
|
||||
#define USER_KEY_LEN 6
|
||||
|
||||
/* strlen of ";pid=0x" */
|
||||
#define PID_KEY_LEN 7
|
||||
|
||||
/* get a key struct with a SPNEGO security blob, suitable for session setup */
|
||||
struct key *
|
||||
cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
|
||||
@ -103,7 +106,8 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
|
||||
IP_KEY_LEN + INET6_ADDRSTRLEN +
|
||||
MAX_MECH_STR_LEN +
|
||||
UID_KEY_LEN + (sizeof(uid_t) * 2) +
|
||||
USER_KEY_LEN + strlen(sesInfo->userName) + 1;
|
||||
USER_KEY_LEN + strlen(sesInfo->userName) +
|
||||
PID_KEY_LEN + (sizeof(pid_t) * 2) + 1;
|
||||
|
||||
spnego_key = ERR_PTR(-ENOMEM);
|
||||
description = kzalloc(desc_len, GFP_KERNEL);
|
||||
@ -141,6 +145,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
|
||||
dp = description + strlen(description);
|
||||
sprintf(dp, ";user=%s", sesInfo->userName);
|
||||
|
||||
dp = description + strlen(description);
|
||||
sprintf(dp, ";pid=0x%x", current->pid);
|
||||
|
||||
cFYI(1, ("key description = %s", description));
|
||||
spnego_key = request_key(&cifs_spnego_key_type, description, "");
|
||||
|
||||
|
@ -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,
|
||||
struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
|
||||
struct inode *inode)
|
||||
struct cifs_fattr *fattr)
|
||||
{
|
||||
int i;
|
||||
int num_aces = 0;
|
||||
@ -340,7 +340,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
||||
if (!pdacl) {
|
||||
/* no DACL in the security descriptor, set
|
||||
all the permissions for user/group/other */
|
||||
inode->i_mode |= S_IRWXUGO;
|
||||
fattr->cf_mode |= S_IRWXUGO;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -357,7 +357,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
||||
/* reset rwx permissions for user/group/other.
|
||||
Also, if num_aces is 0 i.e. DACL has no ACEs,
|
||||
user/group/other have no permissions */
|
||||
inode->i_mode &= ~(S_IRWXUGO);
|
||||
fattr->cf_mode &= ~(S_IRWXUGO);
|
||||
|
||||
acl_base = (char *)pdacl;
|
||||
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))
|
||||
access_flags_to_mode(ppace[i]->access_req,
|
||||
ppace[i]->type,
|
||||
&(inode->i_mode),
|
||||
&fattr->cf_mode,
|
||||
&user_mask);
|
||||
if (compare_sids(&(ppace[i]->sid), pgrpsid))
|
||||
access_flags_to_mode(ppace[i]->access_req,
|
||||
ppace[i]->type,
|
||||
&(inode->i_mode),
|
||||
&fattr->cf_mode,
|
||||
&group_mask);
|
||||
if (compare_sids(&(ppace[i]->sid), &sid_everyone))
|
||||
access_flags_to_mode(ppace[i]->access_req,
|
||||
ppace[i]->type,
|
||||
&(inode->i_mode),
|
||||
&fattr->cf_mode,
|
||||
&other_mask);
|
||||
|
||||
/* 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 */
|
||||
static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
|
||||
struct inode *inode)
|
||||
struct cifs_fattr *fattr)
|
||||
{
|
||||
int rc;
|
||||
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;
|
||||
__u32 dacloffset;
|
||||
|
||||
if ((inode == NULL) || (pntsd == NULL))
|
||||
if (pntsd == NULL)
|
||||
return -EIO;
|
||||
|
||||
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)
|
||||
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
|
||||
group_sid_ptr, inode);
|
||||
group_sid_ptr, fattr);
|
||||
else
|
||||
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,
|
||||
sizeof(struct cifs_sid)); */
|
||||
|
||||
|
||||
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 */
|
||||
void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
|
||||
const char *path, const __u16 *pfid)
|
||||
void
|
||||
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;
|
||||
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 (pntsd)
|
||||
rc = parse_sec_desc(pntsd, acllen, inode);
|
||||
rc = parse_sec_desc(pntsd, acllen, fattr);
|
||||
if (rc)
|
||||
cFYI(1, ("parse sec desc failed rc = %d", rc));
|
||||
|
||||
|
@ -308,7 +308,6 @@ cifs_alloc_inode(struct super_block *sb)
|
||||
if (!cifs_inode)
|
||||
return NULL;
|
||||
cifs_inode->cifsAttrs = 0x20; /* default */
|
||||
atomic_set(&cifs_inode->inUse, 0);
|
||||
cifs_inode->time = 0;
|
||||
cifs_inode->write_behind_rc = 0;
|
||||
/* Until the file is open and we have gotten oplock
|
||||
|
@ -24,6 +24,19 @@
|
||||
|
||||
#define ROOT_I 2
|
||||
|
||||
/*
|
||||
* ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down
|
||||
* so that it will fit.
|
||||
*/
|
||||
static inline ino_t
|
||||
cifs_uniqueid_to_ino_t(u64 fileid)
|
||||
{
|
||||
ino_t ino = (ino_t) fileid;
|
||||
if (sizeof(ino_t) < sizeof(u64))
|
||||
ino ^= fileid >> (sizeof(u64)-sizeof(ino_t)) * 8;
|
||||
return ino;
|
||||
}
|
||||
|
||||
extern struct file_system_type cifs_fs_type;
|
||||
extern const struct address_space_operations cifs_addr_ops;
|
||||
extern const struct address_space_operations cifs_addr_ops_smallbuf;
|
||||
@ -100,5 +113,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
||||
extern const struct export_operations cifs_export_ops;
|
||||
#endif /* EXPERIMENTAL */
|
||||
|
||||
#define CIFS_VERSION "1.59"
|
||||
#define CIFS_VERSION "1.60"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
@ -364,13 +364,13 @@ struct cifsInodeInfo {
|
||||
struct list_head openFileList;
|
||||
int write_behind_rc;
|
||||
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
|
||||
atomic_t inUse; /* num concurrent users (local openers cifs) of file*/
|
||||
unsigned long time; /* jiffies of last update/check of inode */
|
||||
bool clientCanCacheRead:1; /* read oplock */
|
||||
bool clientCanCacheAll:1; /* read and writebehind oplock */
|
||||
bool oplockPending:1;
|
||||
bool delete_pending:1; /* DELETE_ON_CLOSE is set */
|
||||
u64 server_eof; /* current file size on server */
|
||||
u64 uniqueid; /* server inode number */
|
||||
struct inode vfs_inode;
|
||||
};
|
||||
|
||||
@ -472,6 +472,32 @@ struct dfs_info3_param {
|
||||
char *node_name;
|
||||
};
|
||||
|
||||
/*
|
||||
* common struct for holding inode info when searching for or updating an
|
||||
* inode with new info
|
||||
*/
|
||||
|
||||
#define CIFS_FATTR_DFS_REFERRAL 0x1
|
||||
#define CIFS_FATTR_DELETE_PENDING 0x2
|
||||
#define CIFS_FATTR_NEED_REVAL 0x4
|
||||
|
||||
struct cifs_fattr {
|
||||
u32 cf_flags;
|
||||
u32 cf_cifsattrs;
|
||||
u64 cf_uniqueid;
|
||||
u64 cf_eof;
|
||||
u64 cf_bytes;
|
||||
uid_t cf_uid;
|
||||
gid_t cf_gid;
|
||||
umode_t cf_mode;
|
||||
dev_t cf_rdev;
|
||||
unsigned int cf_nlink;
|
||||
unsigned int cf_dtype;
|
||||
struct timespec cf_atime;
|
||||
struct timespec cf_mtime;
|
||||
struct timespec cf_ctime;
|
||||
};
|
||||
|
||||
static inline void free_dfs_info_param(struct dfs_info3_param *param)
|
||||
{
|
||||
if (param) {
|
||||
|
@ -2328,19 +2328,7 @@ struct file_attrib_tag {
|
||||
typedef struct {
|
||||
__le32 NextEntryOffset;
|
||||
__u32 ResumeKey; /* as with FileIndex - no need to convert */
|
||||
__le64 EndOfFile;
|
||||
__le64 NumOfBytes;
|
||||
__le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */
|
||||
__le64 LastAccessTime;
|
||||
__le64 LastModificationTime;
|
||||
__le64 Uid;
|
||||
__le64 Gid;
|
||||
__le32 Type;
|
||||
__le64 DevMajor;
|
||||
__le64 DevMinor;
|
||||
__le64 UniqueId;
|
||||
__le64 Permissions;
|
||||
__le64 Nlinks;
|
||||
FILE_UNIX_BASIC_INFO basic;
|
||||
char FileName[1];
|
||||
} __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */
|
||||
|
||||
|
@ -98,9 +98,13 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
|
||||
extern int cifs_posix_open(char *full_path, struct inode **pinode,
|
||||
struct super_block *sb, int mode, int oflags,
|
||||
int *poplock, __u16 *pnetfid, int xid);
|
||||
extern void posix_fill_in_inode(struct inode *tmp_inode,
|
||||
FILE_UNIX_BASIC_INFO *pData, int isNewInode);
|
||||
extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum);
|
||||
extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
|
||||
FILE_UNIX_BASIC_INFO *info,
|
||||
struct cifs_sb_info *cifs_sb);
|
||||
extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr);
|
||||
extern struct inode *cifs_iget(struct super_block *sb,
|
||||
struct cifs_fattr *fattr);
|
||||
|
||||
extern int cifs_get_inode_info(struct inode **pinode,
|
||||
const unsigned char *search_path,
|
||||
FILE_ALL_INFO *pfile_info,
|
||||
@ -108,8 +112,9 @@ extern int cifs_get_inode_info(struct inode **pinode,
|
||||
extern int cifs_get_inode_info_unix(struct inode **pinode,
|
||||
const unsigned char *search_path,
|
||||
struct super_block *sb, int xid);
|
||||
extern void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
|
||||
const char *path, const __u16 *pfid);
|
||||
extern void cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
|
||||
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 cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
|
||||
@ -215,7 +220,11 @@ struct cifs_unix_set_info_args {
|
||||
dev_t device;
|
||||
};
|
||||
|
||||
extern int CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *pTcon,
|
||||
extern int CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
|
||||
const struct cifs_unix_set_info_args *args,
|
||||
u16 fid, u32 pid_of_opener);
|
||||
|
||||
extern int CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *pTcon,
|
||||
char *fileName,
|
||||
const struct cifs_unix_set_info_args *args,
|
||||
const struct nls_table *nls_codepage,
|
||||
|
@ -5074,10 +5074,114 @@ SetAttrLgcyRetry:
|
||||
}
|
||||
#endif /* temporarily unneeded SetAttr legacy function */
|
||||
|
||||
static void
|
||||
cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
|
||||
const struct cifs_unix_set_info_args *args)
|
||||
{
|
||||
u64 mode = args->mode;
|
||||
|
||||
/*
|
||||
* Samba server ignores set of file size to zero due to bugs in some
|
||||
* older clients, but we should be precise - we use SetFileSize to
|
||||
* set file size and do not want to truncate file size to zero
|
||||
* accidently as happened on one Samba server beta by putting
|
||||
* zero instead of -1 here
|
||||
*/
|
||||
data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
|
||||
data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
|
||||
data_offset->LastStatusChange = cpu_to_le64(args->ctime);
|
||||
data_offset->LastAccessTime = cpu_to_le64(args->atime);
|
||||
data_offset->LastModificationTime = cpu_to_le64(args->mtime);
|
||||
data_offset->Uid = cpu_to_le64(args->uid);
|
||||
data_offset->Gid = cpu_to_le64(args->gid);
|
||||
/* better to leave device as zero when it is */
|
||||
data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
|
||||
data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
|
||||
data_offset->Permissions = cpu_to_le64(mode);
|
||||
|
||||
if (S_ISREG(mode))
|
||||
data_offset->Type = cpu_to_le32(UNIX_FILE);
|
||||
else if (S_ISDIR(mode))
|
||||
data_offset->Type = cpu_to_le32(UNIX_DIR);
|
||||
else if (S_ISLNK(mode))
|
||||
data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
|
||||
else if (S_ISCHR(mode))
|
||||
data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
|
||||
else if (S_ISBLK(mode))
|
||||
data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
|
||||
else if (S_ISFIFO(mode))
|
||||
data_offset->Type = cpu_to_le32(UNIX_FIFO);
|
||||
else if (S_ISSOCK(mode))
|
||||
data_offset->Type = cpu_to_le32(UNIX_SOCKET);
|
||||
}
|
||||
|
||||
int
|
||||
CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
|
||||
const struct cifs_unix_set_info_args *args,
|
||||
const struct nls_table *nls_codepage, int remap)
|
||||
CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
|
||||
const struct cifs_unix_set_info_args *args,
|
||||
u16 fid, u32 pid_of_opener)
|
||||
{
|
||||
struct smb_com_transaction2_sfi_req *pSMB = NULL;
|
||||
FILE_UNIX_BASIC_INFO *data_offset;
|
||||
int rc = 0;
|
||||
u16 params, param_offset, offset, byte_count, count;
|
||||
|
||||
cFYI(1, ("Set Unix Info (via SetFileInfo)"));
|
||||
rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
|
||||
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
|
||||
|
||||
params = 6;
|
||||
pSMB->MaxSetupCount = 0;
|
||||
pSMB->Reserved = 0;
|
||||
pSMB->Flags = 0;
|
||||
pSMB->Timeout = 0;
|
||||
pSMB->Reserved2 = 0;
|
||||
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
|
||||
offset = param_offset + params;
|
||||
|
||||
data_offset = (FILE_UNIX_BASIC_INFO *)
|
||||
((char *)(&pSMB->hdr.Protocol) + offset);
|
||||
count = sizeof(FILE_UNIX_BASIC_INFO);
|
||||
|
||||
pSMB->MaxParameterCount = cpu_to_le16(2);
|
||||
/* BB find max SMB PDU from sess */
|
||||
pSMB->MaxDataCount = cpu_to_le16(1000);
|
||||
pSMB->SetupCount = 1;
|
||||
pSMB->Reserved3 = 0;
|
||||
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
|
||||
byte_count = 3 /* pad */ + params + count;
|
||||
pSMB->DataCount = cpu_to_le16(count);
|
||||
pSMB->ParameterCount = cpu_to_le16(params);
|
||||
pSMB->TotalDataCount = pSMB->DataCount;
|
||||
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
||||
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
||||
pSMB->DataOffset = cpu_to_le16(offset);
|
||||
pSMB->Fid = fid;
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
|
||||
cifs_fill_unix_set_info(data_offset, args);
|
||||
|
||||
rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
|
||||
if (rc)
|
||||
cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
|
||||
|
||||
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
||||
since file handle passed in no longer valid */
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
|
||||
const struct cifs_unix_set_info_args *args,
|
||||
const struct nls_table *nls_codepage, int remap)
|
||||
{
|
||||
TRANSACTION2_SPI_REQ *pSMB = NULL;
|
||||
TRANSACTION2_SPI_RSP *pSMBr = NULL;
|
||||
@ -5086,7 +5190,6 @@ CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
|
||||
int bytes_returned = 0;
|
||||
FILE_UNIX_BASIC_INFO *data_offset;
|
||||
__u16 params, param_offset, offset, count, byte_count;
|
||||
__u64 mode = args->mode;
|
||||
|
||||
cFYI(1, ("In SetUID/GID/Mode"));
|
||||
setPermsRetry:
|
||||
@ -5137,38 +5240,8 @@ setPermsRetry:
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
|
||||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
/* Samba server ignores set of file size to zero due to bugs in some
|
||||
older clients, but we should be precise - we use SetFileSize to
|
||||
set file size and do not want to truncate file size to zero
|
||||
accidently as happened on one Samba server beta by putting
|
||||
zero instead of -1 here */
|
||||
data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
|
||||
data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
|
||||
data_offset->LastStatusChange = cpu_to_le64(args->ctime);
|
||||
data_offset->LastAccessTime = cpu_to_le64(args->atime);
|
||||
data_offset->LastModificationTime = cpu_to_le64(args->mtime);
|
||||
data_offset->Uid = cpu_to_le64(args->uid);
|
||||
data_offset->Gid = cpu_to_le64(args->gid);
|
||||
/* better to leave device as zero when it is */
|
||||
data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
|
||||
data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
|
||||
data_offset->Permissions = cpu_to_le64(mode);
|
||||
|
||||
if (S_ISREG(mode))
|
||||
data_offset->Type = cpu_to_le32(UNIX_FILE);
|
||||
else if (S_ISDIR(mode))
|
||||
data_offset->Type = cpu_to_le32(UNIX_DIR);
|
||||
else if (S_ISLNK(mode))
|
||||
data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
|
||||
else if (S_ISCHR(mode))
|
||||
data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
|
||||
else if (S_ISBLK(mode))
|
||||
data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
|
||||
else if (S_ISFIFO(mode))
|
||||
data_offset->Type = cpu_to_le32(UNIX_FIFO);
|
||||
else if (S_ISSOCK(mode))
|
||||
data_offset->Type = cpu_to_le32(UNIX_SOCKET);
|
||||
|
||||
cifs_fill_unix_set_info(data_offset, args);
|
||||
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
|
@ -188,6 +188,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
|
||||
FILE_UNIX_BASIC_INFO *presp_data;
|
||||
__u32 posix_flags = 0;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
struct cifs_fattr fattr;
|
||||
|
||||
cFYI(1, ("posix open %s", full_path));
|
||||
|
||||
@ -236,22 +237,21 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
|
||||
if (presp_data->Type == cpu_to_le32(-1))
|
||||
goto posix_open_ret; /* open ok, caller does qpathinfo */
|
||||
|
||||
/* get new inode and set it up */
|
||||
if (!pinode)
|
||||
goto posix_open_ret; /* caller does not need info */
|
||||
|
||||
cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);
|
||||
|
||||
/* get new inode and set it up */
|
||||
if (*pinode == NULL) {
|
||||
__u64 unique_id = le64_to_cpu(presp_data->UniqueId);
|
||||
*pinode = cifs_new_inode(sb, &unique_id);
|
||||
*pinode = cifs_iget(sb, &fattr);
|
||||
if (!*pinode) {
|
||||
rc = -ENOMEM;
|
||||
goto posix_open_ret;
|
||||
}
|
||||
} else {
|
||||
cifs_fattr_to_inode(*pinode, &fattr);
|
||||
}
|
||||
/* else an inode was passed in. Update its info, don't create one */
|
||||
|
||||
/* We do not need to close the file if new_inode fails since
|
||||
the caller will retry qpathinfo as long as inode is null */
|
||||
if (*pinode == NULL)
|
||||
goto posix_open_ret;
|
||||
|
||||
posix_fill_in_inode(*pinode, presp_data, 1);
|
||||
|
||||
cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);
|
||||
|
||||
@ -425,9 +425,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
||||
args.uid = NO_CHANGE_64;
|
||||
args.gid = NO_CHANGE_64;
|
||||
}
|
||||
CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
} else {
|
||||
/* BB implement mode setting via Windows security
|
||||
descriptors e.g. */
|
||||
@ -515,10 +516,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
|
||||
args.uid = NO_CHANGE_64;
|
||||
args.gid = NO_CHANGE_64;
|
||||
}
|
||||
rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path,
|
||||
&args, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
|
||||
if (!rc) {
|
||||
rc = cifs_get_inode_info_unix(&newinode, full_path,
|
||||
@ -643,6 +644,15 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* O_EXCL: optimize away the lookup, but don't hash the dentry. Let
|
||||
* the VFS handle the create.
|
||||
*/
|
||||
if (nd->flags & LOOKUP_EXCL) {
|
||||
d_instantiate(direntry, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* can not grab the rename sem here since it would
|
||||
deadlock in the cases (beginning of sys_rename itself)
|
||||
in which we already have the sb rename sem */
|
||||
|
@ -448,9 +448,9 @@ int cifs_open(struct inode *inode, struct file *file)
|
||||
.mtime = NO_CHANGE_64,
|
||||
.device = 0,
|
||||
};
|
||||
CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
}
|
||||
}
|
||||
|
798
fs/cifs/inode.c
798
fs/cifs/inode.c
File diff suppressed because it is too large
Load Diff
@ -63,374 +63,123 @@ static inline void dump_cifs_file_struct(struct file *file, char *label)
|
||||
}
|
||||
#endif /* DEBUG2 */
|
||||
|
||||
/* Returns 1 if new inode created, 2 if both dentry and inode were */
|
||||
/* Might check in the future if inode number changed so we can rehash inode */
|
||||
static int
|
||||
construct_dentry(struct qstr *qstring, struct file *file,
|
||||
struct inode **ptmp_inode, struct dentry **pnew_dentry,
|
||||
__u64 *inum)
|
||||
/*
|
||||
* Find the dentry that matches "name". If there isn't one, create one. If it's
|
||||
* a negative dentry or the uniqueid changed, then drop it and recreate it.
|
||||
*/
|
||||
static struct dentry *
|
||||
cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
|
||||
struct cifs_fattr *fattr)
|
||||
{
|
||||
struct dentry *tmp_dentry = NULL;
|
||||
struct super_block *sb = file->f_path.dentry->d_sb;
|
||||
int rc = 0;
|
||||
struct dentry *dentry, *alias;
|
||||
struct inode *inode;
|
||||
struct super_block *sb = parent->d_inode->i_sb;
|
||||
|
||||
cFYI(1, ("For %s", qstring->name));
|
||||
cFYI(1, ("For %s", name->name));
|
||||
|
||||
qstring->hash = full_name_hash(qstring->name, qstring->len);
|
||||
tmp_dentry = d_lookup(file->f_path.dentry, qstring);
|
||||
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 {
|
||||
tmp_dentry = d_alloc(file->f_path.dentry, qstring);
|
||||
if (tmp_dentry == NULL) {
|
||||
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;
|
||||
dentry = d_lookup(parent, name);
|
||||
if (dentry) {
|
||||
/* FIXME: check for inode number changes? */
|
||||
if (dentry->d_inode != NULL)
|
||||
return dentry;
|
||||
d_drop(dentry);
|
||||
dput(dentry);
|
||||
}
|
||||
|
||||
tmp_dentry->d_time = jiffies;
|
||||
*pnew_dentry = tmp_dentry;
|
||||
return rc;
|
||||
dentry = d_alloc(parent, name);
|
||||
if (dentry == NULL)
|
||||
return NULL;
|
||||
|
||||
inode = cifs_iget(sb, fattr);
|
||||
if (!inode) {
|
||||
dput(dentry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (CIFS_SB(sb)->tcon->nocase)
|
||||
dentry->d_op = &cifs_ci_dentry_ops;
|
||||
else
|
||||
dentry->d_op = &cifs_dentry_ops;
|
||||
|
||||
alias = d_materialise_unique(dentry, inode);
|
||||
if (alias != NULL) {
|
||||
dput(dentry);
|
||||
if (IS_ERR(alias))
|
||||
return NULL;
|
||||
dentry = alias;
|
||||
}
|
||||
|
||||
return dentry;
|
||||
}
|
||||
|
||||
static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
|
||||
char *buf, unsigned int *pobject_type, int isNewInode)
|
||||
static void
|
||||
cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
loff_t local_size;
|
||||
struct timespec local_mtime;
|
||||
fattr->cf_uid = cifs_sb->mnt_uid;
|
||||
fattr->cf_gid = cifs_sb->mnt_gid;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
/* Linux can not store file creation time unfortunately so ignore it */
|
||||
if (fattr->cf_cifsattrs & ATTR_READONLY)
|
||||
fattr->cf_mode &= ~S_IWUGO;
|
||||
|
||||
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;
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL &&
|
||||
fattr->cf_cifsattrs & ATTR_SYSTEM) {
|
||||
if (fattr->cf_eof == 0) {
|
||||
fattr->cf_mode &= ~S_IFMT;
|
||||
fattr->cf_mode |= S_IFIFO;
|
||||
fattr->cf_dtype = DT_FIFO;
|
||||
} else {
|
||||
/*
|
||||
* trying to get the type can be slow, so just call
|
||||
* this a regular file for now, and mark for reval
|
||||
* trying to get the type and mode via SFU can be slow,
|
||||
* so just call those regular files for now, and mark
|
||||
* for reval
|
||||
*/
|
||||
tmp_inode->i_mode |= S_IFREG;
|
||||
*pobject_type = DT_REG;
|
||||
cifsInfo->time = 0;
|
||||
fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
|
||||
}
|
||||
} 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 */
|
||||
if (atomic_read(&cifsInfo->inUse) == 0)
|
||||
atomic_set(&cifsInfo->inUse, 1);
|
||||
|
||||
cifsInfo->server_eof = end_of_file;
|
||||
spin_lock(&tmp_inode->i_lock);
|
||||
if (is_size_safe_to_change(cifsInfo, end_of_file)) {
|
||||
/* can not safely change the file size here if the
|
||||
client is writing to it due to potential races */
|
||||
i_size_write(tmp_inode, end_of_file);
|
||||
|
||||
/* 512 bytes (2**9) is the fake blocksize that must be used */
|
||||
/* for this calculation, even though the reported blocksize is larger */
|
||||
tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9;
|
||||
}
|
||||
spin_unlock(&tmp_inode->i_lock);
|
||||
|
||||
if (allocation_size < end_of_file)
|
||||
cFYI(1, ("May be sparse file, allocation less than file size"));
|
||||
cFYI(1, ("File Size %ld and blocks %llu",
|
||||
(unsigned long)tmp_inode->i_size,
|
||||
(unsigned long long)tmp_inode->i_blocks));
|
||||
if (S_ISREG(tmp_inode->i_mode)) {
|
||||
cFYI(1, ("File inode"));
|
||||
tmp_inode->i_op = &cifs_file_inode_ops;
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
||||
tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
|
||||
else
|
||||
tmp_inode->i_fop = &cifs_file_direct_ops;
|
||||
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
||||
tmp_inode->i_fop = &cifs_file_nobrl_ops;
|
||||
else
|
||||
tmp_inode->i_fop = &cifs_file_ops;
|
||||
|
||||
if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
|
||||
(cifs_sb->tcon->ses->server->maxBuf <
|
||||
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
|
||||
tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
|
||||
else
|
||||
tmp_inode->i_data.a_ops = &cifs_addr_ops;
|
||||
|
||||
if (isNewInode)
|
||||
return; /* No sense invalidating pages for new inode
|
||||
since 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);
|
||||
}
|
||||
}
|
||||
|
||||
static void unix_fill_in_inode(struct inode *tmp_inode,
|
||||
FILE_UNIX_INFO *pfindData, unsigned int *pobject_type, int isNewInode)
|
||||
void
|
||||
cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
loff_t local_size;
|
||||
struct timespec local_mtime;
|
||||
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);
|
||||
|
||||
struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
|
||||
cifs_fill_common_info(fattr, cifs_sb);
|
||||
}
|
||||
|
||||
__u32 type = le32_to_cpu(pfindData->Type);
|
||||
__u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes);
|
||||
__u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
|
||||
cifsInfo->time = jiffies;
|
||||
atomic_inc(&cifsInfo->inUse);
|
||||
void
|
||||
cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
int offset = cifs_sb->tcon->ses->server->timeAdj;
|
||||
|
||||
/* save mtime and size */
|
||||
local_mtime = tmp_inode->i_mtime;
|
||||
local_size = tmp_inode->i_size;
|
||||
memset(fattr, 0, sizeof(*fattr));
|
||||
fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate,
|
||||
info->LastAccessTime, offset);
|
||||
fattr->cf_ctime = cnvrtDosUnixTm(info->LastWriteDate,
|
||||
info->LastWriteTime, offset);
|
||||
fattr->cf_mtime = cnvrtDosUnixTm(info->LastWriteDate,
|
||||
info->LastWriteTime, offset);
|
||||
|
||||
tmp_inode->i_atime =
|
||||
cifs_NTtimeToUnix(pfindData->LastAccessTime);
|
||||
tmp_inode->i_mtime =
|
||||
cifs_NTtimeToUnix(pfindData->LastModificationTime);
|
||||
tmp_inode->i_ctime =
|
||||
cifs_NTtimeToUnix(pfindData->LastStatusChange);
|
||||
fattr->cf_cifsattrs = le16_to_cpu(info->Attributes);
|
||||
fattr->cf_bytes = le32_to_cpu(info->AllocationSize);
|
||||
fattr->cf_eof = le32_to_cpu(info->DataSize);
|
||||
|
||||
tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
|
||||
/* since we set the inode type below we need to mask off type
|
||||
to avoid strange results if bits above were corrupt */
|
||||
tmp_inode->i_mode &= ~S_IFMT;
|
||||
if (type == UNIX_FILE) {
|
||||
*pobject_type = DT_REG;
|
||||
tmp_inode->i_mode |= S_IFREG;
|
||||
} else if (type == UNIX_SYMLINK) {
|
||||
*pobject_type = DT_LNK;
|
||||
tmp_inode->i_mode |= S_IFLNK;
|
||||
} else if (type == UNIX_DIR) {
|
||||
*pobject_type = DT_DIR;
|
||||
tmp_inode->i_mode |= S_IFDIR;
|
||||
} else if (type == UNIX_CHARDEV) {
|
||||
*pobject_type = DT_CHR;
|
||||
tmp_inode->i_mode |= S_IFCHR;
|
||||
tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
|
||||
le64_to_cpu(pfindData->DevMinor) & MINORMASK);
|
||||
} else if (type == UNIX_BLOCKDEV) {
|
||||
*pobject_type = DT_BLK;
|
||||
tmp_inode->i_mode |= S_IFBLK;
|
||||
tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
|
||||
le64_to_cpu(pfindData->DevMinor) & MINORMASK);
|
||||
} else if (type == UNIX_FIFO) {
|
||||
*pobject_type = DT_FIFO;
|
||||
tmp_inode->i_mode |= S_IFIFO;
|
||||
} else if (type == UNIX_SOCKET) {
|
||||
*pobject_type = DT_SOCK;
|
||||
tmp_inode->i_mode |= S_IFSOCK;
|
||||
} else {
|
||||
/* safest to just call it a file */
|
||||
*pobject_type = DT_REG;
|
||||
tmp_inode->i_mode |= S_IFREG;
|
||||
cFYI(1, ("unknown inode type %d", type));
|
||||
}
|
||||
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
|
||||
tmp_inode->i_uid = cifs_sb->mnt_uid;
|
||||
else
|
||||
tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
|
||||
tmp_inode->i_gid = cifs_sb->mnt_gid;
|
||||
else
|
||||
tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
|
||||
tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
|
||||
|
||||
cifsInfo->server_eof = end_of_file;
|
||||
spin_lock(&tmp_inode->i_lock);
|
||||
if (is_size_safe_to_change(cifsInfo, end_of_file)) {
|
||||
/* can not safely change the file size here if the
|
||||
client is writing to it due to potential races */
|
||||
i_size_write(tmp_inode, end_of_file);
|
||||
|
||||
/* 512 bytes (2**9) is the fake blocksize that must be used */
|
||||
/* for this calculation, not the real blocksize */
|
||||
tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
|
||||
}
|
||||
spin_unlock(&tmp_inode->i_lock);
|
||||
|
||||
if (S_ISREG(tmp_inode->i_mode)) {
|
||||
cFYI(1, ("File inode"));
|
||||
tmp_inode->i_op = &cifs_file_inode_ops;
|
||||
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
||||
tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
|
||||
else
|
||||
tmp_inode->i_fop = &cifs_file_direct_ops;
|
||||
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
||||
tmp_inode->i_fop = &cifs_file_nobrl_ops;
|
||||
else
|
||||
tmp_inode->i_fop = &cifs_file_ops;
|
||||
|
||||
if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
|
||||
(cifs_sb->tcon->ses->server->maxBuf <
|
||||
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
|
||||
tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
|
||||
else
|
||||
tmp_inode->i_data.a_ops = &cifs_addr_ops;
|
||||
|
||||
if (isNewInode)
|
||||
return; /* No sense invalidating pages for new inode
|
||||
since we have not started caching readahead
|
||||
file data for it yet */
|
||||
|
||||
if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
|
||||
(local_size == tmp_inode->i_size)) {
|
||||
cFYI(1, ("inode exists but unchanged"));
|
||||
} else {
|
||||
/* file may have changed on server */
|
||||
cFYI(1, ("invalidate inode, readdir detected change"));
|
||||
invalidate_remote_inode(tmp_inode);
|
||||
}
|
||||
} else if (S_ISDIR(tmp_inode->i_mode)) {
|
||||
cFYI(1, ("Directory inode"));
|
||||
tmp_inode->i_op = &cifs_dir_inode_ops;
|
||||
tmp_inode->i_fop = &cifs_dir_ops;
|
||||
} else if (S_ISLNK(tmp_inode->i_mode)) {
|
||||
cFYI(1, ("Symbolic Link inode"));
|
||||
tmp_inode->i_op = &cifs_symlink_inode_ops;
|
||||
/* tmp_inode->i_fop = *//* do not need to set to anything */
|
||||
} else {
|
||||
cFYI(1, ("Special inode"));
|
||||
init_special_inode(tmp_inode, tmp_inode->i_mode,
|
||||
tmp_inode->i_rdev);
|
||||
}
|
||||
cifs_fill_common_info(fattr, cifs_sb);
|
||||
}
|
||||
|
||||
/* BB eventually need to add the following helper function to
|
||||
@ -872,7 +621,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
|
||||
len = strnlen(filename, PATH_MAX);
|
||||
}
|
||||
|
||||
*pinum = le64_to_cpu(pFindData->UniqueId);
|
||||
*pinum = le64_to_cpu(pFindData->basic.UniqueId);
|
||||
} else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
|
||||
FILE_DIRECTORY_INFO *pFindData =
|
||||
(FILE_DIRECTORY_INFO *)current_entry;
|
||||
@ -932,11 +681,12 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
|
||||
int rc = 0;
|
||||
struct qstr qstring;
|
||||
struct cifsFileInfo *pCifsF;
|
||||
unsigned int obj_type;
|
||||
__u64 inum;
|
||||
u64 inum;
|
||||
ino_t ino;
|
||||
struct super_block *sb;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct inode *tmp_inode;
|
||||
struct dentry *tmp_dentry;
|
||||
struct cifs_fattr fattr;
|
||||
|
||||
/* get filename and len into qstring */
|
||||
/* get dentry */
|
||||
@ -954,60 +704,53 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
|
||||
if (rc != 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;
|
||||
rc = cifs_get_name_from_search_buf(&qstring, pfindEntry,
|
||||
pCifsF->srch_inf.info_level,
|
||||
pCifsF->srch_inf.unicode, cifs_sb,
|
||||
max_len,
|
||||
&inum /* returned */);
|
||||
max_len, &inum /* returned */);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* only these two infolevels return valid inode numbers */
|
||||
if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX ||
|
||||
pCifsF->srch_inf.info_level == 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))
|
||||
return -ENOMEM;
|
||||
|
||||
/* we pass in rc below, indicating whether it is a new inode,
|
||||
so we can figure out whether to invalidate the inode cached
|
||||
data if the file has changed */
|
||||
if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
|
||||
unix_fill_in_inode(tmp_inode,
|
||||
(FILE_UNIX_INFO *)pfindEntry,
|
||||
&obj_type, rc);
|
||||
cifs_unix_basic_to_fattr(&fattr,
|
||||
&((FILE_UNIX_INFO *) pfindEntry)->basic,
|
||||
cifs_sb);
|
||||
else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
|
||||
fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
|
||||
pfindEntry, &obj_type, rc);
|
||||
cifs_std_info_to_fattr(&fattr, (FIND_FILE_STANDARD_INFO *)
|
||||
pfindEntry, cifs_sb);
|
||||
else
|
||||
fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
|
||||
cifs_dir_info_to_fattr(&fattr, (FILE_DIRECTORY_INFO *)
|
||||
pfindEntry, cifs_sb);
|
||||
|
||||
if (rc) /* new inode - needs to be tied to dentry */ {
|
||||
d_instantiate(tmp_dentry, tmp_inode);
|
||||
if (rc == 2)
|
||||
d_rehash(tmp_dentry);
|
||||
}
|
||||
/* FIXME: make _to_fattr functions fill this out */
|
||||
if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO)
|
||||
fattr.cf_uniqueid = inum;
|
||||
else
|
||||
fattr.cf_uniqueid = iunique(sb, ROOT_I);
|
||||
|
||||
ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
|
||||
tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr);
|
||||
|
||||
rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
|
||||
tmp_inode->i_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) {
|
||||
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;
|
||||
}
|
||||
|
||||
dput(tmp_dentry);
|
||||
return rc;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user