| 1 | |
| 2 | |
| 3 | *
|
| 4 | * vfs operations that deal with dentries
|
| 5 | *
|
| 6 | * Copyright (C) International Business Machines Corp., 2002,2009
|
| 7 | * Author(s): Steve French ([email protected])
|
| 8 | *
|
| 9 |
|
| 10 | #include <linux/fs.h>
|
| 11 | #include <linux/stat.h>
|
| 12 | #include <linux/slab.h>
|
| 13 | #include <linux/namei.h>
|
| 14 | #include <linux/mount.h>
|
| 15 | #include <linux/file.h>
|
| 16 | #include "cifsfs.h"
|
| 17 | #include "cifsglob.h"
|
| 18 | #include "cifsproto.h"
|
| 19 | #include "cifs_debug.h"
|
| 20 | #include "cifs_fs_sb.h"
|
| 21 | #include "cifs_unicode.h"
|
| 22 | #include "fs_context.h"
|
| 23 | #include "cifs_ioctl.h"
|
| 24 | #include "fscache.h"
|
| 25 | #include "cached_dir.h"
|
| 26 |
|
| 27 | static void
|
| 28 | renew_parental_timestamps(struct dentry *direntry)
|
| 29 | {
|
| 30 | |
| 31 | really need this
|
| 32 | do {
|
| 33 | cifs_set_time(direntry, jiffies);
|
| 34 | direntry = direntry->d_parent;
|
| 35 | } while (!IS_ROOT(direntry));
|
| 36 | }
|
| 37 |
|
| 38 | char *
|
| 39 | cifs_build_path_to_root(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb,
|
| 40 | struct cifs_tcon *tcon, int add_treename)
|
| 41 | {
|
| 42 | int pplen = ctx->prepath ? strlen(ctx->prepath) + 1 : 0;
|
| 43 | int dfsplen;
|
| 44 | char *full_path = NULL;
|
| 45 |
|
| 46 |
|
| 47 | if (pplen == 0) {
|
| 48 | full_path = kzalloc(1, GFP_KERNEL);
|
| 49 | return full_path;
|
| 50 | }
|
| 51 |
|
| 52 | if (add_treename)
|
| 53 | dfsplen = strnlen(tcon->tree_name, MAX_TREE_SIZE + 1);
|
| 54 | else
|
| 55 | dfsplen = 0;
|
| 56 |
|
| 57 | full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL);
|
| 58 | if (full_path == NULL)
|
| 59 | return full_path;
|
| 60 |
|
| 61 | if (dfsplen)
|
| 62 | memcpy(full_path, tcon->tree_name, dfsplen);
|
| 63 | full_path[dfsplen] = CIFS_DIR_SEP(cifs_sb);
|
| 64 | memcpy(full_path + dfsplen + 1, ctx->prepath, pplen);
|
| 65 | convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
|
| 66 | return full_path;
|
| 67 | }
|
| 68 |
|
| 69 |
|
| 70 | const char *
|
| 71 | build_path_from_dentry(struct dentry *direntry, void *page)
|
| 72 | {
|
| 73 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
|
| 74 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
| 75 | bool prefix = tcon->Flags & SMB_SHARE_IS_IN_DFS;
|
| 76 |
|
| 77 | return build_path_from_dentry_optional_prefix(direntry, page,
|
| 78 | prefix);
|
| 79 | }
|
| 80 |
|
| 81 | char *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
|
| 82 | const char *tree, int tree_len,
|
| 83 | bool prefix)
|
| 84 | {
|
| 85 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry);
|
| 86 | unsigned int sbflags = cifs_sb_flags(cifs_sb);
|
| 87 | char dirsep = CIFS_DIR_SEP(cifs_sb);
|
| 88 | int pplen = 0;
|
| 89 | int dfsplen;
|
| 90 | char *s;
|
| 91 |
|
| 92 | if (unlikely(!page))
|
| 93 | return ERR_PTR(-ENOMEM);
|
| 94 |
|
| 95 | if (prefix)
|
| 96 | dfsplen = strnlen(tree, tree_len + 1);
|
| 97 | else
|
| 98 | dfsplen = 0;
|
| 99 |
|
| 100 | if (sbflags & CIFS_MOUNT_USE_PREFIX_PATH)
|
| 101 | pplen = cifs_sb->prepath ? strlen(cifs_sb->prepath) + 1 : 0;
|
| 102 |
|
| 103 | s = dentry_path_raw(direntry, page, PATH_MAX);
|
| 104 | if (IS_ERR(s))
|
| 105 | return s;
|
| 106 | if (!s[1]) |
| 107 | s++;
|
| 108 | if (s < (char *)page + pplen + dfsplen)
|
| 109 | return ERR_PTR(-ENAMETOOLONG);
|
| 110 | if (pplen) {
|
| 111 | cifs_dbg(FYI, "using cifs_sb prepath <%s>\n", cifs_sb->prepath);
|
| 112 | s -= pplen;
|
| 113 | memcpy(s + 1, cifs_sb->prepath, pplen - 1);
|
| 114 | *s = '/';
|
| 115 | }
|
| 116 | if (dirsep != '/') {
|
| 117 |
|
| 118 | strreplace(s, '/', dirsep);
|
| 119 | }
|
| 120 | if (dfsplen) {
|
| 121 | s -= dfsplen;
|
| 122 | memcpy(s, tree, dfsplen);
|
| 123 | if (sbflags & CIFS_MOUNT_POSIX_PATHS) {
|
| 124 | int i;
|
| 125 | for (i = 0; i < dfsplen; i++) {
|
| 126 | if (s[i] == '\\')
|
| 127 | s[i] = '/';
|
| 128 | }
|
| 129 | }
|
| 130 | }
|
| 131 | return s;
|
| 132 | }
|
| 133 |
|
| 134 | char *build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
|
| 135 | bool prefix)
|
| 136 | {
|
| 137 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
|
| 138 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
| 139 |
|
| 140 | return __build_path_from_dentry_optional_prefix(direntry, page, tcon->tree_name,
|
| 141 | MAX_TREE_SIZE, prefix);
|
| 142 | }
|
| 143 |
|
| 144 | |
| 145 | * Don't allow path components longer than the server max.
|
| 146 | * Don't allow the separator character in a path component.
|
| 147 | * The VFS will not allow "/", but "\" is allowed by posix.
|
| 148 |
|
| 149 | static int
|
| 150 | check_name(struct dentry *direntry, struct cifs_tcon *tcon)
|
| 151 | {
|
| 152 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry);
|
| 153 | int i;
|
| 154 |
|
| 155 | if (unlikely(tcon->fsAttrInfo.MaxPathNameComponentLength &&
|
| 156 | direntry->d_name.len >
|
| 157 | le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength)))
|
| 158 | return -ENAMETOOLONG;
|
| 159 |
|
| 160 | if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_POSIX_PATHS)) {
|
| 161 | for (i = 0; i < direntry->d_name.len; i++) {
|
| 162 | if (direntry->d_name.name[i] == '\\') {
|
| 163 | cifs_dbg(FYI, "Invalid file name\n");
|
| 164 | return -EINVAL;
|
| 165 | }
|
| 166 | }
|
| 167 | }
|
| 168 | return 0;
|
| 169 | }
|
| 170 |
|
| 171 | static char *alloc_parent_path(struct dentry *dentry, size_t namelen)
|
| 172 | {
|
| 173 | struct cifs_sb_info *cifs_sb = CIFS_SB(dentry);
|
| 174 | void *page = alloc_dentry_path();
|
| 175 | const char *path;
|
| 176 | size_t size;
|
| 177 | char *npath;
|
| 178 |
|
| 179 | path = build_path_from_dentry(dentry->d_parent, page);
|
| 180 | if (IS_ERR(path)) {
|
| 181 | npath = ERR_CAST(path);
|
| 182 | goto out;
|
| 183 | }
|
| 184 |
|
| 185 | size = strlen(path) + namelen + 2;
|
| 186 | npath = kmalloc(size, GFP_KERNEL);
|
| 187 | if (!npath)
|
| 188 | npath = ERR_PTR(-ENOMEM);
|
| 189 | else
|
| 190 | scnprintf(npath, size, "%s%c", path, CIFS_DIR_SEP(cifs_sb));
|
| 191 | out:
|
| 192 | free_dentry_path(page);
|
| 193 | return npath;
|
| 194 | }
|
| 195 |
|
| 196 |
|
| 197 | static int __cifs_do_create(struct inode *dir, struct dentry *direntry,
|
| 198 | const char *full_path, unsigned int xid,
|
| 199 | struct tcon_link *tlink, unsigned int oflags,
|
| 200 | umode_t mode, __u32 *oplock, struct cifs_fid *fid,
|
| 201 | struct cifs_open_info_data *buf,
|
| 202 | struct inode **inode, bool *opened)
|
| 203 | {
|
| 204 | int rc = -ENOENT;
|
| 205 | int create_options = CREATE_NOT_DIR;
|
| 206 | int desired_access;
|
| 207 | struct cifs_sb_info *cifs_sb = CIFS_SB(dir);
|
| 208 | struct cifs_tcon *tcon = tlink_tcon(tlink);
|
| 209 | struct inode *newinode = NULL;
|
| 210 | unsigned int sbflags = cifs_sb_flags(cifs_sb);
|
| 211 | int disposition;
|
| 212 | struct TCP_Server_Info *server = tcon->ses->server;
|
| 213 | struct cifs_open_parms oparms;
|
| 214 | struct cached_fid *parent_cfid = NULL;
|
| 215 | int rdwr_for_fscache = 0;
|
| 216 | __le32 lease_flags = 0;
|
| 217 |
|
| 218 | *inode = NULL;
|
| 219 | *opened = false;
|
| 220 | *oplock = 0;
|
| 221 | if (tcon->ses->server->oplocks)
|
| 222 | *oplock = REQ_OPLOCK;
|
| 223 |
|
| 224 |
|
| 225 | if (cifs_fscache_enabled(dir) && (oflags & O_ACCMODE) == O_WRONLY)
|
| 226 | rdwr_for_fscache = 1;
|
| 227 |
|
| 228 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
|
| 229 | if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open &&
|
| 230 | (CIFS_UNIX_POSIX_PATH_OPS_CAP &
|
| 231 | le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
| 232 | rc = cifs_posix_open(full_path, &newinode, dir->i_sb, mode,
|
| 233 | oflags, oplock, &fid->netfid, xid);
|
| 234 | switch (rc) {
|
| 235 | case 0:
|
| 236 | *opened = true;
|
| 237 | if (newinode == NULL) {
|
| 238 |
|
| 239 | goto cifs_create_get_file_info;
|
| 240 | }
|
| 241 |
|
| 242 | if ((oflags & __O_REGULAR) && !S_ISREG(newinode->i_mode)) {
|
| 243 | CIFSSMBClose(xid, tcon, fid->netfid);
|
| 244 | iput(newinode);
|
| 245 | return -EFTYPE;
|
| 246 | }
|
| 247 |
|
| 248 | if (S_ISDIR(newinode->i_mode)) {
|
| 249 | CIFSSMBClose(xid, tcon, fid->netfid);
|
| 250 | iput(newinode);
|
| 251 | return -EISDIR;
|
| 252 | }
|
| 253 |
|
| 254 | if (!S_ISREG(newinode->i_mode)) {
|
| 255 | |
| 256 | * The server may allow us to open things like
|
| 257 | * FIFOs, but the client isn't set up to deal
|
| 258 | * with that. Keep the handle until the caller
|
| 259 | * can finish the lookup.
|
| 260 |
|
| 261 | goto cifs_create_get_file_info;
|
| 262 | }
|
| 263 |
|
| 264 | goto cifs_create_set_dentry;
|
| 265 |
|
| 266 | case -ENOENT:
|
| 267 | goto cifs_create_get_file_info;
|
| 268 |
|
| 269 | case -EIO:
|
| 270 | case -EINVAL:
|
| 271 | |
| 272 | * EIO could indicate that (posix open) operation is not
|
| 273 | * supported, despite what server claimed in capability
|
| 274 | * negotiation.
|
| 275 | *
|
| 276 | * POSIX open in samba versions 3.3.1 and earlier could
|
| 277 | * incorrectly fail with invalid parameter.
|
| 278 |
|
| 279 | tcon->broken_posix_open = true;
|
| 280 | break;
|
| 281 |
|
| 282 | case -EREMOTE:
|
| 283 | case -EOPNOTSUPP:
|
| 284 | |
| 285 | * EREMOTE indicates DFS junction, which is not handled
|
| 286 | * in posix open. If either that or op not supported
|
| 287 | * returned, follow the normal lookup.
|
| 288 |
|
| 289 | break;
|
| 290 |
|
| 291 | default:
|
| 292 | return rc;
|
| 293 | }
|
| 294 | |
| 295 | * fallthrough to retry, using older open call, this is case
|
| 296 | * where server does not support this SMB level, and falsely
|
| 297 | * claims capability (also get here for DFS case which should be
|
| 298 | * rare for path not covered on files)
|
| 299 |
|
| 300 | }
|
| 301 | #endif
|
| 302 |
|
| 303 | desired_access = 0;
|
| 304 | if (OPEN_FMODE(oflags) & FMODE_READ)
|
| 305 | desired_access |= GENERIC_READ;
|
| 306 | if (OPEN_FMODE(oflags) & FMODE_WRITE)
|
| 307 | desired_access |= GENERIC_WRITE;
|
| 308 | if (rdwr_for_fscache == 1)
|
| 309 | desired_access |= GENERIC_READ;
|
| 310 | if (oflags & O_TMPFILE)
|
| 311 | desired_access |= DELETE;
|
| 312 |
|
| 313 | disposition = FILE_OVERWRITE_IF;
|
| 314 | if (oflags & O_CREAT) {
|
| 315 | if (oflags & O_EXCL)
|
| 316 | disposition = FILE_CREATE;
|
| 317 | else if (oflags & O_TRUNC)
|
| 318 | disposition = FILE_OVERWRITE_IF;
|
| 319 | else
|
| 320 | disposition = FILE_OPEN_IF;
|
| 321 | } else if (oflags & O_TMPFILE) {
|
| 322 | disposition = FILE_CREATE;
|
| 323 | } else {
|
| 324 | cifs_dbg(FYI, "Create flag not set in create function\n");
|
| 325 | }
|
| 326 |
|
| 327 | |
| 328 | * BB add processing to set equivalent of mode - e.g. via CreateX with
|
| 329 | * ACLs
|
| 330 |
|
| 331 |
|
| 332 | if (!server->ops->open)
|
| 333 | return -EOPNOTSUPP;
|
| 334 |
|
| 335 | create_options |= cifs_open_create_options(oflags, create_options);
|
| 336 | |
| 337 | * if we're not using unix extensions, see if we need to set
|
| 338 | * ATTR_READONLY on the create call
|
| 339 |
|
| 340 | if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
|
| 341 | create_options |= CREATE_OPTION_READONLY;
|
| 342 |
|
| 343 |
|
| 344 | retry_open:
|
| 345 | if (tcon->cfids && direntry->d_parent && server->dialect >= SMB30_PROT_ID) {
|
| 346 | parent_cfid = NULL;
|
| 347 | spin_lock(&tcon->cfids->cfid_list_lock);
|
| 348 | list_for_each_entry(parent_cfid, &tcon->cfids->entries, entry) {
|
| 349 | if (parent_cfid->dentry == direntry->d_parent) {
|
| 350 | cifs_dbg(FYI, "found a parent cached file handle\n");
|
| 351 | if (is_valid_cached_dir(parent_cfid)) {
|
| 352 | lease_flags
|
| 353 | |= SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE;
|
| 354 | memcpy(fid->parent_lease_key,
|
| 355 | parent_cfid->fid.lease_key,
|
| 356 | SMB2_LEASE_KEY_SIZE);
|
| 357 | parent_cfid->dirents.is_valid = false;
|
| 358 | parent_cfid->dirents.is_failed = true;
|
| 359 | }
|
| 360 | break;
|
| 361 | }
|
| 362 | }
|
| 363 | spin_unlock(&tcon->cfids->cfid_list_lock);
|
| 364 | }
|
| 365 |
|
| 366 | oparms = (struct cifs_open_parms) {
|
| 367 | .tcon = tcon,
|
| 368 | .cifs_sb = cifs_sb,
|
| 369 | .desired_access = desired_access,
|
| 370 | .create_options = cifs_create_options(cifs_sb, create_options),
|
| 371 | .disposition = disposition,
|
| 372 | .path = full_path,
|
| 373 | .fid = fid,
|
| 374 | .lease_flags = lease_flags,
|
| 375 | .mode = mode,
|
| 376 | };
|
| 377 | rc = server->ops->open(xid, &oparms, oplock, buf);
|
| 378 | if (rc) {
|
| 379 | cifs_dbg(FYI, "cifs_create returned 0x%x\n", rc);
|
| 380 | if (rc == -EACCES && rdwr_for_fscache == 1) {
|
| 381 | desired_access &= ~GENERIC_READ;
|
| 382 | rdwr_for_fscache = 2;
|
| 383 | goto retry_open;
|
| 384 | }
|
| 385 | return rc;
|
| 386 | }
|
| 387 | *opened = true;
|
| 388 | if (rdwr_for_fscache == 2)
|
| 389 | cifs_invalidate_cache(dir, FSCACHE_INVAL_DIO_WRITE);
|
| 390 |
|
| 391 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
|
| 392 | |
| 393 | * If Open reported that we actually created a file then we now have to
|
| 394 | * set the mode if possible.
|
| 395 |
|
| 396 | if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) {
|
| 397 | struct cifs_unix_set_info_args args = {
|
| 398 | .mode = mode,
|
| 399 | .ctime = NO_CHANGE_64,
|
| 400 | .atime = NO_CHANGE_64,
|
| 401 | .mtime = NO_CHANGE_64,
|
| 402 | .device = 0,
|
| 403 | };
|
| 404 |
|
| 405 | if (sbflags & CIFS_MOUNT_SET_UID) {
|
| 406 | args.uid = current_fsuid();
|
| 407 | if (dir->i_mode & S_ISGID)
|
| 408 | args.gid = dir->i_gid;
|
| 409 | else
|
| 410 | args.gid = current_fsgid();
|
| 411 | } else {
|
| 412 | args.uid = INVALID_UID;
|
| 413 | args.gid = INVALID_GID;
|
| 414 | }
|
| 415 | CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid->netfid,
|
| 416 | current->tgid);
|
| 417 | } else {
|
| 418 | |
| 419 | * BB implement mode setting via Windows security
|
| 420 | * descriptors e.g.
|
| 421 |
|
| 422 |
|
| 423 |
|
| 424 | }
|
| 425 |
|
| 426 | cifs_create_get_file_info:
|
| 427 |
|
| 428 | if (tcon->unix_ext)
|
| 429 | rc = cifs_get_inode_info_unix(&newinode, full_path, dir->i_sb,
|
| 430 | xid);
|
| 431 | else {
|
| 432 | #else
|
| 433 | {
|
| 434 | #endif
|
| 435 |
|
| 436 | rc = cifs_get_inode_info(&newinode, full_path, buf, dir->i_sb, xid, fid);
|
| 437 | if (newinode) {
|
| 438 | if (server->ops->set_lease_key)
|
| 439 | server->ops->set_lease_key(newinode, fid);
|
| 440 | if ((*oplock & CIFS_CREATE_ACTION) && S_ISREG(newinode->i_mode)) {
|
| 441 | if (sbflags & CIFS_MOUNT_DYNPERM)
|
| 442 | newinode->i_mode = mode;
|
| 443 | if (sbflags & CIFS_MOUNT_SET_UID) {
|
| 444 | newinode->i_uid = current_fsuid();
|
| 445 | if (dir->i_mode & S_ISGID)
|
| 446 | newinode->i_gid = dir->i_gid;
|
| 447 | else
|
| 448 | newinode->i_gid = current_fsgid();
|
| 449 | }
|
| 450 | }
|
| 451 | }
|
| 452 | }
|
| 453 |
|
| 454 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
|
| 455 | cifs_create_set_dentry:
|
| 456 | #endif
|
| 457 | if (rc != 0) {
|
| 458 | cifs_dbg(FYI, "Create worked, get_inode_info failed rc = %d\n",
|
| 459 | rc);
|
| 460 | goto out_err;
|
| 461 | }
|
| 462 |
|
| 463 | if (newinode) {
|
| 464 | if ((oflags & __O_REGULAR) && !S_ISREG(newinode->i_mode)) {
|
| 465 | rc = -EFTYPE;
|
| 466 | goto out_err;
|
| 467 | }
|
| 468 | if (S_ISDIR(newinode->i_mode)) {
|
| 469 | rc = -EISDIR;
|
| 470 | goto out_err;
|
| 471 | }
|
| 472 | }
|
| 473 |
|
| 474 | *inode = newinode;
|
| 475 | return rc;
|
| 476 |
|
| 477 | out_err:
|
| 478 | if (*opened && server->ops->close)
|
| 479 | server->ops->close(xid, tcon, fid);
|
| 480 | if (newinode)
|
| 481 | iput(newinode);
|
| 482 | return rc;
|
| 483 | }
|
| 484 |
|
| 485 | static int cifs_do_create(struct inode *dir, struct dentry *direntry,
|
| 486 | unsigned int xid, struct tcon_link *tlink,
|
| 487 | unsigned int oflags, umode_t mode,
|
| 488 | __u32 *oplock, struct cifs_fid *fid,
|
| 489 | struct cifs_open_info_data *buf,
|
| 490 | struct inode **inode, bool *opened)
|
| 491 | {
|
| 492 | void *page = alloc_dentry_path();
|
| 493 | const char *full_path;
|
| 494 | int rc;
|
| 495 |
|
| 496 | full_path = build_path_from_dentry(direntry, page);
|
| 497 | if (IS_ERR(full_path)) {
|
| 498 | rc = PTR_ERR(full_path);
|
| 499 | *opened = false;
|
| 500 | } else {
|
| 501 | rc = __cifs_do_create(dir, direntry, full_path, xid,
|
| 502 | tlink, oflags, mode, oplock,
|
| 503 | fid, buf, inode, opened);
|
| 504 | }
|
| 505 | free_dentry_path(page);
|
| 506 | return rc;
|
| 507 | }
|
| 508 |
|
| 509 |
|
| 510 | |
| 511 | * Look up, create and open a CIFS file.
|
| 512 | *
|
| 513 | * The initial dentry state is in-lookup or hashed-negative. On success, dentry
|
| 514 | * will become hashed-positive by calling d_splice_alias() if in-lookup,
|
| 515 | * otherwise d_instantiate().
|
| 516 |
|
| 517 | int cifs_atomic_open(struct inode *dir, struct dentry *direntry,
|
| 518 | struct file *file, unsigned int oflags, umode_t mode)
|
| 519 | {
|
| 520 | struct cifs_sb_info *cifs_sb = CIFS_SB(dir);
|
| 521 | struct cifs_open_info_data buf = {};
|
| 522 | struct TCP_Server_Info *server;
|
| 523 | struct cifsFileInfo *file_info;
|
| 524 | struct cifs_pending_open open;
|
| 525 | struct cifs_fid fid = {};
|
| 526 | struct tcon_link *tlink;
|
| 527 | struct cifs_tcon *tcon;
|
| 528 | unsigned int sbflags;
|
| 529 | struct dentry *alias;
|
| 530 | struct inode *inode;
|
| 531 | unsigned int xid;
|
| 532 | __u32 oplock;
|
| 533 | bool is_regular;
|
| 534 | bool opened;
|
| 535 | int rc;
|
| 536 |
|
| 537 | if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
| 538 | return smb_EIO(smb_eio_trace_forced_shutdown);
|
| 539 |
|
| 540 | |
| 541 | * Posix open is only called (at lookup time) for file create now. For
|
| 542 | * opens (rather than creates), because we do not know if it is a file
|
| 543 | * or directory yet, and current Samba no longer allows us to do posix
|
| 544 | * open on dirs, we could end up wasting an open call on what turns out
|
| 545 | * to be a dir. For file opens, we wait to call posix open till
|
| 546 | * cifs_open. It could be added to atomic_open in the future but the
|
| 547 | * performance tradeoff of the extra network request when EISDIR or
|
| 548 | * EACCES is returned would have to be weighed against the 50% reduction
|
| 549 | * in network traffic in the other paths.
|
| 550 |
|
| 551 | if (!(oflags & O_CREAT)) {
|
| 552 | |
| 553 | * Check for hashed negative dentry. We have already revalidated
|
| 554 | * the dentry and it is fine. No need to perform another lookup.
|
| 555 |
|
| 556 | if (!d_in_lookup(direntry))
|
| 557 | return -ENOENT;
|
| 558 |
|
| 559 | return finish_no_open(file, cifs_lookup(dir, direntry, 0));
|
| 560 | }
|
| 561 |
|
| 562 | xid = get_xid();
|
| 563 |
|
| 564 | cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
|
| 565 | dir, direntry, direntry);
|
| 566 |
|
| 567 | tlink = cifs_sb_tlink(cifs_sb);
|
| 568 | if (IS_ERR(tlink)) {
|
| 569 | rc = PTR_ERR(tlink);
|
| 570 | goto out_free_xid;
|
| 571 | }
|
| 572 |
|
| 573 | tcon = tlink_tcon(tlink);
|
| 574 |
|
| 575 | rc = check_name(direntry, tcon);
|
| 576 | if (rc)
|
| 577 | goto out;
|
| 578 |
|
| 579 | server = tcon->ses->server;
|
| 580 |
|
| 581 | if (server->ops->new_lease_key)
|
| 582 | server->ops->new_lease_key(&fid);
|
| 583 |
|
| 584 | cifs_add_pending_open(&fid, tlink, &open);
|
| 585 |
|
| 586 | rc = cifs_do_create(dir, direntry, xid, tlink, oflags, mode,
|
| 587 | &oplock, &fid, &buf, &inode, &opened);
|
| 588 | if (rc) {
|
| 589 | cifs_del_pending_open(&open);
|
| 590 | goto out;
|
| 591 | }
|
| 592 |
|
| 593 | is_regular = S_ISREG(inode->i_mode);
|
| 594 | if (!is_regular || !opened) {
|
| 595 | if (opened && server->ops->close)
|
| 596 | server->ops->close(xid, tcon, &fid);
|
| 597 | cifs_del_pending_open(&open);
|
| 598 | if (S_ISLNK(inode->i_mode) &&
|
| 599 | (oflags & (O_NOFOLLOW | __O_REGULAR)) ==
|
| 600 | (O_NOFOLLOW | __O_REGULAR) && !(oflags & O_EXCL)) {
|
| 601 | iput(inode);
|
| 602 | rc = -ELOOP;
|
| 603 | goto out;
|
| 604 | }
|
| 605 | }
|
| 606 |
|
| 607 | if (d_in_lookup(direntry)) {
|
| 608 | alias = d_splice_alias(inode, direntry);
|
| 609 | if (!IS_ERR_OR_NULL(alias))
|
| 610 | direntry = alias;
|
| 611 | } else {
|
| 612 | d_instantiate(direntry, inode);
|
| 613 | }
|
| 614 |
|
| 615 | if (is_regular && opened &&
|
| 616 | (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
|
| 617 | file->f_mode |= FMODE_CREATED;
|
| 618 |
|
| 619 | if (!is_regular || !opened) {
|
| 620 | rc = finish_no_open(file, NULL);
|
| 621 | goto out;
|
| 622 | }
|
| 623 |
|
| 624 | rc = finish_open(file, direntry, generic_file_open);
|
| 625 | if (rc) {
|
| 626 | if (server->ops->close)
|
| 627 | server->ops->close(xid, tcon, &fid);
|
| 628 | cifs_del_pending_open(&open);
|
| 629 | goto out;
|
| 630 | }
|
| 631 |
|
| 632 | sbflags = cifs_sb_flags(cifs_sb);
|
| 633 | if ((file->f_flags & O_DIRECT) && (sbflags & CIFS_MOUNT_STRICT_IO)) {
|
| 634 | if (sbflags & CIFS_MOUNT_NO_BRL)
|
| 635 | file->f_op = &cifs_file_direct_nobrl_ops;
|
| 636 | else
|
| 637 | file->f_op = &cifs_file_direct_ops;
|
| 638 | }
|
| 639 |
|
| 640 | file_info = cifs_new_fileinfo(&fid, file, tlink, oplock, buf.symlink_target);
|
| 641 | if (file_info == NULL) {
|
| 642 | if (server->ops->close)
|
| 643 | server->ops->close(xid, tcon, &fid);
|
| 644 | cifs_del_pending_open(&open);
|
| 645 | rc = -ENOMEM;
|
| 646 | goto out;
|
| 647 | }
|
| 648 |
|
| 649 | fscache_use_cookie(cifs_inode_cookie(file_inode(file)),
|
| 650 | file->f_mode & FMODE_WRITE);
|
| 651 |
|
| 652 | out:
|
| 653 | cifs_put_tlink(tlink);
|
| 654 | out_free_xid:
|
| 655 | free_xid(xid);
|
| 656 | cifs_free_open_info(&buf);
|
| 657 | return rc;
|
| 658 | }
|
| 659 |
|
| 660 | |
| 661 | * Create a CIFS file.
|
| 662 | *
|
| 663 | * The initial dentry state is hashed-negative. On success, dentry will become
|
| 664 | * hashed-positive by calling d_instantiate().
|
| 665 |
|
| 666 | int cifs_create(const struct mnt_idmap *idmap, struct inode *dir,
|
| 667 | struct dentry *direntry, umode_t mode)
|
| 668 | {
|
| 669 | struct cifs_sb_info *cifs_sb = CIFS_SB(dir);
|
| 670 | int rc;
|
| 671 | unsigned int xid = get_xid();
|
| 672 | |
| 673 | * BB below access is probably too much for mknod to request
|
| 674 | * but we have to do query and setpathinfo so requesting
|
| 675 | * less could fail (unless we want to request getatr and setatr
|
| 676 | * permissions (only). At least for POSIX we do not have to
|
| 677 | * request so much.
|
| 678 |
|
| 679 | unsigned oflags = O_EXCL | O_CREAT | O_RDWR;
|
| 680 | struct tcon_link *tlink;
|
| 681 | struct cifs_tcon *tcon;
|
| 682 | struct TCP_Server_Info *server;
|
| 683 | struct inode *inode;
|
| 684 | struct cifs_fid fid;
|
| 685 | __u32 oplock;
|
| 686 | bool opened;
|
| 687 | struct cifs_open_info_data buf = {};
|
| 688 |
|
| 689 | cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
|
| 690 | dir, direntry, direntry);
|
| 691 |
|
| 692 | if (unlikely(cifs_forced_shutdown(cifs_sb))) {
|
| 693 | rc = smb_EIO(smb_eio_trace_forced_shutdown);
|
| 694 | goto out_free_xid;
|
| 695 | }
|
| 696 |
|
| 697 | tlink = cifs_sb_tlink(cifs_sb);
|
| 698 | rc = PTR_ERR(tlink);
|
| 699 | if (IS_ERR(tlink))
|
| 700 | goto out_free_xid;
|
| 701 |
|
| 702 | tcon = tlink_tcon(tlink);
|
| 703 | server = tcon->ses->server;
|
| 704 |
|
| 705 | if (server->ops->new_lease_key)
|
| 706 | server->ops->new_lease_key(&fid);
|
| 707 |
|
| 708 | rc = cifs_do_create(dir, direntry, xid, tlink, oflags,
|
| 709 | mode, &oplock, &fid, &buf, &inode, &opened);
|
| 710 | if (!rc) {
|
| 711 | d_instantiate(direntry, inode);
|
| 712 | if (opened && server->ops->close)
|
| 713 | server->ops->close(xid, tcon, &fid);
|
| 714 | }
|
| 715 |
|
| 716 | cifs_free_open_info(&buf);
|
| 717 | cifs_put_tlink(tlink);
|
| 718 | out_free_xid:
|
| 719 | free_xid(xid);
|
| 720 | return rc;
|
| 721 | }
|
| 722 |
|
| 723 | int cifs_mknod(const struct mnt_idmap *idmap, struct inode *inode,
|
| 724 | struct dentry *direntry, umode_t mode, dev_t device_number)
|
| 725 | {
|
| 726 | int rc = -EPERM;
|
| 727 | unsigned int xid;
|
| 728 | struct cifs_sb_info *cifs_sb;
|
| 729 | struct tcon_link *tlink;
|
| 730 | struct cifs_tcon *tcon;
|
| 731 | const char *full_path;
|
| 732 | void *page;
|
| 733 |
|
| 734 | if (!old_valid_dev(device_number))
|
| 735 | return -EINVAL;
|
| 736 |
|
| 737 | cifs_sb = CIFS_SB(inode->i_sb);
|
| 738 | if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
| 739 | return smb_EIO(smb_eio_trace_forced_shutdown);
|
| 740 |
|
| 741 | tlink = cifs_sb_tlink(cifs_sb);
|
| 742 | if (IS_ERR(tlink))
|
| 743 | return PTR_ERR(tlink);
|
| 744 |
|
| 745 | page = alloc_dentry_path();
|
| 746 | tcon = tlink_tcon(tlink);
|
| 747 | xid = get_xid();
|
| 748 |
|
| 749 | full_path = build_path_from_dentry(direntry, page);
|
| 750 | if (IS_ERR(full_path)) {
|
| 751 | rc = PTR_ERR(full_path);
|
| 752 | goto mknod_out;
|
| 753 | }
|
| 754 |
|
| 755 | trace_smb3_mknod_enter(xid, tcon->tid, tcon->ses->Suid, full_path);
|
| 756 |
|
| 757 | rc = tcon->ses->server->ops->make_node(xid, inode, direntry, tcon,
|
| 758 | full_path, mode,
|
| 759 | device_number);
|
| 760 |
|
| 761 | mknod_out:
|
| 762 | if (rc)
|
| 763 | trace_smb3_mknod_err(xid, tcon->tid, tcon->ses->Suid, rc);
|
| 764 | else
|
| 765 | trace_smb3_mknod_done(xid, tcon->tid, tcon->ses->Suid);
|
| 766 |
|
| 767 | free_dentry_path(page);
|
| 768 | free_xid(xid);
|
| 769 | cifs_put_tlink(tlink);
|
| 770 | return rc;
|
| 771 | }
|
| 772 |
|
| 773 | struct dentry *
|
| 774 | cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
| 775 | unsigned int flags)
|
| 776 | {
|
| 777 | unsigned int xid;
|
| 778 | int rc = 0;
|
| 779 | struct cifs_sb_info *cifs_sb;
|
| 780 | struct tcon_link *tlink;
|
| 781 | struct cifs_tcon *pTcon;
|
| 782 | struct inode *newInode = NULL;
|
| 783 | const char *full_path;
|
| 784 | void *page;
|
| 785 | int retry_count = 0;
|
| 786 | struct dentry *de;
|
| 787 |
|
| 788 | xid = get_xid();
|
| 789 |
|
| 790 | cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
|
| 791 | parent_dir_inode, direntry, direntry);
|
| 792 |
|
| 793 |
|
| 794 |
|
| 795 | cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
|
| 796 | tlink = cifs_sb_tlink(cifs_sb);
|
| 797 | if (IS_ERR(tlink)) {
|
| 798 | de = ERR_CAST(tlink);
|
| 799 | goto free_xid;
|
| 800 | }
|
| 801 | pTcon = tlink_tcon(tlink);
|
| 802 |
|
| 803 | rc = check_name(direntry, pTcon);
|
| 804 | if (unlikely(rc)) {
|
| 805 | de = ERR_PTR(rc);
|
| 806 | goto put_tlink;
|
| 807 | }
|
| 808 |
|
| 809 | |
| 810 | deadlock in the cases (beginning of sys_rename itself)
|
| 811 | in which we already have the sb rename sem
|
| 812 | page = alloc_dentry_path();
|
| 813 | full_path = build_path_from_dentry(direntry, page);
|
| 814 | if (IS_ERR(full_path)) {
|
| 815 | de = ERR_CAST(full_path);
|
| 816 | goto free_dentry_path;
|
| 817 | }
|
| 818 |
|
| 819 | if (d_really_is_positive(direntry)) {
|
| 820 | cifs_dbg(FYI, "non-NULL inode in lookup\n");
|
| 821 | } else {
|
| 822 | struct cached_fid *cfid = NULL;
|
| 823 |
|
| 824 | cifs_dbg(FYI, "NULL inode in lookup\n");
|
| 825 |
|
| 826 | |
| 827 | * We can only rely on negative dentries having the same
|
| 828 | * spelling as the cached dirent if case insensitivity is
|
| 829 | * forced on mount.
|
| 830 | *
|
| 831 | * XXX: if servers correctly announce Case Sensitivity Search
|
| 832 | * on GetInfo of FileFSAttributeInformation, then we can take
|
| 833 | * correct action even if case insensitive is not forced on
|
| 834 | * mount.
|
| 835 |
|
| 836 | if (pTcon->nocase && !open_cached_dir_by_dentry(pTcon, direntry->d_parent, &cfid)) {
|
| 837 | |
| 838 | * dentry is negative and parent is fully cached:
|
| 839 | * we can assume file does not exist
|
| 840 |
|
| 841 | if (cfid->dirents.is_valid) {
|
| 842 | close_cached_dir(cfid);
|
| 843 | goto out;
|
| 844 | }
|
| 845 | close_cached_dir(cfid);
|
| 846 | }
|
| 847 | }
|
| 848 | cifs_dbg(FYI, "Full path: %s inode = 0x%p\n",
|
| 849 | full_path, d_inode(direntry));
|
| 850 |
|
| 851 | again:
|
| 852 | if (pTcon->posix_extensions) {
|
| 853 | rc = smb311_posix_get_inode_info(&newInode, full_path, NULL,
|
| 854 | parent_dir_inode->i_sb, xid);
|
| 855 | } else if (pTcon->unix_ext) {
|
| 856 | rc = cifs_get_inode_info_unix(&newInode, full_path,
|
| 857 | parent_dir_inode->i_sb, xid);
|
| 858 | } else {
|
| 859 | rc = cifs_get_inode_info(&newInode, full_path, NULL,
|
| 860 | parent_dir_inode->i_sb, xid, NULL);
|
| 861 | }
|
| 862 |
|
| 863 | if (rc == 0) {
|
| 864 | |
| 865 | directories are presumed to be good here
|
| 866 | renew_parental_timestamps(direntry);
|
| 867 | } else if (rc == -EAGAIN && retry_count++ < 10) {
|
| 868 | goto again;
|
| 869 | } else if (rc == -ENOENT) {
|
| 870 | cifs_set_time(direntry, jiffies);
|
| 871 | newInode = NULL;
|
| 872 | } else {
|
| 873 | if (rc != -EACCES) {
|
| 874 | cifs_dbg(FYI, "Unexpected lookup error %d\n", rc);
|
| 875 | |
| 876 | is a common return code
|
| 877 | }
|
| 878 | newInode = ERR_PTR(rc);
|
| 879 | }
|
| 880 |
|
| 881 | out:
|
| 882 | de = d_splice_alias(newInode, direntry);
|
| 883 | free_dentry_path:
|
| 884 | free_dentry_path(page);
|
| 885 | put_tlink:
|
| 886 | cifs_put_tlink(tlink);
|
| 887 | free_xid:
|
| 888 | free_xid(xid);
|
| 889 | return de;
|
| 890 | }
|
| 891 |
|
| 892 | static int
|
| 893 | cifs_d_revalidate(struct inode *dir, const struct qstr *name,
|
| 894 | struct dentry *direntry, unsigned int flags)
|
| 895 | {
|
| 896 | if (flags & LOOKUP_RCU)
|
| 897 | return -ECHILD;
|
| 898 |
|
| 899 | if (d_really_is_positive(direntry)) {
|
| 900 | int rc;
|
| 901 | struct inode *inode = d_inode(direntry);
|
| 902 |
|
| 903 | if ((flags & LOOKUP_REVAL) && !CIFS_CACHE_READ(CIFS_I(inode)))
|
| 904 | CIFS_I(inode)->time = 0;
|
| 905 |
|
| 906 | rc = cifs_revalidate_dentry(direntry);
|
| 907 | if (rc) {
|
| 908 | cifs_dbg(FYI, "cifs_revalidate_dentry failed with rc=%d", rc);
|
| 909 | switch (rc) {
|
| 910 | case -ENOENT:
|
| 911 | case -ESTALE:
|
| 912 | |
| 913 | * Those errors mean the dentry is invalid
|
| 914 | * (file was deleted or recreated)
|
| 915 |
|
| 916 | return 0;
|
| 917 | default:
|
| 918 | |
| 919 | * Otherwise some unexpected error happened
|
| 920 | * report it as-is to VFS layer
|
| 921 |
|
| 922 | return rc;
|
| 923 | }
|
| 924 | }
|
| 925 | else {
|
| 926 | |
| 927 | * If the inode wasn't known to be a dfs entry when
|
| 928 | * the dentry was instantiated, such as when created
|
| 929 | * via ->readdir(), it needs to be set now since the
|
| 930 | * attributes will have been updated by
|
| 931 | * cifs_revalidate_dentry().
|
| 932 |
|
| 933 | if (IS_AUTOMOUNT(inode) &&
|
| 934 | !(direntry->d_flags & DCACHE_NEED_AUTOMOUNT)) {
|
| 935 | spin_lock(&direntry->d_lock);
|
| 936 | direntry->d_flags |= DCACHE_NEED_AUTOMOUNT;
|
| 937 | spin_unlock(&direntry->d_lock);
|
| 938 | }
|
| 939 |
|
| 940 | return 1;
|
| 941 | }
|
| 942 | } else {
|
| 943 | struct cifs_sb_info *cifs_sb = CIFS_SB(dir->i_sb);
|
| 944 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
| 945 | struct cached_fid *cfid;
|
| 946 |
|
| 947 | if (!open_cached_dir_by_dentry(tcon, direntry->d_parent, &cfid)) {
|
| 948 | |
| 949 | * dentry is negative and parent is fully cached:
|
| 950 | * we can assume file does not exist
|
| 951 |
|
| 952 | if (cfid->dirents.is_valid) {
|
| 953 | close_cached_dir(cfid);
|
| 954 | return 1;
|
| 955 | }
|
| 956 | close_cached_dir(cfid);
|
| 957 | }
|
| 958 | }
|
| 959 |
|
| 960 | |
| 961 | * This may be nfsd (or something), anyway, we can't see the
|
| 962 | * intent of this. So, since this can be for creation, drop it.
|
| 963 |
|
| 964 | if (!flags)
|
| 965 | return 0;
|
| 966 |
|
| 967 | |
| 968 | * Drop the negative dentry, in order to make sure to use the
|
| 969 | * case sensitive name which is specified by user if this is
|
| 970 | * for creation.
|
| 971 |
|
| 972 | if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
|
| 973 | return 0;
|
| 974 |
|
| 975 | if (time_after(jiffies, cifs_get_time(direntry) + HZ) || !lookupCacheEnabled)
|
| 976 | return 0;
|
| 977 |
|
| 978 | return 1;
|
| 979 | }
|
| 980 |
|
| 981 | |
| 982 | {
|
| 983 | int rc = 0;
|
| 984 |
|
| 985 | cifs_dbg(FYI, "In cifs d_delete, name = %pd\n", direntry);
|
| 986 |
|
| 987 | return rc;
|
| 988 | }
|
| 989 |
|
| 990 | const struct dentry_operations cifs_dentry_ops = {
|
| 991 | .d_revalidate = cifs_d_revalidate,
|
| 992 | .d_automount = cifs_d_automount,
|
| 993 |
|
| 994 | };
|
| 995 |
|
| 996 | static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q)
|
| 997 | {
|
| 998 | struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls;
|
| 999 | unsigned long hash;
|
| 1000 | wchar_t c;
|
| 1001 | int i, charlen;
|
| 1002 |
|
| 1003 | hash = init_name_hash(dentry);
|
| 1004 | for (i = 0; i < q->len; i += charlen) {
|
| 1005 | charlen = codepage->char2uni(&q->name[i], q->len - i, &c);
|
| 1006 |
|
| 1007 | if (unlikely(charlen < 0))
|
| 1008 | return charlen;
|
| 1009 | hash = partial_name_hash(cifs_toupper(c), hash);
|
| 1010 | }
|
| 1011 | q->hash = end_name_hash(hash);
|
| 1012 |
|
| 1013 | return 0;
|
| 1014 | }
|
| 1015 |
|
| 1016 | static int cifs_ci_compare(const struct dentry *dentry,
|
| 1017 | unsigned int len, const char *str, const struct qstr *name)
|
| 1018 | {
|
| 1019 | struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls;
|
| 1020 | wchar_t c1, c2;
|
| 1021 | int i, l1, l2;
|
| 1022 |
|
| 1023 | |
| 1024 | * We make the assumption here that uppercase characters in the local
|
| 1025 | * codepage are always the same length as their lowercase counterparts.
|
| 1026 | *
|
| 1027 | * If that's ever not the case, then this will fail to match it.
|
| 1028 |
|
| 1029 | if (name->len != len)
|
| 1030 | return 1;
|
| 1031 |
|
| 1032 | for (i = 0; i < len; i += l1) {
|
| 1033 |
|
| 1034 | l1 = codepage->char2uni(&str[i], len - i, &c1);
|
| 1035 | l2 = codepage->char2uni(&name->name[i], name->len - i, &c2);
|
| 1036 |
|
| 1037 | |
| 1038 | * If we can't convert either character, just declare it to
|
| 1039 | * be 1 byte long and compare the original byte.
|
| 1040 |
|
| 1041 | if (unlikely(l1 < 0 && l2 < 0)) {
|
| 1042 | if (str[i] != name->name[i])
|
| 1043 | return 1;
|
| 1044 | l1 = 1;
|
| 1045 | continue;
|
| 1046 | }
|
| 1047 |
|
| 1048 | |
| 1049 | * Here, we again ass|u|me that upper/lowercase versions of
|
| 1050 | * a character are the same length in the local NLS.
|
| 1051 |
|
| 1052 | if (l1 != l2)
|
| 1053 | return 1;
|
| 1054 |
|
| 1055 |
|
| 1056 | if (cifs_toupper(c1) != cifs_toupper(c2))
|
| 1057 | return 1;
|
| 1058 | }
|
| 1059 |
|
| 1060 | return 0;
|
| 1061 | }
|
| 1062 |
|
| 1063 | static int set_tmpfile_attr(const unsigned int xid, unsigned int oflags,
|
| 1064 | struct inode *inode, const char *full_path,
|
| 1065 | struct TCP_Server_Info *server)
|
| 1066 | {
|
| 1067 | struct cifsInodeInfo *cinode = CIFS_I(inode);
|
| 1068 | FILE_BASIC_INFO fi;
|
| 1069 |
|
| 1070 | cinode->cifsAttrs |= ATTR_HIDDEN;
|
| 1071 | if (oflags & O_EXCL)
|
| 1072 | cinode->cifsAttrs |= ATTR_TEMPORARY;
|
| 1073 |
|
| 1074 | fi = (FILE_BASIC_INFO) {
|
| 1075 | .Attributes = cpu_to_le32(cinode->cifsAttrs),
|
| 1076 | };
|
| 1077 | return server->ops->set_file_info(inode, full_path, &fi, xid);
|
| 1078 | }
|
| 1079 |
|
| 1080 | |
| 1081 | * Create a hidden temporary CIFS file with delete-on-close bit set.
|
| 1082 | *
|
| 1083 | * The initial dentry state is unhashed-negative. On success, dentry will
|
| 1084 | * become unhashed-positive by calling d_instantiate().
|
| 1085 |
|
| 1086 | int cifs_tmpfile(const struct mnt_idmap *idmap, struct inode *dir,
|
| 1087 | struct file *file, umode_t mode)
|
| 1088 | {
|
| 1089 | struct dentry *dentry = file->f_path.dentry;
|
| 1090 | struct cifs_sb_info *cifs_sb = CIFS_SB(dir);
|
| 1091 | size_t namesize = CIFS_TMPNAME_LEN + 1;
|
| 1092 | char *path __free(kfree) = NULL, *name;
|
| 1093 | unsigned int oflags = file->f_flags;
|
| 1094 | int retries = 0, max_retries = 16;
|
| 1095 | struct TCP_Server_Info *server;
|
| 1096 | struct cifs_pending_open open;
|
| 1097 | struct cifsFileInfo *cfile;
|
| 1098 | struct cifs_fid fid = {};
|
| 1099 | struct tcon_link *tlink;
|
| 1100 | struct cifs_tcon *tcon;
|
| 1101 | unsigned int sbflags;
|
| 1102 | struct inode *inode;
|
| 1103 | unsigned int xid;
|
| 1104 | __u32 oplock;
|
| 1105 | bool opened;
|
| 1106 | int namelen;
|
| 1107 | int rc;
|
| 1108 |
|
| 1109 | if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
| 1110 | return smb_EIO(smb_eio_trace_forced_shutdown);
|
| 1111 |
|
| 1112 | tlink = cifs_sb_tlink(cifs_sb);
|
| 1113 | if (IS_ERR(tlink))
|
| 1114 | return PTR_ERR(tlink);
|
| 1115 | tcon = tlink_tcon(tlink);
|
| 1116 | server = tcon->ses->server;
|
| 1117 |
|
| 1118 | xid = get_xid();
|
| 1119 |
|
| 1120 | if (server->vals->protocol_id < SMB20_PROT_ID) {
|
| 1121 | cifs_dbg(VFS | ONCE, "O_TMPFILE is supported only in SMB2+\n");
|
| 1122 | rc = -EOPNOTSUPP;
|
| 1123 | goto out;
|
| 1124 | }
|
| 1125 |
|
| 1126 | if (server->ops->new_lease_key)
|
| 1127 | server->ops->new_lease_key(&fid);
|
| 1128 | cifs_add_pending_open(&fid, tlink, &open);
|
| 1129 |
|
| 1130 | path = alloc_parent_path(dentry, namesize - 1);
|
| 1131 | if (IS_ERR(path)) {
|
| 1132 | cifs_del_pending_open(&open);
|
| 1133 | rc = PTR_ERR(path);
|
| 1134 | path = NULL;
|
| 1135 | goto out;
|
| 1136 | }
|
| 1137 |
|
| 1138 | name = path + strlen(path);
|
| 1139 | do {
|
| 1140 |
|
| 1141 | namelen = scnprintf(name, namesize, CIFS_TMPNAME_PREFIX "%x",
|
| 1142 | atomic_inc_return(&cifs_tmpcounter));
|
| 1143 | rc = __cifs_do_create(dir, dentry, path, xid, tlink, oflags,
|
| 1144 | mode, &oplock, &fid, NULL, &inode, &opened);
|
| 1145 | if (!rc) {
|
| 1146 | rc = d_mark_tmpfile_name(file, &QSTR_LEN(name, namelen));
|
| 1147 | if (rc) {
|
| 1148 | cifs_dbg(VFS | ONCE, "%s: failed to set filename in dentry: %d\n",
|
| 1149 | __func__, rc);
|
| 1150 | rc = -EISDIR;
|
| 1151 | iput(inode);
|
| 1152 | goto err_open;
|
| 1153 | }
|
| 1154 | set_nlink(inode, 0);
|
| 1155 | mark_inode_dirty(inode);
|
| 1156 | d_instantiate(dentry, inode);
|
| 1157 | break;
|
| 1158 | }
|
| 1159 | } while (unlikely(rc == -EEXIST) && ++retries < max_retries);
|
| 1160 |
|
| 1161 | if (rc) {
|
| 1162 | if (rc == -ENOENT)
|
| 1163 | rc = -EOPNOTSUPP;
|
| 1164 | cifs_del_pending_open(&open);
|
| 1165 | goto out;
|
| 1166 | }
|
| 1167 |
|
| 1168 | rc = finish_open(file, dentry, generic_file_open);
|
| 1169 | if (rc)
|
| 1170 | goto err_open;
|
| 1171 |
|
| 1172 | sbflags = cifs_sb_flags(cifs_sb);
|
| 1173 | if ((file->f_flags & O_DIRECT) && (sbflags & CIFS_MOUNT_STRICT_IO)) {
|
| 1174 | if (sbflags & CIFS_MOUNT_NO_BRL)
|
| 1175 | file->f_op = &cifs_file_direct_nobrl_ops;
|
| 1176 | else
|
| 1177 | file->f_op = &cifs_file_direct_ops;
|
| 1178 | }
|
| 1179 |
|
| 1180 | cfile = cifs_new_fileinfo(&fid, file, tlink, oplock, NULL);
|
| 1181 | if (!cfile) {
|
| 1182 | rc = -ENOMEM;
|
| 1183 | goto err_open;
|
| 1184 | }
|
| 1185 |
|
| 1186 | rc = set_tmpfile_attr(xid, oflags, inode, path, server);
|
| 1187 | if (rc)
|
| 1188 | goto out;
|
| 1189 |
|
| 1190 | fscache_use_cookie(cifs_inode_cookie(file_inode(file)),
|
| 1191 | file->f_mode & FMODE_WRITE);
|
| 1192 | out:
|
| 1193 | cifs_put_tlink(tlink);
|
| 1194 | free_xid(xid);
|
| 1195 | return rc;
|
| 1196 | err_open:
|
| 1197 | cifs_del_pending_open(&open);
|
| 1198 | if (server->ops->close)
|
| 1199 | server->ops->close(xid, tcon, &fid);
|
| 1200 | goto out;
|
| 1201 | }
|
| 1202 |
|
| 1203 | char *cifs_silly_fullpath(struct dentry *dentry)
|
| 1204 | {
|
| 1205 | unsigned char name[CIFS_SILLYNAME_LEN + 1];
|
| 1206 | int retries = 0, max_retries = 16;
|
| 1207 | size_t namesize = sizeof(name);
|
| 1208 | struct dentry *sdentry = NULL;
|
| 1209 | char *path;
|
| 1210 |
|
| 1211 | do {
|
| 1212 | dput(sdentry);
|
| 1213 | scnprintf(name, namesize, CIFS_SILLYNAME_PREFIX "%x",
|
| 1214 | atomic_inc_return(&cifs_sillycounter));
|
| 1215 | sdentry = lookup_noperm(&QSTR(name), dentry->d_parent);
|
| 1216 | if (IS_ERR(sdentry))
|
| 1217 | return ERR_CAST(sdentry);
|
| 1218 | if (d_is_negative(sdentry)) {
|
| 1219 | dput(sdentry);
|
| 1220 | path = alloc_parent_path(dentry, CIFS_SILLYNAME_LEN);
|
| 1221 | if (!IS_ERR(path))
|
| 1222 | strcat(path, name);
|
| 1223 | return path;
|
| 1224 | }
|
| 1225 | } while (++retries < max_retries);
|
| 1226 | dput(sdentry);
|
| 1227 | return ERR_PTR(-EBUSY);
|
| 1228 | }
|
| 1229 |
|
| 1230 | const struct dentry_operations cifs_ci_dentry_ops = {
|
| 1231 | .d_revalidate = cifs_d_revalidate,
|
| 1232 | .d_hash = cifs_ci_hash,
|
| 1233 | .d_compare = cifs_ci_compare,
|
| 1234 | .d_automount = cifs_d_automount,
|
| 1235 | };
|