⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pvfs_resolve.c

📁 samba最新软件
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    Unix SMB/CIFS implementation.   POSIX NTVFS backend - filename resolution   Copyright (C) Andrew Tridgell 2004   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 3 of the License, or   (at your option) any later version.      This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.      You should have received a copy of the GNU General Public License   along with this program.  If not, see <http://www.gnu.org/licenses/>.*//*  this is the core code for converting a filename from the format as  given by a client to a posix filename, including any case-matching  required, and checks for legal characters*/#include "includes.h"#include "vfs_posix.h"#include "system/dir.h"#include "param/param.h"/**  compare two filename components. This is where the name mangling hook will go*/static int component_compare(struct pvfs_state *pvfs, const char *comp, const char *name){	int ret;	ret = strcasecmp_m(comp, name);	if (ret != 0) {		char *shortname = pvfs_short_name_component(pvfs, name);		if (shortname) {			ret = strcasecmp_m(comp, shortname);			talloc_free(shortname);		}	}	return ret;}/*  search for a filename in a case insensitive fashion  TODO: add a cache for previously resolved case-insensitive names  TODO: add mangled name support*/static NTSTATUS pvfs_case_search(struct pvfs_state *pvfs, struct pvfs_filename *name){	/* break into a series of components */	int num_components;	char **components;	char *p, *partial_name;	int i;	/* break up the full name info pathname components */	num_components=2;	p = name->full_name + strlen(pvfs->base_directory) + 1;	for (;*p;p++) {		if (*p == '/') {			num_components++;		}	}	components = talloc_array(name, char *, num_components);	p = name->full_name + strlen(pvfs->base_directory);	*p++ = 0;	components[0] = name->full_name;	for (i=1;i<num_components;i++) {		components[i] = p;		p = strchr(p, '/');		if (p) *p++ = 0;		if (pvfs_is_reserved_name(pvfs, components[i])) {			return NT_STATUS_ACCESS_DENIED;		}	}	partial_name = talloc_strdup(name, components[0]);	if (!partial_name) {		return NT_STATUS_NO_MEMORY;	}	/* for each component, check if it exists as-is, and if not then	   do a directory scan */	for (i=1;i<num_components;i++) {		char *test_name;		DIR *dir;		struct dirent *de;		char *long_component;		/* possibly remap from the short name cache */		long_component = pvfs_mangled_lookup(pvfs, name, components[i]);		if (long_component) {			components[i] = long_component;		}		test_name = talloc_asprintf(name, "%s/%s", partial_name, components[i]);		if (!test_name) {			return NT_STATUS_NO_MEMORY;		}		/* check if this component exists as-is */		if (stat(test_name, &name->st) == 0) {			if (i<num_components-1 && !S_ISDIR(name->st.st_mode)) {				return NT_STATUS_OBJECT_PATH_NOT_FOUND;			}			talloc_free(partial_name);			partial_name = test_name;			if (i == num_components - 1) {				name->exists = true;			}			continue;		}		/* the filesystem might be case insensitive, in which		   case a search is pointless unless the name is		   mangled */		if ((pvfs->flags & PVFS_FLAG_CI_FILESYSTEM) &&		    !pvfs_is_mangled_component(pvfs, components[i])) {			if (i < num_components-1) {				return NT_STATUS_OBJECT_PATH_NOT_FOUND;			}			partial_name = test_name;			continue;		}				dir = opendir(partial_name);		if (!dir) {			return pvfs_map_errno(pvfs, errno);		}		while ((de = readdir(dir))) {			if (component_compare(pvfs, components[i], de->d_name) == 0) {				break;			}		}		if (!de) {			if (i < num_components-1) {				closedir(dir);				return NT_STATUS_OBJECT_PATH_NOT_FOUND;			}		} else {			components[i] = talloc_strdup(name, de->d_name);		}		test_name = talloc_asprintf(name, "%s/%s", partial_name, components[i]);		talloc_free(partial_name);		partial_name = test_name;		closedir(dir);	}	if (!name->exists) {		if (stat(partial_name, &name->st) == 0) {			name->exists = true;		}	}	talloc_free(name->full_name);	name->full_name = partial_name;	if (name->exists) {		return pvfs_fill_dos_info(pvfs, name, -1);	}	return NT_STATUS_OK;}/*  parse a alternate data stream name*/static NTSTATUS parse_stream_name(struct pvfs_filename *name, const char *s){	char *p;	name->stream_name = talloc_strdup(name, s+1);	if (name->stream_name == NULL) {		return NT_STATUS_NO_MEMORY;	}	p = strchr_m(name->stream_name, ':');	if (p == NULL) {		name->stream_id = pvfs_name_hash(name->stream_name, 						 strlen(name->stream_name));		return NT_STATUS_OK;	}	if (strcasecmp_m(p, ":$DATA") != 0) {		return NT_STATUS_OBJECT_NAME_INVALID;	}	*p = 0;	if (strcmp(name->stream_name, "") == 0) {		/*		 * we don't set stream_name to NULL, here		 * as this would be wrong for directories		 *		 * pvfs_fill_dos_info() will set it to NULL		 * if it's not a directory.		 */		name->stream_id = 0;	} else {		name->stream_id = pvfs_name_hash(name->stream_name, 						 strlen(name->stream_name));	}						 	return NT_STATUS_OK;	}/*  convert a CIFS pathname to a unix pathname. Note that this does NOT  take into account case insensitivity, and in fact does not access  the filesystem at all. It is merely a reformatting and charset  checking routine.  errors are returned if the filename is illegal given the flags*/static NTSTATUS pvfs_unix_path(struct pvfs_state *pvfs, const char *cifs_name,			       uint_t flags, struct pvfs_filename *name){	char *ret, *p, *p_start;	NTSTATUS status;	name->original_name = talloc_strdup(name, cifs_name);	name->stream_name = NULL;	name->stream_id = 0;	name->has_wildcard = false;	while (*cifs_name == '\\') {		cifs_name++;	}	if (*cifs_name == 0) {		name->full_name = talloc_asprintf(name, "%s/.", pvfs->base_directory);		if (name->full_name == NULL) {			return NT_STATUS_NO_MEMORY;		}		return NT_STATUS_OK;	}	ret = talloc_asprintf(name, "%s/%s", pvfs->base_directory, cifs_name);	if (ret == NULL) {		return NT_STATUS_NO_MEMORY;	}	p = ret + strlen(pvfs->base_directory) + 1;	/* now do an in-place conversion of '\' to '/', checking	   for legal characters */	p_start = p;	while (*p) {		size_t c_size;		codepoint_t c = next_codepoint(lp_iconv_convenience(pvfs->ntvfs->ctx->lp_ctx), p, &c_size);		switch (c) {		case '\\':			if (name->has_wildcard) {				/* wildcards are only allowed in the last part				   of a name */				return NT_STATUS_ILLEGAL_CHARACTER;			}			if (p > p_start && (p[1] == '\\' || p[1] == '\0')) {				/* see if it is definately a "\\" or				 * a trailing "\". If it is then fail here,				 * and let the next layer up try again after				 * pvfs_reduce_name() if it wants to. This is				 * much more efficient on average than always				 * scanning for these separately				 */				return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;			} else {				*p = '/';			}			break;		case ':':			if (!(flags & PVFS_RESOLVE_STREAMS)) {				return NT_STATUS_ILLEGAL_CHARACTER;			}			if (name->has_wildcard) {				return NT_STATUS_ILLEGAL_CHARACTER;			}			status = parse_stream_name(name, p);			if (!NT_STATUS_IS_OK(status)) {				return status;			}			*p-- = 0;			break;		case '*':		case '>':		case '<':		case '?':		case '"':			if (!(flags & PVFS_RESOLVE_WILDCARD)) {				return NT_STATUS_OBJECT_NAME_INVALID;			}			name->has_wildcard = true;			break;		case '/':		case '|':			return NT_STATUS_ILLEGAL_CHARACTER;		case '.':			/* see if it is definately a .. or			   . component. If it is then fail here, and			   let the next layer up try again after			   pvfs_reduce_name() if it wants to. This is			   much more efficient on average than always			   scanning for these separately */			if (p[1] == '.' && 			    (p[2] == 0 || p[2] == '\\') &&			    (p == p_start || p[-1] == '/')) {				return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;			}			if ((p[1] == 0 || p[1] == '\\') &&			    (p == p_start || p[-1] == '/')) {				return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;			}			break;		}		p += c_size;	}	name->full_name = ret;	return NT_STATUS_OK;}/*  reduce a name that contains .. components or repeated \ separators  return NULL if it can't be reduced*/static NTSTATUS pvfs_reduce_name(TALLOC_CTX *mem_ctx, 				 struct smb_iconv_convenience *iconv_convenience, 				 const char **fname, uint_t flags){	codepoint_t c;	size_t c_size, len;	int i, num_components, err_count;	char **components;	char *p, *s, *ret;	s = talloc_strdup(mem_ctx, *fname);	if (s == NULL) return NT_STATUS_NO_MEMORY;	for (num_components=1, p=s; *p; p += c_size) {		c = next_codepoint(iconv_convenience, p, &c_size);		if (c == '\\') num_components++;	}	components = talloc_array(s, char *, num_components+1);	if (components == NULL) {		talloc_free(s);		return NT_STATUS_NO_MEMORY;	}	components[0] = s;	for (i=0, p=s; *p; p += c_size) {		c = next_codepoint(iconv_convenience, p, &c_size);		if (c == '\\') {			*p = 0;			components[++i] = p+1;		}	}	components[i+1] = NULL;	/*	  rather bizarre!

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -