/* * Find snapshot node corresponding to 'node', and return it in * 'vss_node', as follows: * - find the path from fsrootvp to node, appending it to the * the snapshot path * - lookup the vnode and smb_node (vss_node). */ static int smb_vss_lookup_node(smb_request_t *sr, smb_node_t *node, vnode_t *fsrootvp, char *snapname, smb_node_t *dnode, smb_node_t **vss_node) { char *p, *path; int err, len; vnode_t *vp = NULL; *vss_node = NULL; path = kmem_alloc(MAXPATHLEN, KM_SLEEP); (void) snprintf(path, MAXPATHLEN, ".zfs/snapshot/%s/", snapname); len = strlen(path); p = path + len; err = smb_node_getpath(node, fsrootvp, p, MAXPATHLEN - len); if (err == 0) { vp = smb_lookuppathvptovp(sr, path, fsrootvp, fsrootvp); if (vp) { *vss_node = smb_node_lookup(sr, NULL, zone_kcred(), vp, snapname, dnode, NULL); VN_RELE(vp); } } kmem_free(path, MAXPATHLEN); if (*vss_node != NULL) return (0); return (err ? err : ENOENT); }
/* * smb_odir_openat * * Create an odir representing the extended attribute directory * associated with the file (or directory) represented by unode. * * Returns: * odid - Unique identifier of newly created odir. * 0 - error, error details set in sr. */ uint16_t smb_odir_openat(smb_request_t *sr, smb_node_t *unode) { int rc; vnode_t *xattr_dvp; uint16_t odid; cred_t *cr; char pattern[SMB_STREAM_PREFIX_LEN + 2]; smb_node_t *xattr_dnode; ASSERT(sr); ASSERT(sr->sr_magic == SMB_REQ_MAGIC); ASSERT(unode); ASSERT(unode->n_magic == SMB_NODE_MAGIC); if (SMB_TREE_CONTAINS_NODE(sr, unode) == 0 || SMB_TREE_HAS_ACCESS(sr, ACE_LIST_DIRECTORY) == 0) { smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERROR_ACCESS_DENIED); return (0); } cr = zone_kcred(); /* find the xattrdir vnode */ rc = smb_vop_lookup_xattrdir(unode->vp, &xattr_dvp, LOOKUP_XATTR, cr); if (rc != 0) { smbsr_errno(sr, rc); return (0); } /* lookup the xattrdir's smb_node */ xattr_dnode = smb_node_lookup(sr, NULL, cr, xattr_dvp, XATTR_DIR, unode, NULL); VN_RELE(xattr_dvp); if (xattr_dnode == NULL) { smbsr_error(sr, NT_STATUS_NO_MEMORY, ERRDOS, ERROR_NOT_ENOUGH_MEMORY); return (0); } (void) snprintf(pattern, sizeof (pattern), "%s*", SMB_STREAM_PREFIX); odid = smb_odir_create(sr, xattr_dnode, pattern, SMB_SEARCH_ATTRIBUTES, cr); smb_node_release(xattr_dnode); return (odid); }
int smb_pathname(smb_request_t *sr, char *path, int flags, smb_node_t *root_node, smb_node_t *cur_node, smb_node_t **dir_node, smb_node_t **ret_node, cred_t *cred) { char *component, *real_name, *namep; pathname_t pn, rpn, upn, link_pn; smb_node_t *dnode, *fnode; smb_attr_t attr; vnode_t *rootvp, *vp; size_t pathleft; int err = 0; int nlink = 0; int local_flags; uint32_t abe_flag = 0; char namebuf[MAXNAMELEN]; if (path == NULL) return (EINVAL); ASSERT(root_node); ASSERT(cur_node); ASSERT(ret_node); *ret_node = NULL; if (dir_node) *dir_node = NULL; (void) pn_alloc(&upn); if ((err = pn_set(&upn, path)) != 0) { (void) pn_free(&upn); return (err); } if (SMB_TREE_SUPPORTS_ABE(sr)) abe_flag = SMB_ABE; (void) pn_alloc(&pn); (void) pn_alloc(&rpn); component = kmem_alloc(MAXNAMELEN, KM_SLEEP); real_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); fnode = NULL; dnode = cur_node; smb_node_ref(dnode); rootvp = root_node->vp; while ((pathleft = pn_pathleft(&upn)) != 0) { if (fnode) { smb_node_release(dnode); dnode = fnode; fnode = NULL; } if ((err = pn_getcomponent(&upn, component)) != 0) break; if ((namep = smb_pathname_catia_v5tov4(sr, component, namebuf, sizeof (namebuf))) == NULL) { err = EILSEQ; break; } if ((err = pn_set(&pn, namep)) != 0) break; local_flags = flags & FIGNORECASE; err = smb_pathname_lookup(&pn, &rpn, local_flags, &vp, rootvp, dnode->vp, &attr, cred); if (err) { if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) || !smb_maybe_mangled(component)) break; if ((err = smb_unmangle(dnode, component, real_name, MAXNAMELEN, abe_flag)) != 0) break; if ((namep = smb_pathname_catia_v5tov4(sr, real_name, namebuf, sizeof (namebuf))) == NULL) { err = EILSEQ; break; } if ((err = pn_set(&pn, namep)) != 0) break; local_flags = 0; err = smb_pathname_lookup(&pn, &rpn, local_flags, &vp, rootvp, dnode->vp, &attr, cred); if (err) break; } /* * This check MUST be done before symlink check * since a reparse point is of type VLNK but should * not be handled like a regular symlink. */ if (attr.sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) { err = EREMOTE; VN_RELE(vp); break; } if ((vp->v_type == VLNK) && ((flags & FOLLOW) || pn_pathleft(&upn))) { if (++nlink > MAXSYMLINKS) { err = ELOOP; VN_RELE(vp); break; } (void) pn_alloc(&link_pn); err = pn_getsymlink(vp, &link_pn, cred); VN_RELE(vp); if (err == 0) { if (pn_pathleft(&link_pn) == 0) (void) pn_set(&link_pn, "."); err = pn_insert(&upn, &link_pn, strlen(component)); } pn_free(&link_pn); if (err) break; if (upn.pn_pathlen == 0) { err = ENOENT; break; } if (upn.pn_path[0] == '/') { fnode = root_node; smb_node_ref(fnode); } if (pn_fixslash(&upn)) flags |= FOLLOW; } else { if (flags & FIGNORECASE) { if (strcmp(rpn.pn_path, "/") != 0) pn_setlast(&rpn); namep = rpn.pn_path; } else { namep = pn.pn_path; } namep = smb_pathname_catia_v4tov5(sr, namep, namebuf, sizeof (namebuf)); fnode = smb_node_lookup(sr, NULL, cred, vp, namep, dnode, NULL); VN_RELE(vp); if (fnode == NULL) { err = ENOMEM; break; } } while (upn.pn_path[0] == '/') { upn.pn_path++; upn.pn_pathlen--; } } if ((pathleft) && (err == ENOENT)) err = ENOTDIR; if (err) { if (fnode) smb_node_release(fnode); if (dnode) smb_node_release(dnode); } else { *ret_node = fnode; if (dir_node) *dir_node = dnode; else smb_node_release(dnode); } kmem_free(component, MAXNAMELEN); kmem_free(real_name, MAXNAMELEN); (void) pn_free(&pn); (void) pn_free(&rpn); (void) pn_free(&upn); return (err); }