aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifspdu.h73
-rw-r--r--fs/cifs/cifsproto.h8
-rw-r--r--fs/cifs/cifssmb.c215
-rw-r--r--fs/cifs/dir.c7
-rw-r--r--fs/cifs/file.c29
5 files changed, 330 insertions, 2 deletions
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 026c88f486a2..cf466595b0d4 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -40,6 +40,7 @@
40#define SMB_COM_SETATTR 0x09 /* trivial response */ 40#define SMB_COM_SETATTR 0x09 /* trivial response */
41#define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ 41#define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */
42#define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ 42#define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/
43#define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */
43#define SMB_COM_READ_ANDX 0x2E 44#define SMB_COM_READ_ANDX 0x2E
44#define SMB_COM_WRITE_ANDX 0x2F 45#define SMB_COM_WRITE_ANDX 0x2F
45#define SMB_COM_TRANSACTION2 0x32 46#define SMB_COM_TRANSACTION2 0x32
@@ -625,6 +626,7 @@ typedef struct smb_com_findclose_req {
625} FINDCLOSE_REQ; 626} FINDCLOSE_REQ;
626 627
627/* OpenFlags */ 628/* OpenFlags */
629#define REQ_MORE_INFO 0x00000001 /* legacy (OPEN_AND_X) only */
628#define REQ_OPLOCK 0x00000002 630#define REQ_OPLOCK 0x00000002
629#define REQ_BATCHOPLOCK 0x00000004 631#define REQ_BATCHOPLOCK 0x00000004
630#define REQ_OPENDIRONLY 0x00000008 632#define REQ_OPENDIRONLY 0x00000008
@@ -680,6 +682,62 @@ typedef struct smb_com_open_rsp {
680 __u16 ByteCount; /* bct = 0 */ 682 __u16 ByteCount; /* bct = 0 */
681} OPEN_RSP; 683} OPEN_RSP;
682 684
685/* format of legacy open request */
686typedef struct smb_com_openx_req {
687 struct smb_hdr hdr; /* wct = 15 */
688 __u8 AndXCommand;
689 __u8 AndXReserved;
690 __le16 AndXOffset;
691 __le16 OpenFlags;
692 __le16 Mode;
693 __le16 Sattr; /* search attributes */
694 __le16 FileAttributes; /* dos attrs */
695 __le32 CreateTime; /* os2 format */
696 __le16 OpenFunction;
697 __le32 EndOfFile;
698 __le32 Timeout;
699 __le32 Reserved;
700 __u16 ByteCount; /* file name follows */
701 char fileName[1];
702} OPENX_REQ;
703
704typedef struct smb_com_openx_rsp {
705 struct smb_hdr hdr; /* wct = 15 */
706 __u8 AndXCommand;
707 __u8 AndXReserved;
708 __le16 AndXOffset;
709 __u16 Fid;
710 __le16 FileAttributes;
711 __le32 LastWriteTime; /* os2 format */
712 __le32 EndOfFile;
713 __le16 Access;
714 __le16 FileType;
715 __le16 IPCState;
716 __le16 Action;
717 __u32 FileId;
718 __u16 Reserved;
719 __u16 ByteCount;
720} OPENX_RSP;
721
722/* Legacy write request for older servers */
723typedef struct smb_com_writex_req {
724 struct smb_hdr hdr; /* wct = 12 */
725 __u8 AndXCommand;
726 __u8 AndXReserved;
727 __le16 AndXOffset;
728 __u16 Fid;
729 __le32 OffsetLow;
730 __u32 Reserved; /* Timeout */
731 __le16 WriteMode; /* 1 = write through */
732 __le16 Remaining;
733 __le16 Reserved2;
734 __le16 DataLengthLow;
735 __le16 DataOffset;
736 __le16 ByteCount;
737 __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */
738 char Data[0];
739} WRITEX_REQ;
740
683typedef struct smb_com_write_req { 741typedef struct smb_com_write_req {
684 struct smb_hdr hdr; /* wct = 14 */ 742 struct smb_hdr hdr; /* wct = 14 */
685 __u8 AndXCommand; 743 __u8 AndXCommand;
@@ -711,6 +769,21 @@ typedef struct smb_com_write_rsp {
711 __u16 ByteCount; 769 __u16 ByteCount;
712} WRITE_RSP; 770} WRITE_RSP;
713 771
772/* legacy read request for older servers */
773typedef struct smb_com_readx_req {
774 struct smb_hdr hdr; /* wct = 10 */
775 __u8 AndXCommand;
776 __u8 AndXReserved;
777 __le16 AndXOffset;
778 __u16 Fid;
779 __le32 OffsetLow;
780 __le16 MaxCount;
781 __le16 MinCount; /* obsolete */
782 __le32 Reserved;
783 __le16 Remaining;
784 __le16 ByteCount;
785} READX_REQ;
786
714typedef struct smb_com_read_req { 787typedef struct smb_com_read_req {
715 struct smb_hdr hdr; /* wct = 12 */ 788 struct smb_hdr hdr; /* wct = 12 */
716 __u8 AndXCommand; 789 __u8 AndXCommand;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 28b1ebbd3801..c411f2e001aa 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -218,9 +218,17 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
218 const int access_flags, const int omode, 218 const int access_flags, const int omode,
219 __u16 * netfid, int *pOplock, FILE_ALL_INFO *, 219 __u16 * netfid, int *pOplock, FILE_ALL_INFO *,
220 const struct nls_table *nls_codepage, int remap); 220 const struct nls_table *nls_codepage, int remap);
221extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
222 const char *fileName, const int disposition,
223 const int access_flags, const int omode,
224 __u16 * netfid, int *pOplock, FILE_ALL_INFO *,
225 const struct nls_table *nls_codepage, int remap);
221extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, 226extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
222 const int smb_file_id); 227 const int smb_file_id);
223 228
229extern int SMBLegacyRead(const int xid, struct cifsTconInfo *tcon,
230 const int netfid, unsigned int count,
231 const __u64 lseek, unsigned int *nbytes, char **buf);
224extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, 232extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
225 const int netfid, unsigned int count, 233 const int netfid, unsigned int count,
226 const __u64 lseek, unsigned int *nbytes, char **buf); 234 const __u64 lseek, unsigned int *nbytes, char **buf);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 67a6240ff2ba..c8ae3ef422ba 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -680,6 +680,146 @@ MkDirRetry:
680 return rc; 680 return rc;
681} 681}
682 682
683static __u16 convert_disposition(int disposition)
684{
685 __u16 ofun = 0;
686
687 switch (disposition) {
688 case FILE_SUPERSEDE:
689 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
690 break;
691 case FILE_OPEN:
692 ofun = SMBOPEN_OAPPEND;
693 break;
694 case FILE_CREATE:
695 ofun = SMBOPEN_OCREATE;
696 break;
697 case FILE_OPEN_IF:
698 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
699 break;
700 case FILE_OVERWRITE:
701 ofun = SMBOPEN_OTRUNC;
702 break;
703 case FILE_OVERWRITE_IF:
704 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
705 break;
706 default:
707 cFYI(1,("unknown disposition %d",disposition));
708 ofun = SMBOPEN_OAPPEND; /* regular open */
709 }
710 return ofun;
711}
712
713int
714SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
715 const char *fileName, const int openDisposition,
716 const int access_flags, const int create_options, __u16 * netfid,
717 int *pOplock, FILE_ALL_INFO * pfile_info,
718 const struct nls_table *nls_codepage, int remap)
719{
720 int rc = -EACCES;
721 OPENX_REQ *pSMB = NULL;
722 OPENX_RSP *pSMBr = NULL;
723 int bytes_returned;
724 int name_len;
725 __u16 count;
726
727OldOpenRetry:
728 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
729 (void **) &pSMBr);
730 if (rc)
731 return rc;
732
733 pSMB->AndXCommand = 0xFF; /* none */
734
735 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
736 count = 1; /* account for one byte pad to word boundary */
737 name_len =
738 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
739 fileName, PATH_MAX, nls_codepage, remap);
740 name_len++; /* trailing null */
741 name_len *= 2;
742 } else { /* BB improve check for buffer overruns BB */
743 count = 0; /* no pad */
744 name_len = strnlen(fileName, PATH_MAX);
745 name_len++; /* trailing null */
746 strncpy(pSMB->fileName, fileName, name_len);
747 }
748 if (*pOplock & REQ_OPLOCK)
749 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
750 else if (*pOplock & REQ_BATCHOPLOCK) {
751 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
752 }
753 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
754 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
755 /* 0 = read
756 1 = write
757 2 = rw
758 3 = execute
759 */
760 pSMB->Mode = cpu_to_le16(2);
761 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
762 /* set file as system file if special file such
763 as fifo and server expecting SFU style and
764 no Unix extensions */
765
766 if(create_options & CREATE_OPTION_SPECIAL)
767 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
768 else
769 pSMB->FileAttributes = cpu_to_le16(ATTR_NORMAL);
770
771 /* if ((omode & S_IWUGO) == 0)
772 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
773 /* Above line causes problems due to vfs splitting create into two
774 pieces - need to set mode after file created not while it is
775 being created */
776
777 /* BB FIXME BB */
778/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
779 /* BB FIXME END BB */
780 pSMB->OpenFunction = convert_disposition(openDisposition);
781 count += name_len;
782 pSMB->hdr.smb_buf_length += count;
783
784 pSMB->ByteCount = cpu_to_le16(count);
785 /* long_op set to 1 to allow for oplock break timeouts */
786 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
787 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
788 cifs_stats_inc(&tcon->num_opens);
789 if (rc) {
790 cFYI(1, ("Error in Open = %d", rc));
791 } else {
792 /* BB verify if wct == 15 */
793
794/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
795
796 *netfid = pSMBr->Fid; /* cifs fid stays in le */
797 /* Let caller know file was created so we can set the mode. */
798 /* Do we care about the CreateAction in any other cases? */
799 /* BB FIXME BB */
800/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
801 *pOplock |= CIFS_CREATE_ACTION; */
802 /* BB FIXME END */
803
804 if(pfile_info) {
805 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
806 pfile_info->LastAccessTime = 0; /* BB fixme */
807 pfile_info->LastWriteTime = 0; /* BB fixme */
808 pfile_info->ChangeTime = 0; /* BB fixme */
809 pfile_info->Attributes = pSMBr->FileAttributes;
810 /* the file_info buf is endian converted by caller */
811 pfile_info->AllocationSize = pSMBr->EndOfFile;
812 pfile_info->EndOfFile = pSMBr->EndOfFile;
813 pfile_info->NumberOfLinks = cpu_to_le32(1);
814 }
815 }
816
817 cifs_buf_release(pSMB);
818 if (rc == -EAGAIN)
819 goto OldOpenRetry;
820 return rc;
821}
822
683int 823int
684CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, 824CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
685 const char *fileName, const int openDisposition, 825 const char *fileName, const int openDisposition,
@@ -783,6 +923,81 @@ openRetry:
783 return rc; 923 return rc;
784} 924}
785 925
926int
927SMBLegacyRead(const int xid, struct cifsTconInfo *tcon,
928 const int netfid, unsigned int count,
929 const __u64 lseek, unsigned int *nbytes, char **buf)
930{
931 int rc = -EACCES;
932 READX_REQ *pSMB = NULL;
933 READ_RSP *pSMBr = NULL;
934 char *pReadData = NULL;
935 int bytes_returned;
936
937 cFYI(1,("Legacy read %d bytes fid %d",count,netfid));
938
939 /* field is shorter in legacy read, only 16 bits */
940 if(count > 2048)
941 count = 2048; /* BB FIXME make this configurable */
942
943 if(lseek > 0xFFFFFFFF)
944 return -EIO; /* can not read that far into file on old server */
945
946 *nbytes = 0;
947 rc = smb_init(SMB_COM_READ_ANDX, 10, tcon, (void **) &pSMB,
948 (void **) &pSMBr);
949 if (rc)
950 return rc;
951
952 /* tcon and ses pointer are checked in smb_init */
953 if (tcon->ses->server == NULL)
954 return -ECONNABORTED;
955
956 pSMB->AndXCommand = 0xFF; /* none */
957 pSMB->Fid = netfid;
958 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
959 pSMB->Remaining = 0;
960 pSMB->MaxCount = cpu_to_le16(count);
961 pSMB->Reserved = 0; /* Must Be Zero */
962 pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */
963
964 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
965 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
966 cifs_stats_inc(&tcon->num_reads);
967 if (rc) {
968 cERROR(1, ("Send error in legacy read = %d", rc));
969 } else {
970 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
971 data_length = data_length << 16;
972 data_length += le16_to_cpu(pSMBr->DataLength);
973 *nbytes = data_length;
974
975 /*check that DataLength would not go beyond end of SMB */
976 if ((data_length > CIFSMaxBufSize) || (data_length > count)) {
977 cFYI(1,("bad length %d for count %d",data_length,count));
978 rc = -EIO;
979 *nbytes = 0;
980 } else {
981 pReadData = (char *) (&pSMBr->hdr.Protocol) +
982 le16_to_cpu(pSMBr->DataOffset);
983/* if(rc = copy_to_user(buf, pReadData, data_length)) {
984 cERROR(1,("Faulting on read rc = %d",rc));
985 rc = -EFAULT;
986 }*/ /* can not use copy_to_user when using page cache*/
987 if(*buf)
988 memcpy(*buf,pReadData,data_length);
989 }
990 }
991 if(*buf)
992 cifs_buf_release(pSMB);
993 else
994 *buf = (char *)pSMB;
995
996 /* Note: On -EAGAIN error only caller can retry on handle based calls
997 since file handle passed in no longer valid */
998 return rc;
999}
1000
786/* If no buffer passed in, then caller wants to do the copy 1001/* If no buffer passed in, then caller wants to do the copy
787 as in the case of readpages so the SMB buffer must be 1002 as in the case of readpages so the SMB buffer must be
788 freed by the caller */ 1003 freed by the caller */
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 5311c50734b0..248ddebd67f4 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -184,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
184 desiredAccess, CREATE_NOT_DIR, 184 desiredAccess, CREATE_NOT_DIR,
185 &fileHandle, &oplock, buf, cifs_sb->local_nls, 185 &fileHandle, &oplock, buf, cifs_sb->local_nls,
186 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 186 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
187 if(rc == -EIO) {
188 /* old server, retry the open legacy style */
189 rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
190 desiredAccess, CREATE_NOT_DIR,
191 &fileHandle, &oplock, buf, cifs_sb->local_nls,
192 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
193 }
187 if (rc) { 194 if (rc) {
188 cFYI(1, ("cifs_create returned 0x%x ", rc)); 195 cFYI(1, ("cifs_create returned 0x%x ", rc));
189 } else { 196 } else {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 5857d12611e6..8ae962e7c93f 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -256,6 +256,13 @@ int cifs_open(struct inode *inode, struct file *file)
256 CREATE_NOT_DIR, &netfid, &oplock, buf, 256 CREATE_NOT_DIR, &netfid, &oplock, buf,
257 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags 257 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
258 & CIFS_MOUNT_MAP_SPECIAL_CHR); 258 & CIFS_MOUNT_MAP_SPECIAL_CHR);
259 if (rc == -EIO) {
260 /* Old server, try legacy style OpenX */
261 rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
262 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
263 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
264 & CIFS_MOUNT_MAP_SPECIAL_CHR);
265 }
259 if (rc) { 266 if (rc) {
260 cFYI(1, ("cifs_open returned 0x%x ", rc)); 267 cFYI(1, ("cifs_open returned 0x%x ", rc));
261 goto out; 268 goto out;
@@ -1210,7 +1217,12 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
1210 open_file->netfid, 1217 open_file->netfid,
1211 current_read_size, *poffset, 1218 current_read_size, *poffset,
1212 &bytes_read, &smb_read_data); 1219 &bytes_read, &smb_read_data);
1213 1220 if(rc == -EINVAL) {
1221 rc = SMBLegacyRead(xid, pTcon,
1222 open_file->netfid,
1223 current_read_size, *poffset,
1224 &bytes_read, &smb_read_data);
1225 }
1214 pSMBr = (struct smb_com_read_rsp *)smb_read_data; 1226 pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1215 if (copy_to_user(current_offset, 1227 if (copy_to_user(current_offset,
1216 smb_read_data + 4 /* RFC1001 hdr */ 1228 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 open_file->netfid, 1299 open_file->netfid,
1288 current_read_size, *poffset, 1300 current_read_size, *poffset,
1289 &bytes_read, &current_offset); 1301 &bytes_read, &current_offset);
1302 if(rc == -EINVAL) {
1303 rc = SMBLegacyRead(xid, pTcon,
1304 open_file->netfid,
1305 current_read_size, *poffset,
1306 &bytes_read, &current_offset);
1307 }
1290 } 1308 }
1291 if (rc || (bytes_read == 0)) { 1309 if (rc || (bytes_read == 0)) {
1292 if (total_read) { 1310 if (total_read) {
@@ -1443,7 +1461,14 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
1443 open_file->netfid, 1461 open_file->netfid,
1444 read_size, offset, 1462 read_size, offset,
1445 &bytes_read, &smb_read_data); 1463 &bytes_read, &smb_read_data);
1446 /* BB need to check return code here */ 1464 if (rc == -EINVAL) {
1465 rc = SMBLegacyRead(xid, pTcon,
1466 open_file->netfid,
1467 read_size, offset,
1468 &bytes_read, &smb_read_data);
1469 }
1470
1471 /* BB more RC checks ? */
1447 if (rc== -EAGAIN) { 1472 if (rc== -EAGAIN) {
1448 if (smb_read_data) { 1473 if (smb_read_data) {
1449 cifs_buf_release(smb_read_data); 1474 cifs_buf_release(smb_read_data);