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 {
loff_t index_of_last_entry;
__u16 entries_in_buffer;
__u16 info_level;
__u32 resume_key;
char * ntwrk_buf_start;
char * srch_entries_start;
char * presume_name;
unsigned int resume_name_len;
unsigned endOfSearch:1;
unsigned emptyDir:1;
unsigned unicode:1;
......@@ -265,8 +268,7 @@ struct cifsFileInfo {
unsigned invalidHandle:1; /* file closed via session abend */
struct semaphore fh_sem; /* prevents reopen race after dead ses*/
char * search_resume_name; /* BB removeme BB */
unsigned int resume_name_length; /* BB removeme BB */
__u32 resume_key; /* BB removeme BB */
unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */
struct cifs_search_info srch_inf;
};
......
......@@ -1691,7 +1691,7 @@ struct file_attrib_tag {
typedef struct {
__le32 NextEntryOffset;
__le32 ResumeKey;
__u32 ResumeKey; /* as with FileIndex - no need to convert */
__le64 EndOfFile;
__le64 NumOfBytes;
__le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */
......
......@@ -2377,10 +2377,13 @@ int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon,
T2_FNEXT_RSP_PARMS * parms;
char *response_data;
int rc = 0;
int bytes_returned;
int bytes_returned, name_len;
__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,
(void **) &pSMBr);
......@@ -2418,16 +2421,19 @@ int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon,
psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
} */
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 =
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) {
memcpy(pSMB->ResumeFileName, resume_file_name, name_len);
byte_count += name_len; */ /* BB fixme - add resume file name processing BB */
/* }
params += name_len; */
name_len = psrch_inf->resume_name_len;
params += name_len;
if(name_len < PATH_MAX) {
memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
byte_count += name_len;
} else {
rc = -EINVAL;
goto FNext2_err_exit;
}
byte_count = params + 1 /* pad */ ;
pSMB->TotalParameterCount = cpu_to_le16(params);
pSMB->ParameterCount = pSMB->TotalParameterCount;
......@@ -2438,9 +2444,10 @@ int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
if (rc == -EBADF)
if (rc == -EBADF) {
psrch_inf->endOfSearch = TRUE;
rc = 0; /* search probably was closed at end of search above */
else
} else
cFYI(1, ("FindNext returned = %d", rc));
} else { /* decode response */
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
......@@ -2451,9 +2458,11 @@ int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon,
psrch_inf->unicode = TRUE;
else
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 +
le16_to_cpu(pSMBr->t2.DataOffset);
parms = (T2_FNEXT_RSP_PARMS *)response_data;
cifs_buf_release(psrch_inf->ntwrk_buf_start);
psrch_inf->srch_entries_start = response_data;
psrch_inf->ntwrk_buf_start = (char *)pSMB;
......@@ -2477,7 +2486,7 @@ int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon,
/* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
FNext2_err_exit:
if ((rc != 0) && pSMB)
cifs_buf_release(pSMB);
......@@ -2543,7 +2552,7 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
pSMB->SearchFlags =
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 */
if(name_len < CIFS_MAX_MSGSIZE) {
if(name_len < PATH_MAX) {
memcpy(pSMB->ResumeFileName, resume_file_name, name_len);
byte_count += name_len;
}
......
......@@ -1834,7 +1834,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
break;
}
/* 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) {
cifsFile->resume_name_length =
le32_to_cpu(lastFindData->FileNameLength);
......@@ -2000,7 +2000,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
&findNextParms, searchHandle,
cifsFile->search_resume_name,
cifsFile->resume_name_length,
cifsFile->resume_key,
cifsFile->srch_inf.resume_key,
&Unicode, &UnixSearch);
cFYI(1,("Count: %d End: %d ",
le16_to_cpu(findNextParms.SearchCount),
......@@ -2017,7 +2017,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
break;
}
/* 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) {
cifsFile->resume_name_length =
......
......@@ -91,7 +91,8 @@ static int initiate_cifs_search(const int xid, struct file * file)
}
cifsFile = (struct cifsFileInfo *)file->private_data;
cifsFile->invalidHandle = TRUE;
cifsFile->srch_inf.endOfSearch = FALSE;
cifs_sb = CIFS_SB(file->f_dentry->d_sb);
if(cifs_sb == NULL)
return -EINVAL;
......@@ -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,
&cifsFile->netfid, &cifsFile->srch_inf);
if(rc == 0)
cifsFile->invalidHandle = FALSE;
if(full_path)
kfree(full_path);
return rc;
......@@ -279,6 +282,8 @@ if(cifsFile->srch_inf.endOfSearch) {
(rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){
cFYI(1,("calling findnext2"));
rc = CIFSFindNext2(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf);
if(rc)
return -ENOENT;
}
if(index_to_find < cifsFile->srch_inf.index_of_last_entry) {
/* we found the buffer that contains the entry */
......@@ -314,7 +319,7 @@ if(cifsFile->srch_inf.endOfSearch) {
*ppCurrentEntry = current_entry;
} else {
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) {
......@@ -455,6 +460,61 @@ cifs_filldir2(char * pfindEntry, struct file *file,
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)
{
......@@ -577,7 +637,13 @@ cFYI(1,("readdir2 pos: %lld",file->f_pos)); /* BB removeme BB */
rc = cifs_filldir2(current_entry, file,
filldir, direntry,tmp_buf);
file->f_pos++;
current_entry = nxt_dir_entry(current_entry,end_of_smb);
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);
}
if(tmp_buf != NULL)
kfree(tmp_buf);
......
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