Loading fs/cifs/cifsglob.h +15 −0 Original line number Diff line number Diff line Loading @@ -177,6 +177,7 @@ struct cifs_fid; struct cifs_readdata; struct cifs_writedata; struct cifs_io_parms; struct cifs_search_info; struct smb_version_operations { int (*send_cancel)(struct TCP_Server_Info *, void *, Loading Loading @@ -313,6 +314,20 @@ struct smb_version_operations { int (*sync_write)(const unsigned int, struct cifsFileInfo *, struct cifs_io_parms *, unsigned int *, struct kvec *, unsigned long); /* open dir, start readdir */ int (*query_dir_first)(const unsigned int, struct cifs_tcon *, const char *, struct cifs_sb_info *, struct cifs_fid *, __u16, struct cifs_search_info *); /* continue readdir */ int (*query_dir_next)(const unsigned int, struct cifs_tcon *, struct cifs_fid *, __u16, struct cifs_search_info *srch_inf); /* close dir */ int (*close_dir)(const unsigned int, struct cifs_tcon *, struct cifs_fid *); /* calculate a size of SMB message */ unsigned int (*calc_smb_size)(void *); }; struct smb_version_values { Loading fs/cifs/cifsproto.h +1 −1 Original line number Diff line number Diff line Loading @@ -100,7 +100,7 @@ extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, unsigned int bytes_written); extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); extern unsigned int smbCalcSize(struct smb_hdr *ptr); extern unsigned int smbCalcSize(void *buf); extern int decode_negTokenInit(unsigned char *security_blob, int length, struct TCP_Server_Info *server); extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len); Loading fs/cifs/file.c +34 −26 Original line number Diff line number Diff line Loading @@ -618,39 +618,47 @@ int cifs_closedir(struct inode *inode, struct file *file) int rc = 0; unsigned int xid; struct cifsFileInfo *cfile = file->private_data; char *tmp; struct cifs_tcon *tcon; struct TCP_Server_Info *server; char *buf; cFYI(1, "Closedir inode = 0x%p", inode); xid = get_xid(); if (cfile == NULL) return rc; if (cfile) { struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); xid = get_xid(); tcon = tlink_tcon(cfile->tlink); server = tcon->ses->server; cFYI(1, "Freeing private data in close dir"); spin_lock(&cifs_file_list_lock); if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { cfile->invalidHandle = true; spin_unlock(&cifs_file_list_lock); rc = CIFSFindClose(xid, tcon, cfile->fid.netfid); if (server->ops->close_dir) rc = server->ops->close_dir(xid, tcon, &cfile->fid); else rc = -ENOSYS; cFYI(1, "Closing uncompleted readdir with rc %d", rc); /* not much we can do if it fails anyway, ignore rc */ rc = 0; } else spin_unlock(&cifs_file_list_lock); tmp = cfile->srch_inf.ntwrk_buf_start; if (tmp) { buf = cfile->srch_inf.ntwrk_buf_start; if (buf) { cFYI(1, "closedir free smb buf in srch struct"); cfile->srch_inf.ntwrk_buf_start = NULL; if (cfile->srch_inf.smallBuf) cifs_small_buf_release(tmp); cifs_small_buf_release(buf); else cifs_buf_release(tmp); cifs_buf_release(buf); } cifs_put_tlink(cfile->tlink); kfree(file->private_data); file->private_data = NULL; } /* BB can we lock the filestruct while this is going on? */ free_xid(xid); return rc; Loading fs/cifs/netmisc.c +2 −1 Original line number Diff line number Diff line Loading @@ -913,8 +913,9 @@ map_smb_to_linux_error(char *buf, bool logErr) * portion, the number of word parameters and the data portion of the message */ unsigned int smbCalcSize(struct smb_hdr *ptr) smbCalcSize(void *buf) { struct smb_hdr *ptr = (struct smb_hdr *)buf; return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + 2 /* size of the bcc field */ + get_bcc(ptr)); } Loading fs/cifs/readdir.c +90 −75 Original line number Diff line number Diff line Loading @@ -220,7 +220,8 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, } */ static int initiate_cifs_search(const unsigned int xid, struct file *file) static int initiate_cifs_search(const unsigned int xid, struct file *file) { __u16 search_flags; int rc = 0; Loading @@ -229,6 +230,7 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file) struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); struct tcon_link *tlink = NULL; struct cifs_tcon *tcon; struct TCP_Server_Info *server; if (file->private_data == NULL) { tlink = cifs_sb_tlink(cifs_sb); Loading @@ -248,6 +250,13 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file) tcon = tlink_tcon(cifsFile->tlink); } server = tcon->ses->server; if (!server->ops->query_dir_first) { rc = -ENOSYS; goto error_exit; } cifsFile->invalidHandle = true; cifsFile->srch_inf.endOfSearch = false; Loading Loading @@ -278,10 +287,10 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file) if (backup_cred(cifs_sb)) search_flags |= CIFS_SEARCH_BACKUP_SEARCH; rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls, &cifsFile->fid.netfid, search_flags, &cifsFile->srch_inf, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); rc = server->ops->query_dir_first(xid, tcon, full_path, cifs_sb, &cifsFile->fid, search_flags, &cifsFile->srch_inf); if (rc == 0) cifsFile->invalidHandle = false; /* BB add following call to handle readdir on new NTFS symlink errors Loading Loading @@ -501,62 +510,67 @@ static int cifs_save_resume_key(const char *current_entry, return rc; } /* find the corresponding entry in the search */ /* Note that the SMB server returns search entries for . and .. which complicates logic here if we choose to parse for them and we do not assume that they are located in the findfirst return buffer.*/ /* We start counting in the buffer with entry 2 and increment for every entry (do not increment for . or .. entry) */ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon, struct file *file, char **ppCurrentEntry, int *num_to_ret) /* * Find the corresponding entry in the search. Note that the SMB server returns * search entries for . and .. which complicates logic here if we choose to * parse for them and we do not assume that they are located in the findfirst * return buffer. We start counting in the buffer with entry 2 and increment for * every entry (do not increment for . or .. entry). */ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, struct file *file, char **current_entry, int *num_to_ret) { __u16 search_flags; int rc = 0; int pos_in_buf = 0; loff_t first_entry_in_buffer; loff_t index_to_find = file->f_pos; struct cifsFileInfo *cifsFile = file->private_data; struct cifsFileInfo *cfile = file->private_data; struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); struct TCP_Server_Info *server = tcon->ses->server; /* check if index in the buffer */ if ((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL)) if (!server->ops->query_dir_first || !server->ops->query_dir_next) return -ENOSYS; if ((cfile == NULL) || (current_entry == NULL) || (num_to_ret == NULL)) return -ENOENT; *ppCurrentEntry = NULL; first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry - cifsFile->srch_inf.entries_in_buffer; *current_entry = NULL; first_entry_in_buffer = cfile->srch_inf.index_of_last_entry - cfile->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 */ /* * 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. */ 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)) { if (((index_to_find < cfile->srch_inf.index_of_last_entry) && is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) { /* close and restart search */ cFYI(1, "search backing up - close and restart search"); spin_lock(&cifs_file_list_lock); if (!cifsFile->srch_inf.endOfSearch && !cifsFile->invalidHandle) { cifsFile->invalidHandle = true; if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { cfile->invalidHandle = true; spin_unlock(&cifs_file_list_lock); CIFSFindClose(xid, pTcon, cifsFile->fid.netfid); if (server->ops->close) server->ops->close(xid, tcon, &cfile->fid); } else spin_unlock(&cifs_file_list_lock); if (cifsFile->srch_inf.ntwrk_buf_start) { if (cfile->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. if (cfile->srch_inf.smallBuf) cifs_small_buf_release(cfile->srch_inf. ntwrk_buf_start); else cifs_buf_release(cifsFile->srch_inf. cifs_buf_release(cfile->srch_inf. ntwrk_buf_start); cifsFile->srch_inf.ntwrk_buf_start = NULL; cfile->srch_inf.ntwrk_buf_start = NULL; } rc = initiate_cifs_search(xid, file); if (rc) { Loading @@ -565,65 +579,64 @@ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon, return rc; } /* FindFirst/Next set last_entry to NULL on malformed reply */ if (cifsFile->srch_inf.last_entry) cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile); if (cfile->srch_inf.last_entry) cifs_save_resume_key(cfile->srch_inf.last_entry, cfile); } search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME; if (backup_cred(cifs_sb)) search_flags |= CIFS_SEARCH_BACKUP_SEARCH; while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && (rc == 0) && !cifsFile->srch_inf.endOfSearch) { while ((index_to_find >= cfile->srch_inf.index_of_last_entry) && (rc == 0) && !cfile->srch_inf.endOfSearch) { cFYI(1, "calling findnext2"); rc = CIFSFindNext(xid, pTcon, cifsFile->fid.netfid, search_flags, &cifsFile->srch_inf); rc = server->ops->query_dir_next(xid, tcon, &cfile->fid, search_flags, &cfile->srch_inf); /* FindFirst/Next set last_entry to NULL on malformed reply */ if (cifsFile->srch_inf.last_entry) cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile); if (cfile->srch_inf.last_entry) cifs_save_resume_key(cfile->srch_inf.last_entry, cfile); if (rc) return -ENOENT; } if (index_to_find < cifsFile->srch_inf.index_of_last_entry) { if (index_to_find < cfile->srch_inf.index_of_last_entry) { /* we found the buffer that contains the entry */ /* scan and find it */ int i; char *current_entry; 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; char *cur_ent; char *end_of_smb = cfile->srch_inf.ntwrk_buf_start + server->ops->calc_smb_size( cfile->srch_inf.ntwrk_buf_start); cur_ent = cfile->srch_inf.srch_entries_start; first_entry_in_buffer = cfile->srch_inf.index_of_last_entry - cfile->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); for (i = 0; (i < (pos_in_buf)) && (current_entry != NULL); i++) { for (i = 0; (i < (pos_in_buf)) && (cur_ent != 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); cur_ent = nxt_dir_entry(cur_ent, end_of_smb, cfile->srch_inf.info_level); } if ((current_entry == NULL) && (i < pos_in_buf)) { if ((cur_ent == NULL) && (i < pos_in_buf)) { /* BB fixme - check if we should flag this error */ cERROR(1, "reached end of buf searching for pos in buf" " %d index to find %lld rc %d", pos_in_buf, index_to_find, rc); " %d index to find %lld rc %d", pos_in_buf, index_to_find, rc); } rc = 0; *ppCurrentEntry = current_entry; *current_entry = cur_ent; } else { cFYI(1, "index not in buffer - could not findnext into it"); return 0; } if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { if (pos_in_buf >= cfile->srch_inf.entries_in_buffer) { cFYI(1, "can not return entries pos_in_buf beyond last"); *num_to_ret = 0; } else *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; *num_to_ret = cfile->srch_inf.entries_in_buffer - pos_in_buf; return rc; } Loading Loading @@ -723,7 +736,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) int rc = 0; unsigned int xid; int i; struct cifs_tcon *pTcon; struct cifs_tcon *tcon; struct cifsFileInfo *cifsFile = NULL; char *current_entry; int num_to_fill = 0; Loading Loading @@ -781,12 +794,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) } } /* else { cifsFile->invalidHandle = true; CIFSFindClose(xid, pTcon, cifsFile->fid.netfid); tcon->ses->server->close(xid, tcon, &cifsFile->fid); } */ pTcon = tlink_tcon(cifsFile->tlink); rc = find_cifs_entry(xid, pTcon, file, ¤t_entry, &num_to_fill); tcon = tlink_tcon(cifsFile->tlink); rc = find_cifs_entry(xid, tcon, file, ¤t_entry, &num_to_fill); if (rc) { cFYI(1, "fce error %d", rc); goto rddir2_exit; Loading @@ -798,7 +811,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) } 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 *) max_len = tcon->ses->server->ops->calc_smb_size( cifsFile->srch_inf.ntwrk_buf_start); end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; Loading @@ -815,10 +828,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) 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 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; Loading Loading
fs/cifs/cifsglob.h +15 −0 Original line number Diff line number Diff line Loading @@ -177,6 +177,7 @@ struct cifs_fid; struct cifs_readdata; struct cifs_writedata; struct cifs_io_parms; struct cifs_search_info; struct smb_version_operations { int (*send_cancel)(struct TCP_Server_Info *, void *, Loading Loading @@ -313,6 +314,20 @@ struct smb_version_operations { int (*sync_write)(const unsigned int, struct cifsFileInfo *, struct cifs_io_parms *, unsigned int *, struct kvec *, unsigned long); /* open dir, start readdir */ int (*query_dir_first)(const unsigned int, struct cifs_tcon *, const char *, struct cifs_sb_info *, struct cifs_fid *, __u16, struct cifs_search_info *); /* continue readdir */ int (*query_dir_next)(const unsigned int, struct cifs_tcon *, struct cifs_fid *, __u16, struct cifs_search_info *srch_inf); /* close dir */ int (*close_dir)(const unsigned int, struct cifs_tcon *, struct cifs_fid *); /* calculate a size of SMB message */ unsigned int (*calc_smb_size)(void *); }; struct smb_version_values { Loading
fs/cifs/cifsproto.h +1 −1 Original line number Diff line number Diff line Loading @@ -100,7 +100,7 @@ extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, unsigned int bytes_written); extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); extern unsigned int smbCalcSize(struct smb_hdr *ptr); extern unsigned int smbCalcSize(void *buf); extern int decode_negTokenInit(unsigned char *security_blob, int length, struct TCP_Server_Info *server); extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len); Loading
fs/cifs/file.c +34 −26 Original line number Diff line number Diff line Loading @@ -618,39 +618,47 @@ int cifs_closedir(struct inode *inode, struct file *file) int rc = 0; unsigned int xid; struct cifsFileInfo *cfile = file->private_data; char *tmp; struct cifs_tcon *tcon; struct TCP_Server_Info *server; char *buf; cFYI(1, "Closedir inode = 0x%p", inode); xid = get_xid(); if (cfile == NULL) return rc; if (cfile) { struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); xid = get_xid(); tcon = tlink_tcon(cfile->tlink); server = tcon->ses->server; cFYI(1, "Freeing private data in close dir"); spin_lock(&cifs_file_list_lock); if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { cfile->invalidHandle = true; spin_unlock(&cifs_file_list_lock); rc = CIFSFindClose(xid, tcon, cfile->fid.netfid); if (server->ops->close_dir) rc = server->ops->close_dir(xid, tcon, &cfile->fid); else rc = -ENOSYS; cFYI(1, "Closing uncompleted readdir with rc %d", rc); /* not much we can do if it fails anyway, ignore rc */ rc = 0; } else spin_unlock(&cifs_file_list_lock); tmp = cfile->srch_inf.ntwrk_buf_start; if (tmp) { buf = cfile->srch_inf.ntwrk_buf_start; if (buf) { cFYI(1, "closedir free smb buf in srch struct"); cfile->srch_inf.ntwrk_buf_start = NULL; if (cfile->srch_inf.smallBuf) cifs_small_buf_release(tmp); cifs_small_buf_release(buf); else cifs_buf_release(tmp); cifs_buf_release(buf); } cifs_put_tlink(cfile->tlink); kfree(file->private_data); file->private_data = NULL; } /* BB can we lock the filestruct while this is going on? */ free_xid(xid); return rc; Loading
fs/cifs/netmisc.c +2 −1 Original line number Diff line number Diff line Loading @@ -913,8 +913,9 @@ map_smb_to_linux_error(char *buf, bool logErr) * portion, the number of word parameters and the data portion of the message */ unsigned int smbCalcSize(struct smb_hdr *ptr) smbCalcSize(void *buf) { struct smb_hdr *ptr = (struct smb_hdr *)buf; return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + 2 /* size of the bcc field */ + get_bcc(ptr)); } Loading
fs/cifs/readdir.c +90 −75 Original line number Diff line number Diff line Loading @@ -220,7 +220,8 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, } */ static int initiate_cifs_search(const unsigned int xid, struct file *file) static int initiate_cifs_search(const unsigned int xid, struct file *file) { __u16 search_flags; int rc = 0; Loading @@ -229,6 +230,7 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file) struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); struct tcon_link *tlink = NULL; struct cifs_tcon *tcon; struct TCP_Server_Info *server; if (file->private_data == NULL) { tlink = cifs_sb_tlink(cifs_sb); Loading @@ -248,6 +250,13 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file) tcon = tlink_tcon(cifsFile->tlink); } server = tcon->ses->server; if (!server->ops->query_dir_first) { rc = -ENOSYS; goto error_exit; } cifsFile->invalidHandle = true; cifsFile->srch_inf.endOfSearch = false; Loading Loading @@ -278,10 +287,10 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file) if (backup_cred(cifs_sb)) search_flags |= CIFS_SEARCH_BACKUP_SEARCH; rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls, &cifsFile->fid.netfid, search_flags, &cifsFile->srch_inf, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); rc = server->ops->query_dir_first(xid, tcon, full_path, cifs_sb, &cifsFile->fid, search_flags, &cifsFile->srch_inf); if (rc == 0) cifsFile->invalidHandle = false; /* BB add following call to handle readdir on new NTFS symlink errors Loading Loading @@ -501,62 +510,67 @@ static int cifs_save_resume_key(const char *current_entry, return rc; } /* find the corresponding entry in the search */ /* Note that the SMB server returns search entries for . and .. which complicates logic here if we choose to parse for them and we do not assume that they are located in the findfirst return buffer.*/ /* We start counting in the buffer with entry 2 and increment for every entry (do not increment for . or .. entry) */ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon, struct file *file, char **ppCurrentEntry, int *num_to_ret) /* * Find the corresponding entry in the search. Note that the SMB server returns * search entries for . and .. which complicates logic here if we choose to * parse for them and we do not assume that they are located in the findfirst * return buffer. We start counting in the buffer with entry 2 and increment for * every entry (do not increment for . or .. entry). */ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, struct file *file, char **current_entry, int *num_to_ret) { __u16 search_flags; int rc = 0; int pos_in_buf = 0; loff_t first_entry_in_buffer; loff_t index_to_find = file->f_pos; struct cifsFileInfo *cifsFile = file->private_data; struct cifsFileInfo *cfile = file->private_data; struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); struct TCP_Server_Info *server = tcon->ses->server; /* check if index in the buffer */ if ((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL)) if (!server->ops->query_dir_first || !server->ops->query_dir_next) return -ENOSYS; if ((cfile == NULL) || (current_entry == NULL) || (num_to_ret == NULL)) return -ENOENT; *ppCurrentEntry = NULL; first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry - cifsFile->srch_inf.entries_in_buffer; *current_entry = NULL; first_entry_in_buffer = cfile->srch_inf.index_of_last_entry - cfile->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 */ /* * 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. */ 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)) { if (((index_to_find < cfile->srch_inf.index_of_last_entry) && is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) { /* close and restart search */ cFYI(1, "search backing up - close and restart search"); spin_lock(&cifs_file_list_lock); if (!cifsFile->srch_inf.endOfSearch && !cifsFile->invalidHandle) { cifsFile->invalidHandle = true; if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { cfile->invalidHandle = true; spin_unlock(&cifs_file_list_lock); CIFSFindClose(xid, pTcon, cifsFile->fid.netfid); if (server->ops->close) server->ops->close(xid, tcon, &cfile->fid); } else spin_unlock(&cifs_file_list_lock); if (cifsFile->srch_inf.ntwrk_buf_start) { if (cfile->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. if (cfile->srch_inf.smallBuf) cifs_small_buf_release(cfile->srch_inf. ntwrk_buf_start); else cifs_buf_release(cifsFile->srch_inf. cifs_buf_release(cfile->srch_inf. ntwrk_buf_start); cifsFile->srch_inf.ntwrk_buf_start = NULL; cfile->srch_inf.ntwrk_buf_start = NULL; } rc = initiate_cifs_search(xid, file); if (rc) { Loading @@ -565,65 +579,64 @@ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon, return rc; } /* FindFirst/Next set last_entry to NULL on malformed reply */ if (cifsFile->srch_inf.last_entry) cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile); if (cfile->srch_inf.last_entry) cifs_save_resume_key(cfile->srch_inf.last_entry, cfile); } search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME; if (backup_cred(cifs_sb)) search_flags |= CIFS_SEARCH_BACKUP_SEARCH; while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && (rc == 0) && !cifsFile->srch_inf.endOfSearch) { while ((index_to_find >= cfile->srch_inf.index_of_last_entry) && (rc == 0) && !cfile->srch_inf.endOfSearch) { cFYI(1, "calling findnext2"); rc = CIFSFindNext(xid, pTcon, cifsFile->fid.netfid, search_flags, &cifsFile->srch_inf); rc = server->ops->query_dir_next(xid, tcon, &cfile->fid, search_flags, &cfile->srch_inf); /* FindFirst/Next set last_entry to NULL on malformed reply */ if (cifsFile->srch_inf.last_entry) cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile); if (cfile->srch_inf.last_entry) cifs_save_resume_key(cfile->srch_inf.last_entry, cfile); if (rc) return -ENOENT; } if (index_to_find < cifsFile->srch_inf.index_of_last_entry) { if (index_to_find < cfile->srch_inf.index_of_last_entry) { /* we found the buffer that contains the entry */ /* scan and find it */ int i; char *current_entry; 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; char *cur_ent; char *end_of_smb = cfile->srch_inf.ntwrk_buf_start + server->ops->calc_smb_size( cfile->srch_inf.ntwrk_buf_start); cur_ent = cfile->srch_inf.srch_entries_start; first_entry_in_buffer = cfile->srch_inf.index_of_last_entry - cfile->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); for (i = 0; (i < (pos_in_buf)) && (current_entry != NULL); i++) { for (i = 0; (i < (pos_in_buf)) && (cur_ent != 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); cur_ent = nxt_dir_entry(cur_ent, end_of_smb, cfile->srch_inf.info_level); } if ((current_entry == NULL) && (i < pos_in_buf)) { if ((cur_ent == NULL) && (i < pos_in_buf)) { /* BB fixme - check if we should flag this error */ cERROR(1, "reached end of buf searching for pos in buf" " %d index to find %lld rc %d", pos_in_buf, index_to_find, rc); " %d index to find %lld rc %d", pos_in_buf, index_to_find, rc); } rc = 0; *ppCurrentEntry = current_entry; *current_entry = cur_ent; } else { cFYI(1, "index not in buffer - could not findnext into it"); return 0; } if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { if (pos_in_buf >= cfile->srch_inf.entries_in_buffer) { cFYI(1, "can not return entries pos_in_buf beyond last"); *num_to_ret = 0; } else *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; *num_to_ret = cfile->srch_inf.entries_in_buffer - pos_in_buf; return rc; } Loading Loading @@ -723,7 +736,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) int rc = 0; unsigned int xid; int i; struct cifs_tcon *pTcon; struct cifs_tcon *tcon; struct cifsFileInfo *cifsFile = NULL; char *current_entry; int num_to_fill = 0; Loading Loading @@ -781,12 +794,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) } } /* else { cifsFile->invalidHandle = true; CIFSFindClose(xid, pTcon, cifsFile->fid.netfid); tcon->ses->server->close(xid, tcon, &cifsFile->fid); } */ pTcon = tlink_tcon(cifsFile->tlink); rc = find_cifs_entry(xid, pTcon, file, ¤t_entry, &num_to_fill); tcon = tlink_tcon(cifsFile->tlink); rc = find_cifs_entry(xid, tcon, file, ¤t_entry, &num_to_fill); if (rc) { cFYI(1, "fce error %d", rc); goto rddir2_exit; Loading @@ -798,7 +811,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) } 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 *) max_len = tcon->ses->server->ops->calc_smb_size( cifsFile->srch_inf.ntwrk_buf_start); end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; Loading @@ -815,10 +828,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) 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 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; Loading