// SPDX-License-Identifier: LGPL-2.1
/*
*
* Directory search handling
*
* Copyright (C) International Business Machines Corp., 2004, 2008
* Copyright (C) Red Hat, Inc., 2011
* Author(s): Steve French (sfrench@us.ibm.com)
*
*/
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
#include "cifsfs.h"
#include "smb2proto.h"
#include "fs_context.h"
#include "cached_dir.h"
/*
* 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.
*/
#define UNICODE_NAME_MAX ((4 * NAME_MAX) + 2)
#ifdef CONFIG_CIFS_DEBUG2
static void dump_cifs_file_struct(struct file *file, char *label)
{
struct cifsFileInfo *cf;
if (file) {
cf = file->private_data;
if (cf == NULL) {
cifs_dbg(FYI, "empty cifs private file data\n");
return;
}
if (cf->invalidHandle)
cifs_dbg(FYI, "Invalid handle\n");
if (cf->srch_inf.endOfSearch)
cifs_dbg(FYI, "end of search\n");
if (cf->srch_inf.emptyDir)
cifs_dbg(FYI, "empty dir\n");
}
}
#else
static inline void dump_cifs_file_struct(struct file *file, char *label)
{
}
#endif /* DEBUG2 */
/*
* Attempt to preload the dcache with the results from the FIND_FIRST/NEXT
*
* Find the dentry that matches "name". If there isn't one, create one. If it's
* a negative dentry or the uniqueid or filetype(mode) changed,
* then drop it and recreate it.
*/
static void
cifs_prime_dcache(struct dentry *parent, struct qstr *name,
struct cifs_fattr *fattr)
{
struct dentry *dentry, *alias;
struct inode *inode;
struct super_block *sb = parent->d_sb;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
cifs_dbg(FYI, "%s: for %s\n", __func__, name->name);
dentry = d_hash_and_lookup(parent, name);
if (!dentry) {
/*
* If we know that the inode will need to be revalidated
* immediately, then don't create a new dentry for it.
* We'll end up doing an on the wire call either way and
* this spares us an invalidation.
*/
if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
return;
retry:
dentry = d_alloc_parallel(parent, name, &wq);
}
if (IS_ERR(dentry))
return;
if (!d_in_lookup(dentry)) {
inode = d_inode(dentry);
if (inode) {
if (d_mountpoint(dentry)) {
dput(dentry);
return;
}
/*
* If we're generating inode numbers, then we don't
* want to clobber the existing one with the one that
* the readdir code created.
*/
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
fattr->cf_uniqueid = CIFS_I(inode)->uniqueid;
/* update inode in place
* if both i_ino and i_mode didn't change */
if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid &&
cifs_fattr_to_inode(inode, fattr) == 0) {
dput(dentry);
return;
}
}
d_invalidate(dentry);
dput(dentry);
goto retry;
} else {
inode = cifs_iget(sb, fattr);
if (!inode)
inode = ERR_PTR(-ENOMEM);
alias = d_splice_alias(