Commit 5bafd765 authored by Steve French's avatar Steve French

[CIFS] Add support for readdir to legacy servers

Fixes oops to OS/2 on ls and removes redundant NTCreateX calls to servers
which do not support NT SMBs.  Key operations to OS/2 work.
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent a8ee0344
...@@ -2,6 +2,10 @@ Version 1.44 ...@@ -2,6 +2,10 @@ Version 1.44
------------ ------------
Rewritten sessionsetup support, including support for legacy SMB Rewritten sessionsetup support, including support for legacy SMB
session setup needed for OS/2 and older servers such as Windows 95 and 98. session setup needed for OS/2 and older servers such as Windows 95 and 98.
Fix oops on ls to OS/2 servers. Add support for level 1 FindFirst
so we can do search (ls etc.) to OS/2. Do not send NTCreateX
or recent levels of FindFirst unless server says it supports NT SMBs
(instead use legacy equivalents from LANMAN dialect).
Version 1.43 Version 1.43
------------ ------------
......
...@@ -1374,6 +1374,9 @@ struct smb_t2_rsp { ...@@ -1374,6 +1374,9 @@ struct smb_t2_rsp {
#define SMB_FILE_MAXIMUM_INFO 0x40d #define SMB_FILE_MAXIMUM_INFO 0x40d
/* Find File infolevels */ /* Find File infolevels */
#define SMB_FIND_FILE_INFO_STANDARD 0x001
#define SMB_FIND_FILE_QUERY_EA_SIZE 0x002
#define SMB_FIND_FILE_QUERY_EAS_FROM_LIST 0x003
#define SMB_FIND_FILE_DIRECTORY_INFO 0x101 #define SMB_FIND_FILE_DIRECTORY_INFO 0x101
#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102 #define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
#define SMB_FIND_FILE_NAMES_INFO 0x103 #define SMB_FIND_FILE_NAMES_INFO 0x103
...@@ -1998,7 +2001,8 @@ typedef struct { ...@@ -1998,7 +2001,8 @@ typedef struct {
struct file_allocation_info { struct file_allocation_info {
__le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */
} __attribute__((packed)); /* size used on disk, level 0x103 for set, 0x105 for query */ } __attribute__((packed)); /* size used on disk, for level 0x103 for set,
0x105 for query */
struct file_end_of_file_info { struct file_end_of_file_info {
__le64 FileSize; /* offset to end of file */ __le64 FileSize; /* offset to end of file */
...@@ -2105,7 +2109,7 @@ typedef struct { ...@@ -2105,7 +2109,7 @@ typedef struct {
__le32 ExtFileAttributes; __le32 ExtFileAttributes;
__le32 FileNameLength; __le32 FileNameLength;
char FileName[1]; char FileName[1];
} __attribute__((packed)) FILE_DIRECTORY_INFO; /* level 0x101 FF response data area */ } __attribute__((packed)) FILE_DIRECTORY_INFO; /* level 0x101 FF resp data */
typedef struct { typedef struct {
__le32 NextEntryOffset; __le32 NextEntryOffset;
...@@ -2120,7 +2124,7 @@ typedef struct { ...@@ -2120,7 +2124,7 @@ typedef struct {
__le32 FileNameLength; __le32 FileNameLength;
__le32 EaSize; /* length of the xattrs */ __le32 EaSize; /* length of the xattrs */
char FileName[1]; char FileName[1];
} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 FF response data area */ } __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 rsp data */
typedef struct { typedef struct {
__le32 NextEntryOffset; __le32 NextEntryOffset;
...@@ -2137,7 +2141,7 @@ typedef struct { ...@@ -2137,7 +2141,7 @@ typedef struct {
__le32 Reserved; __le32 Reserved;
__u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/
char FileName[1]; char FileName[1];
} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF response data area */ } __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */
typedef struct { typedef struct {
__le32 NextEntryOffset; __le32 NextEntryOffset;
...@@ -2155,7 +2159,22 @@ typedef struct { ...@@ -2155,7 +2159,22 @@ typedef struct {
__u8 Reserved; __u8 Reserved;
__u8 ShortName[12]; __u8 ShortName[12];
char FileName[1]; char FileName[1];
} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FF response data area */ } __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FFrsp data */
typedef struct {
__u32 ResumeKey;
__le16 CreationDate; /* SMB Date */
__le16 CreationTime; /* SMB Time */
__le16 LastAccessDate;
__le16 LastAccessTime;
__le16 LastWriteDate;
__le16 LastWriteTime;
__le32 DataSize; /* File Size (EOF) */
__le32 AllocationSize;
__le16 Attributes; /* verify not u32 */
__u8 FileNameLength;
char FileName[1];
} __attribute__((packed)) FIND_FILE_STANDARD_INFO; /* level 0x1 FF resp data */
struct win_dev { struct win_dev {
......
...@@ -178,11 +178,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -178,11 +178,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR, desiredAccess, CREATE_NOT_DIR,
&fileHandle, &oplock, buf, cifs_sb->local_nls, &fileHandle, &oplock, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
else
rc = -EIO; /* no NT SMB support fall into legacy open below */
if(rc == -EIO) { if(rc == -EIO) {
/* old server, retry the open legacy style */ /* old server, retry the open legacy style */
rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
...@@ -369,6 +372,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, ...@@ -369,6 +372,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
/* BB FIXME - add handling for backlevel servers
which need legacy open and check for all
calls to SMBOpen for fallback to
SMBLeagcyOpen */
if(!rc) { if(!rc) {
/* BB Do not bother to decode buf since no /* BB Do not bother to decode buf since no
local inode yet to put timestamps in, local inode yet to put timestamps in,
......
...@@ -260,10 +260,15 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -260,10 +260,15 @@ int cifs_open(struct inode *inode, struct file *file)
rc = -ENOMEM; rc = -ENOMEM;
goto out; goto out;
} }
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
CREATE_NOT_DIR, &netfid, &oplock, buf, if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
& CIFS_MOUNT_MAP_SPECIAL_CHR); & CIFS_MOUNT_MAP_SPECIAL_CHR);
else
rc = -EIO; /* no NT SMB support fall into legacy open below */
if (rc == -EIO) { if (rc == -EIO) {
/* Old server, try legacy style OpenX */ /* Old server, try legacy style OpenX */
rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
......
...@@ -109,32 +109,52 @@ static int construct_dentry(struct qstr *qstring, struct file *file, ...@@ -109,32 +109,52 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
return rc; return rc;
} }
static void fill_in_inode(struct inode *tmp_inode, static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode) char * buf, int *pobject_type, int isNewInode)
{ {
loff_t local_size; loff_t local_size;
struct timespec local_mtime; struct timespec local_mtime;
struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
__u32 attr = le32_to_cpu(pfindData->ExtFileAttributes); __u32 attr;
__u64 allocation_size = le64_to_cpu(pfindData->AllocationSize); __u64 allocation_size;
__u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); __u64 end_of_file;
cifsInfo->cifsAttrs = attr;
cifsInfo->time = jiffies;
/* save mtime and size */ /* save mtime and size */
local_mtime = tmp_inode->i_mtime; local_mtime = tmp_inode->i_mtime;
local_size = tmp_inode->i_size; 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 */
FIND_FILE_STANDARD_INFO * pfindData =
(FIND_FILE_STANDARD_INFO *)buf;
attr = le16_to_cpu(pfindData->Attributes);
allocation_size = le32_to_cpu(pfindData->AllocationSize);
end_of_file = le32_to_cpu(pfindData->DataSize);
tmp_inode->i_atime = CURRENT_TIME;
/* tmp_inode->i_mtime = BB FIXME - add dos time handling
tmp_inode->i_ctime = 0; BB FIXME */
}
/* Linux can not store file creation time unfortunately so ignore it */ /* Linux can not store file creation time unfortunately so ignore it */
tmp_inode->i_atime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); cifsInfo->cifsAttrs = attr;
tmp_inode->i_mtime = cifsInfo->time = jiffies;
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
tmp_inode->i_ctime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
/* treat dos attribute of read-only as read-only mode bit e.g. 555? */ /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
/* 2767 perms - indicate mandatory locking */ /* 2767 perms - indicate mandatory locking */
/* BB fill in uid and gid here? with help from winbind? /* BB fill in uid and gid here? with help from winbind?
...@@ -420,7 +440,10 @@ static int initiate_cifs_search(const int xid, struct file *file) ...@@ -420,7 +440,10 @@ static int initiate_cifs_search(const int xid, struct file *file)
ffirst_retry: ffirst_retry:
/* test for Unix extensions */ /* test for Unix extensions */
if (pTcon->ses->capabilities & CAP_UNIX) { 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) { } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
} else /* not srvinos - BB fixme add check for backlevel? */ { } else /* not srvinos - BB fixme add check for backlevel? */ {
...@@ -456,12 +479,19 @@ static int cifs_unicode_bytelen(char *str) ...@@ -456,12 +479,19 @@ static int cifs_unicode_bytelen(char *str)
return len << 1; 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; char * new_entry;
FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_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)); cFYI(1,("new entry %p old entry %p",new_entry,old_entry));
/* validate that new_entry is not past end of SMB */ /* validate that new_entry is not past end of SMB */
if(new_entry >= end_of_smb) { if(new_entry >= end_of_smb) {
...@@ -469,7 +499,10 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb) ...@@ -469,7 +499,10 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb)
("search entry %p began after end of SMB %p old entry %p", ("search entry %p began after end of SMB %p old entry %p",
new_entry, end_of_smb, old_entry)); new_entry, end_of_smb, old_entry));
return NULL; 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", cERROR(1,("search entry %p extends after end of SMB %p",
new_entry, end_of_smb)); new_entry, end_of_smb));
return NULL; return NULL;
...@@ -487,7 +520,7 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) ...@@ -487,7 +520,7 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
char * filename = NULL; char * filename = NULL;
int len = 0; 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; FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
if(cfile->srch_inf.unicode) { if(cfile->srch_inf.unicode) {
...@@ -496,26 +529,34 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) ...@@ -496,26 +529,34 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
/* BB should we make this strnlen of PATH_MAX? */ /* BB should we make this strnlen of PATH_MAX? */
len = strnlen(filename, 5); 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 * pFindData =
(FILE_DIRECTORY_INFO *)current_entry; (FILE_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); 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 * pFindData =
(FILE_FULL_DIRECTORY_INFO *)current_entry; (FILE_FULL_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); 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 * pFindData =
(SEARCH_ID_FULL_DIR_INFO *)current_entry; (SEARCH_ID_FULL_DIR_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); 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 * pFindData =
(FILE_BOTH_DIRECTORY_INFO *)current_entry; (FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); 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 = le32_to_cpu(pFindData->FileNameLength);
} else { } else {
cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level)); cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level));
} }
...@@ -651,10 +692,12 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, ...@@ -651,10 +692,12 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
- cifsFile->srch_inf.entries_in_buffer; - cifsFile->srch_inf.entries_in_buffer;
pos_in_buf = index_to_find - first_entry_in_buffer; pos_in_buf = index_to_find - first_entry_in_buffer;
cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); cFYI(1,("found entry - pos_in_buf %d",pos_in_buf));
for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
/* go entry by entry figuring out which is first */ /* go entry by entry figuring out which is first */
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)) { if((current_entry == NULL) && (i < pos_in_buf)) {
/* BB fixme - check if we should flag this error */ /* BB fixme - check if we should flag this error */
...@@ -681,7 +724,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, ...@@ -681,7 +724,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
/* inode num, inode type and filename returned */ /* inode num, inode type and filename returned */
static int cifs_get_name_from_search_buf(struct qstr *pqst, static int cifs_get_name_from_search_buf(struct qstr *pqst,
char *current_entry, __u16 level, unsigned int unicode, 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; int rc = 0;
unsigned int len = 0; unsigned int len = 0;
...@@ -725,10 +768,22 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, ...@@ -725,10 +768,22 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
(FILE_BOTH_DIRECTORY_INFO *)current_entry; (FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); 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 { } else {
cFYI(1,("Unknown findfirst level %d",level)); cFYI(1,("Unknown findfirst level %d",level));
return -EINVAL; return -EINVAL;
} }
if(len > max_len) {
cERROR(1,("bad search response length %d past smb end", len));
return -EINVAL;
}
if(unicode) { if(unicode) {
/* BB fixme - test with long names */ /* BB fixme - test with long names */
/* Note converted filename can be longer than in unicode */ /* Note converted filename can be longer than in unicode */
...@@ -748,7 +803,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, ...@@ -748,7 +803,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
} }
static int cifs_filldir(char *pfindEntry, struct file *file, 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; int rc = 0;
struct qstr qstring; struct qstr qstring;
...@@ -784,6 +839,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file, ...@@ -784,6 +839,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
rc = cifs_get_name_from_search_buf(&qstring,pfindEntry, rc = cifs_get_name_from_search_buf(&qstring,pfindEntry,
pCifsF->srch_inf.info_level, pCifsF->srch_inf.info_level,
pCifsF->srch_inf.unicode,cifs_sb, pCifsF->srch_inf.unicode,cifs_sb,
max_len,
&inum /* returned */); &inum /* returned */);
if(rc) if(rc)
...@@ -805,13 +861,16 @@ static int cifs_filldir(char *pfindEntry, struct file *file, ...@@ -805,13 +861,16 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
/* we pass in rc below, indicating whether it is a new inode, /* we pass in rc below, indicating whether it is a new inode,
so we can figure out whether to invalidate the inode cached so we can figure out whether to invalidate the inode cached
data if the file has changed */ 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, unix_fill_in_inode(tmp_inode,
(FILE_UNIX_INFO *)pfindEntry,&obj_type, rc); (FILE_UNIX_INFO *)pfindEntry,
} else { &obj_type, rc);
fill_in_inode(tmp_inode, else if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
(FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); 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);
rc = filldir(direntry,qstring.name,qstring.len,file->f_pos, rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,
tmp_inode->i_ino,obj_type); tmp_inode->i_ino,obj_type);
...@@ -871,6 +930,12 @@ static int cifs_save_resume_key(const char *current_entry, ...@@ -871,6 +930,12 @@ static int cifs_save_resume_key(const char *current_entry,
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex; 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;
} else { } else {
cFYI(1,("Unknown findfirst level %d",level)); cFYI(1,("Unknown findfirst level %d",level));
return -EINVAL; return -EINVAL;
...@@ -891,6 +956,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -891,6 +956,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
int num_to_fill = 0; int num_to_fill = 0;
char * tmp_buf = NULL; char * tmp_buf = NULL;
char * end_of_smb; char * end_of_smb;
int max_len;
xid = GetXid(); xid = GetXid();
...@@ -966,10 +1032,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -966,10 +1032,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
goto rddir2_exit; goto rddir2_exit;
} }
cFYI(1,("loop through %d times filling dir for net buf %p", cFYI(1,("loop through %d times filling dir for net buf %p",
num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); num_to_fill,cifsFile->srch_inf.ntwrk_buf_start));
end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len = smbCalcSize((struct smb_hdr *)
smbCalcSize((struct smb_hdr *) cifsFile->srch_inf.ntwrk_buf_start);
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 /* To be safe - for UCS to UTF-8 with strings loaded
with the rare long characters alloc more to account for with the rare long characters alloc more to account for
such multibyte target UTF-8 characters. cifs_unicode.c, such multibyte target UTF-8 characters. cifs_unicode.c,
...@@ -984,8 +1051,8 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -984,8 +1051,8 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
} }
/* if buggy server returns . and .. late do /* if buggy server returns . and .. late do
we want to check for that here? */ we want to check for that here? */
rc = cifs_filldir(current_entry, file, rc = cifs_filldir(current_entry, file,
filldir, direntry,tmp_buf); filldir, direntry, tmp_buf, max_len);
file->f_pos++; file->f_pos++;
if(file->f_pos == if(file->f_pos ==
cifsFile->srch_inf.index_of_last_entry) { cifsFile->srch_inf.index_of_last_entry) {
...@@ -994,8 +1061,9 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -994,8 +1061,9 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
cifs_save_resume_key(current_entry,cifsFile); cifs_save_resume_key(current_entry,cifsFile);
break; break;
} else } else
current_entry = nxt_dir_entry(current_entry, current_entry =
end_of_smb); nxt_dir_entry(current_entry, end_of_smb,
cifsFile->srch_inf.info_level);
} }
kfree(tmp_buf); kfree(tmp_buf);
break; break;
......
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