Loading fs/cifs/cifspdu.h +73 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ #define SMB_COM_SETATTR 0x09 /* trivial response */ #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ #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_WRITE_ANDX 0x2F #define SMB_COM_TRANSACTION2 0x32 Loading Loading @@ -625,6 +626,7 @@ typedef struct smb_com_findclose_req { } FINDCLOSE_REQ; /* OpenFlags */ #define REQ_MORE_INFO 0x00000001 /* legacy (OPEN_AND_X) only */ #define REQ_OPLOCK 0x00000002 #define REQ_BATCHOPLOCK 0x00000004 #define REQ_OPENDIRONLY 0x00000008 Loading Loading @@ -680,6 +682,62 @@ typedef struct smb_com_open_rsp { __u16 ByteCount; /* bct = 0 */ } 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 { struct smb_hdr hdr; /* wct = 14 */ __u8 AndXCommand; Loading Loading @@ -711,6 +769,21 @@ typedef struct smb_com_write_rsp { __u16 ByteCount; } 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 { struct smb_hdr hdr; /* wct = 12 */ __u8 AndXCommand; Loading fs/cifs/cifsproto.h +8 −0 Original line number Diff line number Diff line Loading @@ -218,9 +218,17 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, const int access_flags, const int omode, __u16 * netfid, int *pOplock, FILE_ALL_INFO *, 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, 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, const int netfid, unsigned int count, const __u64 lseek, unsigned int *nbytes, char **buf); Loading fs/cifs/cifssmb.c +215 −0 Original line number Diff line number Diff line Loading @@ -680,6 +680,146 @@ CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, 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 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, const char *fileName, const int openDisposition, Loading Loading @@ -783,6 +923,81 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, 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 as in the case of readpages so the SMB buffer must be freed by the caller */ Loading fs/cifs/dir.c +7 −0 Original line number Diff line number Diff line Loading @@ -184,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, desiredAccess, CREATE_NOT_DIR, &fileHandle, &oplock, buf, cifs_sb->local_nls, 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) { cFYI(1, ("cifs_create returned 0x%x ", rc)); } else { Loading fs/cifs/file.c +27 −2 Original line number Diff line number Diff line Loading @@ -256,6 +256,13 @@ int cifs_open(struct inode *inode, struct file *file) CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 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) { cFYI(1, ("cifs_open returned 0x%x ", rc)); goto out; Loading Loading @@ -1210,7 +1217,12 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, open_file->netfid, current_read_size, *poffset, &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; if (copy_to_user(current_offset, smb_read_data + 4 /* RFC1001 hdr */ Loading Loading @@ -1287,6 +1299,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, open_file->netfid, current_read_size, *poffset, &bytes_read, ¤t_offset); if(rc == -EINVAL) { rc = SMBLegacyRead(xid, pTcon, open_file->netfid, current_read_size, *poffset, &bytes_read, ¤t_offset); } } if (rc || (bytes_read == 0)) { if (total_read) { Loading Loading @@ -1443,7 +1461,14 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, open_file->netfid, read_size, offset, &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 (smb_read_data) { cifs_buf_release(smb_read_data); Loading Loading
fs/cifs/cifspdu.h +73 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ #define SMB_COM_SETATTR 0x09 /* trivial response */ #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ #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_WRITE_ANDX 0x2F #define SMB_COM_TRANSACTION2 0x32 Loading Loading @@ -625,6 +626,7 @@ typedef struct smb_com_findclose_req { } FINDCLOSE_REQ; /* OpenFlags */ #define REQ_MORE_INFO 0x00000001 /* legacy (OPEN_AND_X) only */ #define REQ_OPLOCK 0x00000002 #define REQ_BATCHOPLOCK 0x00000004 #define REQ_OPENDIRONLY 0x00000008 Loading Loading @@ -680,6 +682,62 @@ typedef struct smb_com_open_rsp { __u16 ByteCount; /* bct = 0 */ } 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 { struct smb_hdr hdr; /* wct = 14 */ __u8 AndXCommand; Loading Loading @@ -711,6 +769,21 @@ typedef struct smb_com_write_rsp { __u16 ByteCount; } 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 { struct smb_hdr hdr; /* wct = 12 */ __u8 AndXCommand; Loading
fs/cifs/cifsproto.h +8 −0 Original line number Diff line number Diff line Loading @@ -218,9 +218,17 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, const int access_flags, const int omode, __u16 * netfid, int *pOplock, FILE_ALL_INFO *, 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, 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, const int netfid, unsigned int count, const __u64 lseek, unsigned int *nbytes, char **buf); Loading
fs/cifs/cifssmb.c +215 −0 Original line number Diff line number Diff line Loading @@ -680,6 +680,146 @@ CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, 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 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, const char *fileName, const int openDisposition, Loading Loading @@ -783,6 +923,81 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, 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 as in the case of readpages so the SMB buffer must be freed by the caller */ Loading
fs/cifs/dir.c +7 −0 Original line number Diff line number Diff line Loading @@ -184,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, desiredAccess, CREATE_NOT_DIR, &fileHandle, &oplock, buf, cifs_sb->local_nls, 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) { cFYI(1, ("cifs_create returned 0x%x ", rc)); } else { Loading
fs/cifs/file.c +27 −2 Original line number Diff line number Diff line Loading @@ -256,6 +256,13 @@ int cifs_open(struct inode *inode, struct file *file) CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 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) { cFYI(1, ("cifs_open returned 0x%x ", rc)); goto out; Loading Loading @@ -1210,7 +1217,12 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, open_file->netfid, current_read_size, *poffset, &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; if (copy_to_user(current_offset, smb_read_data + 4 /* RFC1001 hdr */ Loading Loading @@ -1287,6 +1299,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, open_file->netfid, current_read_size, *poffset, &bytes_read, ¤t_offset); if(rc == -EINVAL) { rc = SMBLegacyRead(xid, pTcon, open_file->netfid, current_read_size, *poffset, &bytes_read, ¤t_offset); } } if (rc || (bytes_read == 0)) { if (total_read) { Loading Loading @@ -1443,7 +1461,14 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, open_file->netfid, read_size, offset, &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 (smb_read_data) { cifs_buf_release(smb_read_data); Loading