X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fcifs%2Ffile.c;h=3d9b91d27d3acbcf4e08682d8459cdb89d4a1503;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=73505c6ccf3cf2b063392651de68e1f2f604fa95;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 73505c6cc..3d9b91d27 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -35,6 +35,8 @@ #include "cifs_debug.h" #include "cifs_fs_sb.h" +extern int cifs_readdir2(struct file *file, void *direntry, filldir_t filldir); /* BB removeme BB */ + int cifs_open(struct inode *inode, struct file *file) { @@ -62,7 +64,7 @@ cifs_open(struct inode *inode, struct file *file) read_lock(&GlobalSMBSeslock); list_for_each(tmp, &pCifsInode->openFileList) { pCifsFile = list_entry(tmp,struct cifsFileInfo, flist); - if((pCifsFile->pfile == NULL)&& (pCifsFile->pid = current->pid)){ + if((pCifsFile->pfile == NULL)&& (pCifsFile->pid == current->tgid)){ /* mode set in cifs_create */ pCifsFile->pfile = file; /* needed for writepage */ file->private_data = pCifsFile; @@ -148,7 +150,7 @@ cifs_open(struct inode *inode, struct file *file) and the first handle has writebehind data, we might be able to simply do a filemap_fdatawrite/filemap_fdatawait first */ buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); - if(buf==0) { + if(buf== NULL) { if (full_path) kfree(full_path); FreeXid(xid); @@ -166,7 +168,7 @@ cifs_open(struct inode *inode, struct file *file) memset(file->private_data, 0, sizeof(struct cifsFileInfo)); pCifsFile = (struct cifsFileInfo *) file->private_data; pCifsFile->netfid = netfid; - pCifsFile->pid = current->pid; + pCifsFile->pid = current->tgid; init_MUTEX(&pCifsFile->fh_sem); pCifsFile->pfile = file; /* needed for writepage */ pCifsFile->pInode = inode; @@ -452,18 +454,44 @@ cifs_closedir(struct inode *inode, struct file *file) { int rc = 0; int xid; - struct cifsFileInfo *pSMBFileStruct = + struct cifsFileInfo *pCFileStruct = (struct cifsFileInfo *) file->private_data; + char * ptmp; cFYI(1, ("Closedir inode = 0x%p with ", inode)); xid = GetXid(); - if (pSMBFileStruct) { + if (pCFileStruct) { + struct cifsTconInfo *pTcon; + struct cifs_sb_info * cifs_sb = CIFS_SB(file->f_dentry->d_sb); + + pTcon = cifs_sb->tcon; + cFYI(1, ("Freeing private data in close dir")); + if(pCFileStruct->srch_inf.endOfSearch == FALSE) { + pCFileStruct->invalidHandle = TRUE; + rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); + cFYI(1,("Closing uncompleted readdir with rc %d",rc)); + /* not much we can do if it fails anywway, ignore rc */ + rc = 0; + } + ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; + if(ptmp) { + cFYI(1,("freeing smb buf in srch struct in closedir")); /* BB removeme BB */ + pCFileStruct->srch_inf.ntwrk_buf_start = NULL; + cifs_buf_release(ptmp); + } + ptmp = pCFileStruct->search_resume_name; + if(ptmp) { + cFYI(1,("freeing resume name in closedir")); /* BB removeme BB */ + pCFileStruct->search_resume_name = NULL; + kfree(ptmp); + } kfree(file->private_data); file->private_data = NULL; } + /* BB can we lock the filestruct while this is going on? */ FreeXid(xid); return rc; } @@ -569,11 +597,133 @@ cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) netfid, length, pfLock->fl_start, numUnlock, numLock, lockType, wait_flag); + if (rc == 0 && (pfLock->fl_flags & FL_POSIX)) + posix_lock_file_wait(file, pfLock); FreeXid(xid); return rc; } ssize_t +cifs_user_write(struct file * file, const char __user * write_data, + size_t write_size, loff_t * poffset) +{ + int rc = 0; + unsigned int bytes_written = 0; + unsigned int total_written; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + int xid, long_op; + struct cifsFileInfo * open_file; + + if(file->f_dentry == NULL) + return -EBADF; + + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + if(cifs_sb == NULL) { + return -EBADF; + } + pTcon = cifs_sb->tcon; + + /*cFYI(1, + (" write %d bytes to offset %lld of %s", write_size, + *poffset, file->f_dentry->d_name.name)); */ + + if (file->private_data == NULL) { + return -EBADF; + } else { + open_file = (struct cifsFileInfo *) file->private_data; + } + + xid = GetXid(); + if(file->f_dentry->d_inode == NULL) { + FreeXid(xid); + return -EBADF; + } + + if (*poffset > file->f_dentry->d_inode->i_size) + long_op = 2; /* writes past end of file can take a long time */ + else + long_op = 1; + + for (total_written = 0; write_size > total_written; + total_written += bytes_written) { + rc = -EAGAIN; + while(rc == -EAGAIN) { + if(file->private_data == NULL) { + /* file has been closed on us */ + FreeXid(xid); + /* if we have gotten here we have written some data + and blocked, and the file has been freed on us + while we blocked so return what we managed to write */ + return total_written; + } + if(open_file->closePend) { + FreeXid(xid); + if(total_written) + return total_written; + else + return -EBADF; + } + if (open_file->invalidHandle) { + if((file->f_dentry == NULL) || + (file->f_dentry->d_inode == NULL)) { + FreeXid(xid); + return total_written; + } + /* we could deadlock if we called + filemap_fdatawait from here so tell + reopen_file not to flush data to server now */ + rc = cifs_reopen_file(file->f_dentry->d_inode, + file,FALSE); + if(rc != 0) + break; + } + + rc = CIFSSMBWrite(xid, pTcon, + open_file->netfid, + write_size - total_written, *poffset, + &bytes_written, + NULL, write_data + total_written, long_op); + } + if (rc || (bytes_written == 0)) { + if (total_written) + break; + else { + FreeXid(xid); + return rc; + } + } else + *poffset += bytes_written; + long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */ + } + +#ifdef CONFIG_CIFS_STATS + if(total_written > 0) { + atomic_inc(&pTcon->num_writes); + spin_lock(&pTcon->stat_lock); + pTcon->bytes_written += total_written; + spin_unlock(&pTcon->stat_lock); + } +#endif + + /* since the write may have blocked check these pointers again */ + if(file->f_dentry) { + if(file->f_dentry->d_inode) { + struct inode *inode = file->f_dentry->d_inode; + inode->i_ctime = inode->i_mtime = + current_fs_time(inode->i_sb); + if (total_written > 0) { + if (*poffset > file->f_dentry->d_inode->i_size) + i_size_write(file->f_dentry->d_inode, *poffset); + } + mark_inode_dirty_sync(file->f_dentry->d_inode); + } + } + FreeXid(xid); + return total_written; +} + +static ssize_t cifs_write(struct file * file, const char *write_data, size_t write_size, loff_t * poffset) { @@ -650,10 +800,10 @@ cifs_write(struct file * file, const char *write_data, } rc = CIFSSMBWrite(xid, pTcon, - open_file->netfid, + open_file->netfid, write_size - total_written, *poffset, &bytes_written, - write_data + total_written, long_op); + write_data + total_written, NULL, long_op); } if (rc || (bytes_written == 0)) { if (total_written) @@ -754,7 +904,7 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to) to-from, &offset); read_lock(&GlobalSMBSeslock); /* Does mm or vfs already set times? */ - inode->i_atime = inode->i_mtime = CURRENT_TIME; + inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); if ((bytes_written > 0) && (offset)) { rc = 0; } else if(bytes_written < 0) { @@ -967,6 +1117,83 @@ int cifs_flush(struct file *file) ssize_t +cifs_user_read(struct file * file, char __user *read_data, size_t read_size, + loff_t * poffset) +{ + int rc = -EACCES; + unsigned int bytes_read = 0; + unsigned int total_read = 0; + unsigned int current_read_size; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + int xid; + struct cifsFileInfo * open_file; + char * smb_read_data; + char __user * current_offset; + struct smb_com_read_rsp * pSMBr; + + xid = GetXid(); + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + pTcon = cifs_sb->tcon; + + if (file->private_data == NULL) { + FreeXid(xid); + return -EBADF; + } + open_file = (struct cifsFileInfo *)file->private_data; + + if((file->f_flags & O_ACCMODE) == O_WRONLY) { + cFYI(1,("attempting read on write only file instance")); + } + + for (total_read = 0,current_offset=read_data; read_size > total_read; + total_read += bytes_read,current_offset+=bytes_read) { + current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize); + rc = -EAGAIN; + smb_read_data = NULL; + while(rc == -EAGAIN) { + if ((open_file->invalidHandle) && (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode, + file,TRUE); + if(rc != 0) + break; + } + + rc = CIFSSMBRead(xid, pTcon, + open_file->netfid, + current_read_size, *poffset, + &bytes_read, &smb_read_data); + + pSMBr = (struct smb_com_read_rsp *)smb_read_data; + copy_to_user(current_offset,smb_read_data + 4/* RFC1001 hdr*/ + + le16_to_cpu(pSMBr->DataOffset), bytes_read); + if(smb_read_data) { + cifs_buf_release(smb_read_data); + smb_read_data = NULL; + } + } + if (rc || (bytes_read == 0)) { + if (total_read) { + break; + } else { + FreeXid(xid); + return rc; + } + } else { +#ifdef CONFIG_CIFS_STATS + atomic_inc(&pTcon->num_reads); + spin_lock(&pTcon->stat_lock); + pTcon->bytes_read += total_read; + spin_unlock(&pTcon->stat_lock); +#endif + *poffset += bytes_read; + } + } + FreeXid(xid); + return total_read; +} + +static ssize_t cifs_read(struct file * file, char *read_data, size_t read_size, loff_t * poffset) { @@ -1037,6 +1264,17 @@ int cifs_file_mmap(struct file * file, struct vm_area_struct * vma) struct dentry * dentry = file->f_dentry; int rc, xid; +#ifdef CIFS_EXPERIMENTAL /* BB fixme reenable when cifs_read_wrapper fixed */ + if(dentry->d_sb) { + struct cifs_sb_info *cifs_sb; + cifs_sb = CIFS_SB(sb); + if(cifs_sb != NULL) { + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) + return -ENODEV + } + } +#endif /* CIFS_EXPERIMENTAL */ + xid = GetXid(); rc = cifs_revalidate(dentry); if (rc) { @@ -1197,8 +1435,6 @@ cifs_readpages(struct file *file, struct address_space *mapping, spin_unlock(&pTcon->stat_lock); #endif if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { - cFYI(1,("Partial page %d of %d read to cache",i++,num_pages)); - i++; /* account for partial page */ /* server copy of file can have smaller size than client */ @@ -1258,7 +1494,8 @@ static int cifs_readpage_worker(struct file *file, struct page *page, loff_t * p cFYI(1,("Bytes read %d ",rc)); } - file->f_dentry->d_inode->i_atime = CURRENT_TIME; + file->f_dentry->d_inode->i_atime = + current_fs_time(file->f_dentry->d_inode->i_sb); if(PAGE_CACHE_SIZE > rc) { memset(read_data+rc, 0, PAGE_CACHE_SIZE - rc); @@ -1346,12 +1583,11 @@ fill_in_inode(struct inode *tmp_inode, { 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); - pfindData->ExtFileAttributes = - le32_to_cpu(pfindData->ExtFileAttributes); - pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); - pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile); - cifsInfo->cifsAttrs = pfindData->ExtFileAttributes; + cifsInfo->cifsAttrs = attr; cifsInfo->time = jiffies; /* Linux can not store file creation time unfortunately so ignore it */ @@ -1374,24 +1610,23 @@ fill_in_inode(struct inode *tmp_inode, cFYI(0, ("CIFS FFIRST: Attributes came in as 0x%x", - pfindData->ExtFileAttributes)); - if (pfindData->ExtFileAttributes & ATTR_REPARSE) { - *pobject_type = DT_LNK; - /* BB can this and S_IFREG or S_IFDIR be set as in Windows? */ - tmp_inode->i_mode |= S_IFLNK; - } else if (pfindData->ExtFileAttributes & ATTR_DIRECTORY) { + attr)); + if (attr & ATTR_DIRECTORY) { *pobject_type = DT_DIR; /* override default perms since we do not lock dirs */ if(atomic_read(&cifsInfo->inUse) == 0) { tmp_inode->i_mode = cifs_sb->mnt_dir_mode; } tmp_inode->i_mode |= S_IFDIR; +/* we no longer mark these because we could not follow them */ +/* } else if (attr & ATTR_REPARSE) { + *pobject_type = DT_LNK; + tmp_inode->i_mode |= S_IFLNK;*/ } else { *pobject_type = DT_REG; tmp_inode->i_mode |= S_IFREG; - if(pfindData->ExtFileAttributes & ATTR_READONLY) + if(attr & ATTR_READONLY) tmp_inode->i_mode &= ~(S_IWUGO); - }/* 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 */ @@ -1402,14 +1637,14 @@ fill_in_inode(struct inode *tmp_inode, if(is_size_safe_to_change(cifsInfo)) { /* can not safely change the file size here if the client is writing to it due to potential races */ - i_size_write(tmp_inode,pfindData->EndOfFile); + i_size_write(tmp_inode,end_of_file); /* 512 bytes (2**9) is the fake blocksize that must be used */ /* for this calculation, even though the reported blocksize is larger */ - tmp_inode->i_blocks = (512 - 1 + pfindData->AllocationSize) >> 9; + tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9; } - if (pfindData->AllocationSize < pfindData->EndOfFile) + if (allocation_size < end_of_file) cFYI(1, ("Possible sparse file: allocation size less than end of file ")); cFYI(1, ("File Size %ld and blocks %ld and blocksize %ld", @@ -1439,6 +1674,9 @@ unix_fill_in_inode(struct inode *tmp_inode, FILE_UNIX_INFO * pfindData, int *pobject_type) { struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); + __u32 type = le32_to_cpu(pfindData->Type); + __u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes); + __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); cifsInfo->time = jiffies; atomic_inc(&cifsInfo->inUse); @@ -1450,30 +1688,29 @@ unix_fill_in_inode(struct inode *tmp_inode, cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange)); tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions); - pfindData->Type = le32_to_cpu(pfindData->Type); - if (pfindData->Type == UNIX_FILE) { + if (type == UNIX_FILE) { *pobject_type = DT_REG; tmp_inode->i_mode |= S_IFREG; - } else if (pfindData->Type == UNIX_SYMLINK) { + } else if (type == UNIX_SYMLINK) { *pobject_type = DT_LNK; tmp_inode->i_mode |= S_IFLNK; - } else if (pfindData->Type == UNIX_DIR) { + } else if (type == UNIX_DIR) { *pobject_type = DT_DIR; tmp_inode->i_mode |= S_IFDIR; - } else if (pfindData->Type == UNIX_CHARDEV) { + } else if (type == UNIX_CHARDEV) { *pobject_type = DT_CHR; tmp_inode->i_mode |= S_IFCHR; tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), le64_to_cpu(pfindData->DevMinor) & MINORMASK); - } else if (pfindData->Type == UNIX_BLOCKDEV) { + } else if (type == UNIX_BLOCKDEV) { *pobject_type = DT_BLK; tmp_inode->i_mode |= S_IFBLK; tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), le64_to_cpu(pfindData->DevMinor) & MINORMASK); - } else if (pfindData->Type == UNIX_FIFO) { + } else if (type == UNIX_FIFO) { *pobject_type = DT_FIFO; tmp_inode->i_mode |= S_IFIFO; - } else if (pfindData->Type == UNIX_SOCKET) { + } else if (type == UNIX_SOCKET) { *pobject_type = DT_SOCK; tmp_inode->i_mode |= S_IFSOCK; } @@ -1482,17 +1719,15 @@ unix_fill_in_inode(struct inode *tmp_inode, tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); - pfindData->NumOfBytes = le64_to_cpu(pfindData->NumOfBytes); if(is_size_safe_to_change(cifsInfo)) { /* can not safely change the file size here if the client is writing to it due to potential races */ - pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile); - i_size_write(tmp_inode,pfindData->EndOfFile); + i_size_write(tmp_inode,end_of_file); /* 512 bytes (2**9) is the fake blocksize that must be used */ /* for this calculation, not the real blocksize */ - tmp_inode->i_blocks = (512 - 1 + pfindData->NumOfBytes) >> 9; + tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; } if (S_ISREG(tmp_inode->i_mode)) { @@ -1515,13 +1750,16 @@ unix_fill_in_inode(struct inode *tmp_inode, } } -static void +/* 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 construct_dentry(struct qstr *qstring, struct file *file, struct inode **ptmp_inode, struct dentry **pnew_dentry) { struct dentry *tmp_dentry; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; + int rc = 0; cFYI(1, ("For %s ", qstring->name)); cifs_sb = CIFS_SB(file->f_dentry->d_sb); @@ -1536,29 +1774,30 @@ construct_dentry(struct qstr *qstring, struct file *file, if(*ptmp_inode == NULL) { *ptmp_inode = new_inode(file->f_dentry->d_sb); if(*ptmp_inode == NULL) - return; + return rc; + rc = 1; d_instantiate(tmp_dentry, *ptmp_inode); - insert_inode_hash(*ptmp_inode); } } else { tmp_dentry = d_alloc(file->f_dentry, qstring); if(tmp_dentry == NULL) { cERROR(1,("Failed allocating dentry")); *ptmp_inode = NULL; - return; + return rc; } *ptmp_inode = new_inode(file->f_dentry->d_sb); tmp_dentry->d_op = &cifs_dentry_ops; if(*ptmp_inode == NULL) - return; + return rc; + rc = 1; d_instantiate(tmp_dentry, *ptmp_inode); d_rehash(tmp_dentry); - insert_inode_hash(*ptmp_inode); } tmp_dentry->d_time = jiffies; *pnew_dentry = tmp_dentry; + return rc; } static void reset_resume_key(struct file * dir_file, @@ -1606,13 +1845,21 @@ cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData, int object_type,rc; pqstring->name = pfindData->FileName; - pqstring->len = pfindData->FileNameLength; + /* pqstring->len is already set by caller */ - construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); + rc = construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); if((tmp_inode == NULL) || (tmp_dentry == NULL)) { return -ENOMEM; } fill_in_inode(tmp_inode, pfindData, &object_type); + if(rc) { + /* We have no reliable way to get inode numbers + from servers w/o Unix extensions yet so we can not set + i_ino from pfindData yet */ + + /* new inode created, let us hash it */ + insert_inode_hash(tmp_inode); + } /* else if inode number changed do we rehash it? */ rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos, tmp_inode->i_ino, object_type); if(rc) { @@ -1636,11 +1883,19 @@ cifs_filldir_unix(struct qstr *pqstring, pqstring->name = pUnixFindData->FileName; pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF); - construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); + rc = construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); if((tmp_inode == NULL) || (tmp_dentry == NULL)) { return -ENOMEM; - } + } + if(rc) { + struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { + tmp_inode->i_ino = + (unsigned long)pUnixFindData->UniqueId; + } + insert_inode_hash(tmp_inode); + } /* else if i_ino has changed should we rehash it? */ unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type); rc = filldir(direntry, pUnixFindData->FileName, pqstring->len, file->f_pos, tmp_inode->i_ino, object_type); @@ -1674,27 +1929,44 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) FILE_DIRECTORY_INFO *lastFindData; FILE_UNIX_INFO *pfindDataUnix; + + /* BB removeme begin */ + if(!experimEnabled) + return cifs_readdir2(file,direntry,filldir); + /* BB removeme end */ + + xid = GetXid(); + if(file->f_dentry == NULL) { + rc = -EIO; + FreeXid(xid); + return rc; + } cifs_sb = CIFS_SB(file->f_dentry->d_sb); pTcon = cifs_sb->tcon; bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; - if(bufsize > CIFS_MAX_MSGSIZE) { + if(bufsize > CIFSMaxBufSize) { + rc = -EIO; FreeXid(xid); - return -EIO; + return rc; } data = kmalloc(bufsize, GFP_KERNEL); pfindData = (FILE_DIRECTORY_INFO *) data; - - if(file->f_dentry == NULL) { + if(data == NULL) { + rc = -ENOMEM; FreeXid(xid); - return -EIO; + return rc; } down(&file->f_dentry->d_sb->s_vfs_rename_sem); full_path = build_wildcard_path_from_dentry(file->f_dentry); up(&file->f_dentry->d_sb->s_vfs_rename_sem); - + if(full_path == NULL) { + kfree(data); + FreeXid(xid); + return -ENOMEM; + } cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos)); switch ((int) file->f_pos) { @@ -1718,8 +1990,8 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) if (file->private_data != NULL) { cifsFile = (struct cifsFileInfo *) file->private_data; - if (cifsFile->endOfSearch) { - if(cifsFile->emptyDir) { + if (cifsFile->srch_inf.endOfSearch) { + if(cifsFile->srch_inf.emptyDir) { cFYI(1, ("End of search, empty dir")); rc = 0; break; @@ -1736,10 +2008,12 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) rc = CIFSFindFirst(xid, pTcon, full_path, pfindData, &findParms, cifs_sb->local_nls, &Unicode, &UnixSearch); - cFYI(1, ("Count: %d End: %d ", findParms.SearchCount, - findParms.EndofSearch)); + cFYI(1, ("Count: %d End: %d ", + le16_to_cpu(findParms.SearchCount), + le16_to_cpu(findParms.EndofSearch))); if (rc == 0) { + __u16 count = le16_to_cpu(findParms.SearchCount); searchHandle = findParms.SearchHandle; if(file->private_data == NULL) file->private_data = @@ -1760,14 +2034,14 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) renew_parental_timestamps(file->f_dentry); lastFindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + - findParms.LastNameOffset); + le16_to_cpu(findParms.LastNameOffset)); if((char *)lastFindData > (char *)pfindData + bufsize) { cFYI(1,("last search entry past end of packet")); rc = -EIO; 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); @@ -1782,6 +2056,10 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) cFYI(1,("Last file: %s with name %d bytes long", lastFindData->FileName, cifsFile->resume_name_length)); + if(cifsFile->search_resume_name == NULL) { + rc = -ENOMEM; + break; + } memcpy(cifsFile->search_resume_name, lastFindData->FileName, cifsFile->resume_name_length); @@ -1811,27 +2089,29 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) cFYI(1,("Last file: %s with name %d bytes long", pfindDataUnix->FileName, cifsFile->resume_name_length)); + if(cifsFile->search_resume_name == NULL) { + rc = -ENOMEM; + break; + } memcpy(cifsFile->search_resume_name, pfindDataUnix->FileName, cifsFile->resume_name_length); } - for (i = 2; i < (unsigned int)findParms.SearchCount + 2; i++) { + for (i = 2; i < count + 2; i++) { if (UnixSearch == FALSE) { - pfindData->FileNameLength = - le32_to_cpu(pfindData->FileNameLength); + __u32 len = le32_to_cpu(pfindData->FileNameLength); if (Unicode == TRUE) - pfindData->FileNameLength = + len = cifs_strfromUCS_le (pfindData->FileName, (wchar_t *) pfindData->FileName, - (pfindData-> - FileNameLength) / 2, + len / 2, cifs_sb->local_nls); - qstring.len = pfindData->FileNameLength; - if (((qstring.len != 1) + qstring.len = len; + if (((len != 1) || (pfindData->FileName[0] != '.')) - && ((qstring.len != 2) + && ((len != 2) || (pfindData-> FileName[0] != '.') || (pfindData-> @@ -1898,13 +2178,13 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) /* if(pfindData > lastFindData) rc = -EIO; break; */ } /* end for loop */ if ((findParms.EndofSearch != 0) && cifsFile) { - cifsFile->endOfSearch = TRUE; - if(findParms.SearchCount == 2) - cifsFile->emptyDir = TRUE; + cifsFile->srch_inf.endOfSearch = TRUE; + if(findParms.SearchCount == cpu_to_le16(2)) + cifsFile->srch_inf.emptyDir = TRUE; } } else { if (cifsFile) - cifsFile->endOfSearch = TRUE; + cifsFile->srch_inf.endOfSearch = TRUE; /* unless parent directory gone do not return error */ rc = 0; } @@ -1917,7 +2197,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) file->f_pos)); } else { cifsFile = (struct cifsFileInfo *) file->private_data; - if (cifsFile->endOfSearch) { + if (cifsFile->srch_inf.endOfSearch) { rc = 0; cFYI(1, ("End of search ")); break; @@ -1927,23 +2207,24 @@ 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 ", - findNextParms.SearchCount, - findNextParms.EndofSearch)); + le16_to_cpu(findNextParms.SearchCount), + le16_to_cpu(findNextParms.EndofSearch))); if ((rc == 0) && (findNextParms.SearchCount != 0)) { /* BB save off resume key, key name and name length */ + __u16 count = le16_to_cpu(findNextParms.SearchCount); lastFindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData - + findNextParms.LastNameOffset); + + le16_to_cpu(findNextParms.LastNameOffset)); if((char *)lastFindData > (char *)pfindData + bufsize) { cFYI(1,("last search entry past end of packet")); rc = -EIO; 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 = @@ -1964,6 +2245,11 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) cFYI(1,("Last file: %s with name %d bytes long", lastFindData->FileName, cifsFile->resume_name_length)); + if(cifsFile->search_resume_name == NULL) { + rc = -ENOMEM; + break; + } + memcpy(cifsFile->search_resume_name, lastFindData->FileName, cifsFile->resume_name_length); @@ -1999,29 +2285,31 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) cFYI(1,("fnext last file: %s with name %d bytes long", pfindDataUnix->FileName, cifsFile->resume_name_length)); + if(cifsFile->search_resume_name == NULL) { + rc = -ENOMEM; + break; + } memcpy(cifsFile->search_resume_name, pfindDataUnix->FileName, cifsFile->resume_name_length); } - for (i = 0; i < findNextParms.SearchCount; i++) { - pfindData->FileNameLength = - le32_to_cpu(pfindData-> + for (i = 0; i < count; i++) { + __u32 len = le32_to_cpu(pfindData-> FileNameLength); if (UnixSearch == FALSE) { if (Unicode == TRUE) - pfindData->FileNameLength = + len = cifs_strfromUCS_le (pfindData->FileName, (wchar_t *) pfindData->FileName, - (pfindData->FileNameLength)/ 2, + len / 2, cifs_sb->local_nls); - qstring.len = - pfindData->FileNameLength; - if (((qstring.len != 1) + qstring.len = len; + if (((len != 1) || (pfindData->FileName[0] != '.')) - && ((qstring.len != 2) + && ((len != 2) || (pfindData->FileName[0] != '.') || (pfindData->FileName[1] != '.'))) { @@ -2089,10 +2377,10 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) /* BB also should check to ensure pointer not beyond end of SMB */ } /* end for loop */ if (findNextParms.EndofSearch != 0) { - cifsFile->endOfSearch = TRUE; + cifsFile->srch_inf.endOfSearch = TRUE; } } else { - cifsFile->endOfSearch = TRUE; + cifsFile->srch_inf.endOfSearch = TRUE; rc = 0; /* unless parent directory disappeared - do not return error here (eg Access Denied or no more files) */ }