diff options
-rw-r--r-- | fs/cifs/cifsproto.h | 7 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 214 | ||||
-rw-r--r-- | fs/cifs/inode.c | 2 | ||||
-rw-r--r-- | fs/cifs/xattr.c | 8 |
4 files changed, 54 insertions, 177 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 5646727e33f5..88e2bc44ac58 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -363,13 +363,10 @@ extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | |||
363 | __u32 filter, struct file *file, int multishot, | 363 | __u32 filter, struct file *file, int multishot, |
364 | const struct nls_table *nls_codepage); | 364 | const struct nls_table *nls_codepage); |
365 | extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, | 365 | extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, |
366 | const unsigned char *searchName, char *EAData, | 366 | const unsigned char *searchName, |
367 | const unsigned char *ea_name, char *EAData, | ||
367 | size_t bufsize, const struct nls_table *nls_codepage, | 368 | size_t bufsize, const struct nls_table *nls_codepage, |
368 | int remap_special_chars); | 369 | int remap_special_chars); |
369 | extern ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon, | ||
370 | const unsigned char *searchName, const unsigned char *ea_name, | ||
371 | unsigned char *ea_value, size_t buf_size, | ||
372 | const struct nls_table *nls_codepage, int remap_special_chars); | ||
373 | extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, | 370 | extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, |
374 | const char *fileName, const char *ea_name, | 371 | const char *fileName, const char *ea_name, |
375 | const void *ea_value, const __u16 ea_value_len, | 372 | const void *ea_value, const __u16 ea_value_len, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index e197e1647d5d..d6d40b883abc 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -5269,12 +5269,22 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | |||
5269 | cifs_buf_release(pSMB); | 5269 | cifs_buf_release(pSMB); |
5270 | return rc; | 5270 | return rc; |
5271 | } | 5271 | } |
5272 | |||
5272 | #ifdef CONFIG_CIFS_XATTR | 5273 | #ifdef CONFIG_CIFS_XATTR |
5274 | /* | ||
5275 | * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common | ||
5276 | * function used by listxattr and getxattr type calls. When ea_name is set, | ||
5277 | * it looks for that attribute name and stuffs that value into the EAData | ||
5278 | * buffer. When ea_name is NULL, it stuffs a list of attribute names into the | ||
5279 | * buffer. In both cases, the return value is either the length of the | ||
5280 | * resulting data or a negative error code. If EAData is a NULL pointer then | ||
5281 | * the data isn't copied to it, but the length is returned. | ||
5282 | */ | ||
5273 | ssize_t | 5283 | ssize_t |
5274 | CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, | 5284 | CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, |
5275 | const unsigned char *searchName, | 5285 | const unsigned char *searchName, const unsigned char *ea_name, |
5276 | char *EAData, size_t buf_size, | 5286 | char *EAData, size_t buf_size, |
5277 | const struct nls_table *nls_codepage, int remap) | 5287 | const struct nls_table *nls_codepage, int remap) |
5278 | { | 5288 | { |
5279 | /* BB assumes one setup word */ | 5289 | /* BB assumes one setup word */ |
5280 | TRANSACTION2_QPI_REQ *pSMB = NULL; | 5290 | TRANSACTION2_QPI_REQ *pSMB = NULL; |
@@ -5403,27 +5413,46 @@ QAllEAsRetry: | |||
5403 | goto QAllEAsOut; | 5413 | goto QAllEAsOut; |
5404 | } | 5414 | } |
5405 | 5415 | ||
5406 | /* account for prefix user. and trailing null */ | 5416 | if (ea_name) { |
5407 | rc += (5 + 1 + name_len); | 5417 | if (strncmp(ea_name, temp_ptr, name_len) == 0) { |
5408 | if (rc < (int) buf_size) { | 5418 | temp_ptr += name_len + 1; |
5409 | memcpy(EAData, "user.", 5); | 5419 | rc = value_len; |
5410 | EAData += 5; | 5420 | if (buf_size == 0) |
5411 | memcpy(EAData, temp_ptr, name_len); | 5421 | goto QAllEAsOut; |
5412 | EAData += name_len; | 5422 | if ((size_t)value_len > buf_size) { |
5413 | /* null terminate name */ | 5423 | rc = -ERANGE; |
5414 | *EAData = 0; | 5424 | goto QAllEAsOut; |
5415 | ++EAData; | 5425 | } |
5416 | } else if (buf_size == 0) { | 5426 | memcpy(EAData, temp_ptr, value_len); |
5417 | /* skip copy - calc size only */ | 5427 | goto QAllEAsOut; |
5428 | } | ||
5418 | } else { | 5429 | } else { |
5419 | /* stop before overrun buffer */ | 5430 | /* account for prefix user. and trailing null */ |
5420 | rc = -ERANGE; | 5431 | rc += (5 + 1 + name_len); |
5421 | break; | 5432 | if (rc < (int) buf_size) { |
5433 | memcpy(EAData, "user.", 5); | ||
5434 | EAData += 5; | ||
5435 | memcpy(EAData, temp_ptr, name_len); | ||
5436 | EAData += name_len; | ||
5437 | /* null terminate name */ | ||
5438 | *EAData = 0; | ||
5439 | ++EAData; | ||
5440 | } else if (buf_size == 0) { | ||
5441 | /* skip copy - calc size only */ | ||
5442 | } else { | ||
5443 | /* stop before overrun buffer */ | ||
5444 | rc = -ERANGE; | ||
5445 | break; | ||
5446 | } | ||
5422 | } | 5447 | } |
5423 | temp_ptr += name_len + 1 + value_len; | 5448 | temp_ptr += name_len + 1 + value_len; |
5424 | temp_fea = (struct fea *)temp_ptr; | 5449 | temp_fea = (struct fea *)temp_ptr; |
5425 | } | 5450 | } |
5426 | 5451 | ||
5452 | /* didn't find the named attribute */ | ||
5453 | if (ea_name) | ||
5454 | rc = -ENODATA; | ||
5455 | |||
5427 | QAllEAsOut: | 5456 | QAllEAsOut: |
5428 | cifs_buf_release(pSMB); | 5457 | cifs_buf_release(pSMB); |
5429 | if (rc == -EAGAIN) | 5458 | if (rc == -EAGAIN) |
@@ -5432,155 +5461,6 @@ QAllEAsOut: | |||
5432 | return (ssize_t)rc; | 5461 | return (ssize_t)rc; |
5433 | } | 5462 | } |
5434 | 5463 | ||
5435 | ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon, | ||
5436 | const unsigned char *searchName, const unsigned char *ea_name, | ||
5437 | unsigned char *ea_value, size_t buf_size, | ||
5438 | const struct nls_table *nls_codepage, int remap) | ||
5439 | { | ||
5440 | TRANSACTION2_QPI_REQ *pSMB = NULL; | ||
5441 | TRANSACTION2_QPI_RSP *pSMBr = NULL; | ||
5442 | int rc = 0; | ||
5443 | int bytes_returned; | ||
5444 | int name_len; | ||
5445 | struct fea *temp_fea; | ||
5446 | char *temp_ptr; | ||
5447 | __u16 params, byte_count; | ||
5448 | |||
5449 | cFYI(1, ("In Query EA path %s", searchName)); | ||
5450 | QEARetry: | ||
5451 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
5452 | (void **) &pSMBr); | ||
5453 | if (rc) | ||
5454 | return rc; | ||
5455 | |||
5456 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
5457 | name_len = | ||
5458 | cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, | ||
5459 | PATH_MAX, nls_codepage, remap); | ||
5460 | name_len++; /* trailing null */ | ||
5461 | name_len *= 2; | ||
5462 | } else { /* BB improve the check for buffer overruns BB */ | ||
5463 | name_len = strnlen(searchName, PATH_MAX); | ||
5464 | name_len++; /* trailing null */ | ||
5465 | strncpy(pSMB->FileName, searchName, name_len); | ||
5466 | } | ||
5467 | |||
5468 | params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; | ||
5469 | pSMB->TotalDataCount = 0; | ||
5470 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
5471 | /* BB find exact max SMB PDU from sess structure BB */ | ||
5472 | pSMB->MaxDataCount = cpu_to_le16(4000); | ||
5473 | pSMB->MaxSetupCount = 0; | ||
5474 | pSMB->Reserved = 0; | ||
5475 | pSMB->Flags = 0; | ||
5476 | pSMB->Timeout = 0; | ||
5477 | pSMB->Reserved2 = 0; | ||
5478 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | ||
5479 | struct smb_com_transaction2_qpi_req, InformationLevel) - 4); | ||
5480 | pSMB->DataCount = 0; | ||
5481 | pSMB->DataOffset = 0; | ||
5482 | pSMB->SetupCount = 1; | ||
5483 | pSMB->Reserved3 = 0; | ||
5484 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); | ||
5485 | byte_count = params + 1 /* pad */ ; | ||
5486 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
5487 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
5488 | pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); | ||
5489 | pSMB->Reserved4 = 0; | ||
5490 | pSMB->hdr.smb_buf_length += byte_count; | ||
5491 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
5492 | |||
5493 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
5494 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
5495 | if (rc) { | ||
5496 | cFYI(1, ("Send error in Query EA = %d", rc)); | ||
5497 | } else { /* decode response */ | ||
5498 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
5499 | |||
5500 | /* BB also check enough total bytes returned */ | ||
5501 | /* BB we need to improve the validity checking | ||
5502 | of these trans2 responses */ | ||
5503 | if (rc || (pSMBr->ByteCount < 4)) | ||
5504 | rc = -EIO; /* bad smb */ | ||
5505 | /* else if (pFindData){ | ||
5506 | memcpy((char *) pFindData, | ||
5507 | (char *) &pSMBr->hdr.Protocol + | ||
5508 | data_offset, kl); | ||
5509 | }*/ else { | ||
5510 | /* check that length of list is not more than bcc */ | ||
5511 | /* check that each entry does not go beyond length | ||
5512 | of list */ | ||
5513 | /* check that each element of each entry does not | ||
5514 | go beyond end of list */ | ||
5515 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
5516 | struct fealist *ea_response_data; | ||
5517 | rc = -ENODATA; | ||
5518 | /* validate_trans2_offsets() */ | ||
5519 | /* BB check if start of smb + data_offset > &bcc+ bcc*/ | ||
5520 | ea_response_data = (struct fealist *) | ||
5521 | (((char *) &pSMBr->hdr.Protocol) + | ||
5522 | data_offset); | ||
5523 | name_len = le32_to_cpu(ea_response_data->list_len); | ||
5524 | cFYI(1, ("ea length %d", name_len)); | ||
5525 | if (name_len <= 8) { | ||
5526 | /* returned EA size zeroed at top of function */ | ||
5527 | cFYI(1, ("empty EA list returned from server")); | ||
5528 | } else { | ||
5529 | /* account for ea list len */ | ||
5530 | name_len -= 4; | ||
5531 | temp_fea = ea_response_data->list; | ||
5532 | temp_ptr = (char *)temp_fea; | ||
5533 | /* loop through checking if we have a matching | ||
5534 | name and then return the associated value */ | ||
5535 | while (name_len > 0) { | ||
5536 | __u16 value_len; | ||
5537 | name_len -= 4; | ||
5538 | temp_ptr += 4; | ||
5539 | value_len = | ||
5540 | le16_to_cpu(temp_fea->value_len); | ||
5541 | /* BB validate that value_len falls within SMB, | ||
5542 | even though maximum for name_len is 255 */ | ||
5543 | if (memcmp(temp_fea->name, ea_name, | ||
5544 | temp_fea->name_len) == 0) { | ||
5545 | /* found a match */ | ||
5546 | rc = value_len; | ||
5547 | /* account for prefix user. and trailing null */ | ||
5548 | if (rc <= (int)buf_size) { | ||
5549 | memcpy(ea_value, | ||
5550 | temp_fea->name+temp_fea->name_len+1, | ||
5551 | rc); | ||
5552 | /* ea values, unlike ea | ||
5553 | names, are not null | ||
5554 | terminated */ | ||
5555 | } else if (buf_size == 0) { | ||
5556 | /* skip copy - calc size only */ | ||
5557 | } else { | ||
5558 | /* stop before overrun buffer */ | ||
5559 | rc = -ERANGE; | ||
5560 | } | ||
5561 | break; | ||
5562 | } | ||
5563 | name_len -= temp_fea->name_len; | ||
5564 | temp_ptr += temp_fea->name_len; | ||
5565 | /* account for trailing null */ | ||
5566 | name_len--; | ||
5567 | temp_ptr++; | ||
5568 | name_len -= value_len; | ||
5569 | temp_ptr += value_len; | ||
5570 | /* No trailing null to account for in | ||
5571 | value_len. Go on to next EA */ | ||
5572 | temp_fea = (struct fea *)temp_ptr; | ||
5573 | } | ||
5574 | } | ||
5575 | } | ||
5576 | } | ||
5577 | cifs_buf_release(pSMB); | ||
5578 | if (rc == -EAGAIN) | ||
5579 | goto QEARetry; | ||
5580 | |||
5581 | return (ssize_t)rc; | ||
5582 | } | ||
5583 | |||
5584 | int | 5464 | int |
5585 | CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName, | 5465 | CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName, |
5586 | const char *ea_name, const void *ea_value, | 5466 | const char *ea_name, const void *ea_value, |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index e3fda978f481..5e9cc9c2fc7d 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -366,7 +366,7 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, | |||
366 | char ea_value[4]; | 366 | char ea_value[4]; |
367 | __u32 mode; | 367 | __u32 mode; |
368 | 368 | ||
369 | rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS", | 369 | rc = CIFSSMBQAllEAs(xid, cifs_sb->tcon, path, "SETFILEBITS", |
370 | ea_value, 4 /* size of buf */, cifs_sb->local_nls, | 370 | ea_value, 4 /* size of buf */, cifs_sb->local_nls, |
371 | cifs_sb->mnt_cifs_flags & | 371 | cifs_sb->mnt_cifs_flags & |
372 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 372 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index a75afa3dd9e1..3e2ef0de1209 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c | |||
@@ -244,7 +244,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, | |||
244 | /* revalidate/getattr then populate from inode */ | 244 | /* revalidate/getattr then populate from inode */ |
245 | } /* BB add else when above is implemented */ | 245 | } /* BB add else when above is implemented */ |
246 | ea_name += 5; /* skip past user. prefix */ | 246 | ea_name += 5; /* skip past user. prefix */ |
247 | rc = CIFSSMBQueryEA(xid, pTcon, full_path, ea_name, ea_value, | 247 | rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, |
248 | buf_size, cifs_sb->local_nls, | 248 | buf_size, cifs_sb->local_nls, |
249 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 249 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
250 | } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) { | 250 | } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) { |
@@ -252,7 +252,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, | |||
252 | goto get_ea_exit; | 252 | goto get_ea_exit; |
253 | 253 | ||
254 | ea_name += 4; /* skip past os2. prefix */ | 254 | ea_name += 4; /* skip past os2. prefix */ |
255 | rc = CIFSSMBQueryEA(xid, pTcon, full_path, ea_name, ea_value, | 255 | rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, |
256 | buf_size, cifs_sb->local_nls, | 256 | buf_size, cifs_sb->local_nls, |
257 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 257 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
258 | } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, | 258 | } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, |
@@ -364,8 +364,8 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) | |||
364 | /* if proc/fs/cifs/streamstoxattr is set then | 364 | /* if proc/fs/cifs/streamstoxattr is set then |
365 | search server for EAs or streams to | 365 | search server for EAs or streams to |
366 | returns as xattrs */ | 366 | returns as xattrs */ |
367 | rc = CIFSSMBQAllEAs(xid, pTcon, full_path, data, buf_size, | 367 | rc = CIFSSMBQAllEAs(xid, pTcon, full_path, NULL, data, |
368 | cifs_sb->local_nls, | 368 | buf_size, cifs_sb->local_nls, |
369 | cifs_sb->mnt_cifs_flags & | 369 | cifs_sb->mnt_cifs_flags & |
370 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 370 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
371 | 371 | ||