Commit 19c48ffe authored by Steve French's avatar Steve French Committed by Steve French

[CIFS] cifs readdir rewrite fix resume key handling

Signed-off-by: Steve French (sfrench@us.ibm.com)
parent a64a54eb
...@@ -244,8 +244,11 @@ struct cifs_search_info { ...@@ -244,8 +244,11 @@ struct cifs_search_info {
loff_t index_of_last_entry; loff_t index_of_last_entry;
__u16 entries_in_buffer; __u16 entries_in_buffer;
__u16 info_level; __u16 info_level;
__u32 resume_key;
char * ntwrk_buf_start; char * ntwrk_buf_start;
char * srch_entries_start; char * srch_entries_start;
char * presume_name;
unsigned int resume_name_len;
unsigned endOfSearch:1; unsigned endOfSearch:1;
unsigned emptyDir:1; unsigned emptyDir:1;
unsigned unicode:1; unsigned unicode:1;
...@@ -265,8 +268,7 @@ struct cifsFileInfo { ...@@ -265,8 +268,7 @@ struct cifsFileInfo {
unsigned invalidHandle:1; /* file closed via session abend */ unsigned invalidHandle:1; /* file closed via session abend */
struct semaphore fh_sem; /* prevents reopen race after dead ses*/ struct semaphore fh_sem; /* prevents reopen race after dead ses*/
char * search_resume_name; /* BB removeme BB */ char * search_resume_name; /* BB removeme BB */
unsigned int resume_name_length; /* BB removeme BB */ unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */
__u32 resume_key; /* BB removeme BB */
struct cifs_search_info srch_inf; struct cifs_search_info srch_inf;
}; };
......
...@@ -1691,7 +1691,7 @@ struct file_attrib_tag { ...@@ -1691,7 +1691,7 @@ struct file_attrib_tag {
typedef struct { typedef struct {
__le32 NextEntryOffset; __le32 NextEntryOffset;
__le32 ResumeKey; __u32 ResumeKey; /* as with FileIndex - no need to convert */
__le64 EndOfFile; __le64 EndOfFile;
__le64 NumOfBytes; __le64 NumOfBytes;
__le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */ __le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */
......
...@@ -2377,10 +2377,13 @@ int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon, ...@@ -2377,10 +2377,13 @@ int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon,
T2_FNEXT_RSP_PARMS * parms; T2_FNEXT_RSP_PARMS * parms;
char *response_data; char *response_data;
int rc = 0; int rc = 0;
int bytes_returned; int bytes_returned, name_len;
__u16 params, byte_count; __u16 params, byte_count;
cFYI(1, ("In FindNext")); cFYI(1, ("In FindNext2"));
if(psrch_inf->endOfSearch == TRUE)
return -ENOENT;
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr); (void **) &pSMBr);
...@@ -2418,16 +2421,19 @@ int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon, ...@@ -2418,16 +2421,19 @@ int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon,
psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO; psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
} */ } */
pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
pSMB->ResumeKey = 0; /* BB fixme add resume_key BB */ pSMB->ResumeKey = psrch_inf->resume_key;
pSMB->SearchFlags = pSMB->SearchFlags =
cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
/* BB fixme check to make sure we do not cross end of smb with long resume name */
/* if(name_len < CIFS_MAX_MSGSIZE) { name_len = psrch_inf->resume_name_len;
memcpy(pSMB->ResumeFileName, resume_file_name, name_len); params += name_len;
byte_count += name_len; */ /* BB fixme - add resume file name processing BB */ if(name_len < PATH_MAX) {
/* } memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
params += name_len; */ byte_count += name_len;
} else {
rc = -EINVAL;
goto FNext2_err_exit;
}
byte_count = params + 1 /* pad */ ; byte_count = params + 1 /* pad */ ;
pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = cpu_to_le16(params);
pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->ParameterCount = pSMB->TotalParameterCount;
...@@ -2438,9 +2444,10 @@ int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon, ...@@ -2438,9 +2444,10 @@ int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon,
(struct smb_hdr *) pSMBr, &bytes_returned, 0); (struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) { if (rc) {
if (rc == -EBADF) if (rc == -EBADF) {
psrch_inf->endOfSearch = TRUE;
rc = 0; /* search probably was closed at end of search above */ rc = 0; /* search probably was closed at end of search above */
else } else
cFYI(1, ("FindNext returned = %d", rc)); cFYI(1, ("FindNext returned = %d", rc));
} else { /* decode response */ } else { /* decode response */
rc = validate_t2((struct smb_t2_rsp *)pSMBr); rc = validate_t2((struct smb_t2_rsp *)pSMBr);
...@@ -2451,9 +2458,11 @@ int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon, ...@@ -2451,9 +2458,11 @@ int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon,
psrch_inf->unicode = TRUE; psrch_inf->unicode = TRUE;
else else
psrch_inf->unicode = FALSE; psrch_inf->unicode = FALSE;
response_data = (char *) &pSMBr->hdr.Protocol +
le16_to_cpu(pSMBr->t2.ParameterOffset);
parms = (T2_FNEXT_RSP_PARMS *)response_data;
response_data = (char *)&pSMBr->hdr.Protocol + response_data = (char *)&pSMBr->hdr.Protocol +
le16_to_cpu(pSMBr->t2.DataOffset); le16_to_cpu(pSMBr->t2.DataOffset);
parms = (T2_FNEXT_RSP_PARMS *)response_data;
cifs_buf_release(psrch_inf->ntwrk_buf_start); cifs_buf_release(psrch_inf->ntwrk_buf_start);
psrch_inf->srch_entries_start = response_data; psrch_inf->srch_entries_start = response_data;
psrch_inf->ntwrk_buf_start = (char *)pSMB; psrch_inf->ntwrk_buf_start = (char *)pSMB;
...@@ -2477,7 +2486,7 @@ int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon, ...@@ -2477,7 +2486,7 @@ int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon,
/* Note: On -EAGAIN error only caller can retry on handle based calls /* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */ since file handle passed in no longer valid */
FNext2_err_exit:
if ((rc != 0) && pSMB) if ((rc != 0) && pSMB)
cifs_buf_release(pSMB); cifs_buf_release(pSMB);
...@@ -2543,7 +2552,7 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon, ...@@ -2543,7 +2552,7 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
pSMB->SearchFlags = pSMB->SearchFlags =
cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
/* BB add check to make sure we do not cross end of smb */ /* BB add check to make sure we do not cross end of smb */
if(name_len < CIFS_MAX_MSGSIZE) { if(name_len < PATH_MAX) {
memcpy(pSMB->ResumeFileName, resume_file_name, name_len); memcpy(pSMB->ResumeFileName, resume_file_name, name_len);
byte_count += name_len; byte_count += name_len;
} }
......
...@@ -1834,7 +1834,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1834,7 +1834,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
break; break;
} }
/* Offset of resume key same for levels 257 and 514 */ /* Offset of resume key same for levels 257 and 514 */
cifsFile->resume_key = lastFindData->FileIndex; cifsFile->srch_inf.resume_key = lastFindData->FileIndex;
if(UnixSearch == FALSE) { if(UnixSearch == FALSE) {
cifsFile->resume_name_length = cifsFile->resume_name_length =
le32_to_cpu(lastFindData->FileNameLength); le32_to_cpu(lastFindData->FileNameLength);
...@@ -2000,7 +2000,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -2000,7 +2000,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
&findNextParms, searchHandle, &findNextParms, searchHandle,
cifsFile->search_resume_name, cifsFile->search_resume_name,
cifsFile->resume_name_length, cifsFile->resume_name_length,
cifsFile->resume_key, cifsFile->srch_inf.resume_key,
&Unicode, &UnixSearch); &Unicode, &UnixSearch);
cFYI(1,("Count: %d End: %d ", cFYI(1,("Count: %d End: %d ",
le16_to_cpu(findNextParms.SearchCount), le16_to_cpu(findNextParms.SearchCount),
...@@ -2017,7 +2017,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -2017,7 +2017,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
break; break;
} }
/* Offset of resume key same for levels 257 and 514 */ /* Offset of resume key same for levels 257 and 514 */
cifsFile->resume_key = lastFindData->FileIndex; cifsFile->srch_inf.resume_key = lastFindData->FileIndex;
if(UnixSearch == FALSE) { if(UnixSearch == FALSE) {
cifsFile->resume_name_length = cifsFile->resume_name_length =
......
...@@ -91,6 +91,7 @@ static int initiate_cifs_search(const int xid, struct file * file) ...@@ -91,6 +91,7 @@ static int initiate_cifs_search(const int xid, struct file * file)
} }
cifsFile = (struct cifsFileInfo *)file->private_data; cifsFile = (struct cifsFileInfo *)file->private_data;
cifsFile->invalidHandle = TRUE; cifsFile->invalidHandle = TRUE;
cifsFile->srch_inf.endOfSearch = FALSE;
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
if(cifs_sb == NULL) if(cifs_sb == NULL)
...@@ -124,6 +125,8 @@ static int initiate_cifs_search(const int xid, struct file * file) ...@@ -124,6 +125,8 @@ static int initiate_cifs_search(const int xid, struct file * file)
rc = CIFSFindFirst2(xid, pTcon,full_path,cifs_sb->local_nls, rc = CIFSFindFirst2(xid, pTcon,full_path,cifs_sb->local_nls,
&cifsFile->netfid, &cifsFile->srch_inf); &cifsFile->netfid, &cifsFile->srch_inf);
if(rc == 0)
cifsFile->invalidHandle = FALSE;
if(full_path) if(full_path)
kfree(full_path); kfree(full_path);
return rc; return rc;
...@@ -279,6 +282,8 @@ if(cifsFile->srch_inf.endOfSearch) { ...@@ -279,6 +282,8 @@ if(cifsFile->srch_inf.endOfSearch) {
(rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){
cFYI(1,("calling findnext2")); cFYI(1,("calling findnext2"));
rc = CIFSFindNext2(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf); rc = CIFSFindNext2(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf);
if(rc)
return -ENOENT;
} }
if(index_to_find < cifsFile->srch_inf.index_of_last_entry) { if(index_to_find < cifsFile->srch_inf.index_of_last_entry) {
/* we found the buffer that contains the entry */ /* we found the buffer that contains the entry */
...@@ -314,7 +319,7 @@ if(cifsFile->srch_inf.endOfSearch) { ...@@ -314,7 +319,7 @@ if(cifsFile->srch_inf.endOfSearch) {
*ppCurrentEntry = current_entry; *ppCurrentEntry = current_entry;
} else { } else {
cFYI(1,("index not in buffer - could not findnext into it")); cFYI(1,("index not in buffer - could not findnext into it"));
return -ENOENT; /* BB fixme - return 0? */ return 0;
} }
if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
...@@ -455,6 +460,61 @@ cifs_filldir2(char * pfindEntry, struct file *file, ...@@ -455,6 +460,61 @@ cifs_filldir2(char * pfindEntry, struct file *file,
return rc; return rc;
} }
int cifs_save_resume_key(const char * current_entry,struct cifsFileInfo * cifsFile)
{
int rc = 0;
unsigned int len = 0;
__u16 level;
char * filename;
if((cifsFile == NULL) || (current_entry == NULL))
return -EINVAL;
level = cifsFile->srch_inf.info_level;
if(level == SMB_FIND_FILE_UNIX) {
FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
filename = &pFindData->FileName[0];
if(cifsFile->srch_inf.unicode) {
len = cifs_unicode_bytelen(filename);
} else {
/* BB should we make this strnlen of PATH_MAX? */
len = strnlen(filename, PATH_MAX);
}
cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
} else if(level == SMB_FIND_FILE_DIRECTORY_INFO) {
FILE_DIRECTORY_INFO * pFindData =
(FILE_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = pFindData->FileNameLength;
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
FILE_FULL_DIRECTORY_INFO * pFindData =
(FILE_FULL_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = pFindData->FileNameLength;
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
SEARCH_ID_FULL_DIR_INFO * pFindData =
(SEARCH_ID_FULL_DIR_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = pFindData->FileNameLength;
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
FILE_BOTH_DIRECTORY_INFO * pFindData =
(FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = pFindData->FileNameLength;
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else {
cFYI(1,("Unknown findfirst level %d",level));
return -EINVAL;
}
cifsFile->srch_inf.resume_name_len = len;
cifsFile->srch_inf.presume_name = filename;
return rc;
}
int cifs_readdir2(struct file *file, void *direntry, filldir_t filldir) int cifs_readdir2(struct file *file, void *direntry, filldir_t filldir)
{ {
...@@ -577,6 +637,12 @@ cFYI(1,("readdir2 pos: %lld",file->f_pos)); /* BB removeme BB */ ...@@ -577,6 +637,12 @@ cFYI(1,("readdir2 pos: %lld",file->f_pos)); /* BB removeme BB */
rc = cifs_filldir2(current_entry, file, rc = cifs_filldir2(current_entry, file,
filldir, direntry,tmp_buf); filldir, direntry,tmp_buf);
file->f_pos++; file->f_pos++;
if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) {
cFYI(1,("last entry in buf at pos %lld %s",file->f_pos,tmp_buf)); /* BB removeme BB */
/* BB fixme save resume key BB */
cifs_save_resume_key(current_entry,cifsFile);
break;
} else
current_entry = nxt_dir_entry(current_entry,end_of_smb); current_entry = nxt_dir_entry(current_entry,end_of_smb);
} }
if(tmp_buf != NULL) if(tmp_buf != NULL)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment