diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r-- | fs/cifs/cifssmb.c | 160 |
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 |
954 | int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 960 | int |
961 | CIFSSMBWrite2(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 | ||
1014 | int | 1035 | int |
@@ -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 | ||
3292 | int | ||
3293 | CIFSSMBSetFSUnixInfo(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")); | ||
3303 | SETFSUnixRetry: | ||
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 | ||
3258 | int | 3364 | int |
3259 | CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, | 3365 | CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, |