* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/fs.h>
+#include <linux/pagemap.h>
#include <linux/stat.h>
#include <linux/smp_lock.h>
#include "cifspdu.h"
#include "cifs_fs_sb.h"
#include "cifsfs.h"
-/* BB fixme - add debug wrappers around this function to disable it fixme BB */
-/* static void dump_cifs_file_struct(struct file *file, char *label)
+#ifdef CONFIG_CIFS_DEBUG2
+static void dump_cifs_file_struct(struct file *file, char *label)
{
struct cifsFileInfo * cf;
}
}
-} */
+}
+#endif /* DEBUG2 */
/* Returns one if new inode created (which therefore needs to be hashed) */
/* Might check in the future if inode number changed so we can rehash inode */
int rc = 0;
cFYI(1, ("For %s", qstring->name));
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
qstring->hash = full_name_hash(qstring->name, qstring->len);
- tmp_dentry = d_lookup(file->f_dentry, qstring);
+ tmp_dentry = d_lookup(file->f_path.dentry, qstring);
if (tmp_dentry) {
cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode));
*ptmp_inode = tmp_dentry->d_inode;
/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
if(*ptmp_inode == NULL) {
- *ptmp_inode = new_inode(file->f_dentry->d_sb);
+ *ptmp_inode = new_inode(file->f_path.dentry->d_sb);
if(*ptmp_inode == NULL)
return rc;
rc = 1;
- d_instantiate(tmp_dentry, *ptmp_inode);
}
} else {
- tmp_dentry = d_alloc(file->f_dentry, qstring);
+ tmp_dentry = d_alloc(file->f_path.dentry, qstring);
if(tmp_dentry == NULL) {
cERROR(1,("Failed allocating dentry"));
*ptmp_inode = NULL;
return rc;
}
- *ptmp_inode = new_inode(file->f_dentry->d_sb);
+ *ptmp_inode = new_inode(file->f_path.dentry->d_sb);
if (pTcon->nocase)
tmp_dentry->d_op = &cifs_ci_dentry_ops;
else
tmp_dentry->d_op = &cifs_dentry_ops;
if(*ptmp_inode == NULL)
return rc;
- rc = 1;
- d_instantiate(tmp_dentry, *ptmp_inode);
- d_rehash(tmp_dentry);
+ rc = 2;
}
tmp_dentry->d_time = jiffies;
return rc;
}
-static void fill_in_inode(struct inode *tmp_inode,
- FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode)
+static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode)
+{
+ if((tcon) && (tcon->ses) && (tcon->ses->server)) {
+ inode->i_ctime.tv_sec += tcon->ses->server->timeAdj;
+ inode->i_mtime.tv_sec += tcon->ses->server->timeAdj;
+ inode->i_atime.tv_sec += tcon->ses->server->timeAdj;
+ }
+ return;
+}
+
+
+static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
+ char * buf, int *pobject_type, int isNewInode)
{
loff_t local_size;
struct timespec local_mtime;
struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
- __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes);
- __u64 allocation_size = le64_to_cpu(pfindData->AllocationSize);
- __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
-
- cifsInfo->cifsAttrs = attr;
- cifsInfo->time = jiffies;
+ __u32 attr;
+ __u64 allocation_size;
+ __u64 end_of_file;
/* save mtime and size */
local_mtime = tmp_inode->i_mtime;
local_size = tmp_inode->i_size;
+ if(new_buf_type) {
+ FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;
+
+ attr = le32_to_cpu(pfindData->ExtFileAttributes);
+ allocation_size = le64_to_cpu(pfindData->AllocationSize);
+ end_of_file = le64_to_cpu(pfindData->EndOfFile);
+ tmp_inode->i_atime =
+ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
+ tmp_inode->i_mtime =
+ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
+ tmp_inode->i_ctime =
+ cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
+ } else { /* legacy, OS2 and DOS style */
+/* struct timespec ts;*/
+ FIND_FILE_STANDARD_INFO * pfindData =
+ (FIND_FILE_STANDARD_INFO *)buf;
+
+ tmp_inode->i_mtime = cnvrtDosUnixTm(
+ le16_to_cpu(pfindData->LastWriteDate),
+ le16_to_cpu(pfindData->LastWriteTime));
+ tmp_inode->i_atime = cnvrtDosUnixTm(
+ le16_to_cpu(pfindData->LastAccessDate),
+ le16_to_cpu(pfindData->LastAccessTime));
+ tmp_inode->i_ctime = cnvrtDosUnixTm(
+ le16_to_cpu(pfindData->LastWriteDate),
+ le16_to_cpu(pfindData->LastWriteTime));
+ AdjustForTZ(cifs_sb->tcon, tmp_inode);
+ attr = le16_to_cpu(pfindData->Attributes);
+ allocation_size = le32_to_cpu(pfindData->AllocationSize);
+ end_of_file = le32_to_cpu(pfindData->DataSize);
+ }
+
/* Linux can not store file creation time unfortunately so ignore it */
- tmp_inode->i_atime =
- cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
- tmp_inode->i_mtime =
- cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
- tmp_inode->i_ctime =
- cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
+
+ cifsInfo->cifsAttrs = attr;
+ cifsInfo->time = jiffies;
+
/* treat dos attribute of read-only as read-only mode bit e.g. 555? */
/* 2767 perms - indicate mandatory locking */
/* BB fill in uid and gid here? with help from winbind?
tmp_inode->i_mode |= S_IFREG;
if (attr & ATTR_READONLY)
tmp_inode->i_mode &= ~(S_IWUGO);
+ else if ((tmp_inode->i_mode & S_IWUGO) == 0)
+ /* the ATTR_READONLY flag may have been changed on */
+ /* server -- set any w bits allowed by mnt_file_mode */
+ tmp_inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode);
} /* could add code here - to validate if device or weird share type? */
/* can not fill in nlink here as in qpathinfo version and Unx search */
if (allocation_size < end_of_file)
cFYI(1, ("May be sparse file, allocation less than file size"));
- cFYI(1,
- ("File Size %ld and blocks %ld and blocksize %ld",
- (unsigned long)tmp_inode->i_size, tmp_inode->i_blocks,
- tmp_inode->i_blksize));
+ cFYI(1, ("File Size %ld and blocks %llu",
+ (unsigned long)tmp_inode->i_size,
+ (unsigned long long)tmp_inode->i_blocks));
if (S_ISREG(tmp_inode->i_mode)) {
cFYI(1, ("File inode"));
tmp_inode->i_op = &cifs_file_inode_ops;
else
tmp_inode->i_fop = &cifs_file_ops;
- tmp_inode->i_data.a_ops = &cifs_addr_ops;
if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
(cifs_sb->tcon->ses->server->maxBuf <
- 4096 + MAX_CIFS_HDR_SIZE))
- tmp_inode->i_data.a_ops->readpages = NULL;
+ PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
+ tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+ else
+ tmp_inode->i_data.a_ops = &cifs_addr_ops;
+
if(isNewInode)
return; /* No sense invalidating pages for new inode
since have not started caching readahead file
else
tmp_inode->i_fop = &cifs_file_ops;
- tmp_inode->i_data.a_ops = &cifs_addr_ops;
if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
(cifs_sb->tcon->ses->server->maxBuf <
- 4096 + MAX_CIFS_HDR_SIZE))
- tmp_inode->i_data.a_ops->readpages = NULL;
+ PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
+ tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+ else
+ tmp_inode->i_data.a_ops = &cifs_addr_ops;
if(isNewInode)
return; /* No sense invalidating pages for new inode since we
cifsFile->invalidHandle = TRUE;
cifsFile->srch_inf.endOfSearch = FALSE;
- if(file->f_dentry == NULL)
+ if(file->f_path.dentry == NULL)
return -ENOENT;
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
if(cifs_sb == NULL)
return -EINVAL;
if(pTcon == NULL)
return -EINVAL;
- down(&file->f_dentry->d_sb->s_vfs_rename_sem);
- full_path = build_path_from_dentry(file->f_dentry);
- up(&file->f_dentry->d_sb->s_vfs_rename_sem);
+ full_path = build_path_from_dentry(file->f_path.dentry);
if(full_path == NULL) {
return -ENOMEM;
ffirst_retry:
/* test for Unix extensions */
if (pTcon->ses->capabilities & CAP_UNIX) {
- cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
+ cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
+ } else if ((pTcon->ses->capabilities &
+ (CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
+ cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
} else /* not srvinos - BB fixme add check for backlevel? */ {
return len << 1;
}
-static char *nxt_dir_entry(char *old_entry, char *end_of_smb)
+static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
{
char * new_entry;
FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
- new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
+ if(level == SMB_FIND_FILE_INFO_STANDARD) {
+ FIND_FILE_STANDARD_INFO * pfData;
+ pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo;
+
+ new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) +
+ pfData->FileNameLength;
+ } else
+ new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
cFYI(1,("new entry %p old entry %p",new_entry,old_entry));
/* validate that new_entry is not past end of SMB */
if(new_entry >= end_of_smb) {
("search entry %p began after end of SMB %p old entry %p",
new_entry, end_of_smb, old_entry));
return NULL;
- } else if (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb) {
+ } else if(((level == SMB_FIND_FILE_INFO_STANDARD) &&
+ (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) ||
+ ((level != SMB_FIND_FILE_INFO_STANDARD) &&
+ (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) {
cERROR(1,("search entry %p extends after end of SMB %p",
new_entry, end_of_smb));
return NULL;
char * filename = NULL;
int len = 0;
- if(cfile->srch_inf.info_level == 0x202) {
+ if(cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
filename = &pFindData->FileName[0];
if(cfile->srch_inf.unicode) {
/* BB should we make this strnlen of PATH_MAX? */
len = strnlen(filename, 5);
}
- } else if(cfile->srch_inf.info_level == 0x101) {
+ } else if(cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
FILE_DIRECTORY_INFO * pFindData =
(FILE_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
- } else if(cfile->srch_inf.info_level == 0x102) {
+ } else if(cfile->srch_inf.info_level ==
+ SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
FILE_FULL_DIRECTORY_INFO * pFindData =
(FILE_FULL_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
- } else if(cfile->srch_inf.info_level == 0x105) {
+ } else if(cfile->srch_inf.info_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 = le32_to_cpu(pFindData->FileNameLength);
- } else if(cfile->srch_inf.info_level == 0x104) {
+ } else if(cfile->srch_inf.info_level ==
+ SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
FILE_BOTH_DIRECTORY_INFO * pFindData =
(FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
+ } else if(cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
+ FIND_FILE_STANDARD_INFO * pFindData =
+ (FIND_FILE_STANDARD_INFO *)current_entry;
+ filename = &pFindData->FileName[0];
+ len = pFindData->FileNameLength;
} else {
cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level));
}
struct inode * inode;
struct cifsInodeInfo *cifsInfo;
- if(file->f_dentry == NULL)
+ if(file->f_path.dentry == NULL)
return 0;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if(inode == NULL)
return 0;
first_entry_in_buffer =
cifsFile->srch_inf.index_of_last_entry -
cifsFile->srch_inf.entries_in_buffer;
-/* dump_cifs_file_struct(file, "In fce ");*/
+
+ /* if first entry in buf is zero then is first buffer
+ in search response data which means it is likely . and ..
+ will be in this buffer, although some servers do not return
+ . and .. for the root of a drive and for those we need
+ to start two entries earlier */
+
+#ifdef CONFIG_CIFS_DEBUG2
+ dump_cifs_file_struct(file, "In fce ");
+#endif
if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
is_dir_changed(file)) ||
(index_to_find < first_entry_in_buffer)) {
cifsFile->search_resume_name = NULL;
if(cifsFile->srch_inf.ntwrk_buf_start) {
cFYI(1,("freeing SMB ff cache buf on search rewind"));
- cifs_buf_release(cifsFile->srch_inf.ntwrk_buf_start);
+ if(cifsFile->srch_inf.smallBuf)
+ cifs_small_buf_release(cifsFile->srch_inf.
+ ntwrk_buf_start);
+ else
+ cifs_buf_release(cifsFile->srch_inf.
+ ntwrk_buf_start);
}
rc = initiate_cifs_search(xid,file);
if(rc) {
char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
smbCalcSize((struct smb_hdr *)
cifsFile->srch_inf.ntwrk_buf_start);
+
+ current_entry = cifsFile->srch_inf.srch_entries_start;
first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
- cifsFile->srch_inf.entries_in_buffer;
pos_in_buf = index_to_find - first_entry_in_buffer;
- cFYI(1,("found entry - pos_in_buf %d",pos_in_buf));
- current_entry = cifsFile->srch_inf.srch_entries_start;
+ cFYI(1,("found entry - pos_in_buf %d",pos_in_buf));
+
for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
/* go entry by entry figuring out which is first */
- /* if( . or ..)
- skip */
- rc = cifs_entry_is_dot(current_entry,cifsFile);
- if(rc == 1) /* is . or .. so skip */ {
- cFYI(1,("Entry is .")); /* BB removeme BB */
- /* continue; */
- } else if (rc == 2 ) {
- cFYI(1,("Entry is ..")); /* BB removeme BB */
- /* continue; */
- }
- current_entry = nxt_dir_entry(current_entry,end_of_smb);
+ current_entry = nxt_dir_entry(current_entry,end_of_smb,
+ cifsFile->srch_inf.info_level);
}
if((current_entry == NULL) && (i < pos_in_buf)) {
/* BB fixme - check if we should flag this error */
/* inode num, inode type and filename returned */
static int cifs_get_name_from_search_buf(struct qstr *pqst,
char *current_entry, __u16 level, unsigned int unicode,
- struct cifs_sb_info * cifs_sb, ino_t *pinum)
+ struct cifs_sb_info * cifs_sb, int max_len, ino_t *pinum)
{
int rc = 0;
unsigned int len = 0;
(FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
+ } else if(level == SMB_FIND_FILE_INFO_STANDARD) {
+ FIND_FILE_STANDARD_INFO * pFindData =
+ (FIND_FILE_STANDARD_INFO *)current_entry;
+ filename = &pFindData->FileName[0];
+ /* one byte length, no name conversion */
+ len = (unsigned int)pFindData->FileNameLength;
} else {
cFYI(1,("Unknown findfirst level %d",level));
return -EINVAL;
}
+
+ if(len > max_len) {
+ cERROR(1,("bad search response length %d past smb end", len));
+ return -EINVAL;
+ }
+
if(unicode) {
/* BB fixme - test with long names */
/* Note converted filename can be longer than in unicode */
}
static int cifs_filldir(char *pfindEntry, struct file *file,
- filldir_t filldir, void *direntry, char *scratch_buf)
+ filldir_t filldir, void *direntry, char *scratch_buf, int max_len)
{
int rc = 0;
struct qstr qstring;
if((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
return -ENOENT;
- if(file->f_dentry == NULL)
+ if(file->f_path.dentry == NULL)
return -ENOENT;
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ rc = cifs_entry_is_dot(pfindEntry,pCifsF);
+ /* skip . and .. since we added them first */
+ if(rc != 0)
+ return 0;
+
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
qstring.name = scratch_buf;
rc = cifs_get_name_from_search_buf(&qstring,pfindEntry,
pCifsF->srch_inf.info_level,
pCifsF->srch_inf.unicode,cifs_sb,
+ max_len,
&inum /* returned */);
if(rc)
/* we pass in rc below, indicating whether it is a new inode,
so we can figure out whether to invalidate the inode cached
data if the file has changed */
- if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
+ if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
unix_fill_in_inode(tmp_inode,
- (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc);
- } else {
- fill_in_inode(tmp_inode,
- (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc);
+ (FILE_UNIX_INFO *)pfindEntry,
+ &obj_type, rc);
+ else if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
+ fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
+ pfindEntry, &obj_type, rc);
+ else
+ fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
+
+ if(rc) /* new inode - needs to be tied to dentry */ {
+ d_instantiate(tmp_dentry, tmp_inode);
+ if(rc == 2)
+ d_rehash(tmp_dentry);
}
+
rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,
tmp_inode->i_ino,obj_type);
if(rc) {
cFYI(1,("filldir rc = %d",rc));
+ /* we can not return filldir errors to the caller
+ since they are "normal" when the stat blocksize
+ is too small - we return remapped error instead */
+ rc = -EOVERFLOW;
}
dput(tmp_dentry);
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+ } else if(level == SMB_FIND_FILE_INFO_STANDARD) {
+ FIND_FILE_STANDARD_INFO * pFindData =
+ (FIND_FILE_STANDARD_INFO *)current_entry;
+ filename = &pFindData->FileName[0];
+ /* one byte length, no name conversion */
+ len = (unsigned int)pFindData->FileNameLength;
+ cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
} else {
cFYI(1,("Unknown findfirst level %d",level));
return -EINVAL;
int num_to_fill = 0;
char * tmp_buf = NULL;
char * end_of_smb;
+ int max_len;
xid = GetXid();
- if(file->f_dentry == NULL) {
+ if(file->f_path.dentry == NULL) {
FreeXid(xid);
return -EIO;
}
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
if(pTcon == NULL)
return -EINVAL;
switch ((int) file->f_pos) {
case 0:
- /*if (filldir(direntry, ".", 1, file->f_pos,
- file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
- cERROR(1, ("Filldir for current dir failed "));
+ if (filldir(direntry, ".", 1, file->f_pos,
+ file->f_path.dentry->d_inode->i_ino, DT_DIR) < 0) {
+ cERROR(1, ("Filldir for current dir failed"));
rc = -ENOMEM;
break;
}
- file->f_pos++; */
+ file->f_pos++;
case 1:
- /* if (filldir(direntry, "..", 2, file->f_pos,
- file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
- cERROR(1, ("Filldir for parent dir failed "));
+ if (filldir(direntry, "..", 2, file->f_pos,
+ file->f_path.dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
+ cERROR(1, ("Filldir for parent dir failed"));
rc = -ENOMEM;
break;
}
- file->f_pos++; */
- case 2:
+ file->f_pos++;
+ default:
/* 1) If search is active,
is in current search buffer?
if it before then restart search
return rc;
}
}
- default:
if(file->private_data == NULL) {
rc = -EINVAL;
FreeXid(xid);
kfree(cifsFile->search_resume_name);
cifsFile->search_resume_name = NULL; */
- /* BB account for . and .. in f_pos as special case */
-
rc = find_cifs_entry(xid,pTcon, file,
¤t_entry,&num_to_fill);
if(rc) {
goto rddir2_exit;
}
cFYI(1,("loop through %d times filling dir for net buf %p",
- num_to_fill,cifsFile->srch_inf.ntwrk_buf_start));
- end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
- smbCalcSize((struct smb_hdr *)
- cifsFile->srch_inf.ntwrk_buf_start);
+ num_to_fill,cifsFile->srch_inf.ntwrk_buf_start));
+ max_len = smbCalcSize((struct smb_hdr *)
+ cifsFile->srch_inf.ntwrk_buf_start);
+ end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
+
/* To be safe - for UCS to UTF-8 with strings loaded
with the rare long characters alloc more to account for
such multibyte target UTF-8 characters. cifs_unicode.c,
num_to_fill, i));
break;
}
+ /* if buggy server returns . and .. late do
+ we want to check for that here? */
+ rc = cifs_filldir(current_entry, file,
+ filldir, direntry, tmp_buf, max_len);
+ if(rc == -EOVERFLOW) {
+ rc = 0;
+ break;
+ }
- rc = cifs_filldir(current_entry, file,
- filldir, direntry,tmp_buf);
file->f_pos++;
- if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) {
+ 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 */
+ file->f_pos,tmp_buf));
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,
+ cifsFile->srch_inf.info_level);
}
kfree(tmp_buf);
break;