Commit 8442e7a7 authored by Steve French's avatar Steve French

Properly emulate POSIX semantics for deleting of open files and renaming over...

Properly emulate POSIX semantics for deleting of open files and renaming over open files.  Fix oops in readpages caused by unitialized aops field.
parent 14751427
Version 0.60
------------
Fix oops in readpages caused by not setting address space operations in inode in
rare code path.
Version 0.59
------------
Includes support for deleting of open files and renaming over existing files (per POSIX
requirement). Add readlink support for Windows junction points (directory symlinks).
Version 0.58
------------
Changed read and write to go through pagecache. Added additional address space operations.
......
......@@ -9,8 +9,8 @@ For questions or bug reports please contact sfrench@samba.org (sfrench@us.ibm.co
Build instructions:
==================
extract the kernel from http://www.cifs.bkbits.net/linux-2.5 or
http://www.cifs.bkbits.net/linux-2.4
Get the kernel source e.g. http://linux.bkbits.net/linux-2.5 or http://www.kernel.org
http://cifs.bkbits.net/linux-2.4
make menuconfig (or make xconfig)
select cifs from within the network filesystem choices
save and exit
......@@ -57,7 +57,9 @@ Some administrators also change the "map archive" and the "create mask" paramete
from their defaults. For more information on these see the manual pages
("man smb.conf") on the Samba server system. Note that the cifs vfs, unlike the
smbfs vfs, does not read the smb.conf on the client system (the few optional settings
are passed in on mount via -o parameters instead).
are passed in on mount via -o parameters instead). Note that Samba 2.2.7 or later
includes a fix that allows the CIFS VFS to delete open files (required for strict
POSIX compliance). Windows Servers already supported this feature.
Use instructions:
================
......
......@@ -85,7 +85,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
length =
sprintf(buf,
"\n%d) Name: %s Domain: %s HowManyMounts: %d ServerOS: %s ServerNOS: %s Capabilities: 0x%x\n",
"\n%d) Name: %s Domain: %s HowManyMounts: %d ServerOS: %s ServerNOS: %s\n\tCapabilities: 0x%x",
i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse),
ses->serverOS, ses->serverNOS, ses->capabilities);
buf += length;
......@@ -107,7 +107,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
length =
sprintf(buf,
"\n%d) %s UseCount: %d on FS: %s with characteristics: 0x%x Attributes: 0x%x and PathComponentLengthMax: %d",
"\n%d) %s UseCount: %d on FS: %s with characteristics: 0x%x Attributes: 0x%x\n\tPathComponentLengthMax: %d",
i, tcon->treeName,
atomic_read(&tcon->useCount),
tcon->nativeFileSystem,
......
......@@ -234,6 +234,8 @@
#define ATTR_NOT_CONTENT_INDEXED 0x2000
#define ATTR_ENCRYPTED 0x4000
#define ATTR_POSIX_SEMANTICS 0x01000000
#define ATTR_BACKUP_SEMANTICS 0x02000000
#define ATTR_DELETE_ON_CLOSE 0x04000000
#define ATTR_SEQUENTIAL_SCAN 0x08000000
#define ATTR_RANDOM_ACCESS 0x10000000
#define ATTR_NO_BUFFERING 0x20000000
......@@ -255,8 +257,12 @@
#define FILE_OVERWRITE_IF 0x00000005
/* CreateOptions */
#define CREATE_NOT_FILE 0x00000001 /* if set, indicates must not be file */
#define CREATE_NOT_DIR 0x00000040 /* if set, indicates must not be directory */
#define CREATE_NOT_FILE 0x00000001 /* if set must not be file */
#define CREATE_WRITE_THROUGH 0x00000002
#define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */
#define CREATE_RANDOM_ACCESS 0x00000800
#define CREATE_DELETE_ON_CLOSE 0x00001000
#define OPEN_REPARSE_POINT 0x00200000
/* ImpersonationLevel flags */
#define SECURITY_ANONYMOUS 0
......@@ -744,6 +750,9 @@ typedef struct smb_com_rename_req {
} RENAME_REQ;
#define CREATE_HARD_LINK 0x103
#define MOVEFILE_COPY_ALLOWED 0x0002
#define MOVEFILE_REPLACE_EXISTING 0x0001
typedef struct smb_com_nt_rename_req { /* A5 - also used for create hardlink */
struct smb_hdr hdr; /* wct = 4 */
__u16 SearchAttributes; /* target file attributes */
......@@ -798,7 +807,7 @@ typedef struct smb_com_create_directory_rsp {
__u16 ByteCount; /* bct = 0 */
} CREATE_DIRECTORY_RSP;
typedef struct smb_com_nt_transaction_ioctl_req {
typedef struct smb_com_transaction_ioctl_req {
struct smb_hdr hdr; /* wct = 23 */
__u8 MaxSetupCount;
__u16 Reserved;
......@@ -812,11 +821,11 @@ typedef struct smb_com_nt_transaction_ioctl_req {
__u32 DataOffset;
__u8 SetupCount; /* four setup words follow subcommand */
/* SNIA spec incorrectly included spurious pad here */
__u16 SubCommand; /* 2 = IOCTL/FSCTL */
__u16 SubCommand;/* 2 = IOCTL/FSCTL */
__u32 FunctionCode;
__u16 Fid;
__u8 IsFSCTLFlag; /* 1 = File System Control, 0 = device control (IOCTL) */
__u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS share) */
__u8 IsFsctl; /* 1 = File System Control, 0 = device control (IOCTL)*/
__u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS share)*/
__u16 ByteCount;
__u8 Pad[3];
__u8 Data[1];
......@@ -839,6 +848,17 @@ typedef struct smb_com_transaction_ioctl_rsp {
__u8 Pad[3];
} TRANSACT_IOCTL_RSP;
struct reparse_data {
__u32 ReparseTag;
__u16 ReparseDataLength;
__u16 Reserved;
__u16 AltNameOffset;
__u16 AltNameLen;
__u16 TargetNameOffset;
__u16 TargetNameLen;
char LinkNamesBuf[1];
};
typedef union smb_com_transaction2 {
struct {
struct smb_hdr hdr; /* wct = 14+ */
......
......@@ -184,6 +184,11 @@ extern int CIFSSMBUnixQuerySymLink(const int xid,
const unsigned char *searchName,
char *syminfo, const int buflen,
const struct nls_table *nls_codepage);
extern int CIFSSMBQueryReparseLinkInfo(const int xid,
const struct cifsTconInfo *tcon,
const unsigned char *searchName,
char *symlinkinfo, const int buflen, __u16 fid,
const struct nls_table *nls_codepage);
extern int CIFSSMBOpen(const int xid, const struct cifsTconInfo *tcon,
const char *fileName, const int disposition,
......
......@@ -390,7 +390,7 @@ CIFSSMBMkDir(const int xid, const struct cifsTconInfo *tcon,
int
CIFSSMBOpen(const int xid, const struct cifsTconInfo *tcon,
const char *fileName, const int openDisposition,
const int access_flags, const int omode, __u16 * netfid,
const int access_flags, const int create_options, __u16 * netfid,
int *pOplock, const struct nls_table *nls_codepage)
{
int rc = -EACCES;
......@@ -436,7 +436,7 @@ CIFSSMBOpen(const int xid, const struct cifsTconInfo *tcon,
pSMB->FileAttributes = cpu_to_le32(pSMB->FileAttributes);
pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
pSMB->CreateDisposition = cpu_to_le32(openDisposition);
pSMB->CreateOptions = cpu_to_le32(CREATE_NOT_DIR); /* BB what are these? BB */
pSMB->CreateOptions = cpu_to_le32(create_options);
pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ?? BB */
pSMB->SecurityFlags =
cpu_to_le32(SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY);
......@@ -962,7 +962,7 @@ CIFSSMBUnixQuerySymLink(const int xid, const struct cifsTconInfo *tcon,
int bytes_returned;
int name_len;
cFYI(1, ("\nIn QPathSymLinkInfo (Unix) the path %s", searchName));
cFYI(1, ("\nIn QPathSymLinkInfo (Unix) for path %s", searchName));
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
......@@ -1014,7 +1014,8 @@ CIFSSMBUnixQuerySymLink(const int xid, const struct cifsTconInfo *tcon,
} else { /* decode response */
pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */
if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512))
/* BB also check enough total bytes returned */
rc = -EIO; /* bad smb */
else {
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
......@@ -1041,7 +1042,89 @@ CIFSSMBUnixQuerySymLink(const int xid, const struct cifsTconInfo *tcon,
pSMBr->
DataCount));
}
symlinkinfo[buflen] = 0; /* just in case so the calling code does not go off the end of the buffer */
symlinkinfo[buflen] = 0;
/* just in case so calling code does not go off the end of buffer */
}
}
if (pSMB)
buf_release(pSMB);
return rc;
}
int
CIFSSMBQueryReparseLinkInfo(const int xid, const struct cifsTconInfo *tcon,
const unsigned char *searchName,
char *symlinkinfo, const int buflen,__u16 fid,
const struct nls_table *nls_codepage)
{
int rc = 0;
int bytes_returned;
int name_len;
struct smb_com_transaction_ioctl_req * pSMB;
struct smb_com_transaction_ioctl_rsp * pSMBr;
cFYI(1, ("\nIn Windows reparse style QueryLink info for path %s", searchName));
rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
return rc;
pSMB->TotalParameterCount = 0 ;
pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxSetupCount = 4;
pSMB->Reserved = 0;
pSMB->ParameterOffset = 0;
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 4;
pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
pSMB->IsFsctl = 1; /* FSCTL */
pSMB->IsRootFlag = 0;
pSMB->Fid = fid; /* file handle always le */
pSMB->ByteCount = 0;
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cFYI(1, ("\nSend error in QueryReparseLinkInfo = %d\n", rc));
} else { /* decode response */
pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512))
/* BB also check enough total bytes returned */
rc = -EIO; /* bad smb */
else {
if(pSMBr->DataCount && (pSMBr->DataCount < 2048)) {
/* could also validata reparse tag && better check name length */
struct reparse_data * reparse_buf = (struct reparse_data *)
((char *)&pSMBr->hdr.Protocol + pSMBr->DataOffset);
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len = UniStrnlen((wchar_t *)
(reparse_buf->LinkNamesBuf +
reparse_buf->TargetNameOffset),
min(buflen/2, reparse_buf->TargetNameLen / 2));
cifs_strfromUCS_le(symlinkinfo,
(wchar_t *) (reparse_buf->LinkNamesBuf +
reparse_buf->TargetNameOffset),
name_len, nls_codepage);
} else { /* ASCII names */
strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
reparse_buf->TargetNameOffset,
min(buflen, (int)reparse_buf->TargetNameLen));
}
} else {
rc = -EIO;
cFYI(1,("\nInvalid return data count on get reparse info ioctl"));
}
symlinkinfo[buflen] = 0; /* just in case so the caller
does not go off the end of the buffer */
cFYI(1,("\nreadlink result - %s ",symlinkinfo));
}
}
if (pSMB)
......
......@@ -561,6 +561,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket)
if (rc < 0) {
cFYI(1, ("Error connecting to socket. %d\n", rc));
sock_release(*csocket);
*csocket = NULL;
return rc;
}
}
......@@ -598,6 +599,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
("Error connecting to socket (via ipv6). %d\n",
rc));
sock_release(*csocket);
*csocket = NULL;
return rc;
}
}
......
......@@ -141,7 +141,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode)
/* BB add processing for setting the equivalent of mode - e.g. via CreateX with ACLs */
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OVERWRITE_IF, GENERIC_ALL
/* 0x20197 was used previously */ , mode,
/* 0x20197 was used previously */ , CREATE_NOT_DIR,
&fileHandle, &oplock, cifs_sb->local_nls);
if (rc) {
cFYI(1, ("\ncifs_create returned 0x%x ", rc));
......@@ -267,11 +267,6 @@ cifs_d_revalidate(struct dentry *direntry, int flags)
/* lock_kernel(); *//* surely we do not want to lock the kernel for a whole network round trip which could take seconds */
if (direntry->d_inode) {
cFYI(1,
("In cifs_d_revalidate, name = %s and inode = 0x%p with count %d with time %ld and dentry 0x%p with time %ld\n",
direntry->d_name.name, direntry->d_inode,
direntry->d_inode->i_count.counter,
direntry->d_inode->i_atime.tv_sec, direntry, direntry->d_time));
if (cifs_revalidate(direntry)) {
/* unlock_kernel(); */
return 0;
......
......@@ -35,8 +35,6 @@
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
int
cifs_open(struct inode *inode, struct file *file)
{
......@@ -95,8 +93,7 @@ cifs_open(struct inode *inode, struct file *file)
/* BB pass O_SYNC flag through on file attributes .. BB */
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
-1 /* i.e. dummy value, ignored for time being */,
&netfid, &oplock, cifs_sb->local_nls);
CREATE_NOT_DIR, &netfid, &oplock, cifs_sb->local_nls);
if (rc) {
cFYI(1, ("\ncifs_open returned 0x%x ", rc));
cFYI(1, (" oplock: %d ", oplock));
......@@ -112,6 +109,7 @@ cifs_open(struct inode *inode, struct file *file)
pCifsFile->pfile = file; /* needed for writepage */
list_add(&pCifsFile->tlist,&pTcon->openFileList);
pCifsInode = CIFS_I(file->f_dentry->d_inode);
if(pCifsInode->openFileList.next)
list_add(&pCifsFile->flist,&pCifsInode->openFileList);
if(file->f_flags & O_CREAT) {
/* time to set mode which we can not set earlier due
......@@ -153,6 +151,7 @@ cifs_close(struct inode *inode, struct file *file)
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
if (pSMBFile) {
if(pSMBFile->flist.next)
list_del(&pSMBFile->flist);
list_del(&pSMBFile->tlist);
rc = CIFSSMBClose(xid, pTcon, pSMBFile->netfid);
......@@ -649,6 +648,7 @@ fill_in_inode(struct inode *tmp_inode,
cFYI(1, (" File inode "));
tmp_inode->i_op = &cifs_file_inode_ops;
tmp_inode->i_fop = &cifs_file_ops;
tmp_inode->i_data.a_ops = &cifs_addr_ops;
} else if (S_ISDIR(tmp_inode->i_mode)) {
cFYI(1, (" Directory inode"));
tmp_inode->i_op = &cifs_dir_inode_ops;
......@@ -716,6 +716,7 @@ unix_fill_in_inode(struct inode *tmp_inode,
cFYI(1, (" File inode "));
tmp_inode->i_op = &cifs_file_inode_ops;
tmp_inode->i_fop = &cifs_file_ops;
tmp_inode->i_data.a_ops = &cifs_addr_ops;
} else if (S_ISDIR(tmp_inode->i_mode)) {
cFYI(1, (" Directory inode"));
tmp_inode->i_op = &cifs_dir_inode_ops;
......
......@@ -314,14 +314,24 @@ cifs_unlink(struct inode *inode, struct dentry *direntry)
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
/* BB Should we close the file if it is already open from our client? */
full_path = build_path_from_dentry(direntry);
rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
if (!rc) {
direntry->d_inode->i_nlink--;
} else if (rc == -ETXTBSY) {
int oplock = FALSE;
__u16 netfid;
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
&netfid, &oplock, cifs_sb->local_nls);
if(rc==0) {
CIFSSMBClose(xid, pTcon, netfid);
/* BB In the future chain close with the NTCreateX to narrow window */
direntry->d_inode->i_nlink--;
}
}
cifsInode = CIFS_I(direntry->d_inode);
cifsInode->time = 0; /* will force revalidate to get info when needed */
......@@ -454,6 +464,11 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
rc = CIFSSMBRename(xid, pTcon, fromName, toName,
cifs_sb_source->local_nls);
if(rc == -EEXIST) {
cifs_unlink(target_inode, target_direntry);
rc = CIFSSMBRename(xid, pTcon, fromName, toName,
cifs_sb_source->local_nls);
}
if (fromName)
kfree(fromName);
if (toName)
......
......@@ -176,10 +176,12 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
struct inode *inode = direntry->d_inode;
int rc = -EACCES;
int xid;
int oplock = FALSE;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
char *full_path = NULL;
char tmpbuffer[256];
__u16 fid;
xid = GetXid();
cifs_sb = CIFS_SB(inode->i_sb);
......@@ -196,8 +198,19 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
sizeof (tmpbuffer) - 1,
cifs_sb->local_nls);
else {
/* rc = CIFSSMBQueryReparseLinkInfo */
/* BB Add code to Query ReparsePoint info */
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
OPEN_REPARSE_POINT,&fid, &oplock, cifs_sb->local_nls);
if(!rc) {
rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
tmpbuffer,
sizeof(tmpbuffer) - 1,
fid,
cifs_sb->local_nls);
if(CIFSSMBClose(xid, pTcon, fid)) {
cFYI(1,("Error closing junction point (open for ioctl)"));
}
}
}
/* BB Anything else to do to handle recursive links? */
/* BB Should we be using page ops here? */
......
......@@ -252,7 +252,7 @@ const static struct {
ERRHRD, ERRgeneral, NT_STATUS_DISK_CORRUPT_ERROR}, {
ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_INVALID}, { /* mapping changed since shell does lookup on * and expects file not found */
ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND}, {
ERRDOS, 183, NT_STATUS_OBJECT_NAME_COLLISION}, {
ERRDOS, ERRalreadyexists, NT_STATUS_OBJECT_NAME_COLLISION}, {
ERRHRD, ERRgeneral, NT_STATUS_HANDLE_NOT_WAITABLE}, {
ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED}, {
ERRHRD, ERRgeneral, NT_STATUS_DEVICE_ALREADY_ATTACHED}, {
......@@ -285,7 +285,7 @@ const static struct {
ERRHRD, ERRgeneral, NT_STATUS_EA_CORRUPT_ERROR}, {
ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT}, {
ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED}, {
ERRDOS, ERRnoaccess, NT_STATUS_DELETE_PENDING}, {
ERRDOS, ERRbadfile, NT_STATUS_DELETE_PENDING}, {
ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED}, {
ERRHRD, ERRgeneral, NT_STATUS_UNKNOWN_REVISION}, {
ERRHRD, ERRgeneral, NT_STATUS_REVISION_MISMATCH}, {
......@@ -753,7 +753,7 @@ cifs_print_status(__u32 status_code)
{
int idx = 0;
printk("\nStatus code returned: 0x%08x", status_code);
printk("\nStatus code returned: 0x%08x ", status_code);
while (nt_errs[idx].nt_errstr != NULL) {
if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) ==
......
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