Commit e259237b authored by Steve French's avatar Steve French Committed by Steve French

Fix delete of files with readonly attribute. Reflect setting of

readonly dos attribute in mode when server does not support
CIFS Unix extensions.  Fix abbreviated readdir to servers that
do support CIFS Unix extensions.
parent c707ea8c
Version 0.75
------------
Fix delete of readonly file to Windows servers. Reflect
presence or absence of read only dos attribute in mode
bits for servers that do not support CIFS Unix extensions.
Fix shortened results on readdir of large directories to
servers supporting CIFS Unix extensions (caused by
incorrect resume key).
Version 0.74 Version 0.74
------------ ------------
Fix truncate bug (set file size) that could cause hangs e.g. running fsx Fix truncate bug (set file size) that could cause hangs e.g. running fsx
......
...@@ -2115,25 +2115,25 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, ...@@ -2115,25 +2115,25 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
parm_data = parm_data =
(struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) + (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
pSMB->DataOffset); pSMB->DataOffset);
parm_data->FileSize = size; parm_data->FileSize = size;
pSMB->Fid = fid; pSMB->Fid = fid;
if(SetAllocation) { if(SetAllocation) {
if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
pSMB->InformationLevel = pSMB->InformationLevel =
cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2); cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
else else
pSMB->InformationLevel = pSMB->InformationLevel =
cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO); cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
} else /* Set File Size */ { } else /* Set File Size */ {
if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
pSMB->InformationLevel = pSMB->InformationLevel =
cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2); cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
else else
pSMB->InformationLevel = pSMB->InformationLevel =
cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
} }
pSMB->Reserved4 = 0; pSMB->Reserved4 = 0;
pSMB->hdr.smb_buf_length += pSMB->ByteCount; pSMB->hdr.smb_buf_length += pSMB->ByteCount;
pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
......
...@@ -879,6 +879,9 @@ fill_in_inode(struct inode *tmp_inode, ...@@ -879,6 +879,9 @@ fill_in_inode(struct inode *tmp_inode,
} else { } else {
*pobject_type = DT_REG; *pobject_type = DT_REG;
tmp_inode->i_mode |= S_IFREG; tmp_inode->i_mode |= S_IFREG;
if(pfindData->ExtFileAttributes & ATTR_READONLY)
tmp_inode->i_mode &= ~(S_IWUGO);
}/* could add code here - to validate if device or weird share type? */ }/* could add code here - to validate if device or weird share type? */
/* can not fill in nlink here as in qpathinfo version and Unx search */ /* can not fill in nlink here as in qpathinfo version and Unx search */
...@@ -1199,10 +1202,10 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1199,10 +1202,10 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
cifsFile->search_resume_name = cifsFile->search_resume_name =
kmalloc(cifsFile->resume_name_length, GFP_KERNEL); kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
cFYI(1,("Last file: %s with name %d bytes long", cFYI(1,("Last file: %s with name %d bytes long",
lastFindData->FileName, pfindDataUnix->FileName,
cifsFile->resume_name_length)); cifsFile->resume_name_length));
memcpy(cifsFile->search_resume_name, memcpy(cifsFile->search_resume_name,
lastFindData->FileName, pfindDataUnix->FileName,
cifsFile->resume_name_length); cifsFile->resume_name_length);
} }
for (i = 2; i < findParms.SearchCount + 2; i++) { for (i = 2; i < findParms.SearchCount + 2; i++) {
......
...@@ -233,8 +233,6 @@ cifs_get_inode_info(struct inode **pinode, ...@@ -233,8 +233,6 @@ cifs_get_inode_info(struct inode **pinode,
cifs_NTtimeToUnix(le64_to_cpu(findData.LastWriteTime)); cifs_NTtimeToUnix(le64_to_cpu(findData.LastWriteTime));
inode->i_ctime = inode->i_ctime =
cifs_NTtimeToUnix(le64_to_cpu(findData.ChangeTime)); cifs_NTtimeToUnix(le64_to_cpu(findData.ChangeTime));
/* inode->i_mode = S_IRWXUGO; *//* 777 perms */
/* should we treat the dos attribute of read-only as read-only mode bit e.g. 555 */
inode->i_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); /* 2767 perms indicate mandatory locking - will override for dirs later */ inode->i_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); /* 2767 perms indicate mandatory locking - will override for dirs later */
cFYI(0, cFYI(0,
(" Attributes came in as 0x%x ", findData.Attributes)); (" Attributes came in as 0x%x ", findData.Attributes));
...@@ -247,6 +245,9 @@ cifs_get_inode_info(struct inode **pinode, ...@@ -247,6 +245,9 @@ cifs_get_inode_info(struct inode **pinode,
inode->i_mode |= S_IFDIR; inode->i_mode |= S_IFDIR;
} else { } else {
inode->i_mode |= S_IFREG; inode->i_mode |= S_IFREG;
/* treat the dos attribute of read-only as read-only mode e.g. 555 */
if(cifsInfo->cifsAttrs & ATTR_READONLY)
inode->i_mode &= ~(S_IWUGO);
/* BB add code here - validate if device or weird share or device type? */ /* BB add code here - validate if device or weird share or device type? */
} }
inode->i_size = le64_to_cpu(findData.EndOfFile); inode->i_size = le64_to_cpu(findData.EndOfFile);
...@@ -304,6 +305,7 @@ cifs_unlink(struct inode *inode, struct dentry *direntry) ...@@ -304,6 +305,7 @@ cifs_unlink(struct inode *inode, struct dentry *direntry)
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
char *full_path = NULL; char *full_path = NULL;
struct cifsInodeInfo *cifsInode; struct cifsInodeInfo *cifsInode;
FILE_BASIC_INFO * pinfo_buf;
cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode)); cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
...@@ -330,6 +332,22 @@ cifs_unlink(struct inode *inode, struct dentry *direntry) ...@@ -330,6 +332,22 @@ cifs_unlink(struct inode *inode, struct dentry *direntry)
/* BB In the future chain close with the NTCreateX to narrow window */ /* BB In the future chain close with the NTCreateX to narrow window */
direntry->d_inode->i_nlink--; direntry->d_inode->i_nlink--;
} }
} else if (rc == -EACCES) {
/* try only if r/o attribute set in local lookup data? */
pinfo_buf = (FILE_BASIC_INFO *)kmalloc(sizeof(FILE_BASIC_INFO),GFP_KERNEL);
if(pinfo_buf) {
memset(pinfo_buf,0,sizeof(FILE_BASIC_INFO));
/* ATTRS set to normal clears r/o bit */
pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf,
cifs_sb->local_nls);
kfree(pinfo_buf);
}
if(rc==0) {
rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
if (!rc)
direntry->d_inode->i_nlink--;
}
} }
cifsInode = CIFS_I(direntry->d_inode); cifsInode = CIFS_I(direntry->d_inode);
cifsInode->time = 0; /* will force revalidate to get info when needed */ cifsInode->time = 0; /* will force revalidate to get info when needed */
...@@ -378,15 +396,14 @@ cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) ...@@ -378,15 +396,14 @@ cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
direntry->d_op = &cifs_dentry_ops; direntry->d_op = &cifs_dentry_ops;
d_instantiate(direntry, newinode); d_instantiate(direntry, newinode);
direntry->d_inode->i_nlink = 2; direntry->d_inode->i_nlink = 2;
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
cifs_sb->local_nls); cifs_sb->local_nls);
else { /* BB to be implemented via Windows secrty descriptors*/ else { /* BB to be implemented via Windows secrty descriptors*/
/* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
} }
} }
if (full_path) if (full_path)
kfree(full_path); kfree(full_path);
...@@ -600,7 +617,6 @@ static int cifs_trunc_page(struct address_space *mapping, loff_t from) ...@@ -600,7 +617,6 @@ static int cifs_trunc_page(struct address_space *mapping, loff_t from)
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
kaddr = kmap_atomic(page, KM_USER0); kaddr = kmap_atomic(page, KM_USER0);
memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
flush_dcache_page(page); flush_dcache_page(page);
...@@ -678,17 +694,29 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -678,17 +694,29 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
gid = attrs->ia_gid; gid = attrs->ia_gid;
/* entry->gid = cpu_to_le16(attr->ia_gid); */ /* entry->gid = cpu_to_le16(attr->ia_gid); */
} }
time_buf.Attributes = 0;
if (attrs->ia_valid & ATTR_MODE) { if (attrs->ia_valid & ATTR_MODE) {
cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode)); cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
mode = attrs->ia_mode; mode = attrs->ia_mode;
/* entry->mode = cpu_to_le16(attr->ia_mode); */ /* entry->mode = cpu_to_le16(attr->ia_mode); */
} }
if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
&& (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID))) && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid, rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
cifs_sb->local_nls); cifs_sb->local_nls);
else { /* BB to be implemented - via Windows security descriptors */ else if (attrs->ia_valid & ATTR_MODE) {
if((mode & S_IWUGO) == 0) /* not writeable */ {
if((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
time_buf.Attributes =
cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY);
} else if((mode & S_IWUGO) == S_IWUGO) {
if(cifsInode->cifsAttrs & ATTR_READONLY)
time_buf.Attributes =
cpu_to_le32(cifsInode->cifsAttrs & (~ATTR_READONLY));
}
/* BB to be implemented - via Windows security descriptors or streams */
/* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/ /* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/
} }
...@@ -714,14 +742,12 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -714,14 +742,12 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
} else } else
time_buf.ChangeTime = 0; time_buf.ChangeTime = 0;
if (set_time) { if (set_time | time_buf.Attributes) {
/* BB handle errors better if one attribute not set /* BB what if setting one attribute fails
(such as size) but time setting works */ (such as size) but time setting works */
time_buf.CreationTime = 0; /* do not change */ time_buf.CreationTime = 0; /* do not change */
time_buf.Attributes = 0; /* BB is this ignored by server?
or do I have to query and reset anyway BB */
rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf, rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
cifs_sb->local_nls); cifs_sb->local_nls);
} }
/* do not need local check to inode_check_ok since the server does that */ /* do not need local check to inode_check_ok since the server does that */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment