* 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"
-#ifdef CONFIG_CIFS_DEBUG2
-static void dump_cifs_file_struct(struct file *file, char *label)
+/* BB fixme - add debug wrappers around this function to disable it fixme BB */
+/* 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 */
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_op = &cifs_dentry_ops;
if(*ptmp_inode == NULL)
return rc;
- rc = 2;
+ rc = 1;
+ d_instantiate(tmp_dentry, *ptmp_inode);
+ d_rehash(tmp_dentry);
}
tmp_dentry->d_time = jiffies;
return rc;
}
-static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
- char * buf, int *pobject_type, int isNewInode)
+static void fill_in_inode(struct inode *tmp_inode,
+ FILE_DIRECTORY_INFO *pfindData, 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;
- __u64 allocation_size;
- __u64 end_of_file;
+ __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;
/* 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 */
- 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 */
-
- cifsInfo->cifsAttrs = attr;
- cifsInfo->time = jiffies;
-
+ 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));
/* 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?
if (allocation_size < end_of_file)
cFYI(1, ("May be sparse file, allocation less than file size"));
- cFYI(1, ("File Size %ld and blocks %llu",
- (unsigned long)tmp_inode->i_size,
- (unsigned long long)tmp_inode->i_blocks));
+ 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));
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 <
- 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;
-
+ 4096 + MAX_CIFS_HDR_SIZE))
+ tmp_inode->i_data.a_ops->readpages = NULL;
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 <
- 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;
+ 4096 + MAX_CIFS_HDR_SIZE))
+ tmp_inode->i_data.a_ops->readpages = NULL;
if(isNewInode)
return; /* No sense invalidating pages for new inode since we
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);
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;
- } else if ((pTcon->ses->capabilities &
- (CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
- cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
+ cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
} 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, int level)
+static char *nxt_dir_entry(char *old_entry, char *end_of_smb)
{
char * new_entry;
FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
- 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);
+ 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(((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))) {
+ } else if (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 == SMB_FIND_FILE_UNIX) {
+ if(cfile->srch_inf.info_level == 0x202) {
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 == SMB_FIND_FILE_DIRECTORY_INFO) {
+ } else if(cfile->srch_inf.info_level == 0x101) {
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 ==
- SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
+ } else if(cfile->srch_inf.info_level == 0x102) {
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 ==
- SMB_FIND_FILE_ID_FULL_DIR_INFO) {
+ } else if(cfile->srch_inf.info_level == 0x105) {
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 ==
- SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+ } else if(cfile->srch_inf.info_level == 0x104) {
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));
}
first_entry_in_buffer =
cifsFile->srch_inf.index_of_last_entry -
cifsFile->srch_inf.entries_in_buffer;
-
- /* 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
+/* dump_cifs_file_struct(file, "In fce ");*/
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"));
- 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);
+ 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));
-
+ cFYI(1,("found entry - pos_in_buf %d",pos_in_buf));
+ current_entry = cifsFile->srch_inf.srch_entries_start;
for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
/* go entry by entry figuring out which is first */
- current_entry = nxt_dir_entry(current_entry,end_of_smb,
- cifsFile->srch_inf.info_level);
+ /* 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);
}
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, int max_len, ino_t *pinum)
+ struct cifs_sb_info * cifs_sb, 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, int max_len)
+ filldir_t filldir, void *direntry, char *scratch_buf)
{
int rc = 0;
struct qstr qstring;
if(file->f_dentry == NULL)
return -ENOENT;
- 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_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 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);
+ (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc);
+ } else {
+ fill_in_inode(tmp_inode,
+ (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc);
}
-
rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,
tmp_inode->i_ino,obj_type);
if(rc) {
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;
} 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();
switch ((int) file->f_pos) {
case 0:
- if (filldir(direntry, ".", 1, file->f_pos,
+ /*if (filldir(direntry, ".", 1, file->f_pos,
file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
- cERROR(1, ("Filldir for current dir failed"));
+ 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,
+ /* 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"));
+ cERROR(1, ("Filldir for parent dir failed "));
rc = -ENOMEM;
break;
}
- file->f_pos++;
- default:
+ file->f_pos++; */
+ case 2:
/* 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));
- max_len = smbCalcSize((struct smb_hdr *)
- cifsFile->srch_inf.ntwrk_buf_start);
- end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
-
+ 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);
/* 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!=0) {
- 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));
+ file->f_pos,tmp_buf)); /* BB removeme BB */
cifs_save_resume_key(current_entry,cifsFile);
break;
} else
- current_entry =
- nxt_dir_entry(current_entry, end_of_smb,
- cifsFile->srch_inf.info_level);
+ current_entry = nxt_dir_entry(current_entry,
+ end_of_smb);
}
kfree(tmp_buf);
break;