162306a36Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * vfs operations that deal with dentries 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) International Business Machines Corp., 2002,2009 762306a36Sopenharmony_ci * Author(s): Steve French (sfrench@us.ibm.com) 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/fs.h> 1162306a36Sopenharmony_ci#include <linux/stat.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/namei.h> 1462306a36Sopenharmony_ci#include <linux/mount.h> 1562306a36Sopenharmony_ci#include <linux/file.h> 1662306a36Sopenharmony_ci#include "cifsfs.h" 1762306a36Sopenharmony_ci#include "cifspdu.h" 1862306a36Sopenharmony_ci#include "cifsglob.h" 1962306a36Sopenharmony_ci#include "cifsproto.h" 2062306a36Sopenharmony_ci#include "cifs_debug.h" 2162306a36Sopenharmony_ci#include "cifs_fs_sb.h" 2262306a36Sopenharmony_ci#include "cifs_unicode.h" 2362306a36Sopenharmony_ci#include "fs_context.h" 2462306a36Sopenharmony_ci#include "cifs_ioctl.h" 2562306a36Sopenharmony_ci#include "fscache.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic void 2862306a36Sopenharmony_cirenew_parental_timestamps(struct dentry *direntry) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci /* BB check if there is a way to get the kernel to do this or if we 3162306a36Sopenharmony_ci really need this */ 3262306a36Sopenharmony_ci do { 3362306a36Sopenharmony_ci cifs_set_time(direntry, jiffies); 3462306a36Sopenharmony_ci direntry = direntry->d_parent; 3562306a36Sopenharmony_ci } while (!IS_ROOT(direntry)); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cichar * 3962306a36Sopenharmony_cicifs_build_path_to_root(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb, 4062306a36Sopenharmony_ci struct cifs_tcon *tcon, int add_treename) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci int pplen = ctx->prepath ? strlen(ctx->prepath) + 1 : 0; 4362306a36Sopenharmony_ci int dfsplen; 4462306a36Sopenharmony_ci char *full_path = NULL; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci /* if no prefix path, simply set path to the root of share to "" */ 4762306a36Sopenharmony_ci if (pplen == 0) { 4862306a36Sopenharmony_ci full_path = kzalloc(1, GFP_KERNEL); 4962306a36Sopenharmony_ci return full_path; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (add_treename) 5362306a36Sopenharmony_ci dfsplen = strnlen(tcon->tree_name, MAX_TREE_SIZE + 1); 5462306a36Sopenharmony_ci else 5562306a36Sopenharmony_ci dfsplen = 0; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL); 5862306a36Sopenharmony_ci if (full_path == NULL) 5962306a36Sopenharmony_ci return full_path; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (dfsplen) 6262306a36Sopenharmony_ci memcpy(full_path, tcon->tree_name, dfsplen); 6362306a36Sopenharmony_ci full_path[dfsplen] = CIFS_DIR_SEP(cifs_sb); 6462306a36Sopenharmony_ci memcpy(full_path + dfsplen + 1, ctx->prepath, pplen); 6562306a36Sopenharmony_ci convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb)); 6662306a36Sopenharmony_ci return full_path; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* Note: caller must free return buffer */ 7062306a36Sopenharmony_ciconst char * 7162306a36Sopenharmony_cibuild_path_from_dentry(struct dentry *direntry, void *page) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); 7462306a36Sopenharmony_ci struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 7562306a36Sopenharmony_ci bool prefix = tcon->Flags & SMB_SHARE_IS_IN_DFS; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return build_path_from_dentry_optional_prefix(direntry, page, 7862306a36Sopenharmony_ci prefix); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cichar *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page, 8262306a36Sopenharmony_ci const char *tree, int tree_len, 8362306a36Sopenharmony_ci bool prefix) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci int dfsplen; 8662306a36Sopenharmony_ci int pplen = 0; 8762306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); 8862306a36Sopenharmony_ci char dirsep = CIFS_DIR_SEP(cifs_sb); 8962306a36Sopenharmony_ci char *s; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (unlikely(!page)) 9262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (prefix) 9562306a36Sopenharmony_ci dfsplen = strnlen(tree, tree_len + 1); 9662306a36Sopenharmony_ci else 9762306a36Sopenharmony_ci dfsplen = 0; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) 10062306a36Sopenharmony_ci pplen = cifs_sb->prepath ? strlen(cifs_sb->prepath) + 1 : 0; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci s = dentry_path_raw(direntry, page, PATH_MAX); 10362306a36Sopenharmony_ci if (IS_ERR(s)) 10462306a36Sopenharmony_ci return s; 10562306a36Sopenharmony_ci if (!s[1]) // for root we want "", not "/" 10662306a36Sopenharmony_ci s++; 10762306a36Sopenharmony_ci if (s < (char *)page + pplen + dfsplen) 10862306a36Sopenharmony_ci return ERR_PTR(-ENAMETOOLONG); 10962306a36Sopenharmony_ci if (pplen) { 11062306a36Sopenharmony_ci cifs_dbg(FYI, "using cifs_sb prepath <%s>\n", cifs_sb->prepath); 11162306a36Sopenharmony_ci s -= pplen; 11262306a36Sopenharmony_ci memcpy(s + 1, cifs_sb->prepath, pplen - 1); 11362306a36Sopenharmony_ci *s = '/'; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci if (dirsep != '/') { 11662306a36Sopenharmony_ci /* BB test paths to Windows with '/' in the midst of prepath */ 11762306a36Sopenharmony_ci char *p; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci for (p = s; *p; p++) 12062306a36Sopenharmony_ci if (*p == '/') 12162306a36Sopenharmony_ci *p = dirsep; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci if (dfsplen) { 12462306a36Sopenharmony_ci s -= dfsplen; 12562306a36Sopenharmony_ci memcpy(s, tree, dfsplen); 12662306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { 12762306a36Sopenharmony_ci int i; 12862306a36Sopenharmony_ci for (i = 0; i < dfsplen; i++) { 12962306a36Sopenharmony_ci if (s[i] == '\\') 13062306a36Sopenharmony_ci s[i] = '/'; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci return s; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cichar *build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page, 13862306a36Sopenharmony_ci bool prefix) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); 14162306a36Sopenharmony_ci struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return __build_path_from_dentry_optional_prefix(direntry, page, tcon->tree_name, 14462306a36Sopenharmony_ci MAX_TREE_SIZE, prefix); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/* 14862306a36Sopenharmony_ci * Don't allow path components longer than the server max. 14962306a36Sopenharmony_ci * Don't allow the separator character in a path component. 15062306a36Sopenharmony_ci * The VFS will not allow "/", but "\" is allowed by posix. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_cistatic int 15362306a36Sopenharmony_cicheck_name(struct dentry *direntry, struct cifs_tcon *tcon) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); 15662306a36Sopenharmony_ci int i; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (unlikely(tcon->fsAttrInfo.MaxPathNameComponentLength && 15962306a36Sopenharmony_ci direntry->d_name.len > 16062306a36Sopenharmony_ci le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength))) 16162306a36Sopenharmony_ci return -ENAMETOOLONG; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) { 16462306a36Sopenharmony_ci for (i = 0; i < direntry->d_name.len; i++) { 16562306a36Sopenharmony_ci if (direntry->d_name.name[i] == '\\') { 16662306a36Sopenharmony_ci cifs_dbg(FYI, "Invalid file name\n"); 16762306a36Sopenharmony_ci return -EINVAL; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci return 0; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/* Inode operations in similar order to how they appear in Linux file fs.h */ 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, 17862306a36Sopenharmony_ci struct tcon_link *tlink, unsigned int oflags, umode_t mode, __u32 *oplock, 17962306a36Sopenharmony_ci struct cifs_fid *fid, struct cifs_open_info_data *buf) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci int rc = -ENOENT; 18262306a36Sopenharmony_ci int create_options = CREATE_NOT_DIR; 18362306a36Sopenharmony_ci int desired_access; 18462306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 18562306a36Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(tlink); 18662306a36Sopenharmony_ci const char *full_path; 18762306a36Sopenharmony_ci void *page = alloc_dentry_path(); 18862306a36Sopenharmony_ci struct inode *newinode = NULL; 18962306a36Sopenharmony_ci int disposition; 19062306a36Sopenharmony_ci struct TCP_Server_Info *server = tcon->ses->server; 19162306a36Sopenharmony_ci struct cifs_open_parms oparms; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci *oplock = 0; 19462306a36Sopenharmony_ci if (tcon->ses->server->oplocks) 19562306a36Sopenharmony_ci *oplock = REQ_OPLOCK; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci full_path = build_path_from_dentry(direntry, page); 19862306a36Sopenharmony_ci if (IS_ERR(full_path)) { 19962306a36Sopenharmony_ci free_dentry_path(page); 20062306a36Sopenharmony_ci return PTR_ERR(full_path); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 20462306a36Sopenharmony_ci if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open && 20562306a36Sopenharmony_ci (CIFS_UNIX_POSIX_PATH_OPS_CAP & 20662306a36Sopenharmony_ci le64_to_cpu(tcon->fsUnixInfo.Capability))) { 20762306a36Sopenharmony_ci rc = cifs_posix_open(full_path, &newinode, inode->i_sb, mode, 20862306a36Sopenharmony_ci oflags, oplock, &fid->netfid, xid); 20962306a36Sopenharmony_ci switch (rc) { 21062306a36Sopenharmony_ci case 0: 21162306a36Sopenharmony_ci if (newinode == NULL) { 21262306a36Sopenharmony_ci /* query inode info */ 21362306a36Sopenharmony_ci goto cifs_create_get_file_info; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (S_ISDIR(newinode->i_mode)) { 21762306a36Sopenharmony_ci CIFSSMBClose(xid, tcon, fid->netfid); 21862306a36Sopenharmony_ci iput(newinode); 21962306a36Sopenharmony_ci rc = -EISDIR; 22062306a36Sopenharmony_ci goto out; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (!S_ISREG(newinode->i_mode)) { 22462306a36Sopenharmony_ci /* 22562306a36Sopenharmony_ci * The server may allow us to open things like 22662306a36Sopenharmony_ci * FIFOs, but the client isn't set up to deal 22762306a36Sopenharmony_ci * with that. If it's not a regular file, just 22862306a36Sopenharmony_ci * close it and proceed as if it were a normal 22962306a36Sopenharmony_ci * lookup. 23062306a36Sopenharmony_ci */ 23162306a36Sopenharmony_ci CIFSSMBClose(xid, tcon, fid->netfid); 23262306a36Sopenharmony_ci goto cifs_create_get_file_info; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci /* success, no need to query */ 23562306a36Sopenharmony_ci goto cifs_create_set_dentry; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci case -ENOENT: 23862306a36Sopenharmony_ci goto cifs_create_get_file_info; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci case -EIO: 24162306a36Sopenharmony_ci case -EINVAL: 24262306a36Sopenharmony_ci /* 24362306a36Sopenharmony_ci * EIO could indicate that (posix open) operation is not 24462306a36Sopenharmony_ci * supported, despite what server claimed in capability 24562306a36Sopenharmony_ci * negotiation. 24662306a36Sopenharmony_ci * 24762306a36Sopenharmony_ci * POSIX open in samba versions 3.3.1 and earlier could 24862306a36Sopenharmony_ci * incorrectly fail with invalid parameter. 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ci tcon->broken_posix_open = true; 25162306a36Sopenharmony_ci break; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci case -EREMOTE: 25462306a36Sopenharmony_ci case -EOPNOTSUPP: 25562306a36Sopenharmony_ci /* 25662306a36Sopenharmony_ci * EREMOTE indicates DFS junction, which is not handled 25762306a36Sopenharmony_ci * in posix open. If either that or op not supported 25862306a36Sopenharmony_ci * returned, follow the normal lookup. 25962306a36Sopenharmony_ci */ 26062306a36Sopenharmony_ci break; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci default: 26362306a36Sopenharmony_ci goto out; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci /* 26662306a36Sopenharmony_ci * fallthrough to retry, using older open call, this is case 26762306a36Sopenharmony_ci * where server does not support this SMB level, and falsely 26862306a36Sopenharmony_ci * claims capability (also get here for DFS case which should be 26962306a36Sopenharmony_ci * rare for path not covered on files) 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci desired_access = 0; 27562306a36Sopenharmony_ci if (OPEN_FMODE(oflags) & FMODE_READ) 27662306a36Sopenharmony_ci desired_access |= GENERIC_READ; /* is this too little? */ 27762306a36Sopenharmony_ci if (OPEN_FMODE(oflags) & FMODE_WRITE) 27862306a36Sopenharmony_ci desired_access |= GENERIC_WRITE; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci disposition = FILE_OVERWRITE_IF; 28162306a36Sopenharmony_ci if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) 28262306a36Sopenharmony_ci disposition = FILE_CREATE; 28362306a36Sopenharmony_ci else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) 28462306a36Sopenharmony_ci disposition = FILE_OVERWRITE_IF; 28562306a36Sopenharmony_ci else if ((oflags & O_CREAT) == O_CREAT) 28662306a36Sopenharmony_ci disposition = FILE_OPEN_IF; 28762306a36Sopenharmony_ci else 28862306a36Sopenharmony_ci cifs_dbg(FYI, "Create flag not set in create function\n"); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* 29162306a36Sopenharmony_ci * BB add processing to set equivalent of mode - e.g. via CreateX with 29262306a36Sopenharmony_ci * ACLs 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (!server->ops->open) { 29662306a36Sopenharmony_ci rc = -ENOSYS; 29762306a36Sopenharmony_ci goto out; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* 30162306a36Sopenharmony_ci * if we're not using unix extensions, see if we need to set 30262306a36Sopenharmony_ci * ATTR_READONLY on the create call 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_ci if (!tcon->unix_ext && (mode & S_IWUGO) == 0) 30562306a36Sopenharmony_ci create_options |= CREATE_OPTION_READONLY; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci oparms = (struct cifs_open_parms) { 30862306a36Sopenharmony_ci .tcon = tcon, 30962306a36Sopenharmony_ci .cifs_sb = cifs_sb, 31062306a36Sopenharmony_ci .desired_access = desired_access, 31162306a36Sopenharmony_ci .create_options = cifs_create_options(cifs_sb, create_options), 31262306a36Sopenharmony_ci .disposition = disposition, 31362306a36Sopenharmony_ci .path = full_path, 31462306a36Sopenharmony_ci .fid = fid, 31562306a36Sopenharmony_ci .mode = mode, 31662306a36Sopenharmony_ci }; 31762306a36Sopenharmony_ci rc = server->ops->open(xid, &oparms, oplock, buf); 31862306a36Sopenharmony_ci if (rc) { 31962306a36Sopenharmony_ci cifs_dbg(FYI, "cifs_create returned 0x%x\n", rc); 32062306a36Sopenharmony_ci goto out; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 32462306a36Sopenharmony_ci /* 32562306a36Sopenharmony_ci * If Open reported that we actually created a file then we now have to 32662306a36Sopenharmony_ci * set the mode if possible. 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_ci if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) { 32962306a36Sopenharmony_ci struct cifs_unix_set_info_args args = { 33062306a36Sopenharmony_ci .mode = mode, 33162306a36Sopenharmony_ci .ctime = NO_CHANGE_64, 33262306a36Sopenharmony_ci .atime = NO_CHANGE_64, 33362306a36Sopenharmony_ci .mtime = NO_CHANGE_64, 33462306a36Sopenharmony_ci .device = 0, 33562306a36Sopenharmony_ci }; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 33862306a36Sopenharmony_ci args.uid = current_fsuid(); 33962306a36Sopenharmony_ci if (inode->i_mode & S_ISGID) 34062306a36Sopenharmony_ci args.gid = inode->i_gid; 34162306a36Sopenharmony_ci else 34262306a36Sopenharmony_ci args.gid = current_fsgid(); 34362306a36Sopenharmony_ci } else { 34462306a36Sopenharmony_ci args.uid = INVALID_UID; /* no change */ 34562306a36Sopenharmony_ci args.gid = INVALID_GID; /* no change */ 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid->netfid, 34862306a36Sopenharmony_ci current->tgid); 34962306a36Sopenharmony_ci } else { 35062306a36Sopenharmony_ci /* 35162306a36Sopenharmony_ci * BB implement mode setting via Windows security 35262306a36Sopenharmony_ci * descriptors e.g. 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_ci /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/ 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* Could set r/o dos attribute if mode & 0222 == 0 */ 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cicifs_create_get_file_info: 36062306a36Sopenharmony_ci /* server might mask mode so we have to query for it */ 36162306a36Sopenharmony_ci if (tcon->unix_ext) 36262306a36Sopenharmony_ci rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, 36362306a36Sopenharmony_ci xid); 36462306a36Sopenharmony_ci else { 36562306a36Sopenharmony_ci#else 36662306a36Sopenharmony_ci { 36762306a36Sopenharmony_ci#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 36862306a36Sopenharmony_ci /* TODO: Add support for calling POSIX query info here, but passing in fid */ 36962306a36Sopenharmony_ci rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb, xid, fid); 37062306a36Sopenharmony_ci if (newinode) { 37162306a36Sopenharmony_ci if (server->ops->set_lease_key) 37262306a36Sopenharmony_ci server->ops->set_lease_key(newinode, fid); 37362306a36Sopenharmony_ci if ((*oplock & CIFS_CREATE_ACTION) && S_ISREG(newinode->i_mode)) { 37462306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) 37562306a36Sopenharmony_ci newinode->i_mode = mode; 37662306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 37762306a36Sopenharmony_ci newinode->i_uid = current_fsuid(); 37862306a36Sopenharmony_ci if (inode->i_mode & S_ISGID) 37962306a36Sopenharmony_ci newinode->i_gid = inode->i_gid; 38062306a36Sopenharmony_ci else 38162306a36Sopenharmony_ci newinode->i_gid = current_fsgid(); 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 38862306a36Sopenharmony_cicifs_create_set_dentry: 38962306a36Sopenharmony_ci#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 39062306a36Sopenharmony_ci if (rc != 0) { 39162306a36Sopenharmony_ci cifs_dbg(FYI, "Create worked, get_inode_info failed rc = %d\n", 39262306a36Sopenharmony_ci rc); 39362306a36Sopenharmony_ci goto out_err; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (newinode) 39762306a36Sopenharmony_ci if (S_ISDIR(newinode->i_mode)) { 39862306a36Sopenharmony_ci rc = -EISDIR; 39962306a36Sopenharmony_ci goto out_err; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci d_drop(direntry); 40362306a36Sopenharmony_ci d_add(direntry, newinode); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ciout: 40662306a36Sopenharmony_ci free_dentry_path(page); 40762306a36Sopenharmony_ci return rc; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ciout_err: 41062306a36Sopenharmony_ci if (server->ops->close) 41162306a36Sopenharmony_ci server->ops->close(xid, tcon, fid); 41262306a36Sopenharmony_ci if (newinode) 41362306a36Sopenharmony_ci iput(newinode); 41462306a36Sopenharmony_ci goto out; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ciint 41862306a36Sopenharmony_cicifs_atomic_open(struct inode *inode, struct dentry *direntry, 41962306a36Sopenharmony_ci struct file *file, unsigned oflags, umode_t mode) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci int rc; 42262306a36Sopenharmony_ci unsigned int xid; 42362306a36Sopenharmony_ci struct tcon_link *tlink; 42462306a36Sopenharmony_ci struct cifs_tcon *tcon; 42562306a36Sopenharmony_ci struct TCP_Server_Info *server; 42662306a36Sopenharmony_ci struct cifs_fid fid = {}; 42762306a36Sopenharmony_ci struct cifs_pending_open open; 42862306a36Sopenharmony_ci __u32 oplock; 42962306a36Sopenharmony_ci struct cifsFileInfo *file_info; 43062306a36Sopenharmony_ci struct cifs_open_info_data buf = {}; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb)))) 43362306a36Sopenharmony_ci return -EIO; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* 43662306a36Sopenharmony_ci * Posix open is only called (at lookup time) for file create now. For 43762306a36Sopenharmony_ci * opens (rather than creates), because we do not know if it is a file 43862306a36Sopenharmony_ci * or directory yet, and current Samba no longer allows us to do posix 43962306a36Sopenharmony_ci * open on dirs, we could end up wasting an open call on what turns out 44062306a36Sopenharmony_ci * to be a dir. For file opens, we wait to call posix open till 44162306a36Sopenharmony_ci * cifs_open. It could be added to atomic_open in the future but the 44262306a36Sopenharmony_ci * performance tradeoff of the extra network request when EISDIR or 44362306a36Sopenharmony_ci * EACCES is returned would have to be weighed against the 50% reduction 44462306a36Sopenharmony_ci * in network traffic in the other paths. 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_ci if (!(oflags & O_CREAT)) { 44762306a36Sopenharmony_ci struct dentry *res; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* 45062306a36Sopenharmony_ci * Check for hashed negative dentry. We have already revalidated 45162306a36Sopenharmony_ci * the dentry and it is fine. No need to perform another lookup. 45262306a36Sopenharmony_ci */ 45362306a36Sopenharmony_ci if (!d_in_lookup(direntry)) 45462306a36Sopenharmony_ci return -ENOENT; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci res = cifs_lookup(inode, direntry, 0); 45762306a36Sopenharmony_ci if (IS_ERR(res)) 45862306a36Sopenharmony_ci return PTR_ERR(res); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci return finish_no_open(file, res); 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci xid = get_xid(); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n", 46662306a36Sopenharmony_ci inode, direntry, direntry); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb)); 46962306a36Sopenharmony_ci if (IS_ERR(tlink)) { 47062306a36Sopenharmony_ci rc = PTR_ERR(tlink); 47162306a36Sopenharmony_ci goto out_free_xid; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci tcon = tlink_tcon(tlink); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci rc = check_name(direntry, tcon); 47762306a36Sopenharmony_ci if (rc) 47862306a36Sopenharmony_ci goto out; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci server = tcon->ses->server; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (server->ops->new_lease_key) 48362306a36Sopenharmony_ci server->ops->new_lease_key(&fid); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci cifs_add_pending_open(&fid, tlink, &open); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, 48862306a36Sopenharmony_ci &oplock, &fid, &buf); 48962306a36Sopenharmony_ci if (rc) { 49062306a36Sopenharmony_ci cifs_del_pending_open(&open); 49162306a36Sopenharmony_ci goto out; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) 49562306a36Sopenharmony_ci file->f_mode |= FMODE_CREATED; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci rc = finish_open(file, direntry, generic_file_open); 49862306a36Sopenharmony_ci if (rc) { 49962306a36Sopenharmony_ci if (server->ops->close) 50062306a36Sopenharmony_ci server->ops->close(xid, tcon, &fid); 50162306a36Sopenharmony_ci cifs_del_pending_open(&open); 50262306a36Sopenharmony_ci goto out; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (file->f_flags & O_DIRECT && 50662306a36Sopenharmony_ci CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) { 50762306a36Sopenharmony_ci if (CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) 50862306a36Sopenharmony_ci file->f_op = &cifs_file_direct_nobrl_ops; 50962306a36Sopenharmony_ci else 51062306a36Sopenharmony_ci file->f_op = &cifs_file_direct_ops; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci file_info = cifs_new_fileinfo(&fid, file, tlink, oplock, buf.symlink_target); 51462306a36Sopenharmony_ci if (file_info == NULL) { 51562306a36Sopenharmony_ci if (server->ops->close) 51662306a36Sopenharmony_ci server->ops->close(xid, tcon, &fid); 51762306a36Sopenharmony_ci cifs_del_pending_open(&open); 51862306a36Sopenharmony_ci rc = -ENOMEM; 51962306a36Sopenharmony_ci goto out; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci fscache_use_cookie(cifs_inode_cookie(file_inode(file)), 52362306a36Sopenharmony_ci file->f_mode & FMODE_WRITE); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ciout: 52662306a36Sopenharmony_ci cifs_put_tlink(tlink); 52762306a36Sopenharmony_ciout_free_xid: 52862306a36Sopenharmony_ci free_xid(xid); 52962306a36Sopenharmony_ci cifs_free_open_info(&buf); 53062306a36Sopenharmony_ci return rc; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ciint cifs_create(struct mnt_idmap *idmap, struct inode *inode, 53462306a36Sopenharmony_ci struct dentry *direntry, umode_t mode, bool excl) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci int rc; 53762306a36Sopenharmony_ci unsigned int xid = get_xid(); 53862306a36Sopenharmony_ci /* 53962306a36Sopenharmony_ci * BB below access is probably too much for mknod to request 54062306a36Sopenharmony_ci * but we have to do query and setpathinfo so requesting 54162306a36Sopenharmony_ci * less could fail (unless we want to request getatr and setatr 54262306a36Sopenharmony_ci * permissions (only). At least for POSIX we do not have to 54362306a36Sopenharmony_ci * request so much. 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_ci unsigned oflags = O_EXCL | O_CREAT | O_RDWR; 54662306a36Sopenharmony_ci struct tcon_link *tlink; 54762306a36Sopenharmony_ci struct cifs_tcon *tcon; 54862306a36Sopenharmony_ci struct TCP_Server_Info *server; 54962306a36Sopenharmony_ci struct cifs_fid fid; 55062306a36Sopenharmony_ci __u32 oplock; 55162306a36Sopenharmony_ci struct cifs_open_info_data buf = {}; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %pd and dentry = 0x%p\n", 55462306a36Sopenharmony_ci inode, direntry, direntry); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb)))) { 55762306a36Sopenharmony_ci rc = -EIO; 55862306a36Sopenharmony_ci goto out_free_xid; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb)); 56262306a36Sopenharmony_ci rc = PTR_ERR(tlink); 56362306a36Sopenharmony_ci if (IS_ERR(tlink)) 56462306a36Sopenharmony_ci goto out_free_xid; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci tcon = tlink_tcon(tlink); 56762306a36Sopenharmony_ci server = tcon->ses->server; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (server->ops->new_lease_key) 57062306a36Sopenharmony_ci server->ops->new_lease_key(&fid); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, &oplock, &fid, &buf); 57362306a36Sopenharmony_ci if (!rc && server->ops->close) 57462306a36Sopenharmony_ci server->ops->close(xid, tcon, &fid); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci cifs_free_open_info(&buf); 57762306a36Sopenharmony_ci cifs_put_tlink(tlink); 57862306a36Sopenharmony_ciout_free_xid: 57962306a36Sopenharmony_ci free_xid(xid); 58062306a36Sopenharmony_ci return rc; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ciint cifs_mknod(struct mnt_idmap *idmap, struct inode *inode, 58462306a36Sopenharmony_ci struct dentry *direntry, umode_t mode, dev_t device_number) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci int rc = -EPERM; 58762306a36Sopenharmony_ci unsigned int xid; 58862306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb; 58962306a36Sopenharmony_ci struct tcon_link *tlink; 59062306a36Sopenharmony_ci struct cifs_tcon *tcon; 59162306a36Sopenharmony_ci const char *full_path; 59262306a36Sopenharmony_ci void *page; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (!old_valid_dev(device_number)) 59562306a36Sopenharmony_ci return -EINVAL; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci cifs_sb = CIFS_SB(inode->i_sb); 59862306a36Sopenharmony_ci if (unlikely(cifs_forced_shutdown(cifs_sb))) 59962306a36Sopenharmony_ci return -EIO; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci tlink = cifs_sb_tlink(cifs_sb); 60262306a36Sopenharmony_ci if (IS_ERR(tlink)) 60362306a36Sopenharmony_ci return PTR_ERR(tlink); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci page = alloc_dentry_path(); 60662306a36Sopenharmony_ci tcon = tlink_tcon(tlink); 60762306a36Sopenharmony_ci xid = get_xid(); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci full_path = build_path_from_dentry(direntry, page); 61062306a36Sopenharmony_ci if (IS_ERR(full_path)) { 61162306a36Sopenharmony_ci rc = PTR_ERR(full_path); 61262306a36Sopenharmony_ci goto mknod_out; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci rc = tcon->ses->server->ops->make_node(xid, inode, direntry, tcon, 61662306a36Sopenharmony_ci full_path, mode, 61762306a36Sopenharmony_ci device_number); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cimknod_out: 62062306a36Sopenharmony_ci free_dentry_path(page); 62162306a36Sopenharmony_ci free_xid(xid); 62262306a36Sopenharmony_ci cifs_put_tlink(tlink); 62362306a36Sopenharmony_ci return rc; 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistruct dentry * 62762306a36Sopenharmony_cicifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, 62862306a36Sopenharmony_ci unsigned int flags) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci unsigned int xid; 63162306a36Sopenharmony_ci int rc = 0; /* to get around spurious gcc warning, set to zero here */ 63262306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb; 63362306a36Sopenharmony_ci struct tcon_link *tlink; 63462306a36Sopenharmony_ci struct cifs_tcon *pTcon; 63562306a36Sopenharmony_ci struct inode *newInode = NULL; 63662306a36Sopenharmony_ci const char *full_path; 63762306a36Sopenharmony_ci void *page; 63862306a36Sopenharmony_ci int retry_count = 0; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci xid = get_xid(); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n", 64362306a36Sopenharmony_ci parent_dir_inode, direntry, direntry); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci /* check whether path exists */ 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci cifs_sb = CIFS_SB(parent_dir_inode->i_sb); 64862306a36Sopenharmony_ci tlink = cifs_sb_tlink(cifs_sb); 64962306a36Sopenharmony_ci if (IS_ERR(tlink)) { 65062306a36Sopenharmony_ci free_xid(xid); 65162306a36Sopenharmony_ci return ERR_CAST(tlink); 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci pTcon = tlink_tcon(tlink); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci rc = check_name(direntry, pTcon); 65662306a36Sopenharmony_ci if (unlikely(rc)) { 65762306a36Sopenharmony_ci cifs_put_tlink(tlink); 65862306a36Sopenharmony_ci free_xid(xid); 65962306a36Sopenharmony_ci return ERR_PTR(rc); 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* can not grab the rename sem here since it would 66362306a36Sopenharmony_ci deadlock in the cases (beginning of sys_rename itself) 66462306a36Sopenharmony_ci in which we already have the sb rename sem */ 66562306a36Sopenharmony_ci page = alloc_dentry_path(); 66662306a36Sopenharmony_ci full_path = build_path_from_dentry(direntry, page); 66762306a36Sopenharmony_ci if (IS_ERR(full_path)) { 66862306a36Sopenharmony_ci cifs_put_tlink(tlink); 66962306a36Sopenharmony_ci free_xid(xid); 67062306a36Sopenharmony_ci free_dentry_path(page); 67162306a36Sopenharmony_ci return ERR_CAST(full_path); 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (d_really_is_positive(direntry)) { 67562306a36Sopenharmony_ci cifs_dbg(FYI, "non-NULL inode in lookup\n"); 67662306a36Sopenharmony_ci } else { 67762306a36Sopenharmony_ci cifs_dbg(FYI, "NULL inode in lookup\n"); 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", 68062306a36Sopenharmony_ci full_path, d_inode(direntry)); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ciagain: 68362306a36Sopenharmony_ci if (pTcon->posix_extensions) 68462306a36Sopenharmony_ci rc = smb311_posix_get_inode_info(&newInode, full_path, parent_dir_inode->i_sb, xid); 68562306a36Sopenharmony_ci else if (pTcon->unix_ext) { 68662306a36Sopenharmony_ci rc = cifs_get_inode_info_unix(&newInode, full_path, 68762306a36Sopenharmony_ci parent_dir_inode->i_sb, xid); 68862306a36Sopenharmony_ci } else { 68962306a36Sopenharmony_ci rc = cifs_get_inode_info(&newInode, full_path, NULL, 69062306a36Sopenharmony_ci parent_dir_inode->i_sb, xid, NULL); 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if (rc == 0) { 69462306a36Sopenharmony_ci /* since paths are not looked up by component - the parent 69562306a36Sopenharmony_ci directories are presumed to be good here */ 69662306a36Sopenharmony_ci renew_parental_timestamps(direntry); 69762306a36Sopenharmony_ci } else if (rc == -EAGAIN && retry_count++ < 10) { 69862306a36Sopenharmony_ci goto again; 69962306a36Sopenharmony_ci } else if (rc == -ENOENT) { 70062306a36Sopenharmony_ci cifs_set_time(direntry, jiffies); 70162306a36Sopenharmony_ci newInode = NULL; 70262306a36Sopenharmony_ci } else { 70362306a36Sopenharmony_ci if (rc != -EACCES) { 70462306a36Sopenharmony_ci cifs_dbg(FYI, "Unexpected lookup error %d\n", rc); 70562306a36Sopenharmony_ci /* We special case check for Access Denied - since that 70662306a36Sopenharmony_ci is a common return code */ 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci newInode = ERR_PTR(rc); 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci free_dentry_path(page); 71162306a36Sopenharmony_ci cifs_put_tlink(tlink); 71262306a36Sopenharmony_ci free_xid(xid); 71362306a36Sopenharmony_ci return d_splice_alias(newInode, direntry); 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic int 71762306a36Sopenharmony_cicifs_d_revalidate(struct dentry *direntry, unsigned int flags) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci struct inode *inode; 72062306a36Sopenharmony_ci int rc; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (flags & LOOKUP_RCU) 72362306a36Sopenharmony_ci return -ECHILD; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (d_really_is_positive(direntry)) { 72662306a36Sopenharmony_ci inode = d_inode(direntry); 72762306a36Sopenharmony_ci if ((flags & LOOKUP_REVAL) && !CIFS_CACHE_READ(CIFS_I(inode))) 72862306a36Sopenharmony_ci CIFS_I(inode)->time = 0; /* force reval */ 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci rc = cifs_revalidate_dentry(direntry); 73162306a36Sopenharmony_ci if (rc) { 73262306a36Sopenharmony_ci cifs_dbg(FYI, "cifs_revalidate_dentry failed with rc=%d", rc); 73362306a36Sopenharmony_ci switch (rc) { 73462306a36Sopenharmony_ci case -ENOENT: 73562306a36Sopenharmony_ci case -ESTALE: 73662306a36Sopenharmony_ci /* 73762306a36Sopenharmony_ci * Those errors mean the dentry is invalid 73862306a36Sopenharmony_ci * (file was deleted or recreated) 73962306a36Sopenharmony_ci */ 74062306a36Sopenharmony_ci return 0; 74162306a36Sopenharmony_ci default: 74262306a36Sopenharmony_ci /* 74362306a36Sopenharmony_ci * Otherwise some unexpected error happened 74462306a36Sopenharmony_ci * report it as-is to VFS layer 74562306a36Sopenharmony_ci */ 74662306a36Sopenharmony_ci return rc; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci else { 75062306a36Sopenharmony_ci /* 75162306a36Sopenharmony_ci * If the inode wasn't known to be a dfs entry when 75262306a36Sopenharmony_ci * the dentry was instantiated, such as when created 75362306a36Sopenharmony_ci * via ->readdir(), it needs to be set now since the 75462306a36Sopenharmony_ci * attributes will have been updated by 75562306a36Sopenharmony_ci * cifs_revalidate_dentry(). 75662306a36Sopenharmony_ci */ 75762306a36Sopenharmony_ci if (IS_AUTOMOUNT(inode) && 75862306a36Sopenharmony_ci !(direntry->d_flags & DCACHE_NEED_AUTOMOUNT)) { 75962306a36Sopenharmony_ci spin_lock(&direntry->d_lock); 76062306a36Sopenharmony_ci direntry->d_flags |= DCACHE_NEED_AUTOMOUNT; 76162306a36Sopenharmony_ci spin_unlock(&direntry->d_lock); 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci return 1; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci /* 76962306a36Sopenharmony_ci * This may be nfsd (or something), anyway, we can't see the 77062306a36Sopenharmony_ci * intent of this. So, since this can be for creation, drop it. 77162306a36Sopenharmony_ci */ 77262306a36Sopenharmony_ci if (!flags) 77362306a36Sopenharmony_ci return 0; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci /* 77662306a36Sopenharmony_ci * Drop the negative dentry, in order to make sure to use the 77762306a36Sopenharmony_ci * case sensitive name which is specified by user if this is 77862306a36Sopenharmony_ci * for creation. 77962306a36Sopenharmony_ci */ 78062306a36Sopenharmony_ci if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) 78162306a36Sopenharmony_ci return 0; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci if (time_after(jiffies, cifs_get_time(direntry) + HZ) || !lookupCacheEnabled) 78462306a36Sopenharmony_ci return 0; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci return 1; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci/* static int cifs_d_delete(struct dentry *direntry) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci int rc = 0; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci cifs_dbg(FYI, "In cifs d_delete, name = %pd\n", direntry); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci return rc; 79662306a36Sopenharmony_ci} */ 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ciconst struct dentry_operations cifs_dentry_ops = { 79962306a36Sopenharmony_ci .d_revalidate = cifs_d_revalidate, 80062306a36Sopenharmony_ci .d_automount = cifs_d_automount, 80162306a36Sopenharmony_ci/* d_delete: cifs_d_delete, */ /* not needed except for debugging */ 80262306a36Sopenharmony_ci}; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cistatic int cifs_ci_hash(const struct dentry *dentry, struct qstr *q) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls; 80762306a36Sopenharmony_ci unsigned long hash; 80862306a36Sopenharmony_ci wchar_t c; 80962306a36Sopenharmony_ci int i, charlen; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci hash = init_name_hash(dentry); 81262306a36Sopenharmony_ci for (i = 0; i < q->len; i += charlen) { 81362306a36Sopenharmony_ci charlen = codepage->char2uni(&q->name[i], q->len - i, &c); 81462306a36Sopenharmony_ci /* error out if we can't convert the character */ 81562306a36Sopenharmony_ci if (unlikely(charlen < 0)) 81662306a36Sopenharmony_ci return charlen; 81762306a36Sopenharmony_ci hash = partial_name_hash(cifs_toupper(c), hash); 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci q->hash = end_name_hash(hash); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci return 0; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_cistatic int cifs_ci_compare(const struct dentry *dentry, 82562306a36Sopenharmony_ci unsigned int len, const char *str, const struct qstr *name) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls; 82862306a36Sopenharmony_ci wchar_t c1, c2; 82962306a36Sopenharmony_ci int i, l1, l2; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* 83262306a36Sopenharmony_ci * We make the assumption here that uppercase characters in the local 83362306a36Sopenharmony_ci * codepage are always the same length as their lowercase counterparts. 83462306a36Sopenharmony_ci * 83562306a36Sopenharmony_ci * If that's ever not the case, then this will fail to match it. 83662306a36Sopenharmony_ci */ 83762306a36Sopenharmony_ci if (name->len != len) 83862306a36Sopenharmony_ci return 1; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci for (i = 0; i < len; i += l1) { 84162306a36Sopenharmony_ci /* Convert characters in both strings to UTF-16. */ 84262306a36Sopenharmony_ci l1 = codepage->char2uni(&str[i], len - i, &c1); 84362306a36Sopenharmony_ci l2 = codepage->char2uni(&name->name[i], name->len - i, &c2); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci /* 84662306a36Sopenharmony_ci * If we can't convert either character, just declare it to 84762306a36Sopenharmony_ci * be 1 byte long and compare the original byte. 84862306a36Sopenharmony_ci */ 84962306a36Sopenharmony_ci if (unlikely(l1 < 0 && l2 < 0)) { 85062306a36Sopenharmony_ci if (str[i] != name->name[i]) 85162306a36Sopenharmony_ci return 1; 85262306a36Sopenharmony_ci l1 = 1; 85362306a36Sopenharmony_ci continue; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci /* 85762306a36Sopenharmony_ci * Here, we again ass|u|me that upper/lowercase versions of 85862306a36Sopenharmony_ci * a character are the same length in the local NLS. 85962306a36Sopenharmony_ci */ 86062306a36Sopenharmony_ci if (l1 != l2) 86162306a36Sopenharmony_ci return 1; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci /* Now compare uppercase versions of these characters */ 86462306a36Sopenharmony_ci if (cifs_toupper(c1) != cifs_toupper(c2)) 86562306a36Sopenharmony_ci return 1; 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci return 0; 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ciconst struct dentry_operations cifs_ci_dentry_ops = { 87262306a36Sopenharmony_ci .d_revalidate = cifs_d_revalidate, 87362306a36Sopenharmony_ci .d_hash = cifs_ci_hash, 87462306a36Sopenharmony_ci .d_compare = cifs_ci_compare, 87562306a36Sopenharmony_ci .d_automount = cifs_d_automount, 87662306a36Sopenharmony_ci}; 877