aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/cifssmb.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r--fs/cifs/cifssmb.c160
1 files changed, 133 insertions, 27 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 3c628bf667a5..e555cb5cf493 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -738,7 +738,13 @@ openRetry:
738 } 738 }
739 pSMB->DesiredAccess = cpu_to_le32(access_flags); 739 pSMB->DesiredAccess = cpu_to_le32(access_flags);
740 pSMB->AllocationSize = 0; 740 pSMB->AllocationSize = 0;
741 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); 741 /* set file as system file if special file such
742 as fifo and server expecting SFU style and
743 no Unix extensions */
744 if(create_options & CREATE_OPTION_SPECIAL)
745 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
746 else
747 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
742 /* XP does not handle ATTR_POSIX_SEMANTICS */ 748 /* XP does not handle ATTR_POSIX_SEMANTICS */
743 /* but it helps speed up case sensitive checks for other 749 /* but it helps speed up case sensitive checks for other
744 servers such as Samba */ 750 servers such as Samba */
@@ -752,7 +758,7 @@ openRetry:
752 being created */ 758 being created */
753 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); 759 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
754 pSMB->CreateDisposition = cpu_to_le32(openDisposition); 760 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
755 pSMB->CreateOptions = cpu_to_le32(create_options); 761 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
756 /* BB Expirement with various impersonation levels and verify */ 762 /* BB Expirement with various impersonation levels and verify */
757 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); 763 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
758 pSMB->SecurityFlags = 764 pSMB->SecurityFlags =
@@ -951,56 +957,69 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
951} 957}
952 958
953#ifdef CONFIG_CIFS_EXPERIMENTAL 959#ifdef CONFIG_CIFS_EXPERIMENTAL
954int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, 960int
961CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
955 const int netfid, const unsigned int count, 962 const int netfid, const unsigned int count,
956 const __u64 offset, unsigned int *nbytes, const char __user *buf, 963 const __u64 offset, unsigned int *nbytes, const char *buf,
957 const int long_op) 964 const int long_op)
958{ 965{
959 int rc = -EACCES; 966 int rc = -EACCES;
960 WRITE_REQ *pSMB = NULL; 967 WRITE_REQ *pSMB = NULL;
961 WRITE_RSP *pSMBr = NULL; 968 int bytes_returned;
962 /*int bytes_returned;*/ 969 int smb_hdr_len;
963 unsigned bytes_sent; 970 __u32 bytes_sent;
964 __u16 byte_count; 971 __u16 byte_count;
965 972
973 cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
966 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB); 974 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
967
968 if (rc) 975 if (rc)
969 return rc; 976 return rc;
970
971 pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */
972
973 /* tcon and ses pointer are checked in smb_init */ 977 /* tcon and ses pointer are checked in smb_init */
974 if (tcon->ses->server == NULL) 978 if (tcon->ses->server == NULL)
975 return -ECONNABORTED; 979 return -ECONNABORTED;
976 980
977 pSMB->AndXCommand = 0xFF; /* none */ 981 pSMB->AndXCommand = 0xFF; /* none */
978 pSMB->Fid = netfid; 982 pSMB->Fid = netfid;
979 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); 983 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
980 pSMB->OffsetHigh = cpu_to_le32(offset >> 32); 984 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
981 pSMB->Reserved = 0xFFFFFFFF; 985 pSMB->Reserved = 0xFFFFFFFF;
982 pSMB->WriteMode = 0; 986 pSMB->WriteMode = 0;
983 pSMB->Remaining = 0; 987 pSMB->Remaining = 0;
984 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF; 988
989 /* Can increase buffer size if buffer is big enough in some cases - ie
990 can send more if LARGE_WRITE_X capability returned by the server and if
991 our buffer is big enough or if we convert to iovecs on socket writes
992 and eliminate the copy to the CIFS buffer */
993 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
994 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
995 } else {
996 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
997 & ~0xFF;
998 }
999
985 if (bytes_sent > count) 1000 if (bytes_sent > count)
986 bytes_sent = count; 1001 bytes_sent = count;
987 pSMB->DataLengthHigh = 0;
988 pSMB->DataOffset = 1002 pSMB->DataOffset =
989 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); 1003 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
990 1004
991 byte_count = bytes_sent + 1 /* pad */ ; 1005 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
992 pSMB->DataLengthLow = cpu_to_le16(bytes_sent); 1006 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
993 pSMB->DataLengthHigh = 0; 1007 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
994 pSMB->hdr.smb_buf_length += byte_count; 1008 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1009 pSMB->hdr.smb_buf_length += bytes_sent+1;
995 pSMB->ByteCount = cpu_to_le16(byte_count); 1010 pSMB->ByteCount = cpu_to_le16(byte_count);
996 1011
997/* rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, 1012 rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
998 (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */ /* BB fixme BB */ 1013 buf, bytes_sent, &bytes_returned, long_op);
999 if (rc) { 1014 if (rc) {
1000 cFYI(1, ("Send error in write2 (large write) = %d", rc)); 1015 cFYI(1, ("Send error in write = %d", rc));
1001 *nbytes = 0; 1016 *nbytes = 0;
1002 } else 1017 } else {
1003 *nbytes = le16_to_cpu(pSMBr->Count); 1018 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1019 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1020 *nbytes = (*nbytes) << 16;
1021 *nbytes += le16_to_cpu(pSMBr->Count);
1022 }
1004 1023
1005 cifs_small_buf_release(pSMB); 1024 cifs_small_buf_release(pSMB);
1006 1025
@@ -1009,6 +1028,8 @@ int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1009 1028
1010 return rc; 1029 return rc;
1011} 1030}
1031
1032
1012#endif /* CIFS_EXPERIMENTAL */ 1033#endif /* CIFS_EXPERIMENTAL */
1013 1034
1014int 1035int
@@ -2396,7 +2417,9 @@ findUniqueRetry:
2396 if (rc) { 2417 if (rc) {
2397 cFYI(1, ("Send error in FindFileDirInfo = %d", rc)); 2418 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2398 } else { /* decode response */ 2419 } else { /* decode response */
2399 2420#ifdef CONFIG_CIFS_STATS
2421 atomic_inc(&tcon->num_ffirst);
2422#endif
2400 /* BB fill in */ 2423 /* BB fill in */
2401 } 2424 }
2402 2425
@@ -2414,7 +2437,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2414 const char *searchName, 2437 const char *searchName,
2415 const struct nls_table *nls_codepage, 2438 const struct nls_table *nls_codepage,
2416 __u16 * pnetfid, 2439 __u16 * pnetfid,
2417 struct cifs_search_info * psrch_inf, int remap) 2440 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
2418{ 2441{
2419/* level 257 SMB_ */ 2442/* level 257 SMB_ */
2420 TRANSACTION2_FFIRST_REQ *pSMB = NULL; 2443 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
@@ -2441,7 +2464,7 @@ findFirstRetry:
2441 it got remapped to 0xF03A as if it were part of the 2464 it got remapped to 0xF03A as if it were part of the
2442 directory name instead of a wildcard */ 2465 directory name instead of a wildcard */
2443 name_len *= 2; 2466 name_len *= 2;
2444 pSMB->FileName[name_len] = '\\'; 2467 pSMB->FileName[name_len] = dirsep;
2445 pSMB->FileName[name_len+1] = 0; 2468 pSMB->FileName[name_len+1] = 0;
2446 pSMB->FileName[name_len+2] = '*'; 2469 pSMB->FileName[name_len+2] = '*';
2447 pSMB->FileName[name_len+3] = 0; 2470 pSMB->FileName[name_len+3] = 0;
@@ -2455,7 +2478,7 @@ findFirstRetry:
2455 if(name_len > buffersize-header) 2478 if(name_len > buffersize-header)
2456 free buffer exit; BB */ 2479 free buffer exit; BB */
2457 strncpy(pSMB->FileName, searchName, name_len); 2480 strncpy(pSMB->FileName, searchName, name_len);
2458 pSMB->FileName[name_len] = '\\'; 2481 pSMB->FileName[name_len] = dirsep;
2459 pSMB->FileName[name_len+1] = '*'; 2482 pSMB->FileName[name_len+1] = '*';
2460 pSMB->FileName[name_len+2] = 0; 2483 pSMB->FileName[name_len+2] = 0;
2461 name_len += 3; 2484 name_len += 3;
@@ -2509,6 +2532,9 @@ findFirstRetry:
2509 if (rc == -EAGAIN) 2532 if (rc == -EAGAIN)
2510 goto findFirstRetry; 2533 goto findFirstRetry;
2511 } else { /* decode response */ 2534 } else { /* decode response */
2535#ifdef CONFIG_CIFS_STATS
2536 atomic_inc(&tcon->num_ffirst);
2537#endif
2512 /* BB remember to free buffer if error BB */ 2538 /* BB remember to free buffer if error BB */
2513 rc = validate_t2((struct smb_t2_rsp *)pSMBr); 2539 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2514 if(rc == 0) { 2540 if(rc == 0) {
@@ -2602,6 +2628,9 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2602 if(name_len < PATH_MAX) { 2628 if(name_len < PATH_MAX) {
2603 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len); 2629 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2604 byte_count += name_len; 2630 byte_count += name_len;
2631 /* 14 byte parm len above enough for 2 byte null terminator */
2632 pSMB->ResumeFileName[name_len] = 0;
2633 pSMB->ResumeFileName[name_len+1] = 0;
2605 } else { 2634 } else {
2606 rc = -EINVAL; 2635 rc = -EINVAL;
2607 goto FNext2_err_exit; 2636 goto FNext2_err_exit;
@@ -2622,6 +2651,9 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2622 } else 2651 } else
2623 cFYI(1, ("FindNext returned = %d", rc)); 2652 cFYI(1, ("FindNext returned = %d", rc));
2624 } else { /* decode response */ 2653 } else { /* decode response */
2654#ifdef CONFIG_CIFS_STATS
2655 atomic_inc(&tcon->num_fnext);
2656#endif
2625 rc = validate_t2((struct smb_t2_rsp *)pSMBr); 2657 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2626 2658
2627 if(rc == 0) { 2659 if(rc == 0) {
@@ -2691,6 +2723,9 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle
2691 if (rc) { 2723 if (rc) {
2692 cERROR(1, ("Send error in FindClose = %d", rc)); 2724 cERROR(1, ("Send error in FindClose = %d", rc));
2693 } 2725 }
2726#ifdef CONFIG_CIFS_STATS
2727 atomic_inc(&tcon->num_fclose);
2728#endif
2694 cifs_small_buf_release(pSMB); 2729 cifs_small_buf_release(pSMB);
2695 2730
2696 /* Since session is dead, search handle closed on server already */ 2731 /* Since session is dead, search handle closed on server already */
@@ -3254,6 +3289,77 @@ QFSUnixRetry:
3254 return rc; 3289 return rc;
3255} 3290}
3256 3291
3292int
3293CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
3294{
3295/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3296 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3297 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3298 int rc = 0;
3299 int bytes_returned = 0;
3300 __u16 params, param_offset, offset, byte_count;
3301
3302 cFYI(1, ("In SETFSUnixInfo"));
3303SETFSUnixRetry:
3304 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3305 (void **) &pSMBr);
3306 if (rc)
3307 return rc;
3308
3309 params = 4; /* 2 bytes zero followed by info level. */
3310 pSMB->MaxSetupCount = 0;
3311 pSMB->Reserved = 0;
3312 pSMB->Flags = 0;
3313 pSMB->Timeout = 0;
3314 pSMB->Reserved2 = 0;
3315 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3316 offset = param_offset + params;
3317
3318 pSMB->MaxParameterCount = cpu_to_le16(4);
3319 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3320 pSMB->SetupCount = 1;
3321 pSMB->Reserved3 = 0;
3322 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3323 byte_count = 1 /* pad */ + params + 12;
3324
3325 pSMB->DataCount = cpu_to_le16(12);
3326 pSMB->ParameterCount = cpu_to_le16(params);
3327 pSMB->TotalDataCount = pSMB->DataCount;
3328 pSMB->TotalParameterCount = pSMB->ParameterCount;
3329 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3330 pSMB->DataOffset = cpu_to_le16(offset);
3331
3332 /* Params. */
3333 pSMB->FileNum = 0;
3334 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3335
3336 /* Data. */
3337 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3338 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3339 pSMB->ClientUnixCap = cpu_to_le64(cap);
3340
3341 pSMB->hdr.smb_buf_length += byte_count;
3342 pSMB->ByteCount = cpu_to_le16(byte_count);
3343
3344 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3345 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3346 if (rc) {
3347 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3348 } else { /* decode response */
3349 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3350 if (rc) {
3351 rc = -EIO; /* bad smb */
3352 }
3353 }
3354 cifs_buf_release(pSMB);
3355
3356 if (rc == -EAGAIN)
3357 goto SETFSUnixRetry;
3358
3359 return rc;
3360}
3361
3362
3257 3363
3258int 3364int
3259CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, 3365CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,