diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r-- | fs/cifs/cifssmb.c | 215 |
1 files changed, 215 insertions, 0 deletions
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 | ||
683 | static __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 | |||
713 | int | ||
714 | SMBLegacyOpen(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 | |||
727 | OldOpenRetry: | ||
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 | |||
683 | int | 823 | int |
684 | CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, | 824 | CIFSSMBOpen(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 | ||
926 | int | ||
927 | SMBLegacyRead(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 */ |