提交 a9d02ad4 编写于 作者: S Steve French

[CIFS] Support for legacy servers part 3 - Add support for Open and most

of Read support.
Signed-off-by: NSteve French <sfrench@us.ibm.com>
上级 e22cb8bc
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#define SMB_COM_SETATTR 0x09 /* trivial response */ #define SMB_COM_SETATTR 0x09 /* trivial response */
#define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */
#define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/
#define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */
#define SMB_COM_READ_ANDX 0x2E #define SMB_COM_READ_ANDX 0x2E
#define SMB_COM_WRITE_ANDX 0x2F #define SMB_COM_WRITE_ANDX 0x2F
#define SMB_COM_TRANSACTION2 0x32 #define SMB_COM_TRANSACTION2 0x32
...@@ -625,6 +626,7 @@ typedef struct smb_com_findclose_req { ...@@ -625,6 +626,7 @@ typedef struct smb_com_findclose_req {
} FINDCLOSE_REQ; } FINDCLOSE_REQ;
/* OpenFlags */ /* OpenFlags */
#define REQ_MORE_INFO 0x00000001 /* legacy (OPEN_AND_X) only */
#define REQ_OPLOCK 0x00000002 #define REQ_OPLOCK 0x00000002
#define REQ_BATCHOPLOCK 0x00000004 #define REQ_BATCHOPLOCK 0x00000004
#define REQ_OPENDIRONLY 0x00000008 #define REQ_OPENDIRONLY 0x00000008
...@@ -680,6 +682,62 @@ typedef struct smb_com_open_rsp { ...@@ -680,6 +682,62 @@ typedef struct smb_com_open_rsp {
__u16 ByteCount; /* bct = 0 */ __u16 ByteCount; /* bct = 0 */
} OPEN_RSP; } OPEN_RSP;
/* format of legacy open request */
typedef struct smb_com_openx_req {
struct smb_hdr hdr; /* wct = 15 */
__u8 AndXCommand;
__u8 AndXReserved;
__le16 AndXOffset;
__le16 OpenFlags;
__le16 Mode;
__le16 Sattr; /* search attributes */
__le16 FileAttributes; /* dos attrs */
__le32 CreateTime; /* os2 format */
__le16 OpenFunction;
__le32 EndOfFile;
__le32 Timeout;
__le32 Reserved;
__u16 ByteCount; /* file name follows */
char fileName[1];
} OPENX_REQ;
typedef struct smb_com_openx_rsp {
struct smb_hdr hdr; /* wct = 15 */
__u8 AndXCommand;
__u8 AndXReserved;
__le16 AndXOffset;
__u16 Fid;
__le16 FileAttributes;
__le32 LastWriteTime; /* os2 format */
__le32 EndOfFile;
__le16 Access;
__le16 FileType;
__le16 IPCState;
__le16 Action;
__u32 FileId;
__u16 Reserved;
__u16 ByteCount;
} OPENX_RSP;
/* Legacy write request for older servers */
typedef struct smb_com_writex_req {
struct smb_hdr hdr; /* wct = 12 */
__u8 AndXCommand;
__u8 AndXReserved;
__le16 AndXOffset;
__u16 Fid;
__le32 OffsetLow;
__u32 Reserved; /* Timeout */
__le16 WriteMode; /* 1 = write through */
__le16 Remaining;
__le16 Reserved2;
__le16 DataLengthLow;
__le16 DataOffset;
__le16 ByteCount;
__u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */
char Data[0];
} WRITEX_REQ;
typedef struct smb_com_write_req { typedef struct smb_com_write_req {
struct smb_hdr hdr; /* wct = 14 */ struct smb_hdr hdr; /* wct = 14 */
__u8 AndXCommand; __u8 AndXCommand;
...@@ -711,6 +769,21 @@ typedef struct smb_com_write_rsp { ...@@ -711,6 +769,21 @@ typedef struct smb_com_write_rsp {
__u16 ByteCount; __u16 ByteCount;
} WRITE_RSP; } WRITE_RSP;
/* legacy read request for older servers */
typedef struct smb_com_readx_req {
struct smb_hdr hdr; /* wct = 10 */
__u8 AndXCommand;
__u8 AndXReserved;
__le16 AndXOffset;
__u16 Fid;
__le32 OffsetLow;
__le16 MaxCount;
__le16 MinCount; /* obsolete */
__le32 Reserved;
__le16 Remaining;
__le16 ByteCount;
} READX_REQ;
typedef struct smb_com_read_req { typedef struct smb_com_read_req {
struct smb_hdr hdr; /* wct = 12 */ struct smb_hdr hdr; /* wct = 12 */
__u8 AndXCommand; __u8 AndXCommand;
......
...@@ -218,9 +218,17 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, ...@@ -218,9 +218,17 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
const int access_flags, const int omode, const int access_flags, const int omode,
__u16 * netfid, int *pOplock, FILE_ALL_INFO *, __u16 * netfid, int *pOplock, FILE_ALL_INFO *,
const struct nls_table *nls_codepage, int remap); const struct nls_table *nls_codepage, int remap);
extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int disposition,
const int access_flags, const int omode,
__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
const struct nls_table *nls_codepage, int remap);
extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
const int smb_file_id); const int smb_file_id);
extern int SMBLegacyRead(const int xid, struct cifsTconInfo *tcon,
const int netfid, unsigned int count,
const __u64 lseek, unsigned int *nbytes, char **buf);
extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
const int netfid, unsigned int count, const int netfid, unsigned int count,
const __u64 lseek, unsigned int *nbytes, char **buf); const __u64 lseek, unsigned int *nbytes, char **buf);
......
...@@ -680,6 +680,146 @@ CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, ...@@ -680,6 +680,146 @@ CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
return rc; return rc;
} }
static __u16 convert_disposition(int disposition)
{
__u16 ofun = 0;
switch (disposition) {
case FILE_SUPERSEDE:
ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
break;
case FILE_OPEN:
ofun = SMBOPEN_OAPPEND;
break;
case FILE_CREATE:
ofun = SMBOPEN_OCREATE;
break;
case FILE_OPEN_IF:
ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
break;
case FILE_OVERWRITE:
ofun = SMBOPEN_OTRUNC;
break;
case FILE_OVERWRITE_IF:
ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
break;
default:
cFYI(1,("unknown disposition %d",disposition));
ofun = SMBOPEN_OAPPEND; /* regular open */
}
return ofun;
}
int
SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int openDisposition,
const int access_flags, const int create_options, __u16 * netfid,
int *pOplock, FILE_ALL_INFO * pfile_info,
const struct nls_table *nls_codepage, int remap)
{
int rc = -EACCES;
OPENX_REQ *pSMB = NULL;
OPENX_RSP *pSMBr = NULL;
int bytes_returned;
int name_len;
__u16 count;
OldOpenRetry:
rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
return rc;
pSMB->AndXCommand = 0xFF; /* none */
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
count = 1; /* account for one byte pad to word boundary */
name_len =
cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
fileName, PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve check for buffer overruns BB */
count = 0; /* no pad */
name_len = strnlen(fileName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->fileName, fileName, name_len);
}
if (*pOplock & REQ_OPLOCK)
pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
else if (*pOplock & REQ_BATCHOPLOCK) {
pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
}
pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
/* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
/* 0 = read
1 = write
2 = rw
3 = execute
*/
pSMB->Mode = cpu_to_le16(2);
pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
/* set file as system file if special file such
as fifo and server expecting SFU style and
no Unix extensions */
if(create_options & CREATE_OPTION_SPECIAL)
pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
else
pSMB->FileAttributes = cpu_to_le16(ATTR_NORMAL);
/* if ((omode & S_IWUGO) == 0)
pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
/* Above line causes problems due to vfs splitting create into two
pieces - need to set mode after file created not while it is
being created */
/* BB FIXME BB */
/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
/* BB FIXME END BB */
pSMB->OpenFunction = convert_disposition(openDisposition);
count += name_len;
pSMB->hdr.smb_buf_length += count;
pSMB->ByteCount = cpu_to_le16(count);
/* long_op set to 1 to allow for oplock break timeouts */
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 1);
cifs_stats_inc(&tcon->num_opens);
if (rc) {
cFYI(1, ("Error in Open = %d", rc));
} else {
/* BB verify if wct == 15 */
/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
*netfid = pSMBr->Fid; /* cifs fid stays in le */
/* Let caller know file was created so we can set the mode. */
/* Do we care about the CreateAction in any other cases? */
/* BB FIXME BB */
/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
*pOplock |= CIFS_CREATE_ACTION; */
/* BB FIXME END */
if(pfile_info) {
pfile_info->CreationTime = 0; /* BB convert CreateTime*/
pfile_info->LastAccessTime = 0; /* BB fixme */
pfile_info->LastWriteTime = 0; /* BB fixme */
pfile_info->ChangeTime = 0; /* BB fixme */
pfile_info->Attributes = pSMBr->FileAttributes;
/* the file_info buf is endian converted by caller */
pfile_info->AllocationSize = pSMBr->EndOfFile;
pfile_info->EndOfFile = pSMBr->EndOfFile;
pfile_info->NumberOfLinks = cpu_to_le32(1);
}
}
cifs_buf_release(pSMB);
if (rc == -EAGAIN)
goto OldOpenRetry;
return rc;
}
int int
CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int openDisposition, const char *fileName, const int openDisposition,
...@@ -783,6 +923,81 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, ...@@ -783,6 +923,81 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
return rc; return rc;
} }
int
SMBLegacyRead(const int xid, struct cifsTconInfo *tcon,
const int netfid, unsigned int count,
const __u64 lseek, unsigned int *nbytes, char **buf)
{
int rc = -EACCES;
READX_REQ *pSMB = NULL;
READ_RSP *pSMBr = NULL;
char *pReadData = NULL;
int bytes_returned;
cFYI(1,("Legacy read %d bytes fid %d",count,netfid));
/* field is shorter in legacy read, only 16 bits */
if(count > 2048)
count = 2048; /* BB FIXME make this configurable */
if(lseek > 0xFFFFFFFF)
return -EIO; /* can not read that far into file on old server */
*nbytes = 0;
rc = smb_init(SMB_COM_READ_ANDX, 10, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
return rc;
/* tcon and ses pointer are checked in smb_init */
if (tcon->ses->server == NULL)
return -ECONNABORTED;
pSMB->AndXCommand = 0xFF; /* none */
pSMB->Fid = netfid;
pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
pSMB->Remaining = 0;
pSMB->MaxCount = cpu_to_le16(count);
pSMB->Reserved = 0; /* Must Be Zero */
pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->num_reads);
if (rc) {
cERROR(1, ("Send error in legacy read = %d", rc));
} else {
int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
data_length = data_length << 16;
data_length += le16_to_cpu(pSMBr->DataLength);
*nbytes = data_length;
/*check that DataLength would not go beyond end of SMB */
if ((data_length > CIFSMaxBufSize) || (data_length > count)) {
cFYI(1,("bad length %d for count %d",data_length,count));
rc = -EIO;
*nbytes = 0;
} else {
pReadData = (char *) (&pSMBr->hdr.Protocol) +
le16_to_cpu(pSMBr->DataOffset);
/* if(rc = copy_to_user(buf, pReadData, data_length)) {
cERROR(1,("Faulting on read rc = %d",rc));
rc = -EFAULT;
}*/ /* can not use copy_to_user when using page cache*/
if(*buf)
memcpy(*buf,pReadData,data_length);
}
}
if(*buf)
cifs_buf_release(pSMB);
else
*buf = (char *)pSMB;
/* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
return rc;
}
/* If no buffer passed in, then caller wants to do the copy /* If no buffer passed in, then caller wants to do the copy
as in the case of readpages so the SMB buffer must be as in the case of readpages so the SMB buffer must be
freed by the caller */ freed by the caller */
......
...@@ -184,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -184,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
desiredAccess, CREATE_NOT_DIR, desiredAccess, CREATE_NOT_DIR,
&fileHandle, &oplock, buf, cifs_sb->local_nls, &fileHandle, &oplock, 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 == -EIO) {
/* old server, retry the open legacy style */
rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR,
&fileHandle, &oplock, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
}
if (rc) { if (rc) {
cFYI(1, ("cifs_create returned 0x%x ", rc)); cFYI(1, ("cifs_create returned 0x%x ", rc));
} else { } else {
......
...@@ -256,6 +256,13 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -256,6 +256,13 @@ int cifs_open(struct inode *inode, struct file *file)
CREATE_NOT_DIR, &netfid, &oplock, buf, CREATE_NOT_DIR, &netfid, &oplock, buf,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
& CIFS_MOUNT_MAP_SPECIAL_CHR); & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc == -EIO) {
/* Old server, try legacy style OpenX */
rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
& CIFS_MOUNT_MAP_SPECIAL_CHR);
}
if (rc) { if (rc) {
cFYI(1, ("cifs_open returned 0x%x ", rc)); cFYI(1, ("cifs_open returned 0x%x ", rc));
goto out; goto out;
...@@ -1210,7 +1217,12 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, ...@@ -1210,7 +1217,12 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
open_file->netfid, open_file->netfid,
current_read_size, *poffset, current_read_size, *poffset,
&bytes_read, &smb_read_data); &bytes_read, &smb_read_data);
if(rc == -EINVAL) {
rc = SMBLegacyRead(xid, pTcon,
open_file->netfid,
current_read_size, *poffset,
&bytes_read, &smb_read_data);
}
pSMBr = (struct smb_com_read_rsp *)smb_read_data; pSMBr = (struct smb_com_read_rsp *)smb_read_data;
if (copy_to_user(current_offset, if (copy_to_user(current_offset,
smb_read_data + 4 /* RFC1001 hdr */ smb_read_data + 4 /* RFC1001 hdr */
...@@ -1287,6 +1299,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, ...@@ -1287,6 +1299,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
open_file->netfid, open_file->netfid,
current_read_size, *poffset, current_read_size, *poffset,
&bytes_read, &current_offset); &bytes_read, &current_offset);
if(rc == -EINVAL) {
rc = SMBLegacyRead(xid, pTcon,
open_file->netfid,
current_read_size, *poffset,
&bytes_read, &current_offset);
}
} }
if (rc || (bytes_read == 0)) { if (rc || (bytes_read == 0)) {
if (total_read) { if (total_read) {
...@@ -1443,7 +1461,14 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1443,7 +1461,14 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
open_file->netfid, open_file->netfid,
read_size, offset, read_size, offset,
&bytes_read, &smb_read_data); &bytes_read, &smb_read_data);
/* BB need to check return code here */ if (rc == -EINVAL) {
rc = SMBLegacyRead(xid, pTcon,
open_file->netfid,
read_size, offset,
&bytes_read, &smb_read_data);
}
/* BB more RC checks ? */
if (rc== -EAGAIN) { if (rc== -EAGAIN) {
if (smb_read_data) { if (smb_read_data) {
cifs_buf_release(smb_read_data); cifs_buf_release(smb_read_data);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册