smb_common_search.c revision 7b59d02d2a384be9a08087b14defadd214b3c1dd
1073N/A/*
1073N/A * CDDL HEADER START
1073N/A *
1073N/A * The contents of this file are subject to the terms of the
1073N/A * Common Development and Distribution License (the "License").
1073N/A * You may not use this file except in compliance with the License.
1073N/A *
1073N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1073N/A * or http://www.opensolaris.org/os/licensing.
1073N/A * See the License for the specific language governing permissions
1073N/A * and limitations under the License.
1073N/A *
1073N/A * When distributing Covered Code, include this CDDL HEADER in each
1073N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1073N/A * If applicable, add the following below this CDDL HEADER, with the
1073N/A * fields enclosed by brackets "[]" replaced with your own identifying
1073N/A * information: Portions Copyright [yyyy] [name of copyright owner]
1073N/A *
1073N/A * CDDL HEADER END
1073N/A */
1073N/A/*
1073N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
1073N/A * Use is subject to license terms.
1073N/A */
1073N/A
1073N/A#pragma ident "%Z%%M% %I% %E% SMI"
1073N/A
1073N/A/*
1073N/A * Implementation of smb_rdir_open, smb_rdir_next and smb_rdir_close.
1073N/A */
1073N/A
1073N/A#include <smbsrv/smb_incl.h>
1073N/A#include <smbsrv/smb_fsops.h>
1245N/A
1245N/A/*
1073N/A * smb_rdir_open
1073N/A */
1073N/Aint
1073N/Asmb_rdir_open(smb_request_t *sr, char *path, unsigned short sattr)
1073N/A{
1073N/A smb_odir_t *od;
1073N/A smb_node_t *node;
1073N/A char *last_component;
1415N/A int rc;
1415N/A
1415N/A last_component = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1415N/A
1415N/A if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
1415N/A sr->tid_tree->t_snode, sr->tid_tree->t_snode,
1415N/A &node, last_component)) != 0) {
1415N/A kmem_free(last_component, MAXNAMELEN);
1415N/A smbsr_errno(sr, rc);
1415N/A return (-1);
1415N/A }
1415N/A
1415N/A if ((node->vp)->v_type != VDIR) {
1415N/A smb_node_release(node);
1415N/A kmem_free(last_component, MAXNAMELEN);
1415N/A smbsr_error(sr, 0, ERRDOS, ERRbadpath);
1415N/A return (-1);
1415N/A }
1415N/A
1415N/A rc = smb_fsop_access(sr, sr->user_cr, node, FILE_LIST_DIRECTORY);
1415N/A if (rc != 0) {
1415N/A smb_node_release(node);
1415N/A kmem_free(last_component, MAXNAMELEN);
1415N/A
1245N/A if (sr->smb_com == SMB_COM_SEARCH) {
1245N/A smbsr_warn(sr, NT_STATUS_NO_MORE_FILES,
1245N/A ERRDOS, ERROR_NO_MORE_FILES);
1073N/A return (-2);
1073N/A } else {
1073N/A smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
1073N/A ERRDOS, ERROR_ACCESS_DENIED);
1245N/A return (-1);
1245N/A }
1245N/A }
1245N/A
1245N/A od = smb_odir_open(sr->tid_tree, node, last_component, sr->smb_pid,
1245N/A sattr);
1245N/A kmem_free(last_component, sizeof (od->d_pattern));
1245N/A if (od == NULL) {
1245N/A smb_node_release(node);
1073N/A smbsr_error(sr, 0, ERRDOS, ERROR_NO_MORE_FILES);
1073N/A return (-1);
1073N/A }
1073N/A
1073N/A sr->smb_sid = od->d_sid;
1073N/A sr->sid_odir = od;
1100N/A return (0);
1100N/A}
1100N/A
1100N/A
1100N/A/*
1100N/A * smb_rdir_next
1100N/A *
1100N/A * Returns:
1100N/A * 0 Found an entry
1100N/A * ENOENT There is no (more) entry
1100N/A * error code An error happened
1100N/A */
1100N/Aint
1100N/Asmb_rdir_next(
1100N/A smb_request_t *sr,
1100N/A smb_node_t **rnode,
1100N/A smb_odir_context_t *pc)
1100N/A{
1100N/A struct smb_odir *dir;
1100N/A ino64_t fileid;
1100N/A int rc, n_name;
1100N/A char last_component[MAXNAMELEN];
1100N/A char namebuf[MAXNAMELEN];
1100N/A smb_node_t *tmp_snode;
1100N/A smb_node_t *dnode;
1100N/A smb_node_t *fnode;
1100N/A smb_attr_t ret_attr;
1415N/A
1100N/A ASSERT(sr->sid_odir);
1100N/A dir = sr->sid_odir;
1100N/A
1100N/A if (dir->d_state == SMB_ODIR_STATE_CLOSED) {
1073N/A return (ENOENT);
1073N/A }
1073N/A
1073N/A if (dir->d_wildcards == 0) {
1073N/A /* There are no wildcards in pattern */
1073N/A if (pc->dc_cookie != 0) {
1415N/A /* Already found entry... */
1415N/A return (ENOENT);
1073N/A }
1073N/A
1073N/A pc->dc_name[0] = '\0';
1073N/A pc->dc_shortname[0] = '\0';
1073N/A pc->dc_name83[0] = '\0';
1073N/A
1073N/A rc = smb_fsop_lookup(sr, sr->user_cr, 0,
1073N/A sr->tid_tree->t_snode, dir->d_dir_snode, dir->d_pattern,
1415N/A &fnode, &pc->dc_attr, pc->dc_shortname, pc->dc_name83);
1111N/A
1073N/A if (rc != 0)
1073N/A return (rc);
1415N/A
1415N/A /*
1073N/A * We are here if there was a successful lookup of the
1415N/A * name. The name may be a mangled name. If it was,
1073N/A * then shortname has the copy of it. So, we may
1073N/A * not need to do mangling later.
1073N/A *
1073N/A * dir->name will contain the case-preserved name.
1073N/A * If that name is not available (this should not
1073N/A * happen), then copy dir->pattern into dir->name.
1073N/A */
1073N/A
1073N/A if (fnode->od_name) {
1073N/A (void) strcpy(pc->dc_name, fnode->od_name);
1073N/A } else {
1073N/A (void) strcpy(pc->dc_name, dir->d_pattern);
1073N/A }
1073N/A
1073N/A /* Root of file system? */
1073N/A if ((strcmp(dir->d_pattern, "..") == 0) &&
1073N/A (dir->d_dir_snode == sr->tid_tree->t_snode)) {
1073N/A smb_node_release(fnode);
1073N/A smb_node_ref(sr->tid_tree->t_snode);
1073N/A fnode = sr->tid_tree->t_snode;
1073N/A } else if (pc->dc_attr.sa_vattr.va_type == VLNK) {
1073N/A (void) strcpy(namebuf, dir->d_pattern);
1073N/A
1073N/A tmp_snode = fnode;
1073N/A rc = smb_pathname_reduce(sr, sr->user_cr, namebuf,
1073N/A sr->tid_tree->t_snode, dir->d_dir_snode,
1073N/A &dnode, last_component);
1073N/A
1073N/A if (rc != 0) {
1073N/A fnode = tmp_snode;
1073N/A } else {
1073N/A rc = smb_fsop_lookup(sr, sr->user_cr,
1073N/A SMB_FOLLOW_LINKS, sr->tid_tree->t_snode,
1073N/A dnode, last_component, &fnode, &ret_attr,
1073N/A 0, 0);
1073N/A
1073N/A smb_node_release(dnode);
1073N/A if (rc != 0) {
1073N/A fnode = tmp_snode;
1073N/A } else {
1073N/A pc->dc_attr = ret_attr;
1073N/A smb_node_release(tmp_snode);
1073N/A }
1073N/A }
1073N/A }
1073N/A
1073N/A pc->dc_dattr = smb_node_get_dosattr(fnode);
1073N/A /*
1073N/A * If name not already mangled, do it.
1073N/A *
1073N/A * The name will only be mangled if smb_needs_mangle()
1073N/A * determines that it is required. Mangling due to
1073N/A * case-insensitive collisions is not necessary here.
1073N/A */
1073N/A if (pc->dc_name83[0] == '\0')
1073N/A (void) smb_mangle_name(fnode->attr.sa_vattr.va_nodeid,
1073N/A pc->dc_name, pc->dc_shortname, pc->dc_name83, 0);
1073N/A if (rnode)
1073N/A *rnode = fnode;
1073N/A else
1073N/A smb_node_release(fnode);
1073N/A
1073N/A pc->dc_cookie = (uint32_t)-1;
1073N/A return (0);
1073N/A } /* No wild card search */
1073N/A
1073N/A for (;;) {
1073N/A if (dir->d_state == SMB_ODIR_STATE_CLOSED) {
1073N/A return (ENOENT);
1073N/A }
1073N/A
1073N/A /* sizeof dir->name == 256 */
1073N/A n_name = (sizeof (pc->dc_name)) - 1;
1073N/A
1073N/A rc = smb_fsop_readdir(sr, sr->user_cr, dir->d_dir_snode,
1073N/A &pc->dc_cookie, pc->dc_name, &n_name, &fileid, NULL,
1073N/A NULL, NULL);
1073N/A if (rc != 0) {
1073N/A return (rc);
1073N/A }
1073N/A
1073N/A if (n_name == 0) /* EOF */
1073N/A break;
1073N/A pc->dc_name[n_name] = '\0';
1073N/A
1073N/A /*
1073N/A * Don't return "." or ".." unless SMB_FA_HIDDEN bit is set
1073N/A * We have to code these specially since we cannot set the
1073N/A * SMB_FA_HIDDEN bits in these because they are simply links to
1073N/A * the real directory and the real directory is NOT hidden.
1073N/A */
1073N/A if (((dir->d_sattr & SMB_FA_HIDDEN) == 0) &&
1073N/A ((strcmp(pc->dc_name, ".") == 0) ||
1073N/A ((strcmp(pc->dc_name, "..") == 0)))) {
1073N/A continue;
1073N/A }
1073N/A
1073N/A /* may match a mangled name or "real" name */
1073N/A if (smb_component_match(sr, fileid, dir, pc) <= 0)
1073N/A continue;
1073N/A
1073N/A /* Look up the "real" name */
1073N/A rc = smb_fsop_lookup(sr, sr->user_cr, 0, sr->tid_tree->t_snode,
1073N/A dir->d_dir_snode, pc->dc_name, &fnode, &pc->dc_attr, 0, 0);
1245N/A
1245N/A if (rc != 0) {
1245N/A if (rc != ENOENT)
1245N/A return (rc);
1245N/A
1245N/A continue;
1245N/A }
1073N/A
1073N/A /* Root of file system? */
1073N/A if ((strcmp(pc->dc_name, "..") == 0) &&
1073N/A (dir->d_dir_snode == sr->tid_tree->t_snode)) {
1073N/A smb_node_release(fnode);
1073N/A smb_node_ref(sr->tid_tree->t_snode);
1073N/A fnode = sr->tid_tree->t_snode;
1073N/A } else if (pc->dc_attr.sa_vattr.va_type == VLNK) {
1073N/A (void) strcpy(namebuf, pc->dc_name);
1073N/A
1073N/A smb_node_release(fnode);
1073N/A rc = smb_pathname_reduce(sr, sr->user_cr, namebuf,
1073N/A sr->tid_tree->t_snode, dir->d_dir_snode, &dnode,
1073N/A last_component);
1073N/A
1073N/A if (rc != 0) {
1073N/A continue;
1073N/A }
1073N/A
1073N/A rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
1073N/A sr->tid_tree->t_snode, dnode, last_component,
1073N/A &fnode, &ret_attr, 0, 0);
1073N/A
1073N/A smb_node_release(dnode);
1073N/A if (rc != 0) {
1073N/A continue;
1073N/A }
1073N/A pc->dc_attr = ret_attr;
1073N/A }
1073N/A
1073N/A pc->dc_dattr = smb_node_get_dosattr(fnode);
1073N/A
1073N/A /* Obey search attributes */
1073N/A if ((pc->dc_dattr & SMB_FA_DIRECTORY) &&
1073N/A !(dir->d_sattr & SMB_FA_DIRECTORY)) {
1073N/A smb_node_release(fnode);
1073N/A continue;
1073N/A }
1073N/A
1073N/A if ((pc->dc_dattr & SMB_FA_HIDDEN) &&
1073N/A !(dir->d_sattr & SMB_FA_HIDDEN)) {
1073N/A smb_node_release(fnode);
1073N/A continue;
1073N/A }
1073N/A
1073N/A if ((pc->dc_dattr & SMB_FA_SYSTEM) &&
1073N/A !(dir->d_sattr & SMB_FA_SYSTEM)) {
1073N/A smb_node_release(fnode);
1073N/A continue;
1073N/A }
1073N/A
1073N/A if (rnode)
1073N/A *rnode = fnode;
1073N/A else
1073N/A smb_node_release(fnode);
1073N/A
1073N/A return (0);
1073N/A }
1073N/A
1073N/A return (ENOENT);
1073N/A}
1073N/A
1073N/A/*
1073N/A * smb_rdir_close
1073N/A */
1073N/Avoid
1073N/Asmb_rdir_close(struct smb_request *sr)
1073N/A{
1073N/A smb_odir_t *od = sr->sid_odir;
1073N/A
1073N/A ASSERT(od);
1073N/A ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1073N/A
1073N/A smb_odir_close(od);
1073N/A smb_odir_release(od);
1073N/A sr->sid_odir = NULL;
1073N/A}
1073N/A