trans2.c

来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 2,183 行 · 第 1/5 页

C
2,183
字号
/*    Unix SMB/CIFS implementation.   SMB transaction2 handling   Copyright (C) Jeremy Allison			1994-2003   Copyright (C) Stefan (metze) Metzmacher	2003   Copyright (C) Volker Lendecke		2005   Copyright (C) Steve French			2005   Extensively modified by Andrew Tridgell, 1995   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 2 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, write to the Free Software   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include "includes.h"extern int max_send;extern enum protocol_types Protocol;extern int smb_read_error;extern uint32 global_client_caps;extern struct current_user current_user;#define get_file_size(sbuf) ((sbuf).st_size)#define DIR_ENTRY_SAFETY_MARGIN 4096/******************************************************************** Roundup a value to the nearest allocation roundup size boundary. Only do this for Windows clients.********************************************************************/SMB_BIG_UINT smb_roundup(connection_struct *conn, SMB_BIG_UINT val){	SMB_BIG_UINT rval = lp_allocation_roundup_size(SNUM(conn));	/* Only roundup for Windows clients. */	enum remote_arch_types ra_type = get_remote_arch();	if (rval && (ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {		val = SMB_ROUNDUP(val,rval);	}	return val;}/******************************************************************** Given a stat buffer return the allocated size on disk, taking into account sparse files.********************************************************************/SMB_BIG_UINT get_allocation_size(connection_struct *conn, files_struct *fsp, SMB_STRUCT_STAT *sbuf){	SMB_BIG_UINT ret;	if(S_ISDIR(sbuf->st_mode)) {		return 0;	}#if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)	ret = (SMB_BIG_UINT)STAT_ST_BLOCKSIZE * (SMB_BIG_UINT)sbuf->st_blocks;#else	ret = (SMB_BIG_UINT)get_file_size(*sbuf);#endif	if (fsp && fsp->initial_allocation_size)		ret = MAX(ret,fsp->initial_allocation_size);	return smb_roundup(conn, ret);}/**************************************************************************** Utility functions for dealing with extended attributes.****************************************************************************/static const char *prohibited_ea_names[] = {	SAMBA_POSIX_INHERITANCE_EA_NAME,	SAMBA_XATTR_DOS_ATTRIB,	NULL};/**************************************************************************** Refuse to allow clients to overwrite our private xattrs.****************************************************************************/static BOOL samba_private_attr_name(const char *unix_ea_name){	int i;	for (i = 0; prohibited_ea_names[i]; i++) {		if (strequal( prohibited_ea_names[i], unix_ea_name))			return True;	}	return False;}/**************************************************************************** Get one EA value. Fill in a struct ea_struct.****************************************************************************/static BOOL get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,				const char *fname, char *ea_name, struct ea_struct *pea){	/* Get the value of this xattr. Max size is 64k. */	size_t attr_size = 256;	char *val = NULL;	ssize_t sizeret; again:	val = TALLOC_REALLOC_ARRAY(mem_ctx, val, char, attr_size);	if (!val) {		return False;	}	if (fsp && fsp->fh->fd != -1) {		sizeret = SMB_VFS_FGETXATTR(fsp, fsp->fh->fd, ea_name, val, attr_size);	} else {		sizeret = SMB_VFS_GETXATTR(conn, fname, ea_name, val, attr_size);	}	if (sizeret == -1 && errno == ERANGE && attr_size != 65536) {		attr_size = 65536;		goto again;	}	if (sizeret == -1) {		return False;	}	DEBUG(10,("get_ea_value: EA %s is of length %u: ", ea_name, (unsigned int)sizeret));	dump_data(10, val, sizeret);	pea->flags = 0;	if (strnequal(ea_name, "user.", 5)) {		pea->name = &ea_name[5];	} else {		pea->name = ea_name;	}	pea->value.data = (unsigned char *)val;	pea->value.length = (size_t)sizeret;	return True;}/**************************************************************************** Return a linked list of the total EA's. Plus the total size****************************************************************************/static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,					const char *fname, size_t *pea_total_len){	/* Get a list of all xattrs. Max namesize is 64k. */	size_t ea_namelist_size = 1024;	char *ea_namelist;	char *p;	ssize_t sizeret;	int i;	struct ea_list *ea_list_head = NULL;	*pea_total_len = 0;	if (!lp_ea_support(SNUM(conn))) {		return NULL;	}	for (i = 0, ea_namelist = TALLOC(mem_ctx, ea_namelist_size); i < 6;			ea_namelist = TALLOC_REALLOC_ARRAY(mem_ctx, ea_namelist, char, ea_namelist_size), i++) {		if (fsp && fsp->fh->fd != -1) {			sizeret = SMB_VFS_FLISTXATTR(fsp, fsp->fh->fd, ea_namelist, ea_namelist_size);		} else {			sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist, ea_namelist_size);		}		if (sizeret == -1 && errno == ERANGE) {			ea_namelist_size *= 2;		} else {			break;		}	}	if (sizeret == -1)		return NULL;	DEBUG(10,("get_ea_list_from_file: ea_namelist size = %u\n", (unsigned int)sizeret ));	if (sizeret) {		for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p) + 1) {			struct ea_list *listp, *tmp;			if (strnequal(p, "system.", 7) || samba_private_attr_name(p))				continue;					listp = TALLOC_P(mem_ctx, struct ea_list);			if (!listp)				return NULL;			if (!get_ea_value(mem_ctx, conn, fsp, fname, p, &listp->ea)) {				return NULL;			}			{				fstring dos_ea_name;				push_ascii_fstring(dos_ea_name, listp->ea.name);				*pea_total_len += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;				DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len = %u\n",					(unsigned int)*pea_total_len, dos_ea_name,					(unsigned int)listp->ea.value.length ));			}			DLIST_ADD_END(ea_list_head, listp, tmp);		}		/* Add on 4 for total length. */		if (*pea_total_len) {			*pea_total_len += 4;		}	}	DEBUG(10,("get_ea_list_from_file: total_len = %u\n", (unsigned int)*pea_total_len));	return ea_list_head;}/**************************************************************************** Fill a qfilepathinfo buffer with EA's. Returns the length of the buffer that was filled.****************************************************************************/static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned int total_data_size,	connection_struct *conn, struct ea_list *ea_list){	unsigned int ret_data_size = 4;	char *p = pdata;	SMB_ASSERT(total_data_size >= 4);	if (!lp_ea_support(SNUM(conn))) {		SIVAL(pdata,4,0);		return 4;	}	for (p = pdata + 4; ea_list; ea_list = ea_list->next) {		size_t dos_namelen;		fstring dos_ea_name;		push_ascii_fstring(dos_ea_name, ea_list->ea.name);		dos_namelen = strlen(dos_ea_name);		if (dos_namelen > 255 || dos_namelen == 0) {			break;		}		if (ea_list->ea.value.length > 65535) {			break;		}		if (4 + dos_namelen + 1 + ea_list->ea.value.length > total_data_size) {			break;		}		/* We know we have room. */		SCVAL(p,0,ea_list->ea.flags);		SCVAL(p,1,dos_namelen);		SSVAL(p,2,ea_list->ea.value.length);		fstrcpy(p+4, dos_ea_name);		memcpy( p + 4 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);		total_data_size -= 4 + dos_namelen + 1 + ea_list->ea.value.length;		p += 4 + dos_namelen + 1 + ea_list->ea.value.length;	}	ret_data_size = PTR_DIFF(p, pdata);	DEBUG(10,("fill_ea_buffer: data_size = %u\n", ret_data_size ));	SIVAL(pdata,0,ret_data_size);	return ret_data_size;}static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, const char *fname){	size_t total_ea_len = 0;	TALLOC_CTX *mem_ctx = NULL;	if (!lp_ea_support(SNUM(conn))) {		return 0;	}	mem_ctx = talloc_init("estimate_ea_size");	(void)get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);	talloc_destroy(mem_ctx);	return total_ea_len;}/**************************************************************************** Ensure the EA name is case insensitive by matching any existing EA name.****************************************************************************/static void canonicalize_ea_name(connection_struct *conn, files_struct *fsp, const char *fname, fstring unix_ea_name){	size_t total_ea_len;	TALLOC_CTX *mem_ctx = talloc_init("canonicalize_ea_name");	struct ea_list *ea_list = get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);	for (; ea_list; ea_list = ea_list->next) {		if (strequal(&unix_ea_name[5], ea_list->ea.name)) {			DEBUG(10,("canonicalize_ea_name: %s -> %s\n",				&unix_ea_name[5], ea_list->ea.name));			safe_strcpy(&unix_ea_name[5], ea_list->ea.name, sizeof(fstring)-6);			break;		}	}	talloc_destroy(mem_ctx);}/**************************************************************************** Set or delete an extended attribute.****************************************************************************/NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const char *fname, struct ea_list *ea_list){	if (!lp_ea_support(SNUM(conn))) {		return NT_STATUS_EAS_NOT_SUPPORTED;	}	for (;ea_list; ea_list = ea_list->next) {		int ret;		fstring unix_ea_name;		fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */		fstrcat(unix_ea_name, ea_list->ea.name);		canonicalize_ea_name(conn, fsp, fname, unix_ea_name);		DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, (unsigned int)ea_list->ea.value.length));		if (samba_private_attr_name(unix_ea_name)) {			DEBUG(10,("set_ea: ea name %s is a private Samba name.\n", unix_ea_name));			return NT_STATUS_ACCESS_DENIED;		}		if (ea_list->ea.value.length == 0) {			/* Remove the attribute. */			if (fsp && (fsp->fh->fd != -1)) {				DEBUG(10,("set_ea: deleting ea name %s on file %s by file descriptor.\n",					unix_ea_name, fsp->fsp_name));				ret = SMB_VFS_FREMOVEXATTR(fsp, fsp->fh->fd, unix_ea_name);			} else {				DEBUG(10,("set_ea: deleting ea name %s on file %s.\n",					unix_ea_name, fname));				ret = SMB_VFS_REMOVEXATTR(conn, fname, unix_ea_name);			}#ifdef ENOATTR			/* Removing a non existent attribute always succeeds. */			if (ret == -1 && errno == ENOATTR) {				DEBUG(10,("set_ea: deleting ea name %s didn't exist - succeeding by default.\n",						unix_ea_name));				ret = 0;			}#endif		} else {			if (fsp && (fsp->fh->fd != -1)) {				DEBUG(10,("set_ea: setting ea name %s on file %s by file descriptor.\n",					unix_ea_name, fsp->fsp_name));				ret = SMB_VFS_FSETXATTR(fsp, fsp->fh->fd, unix_ea_name,							ea_list->ea.value.data, ea_list->ea.value.length, 0);			} else {				DEBUG(10,("set_ea: setting ea name %s on file %s.\n",					unix_ea_name, fname));				ret = SMB_VFS_SETXATTR(conn, fname, unix_ea_name,							ea_list->ea.value.data, ea_list->ea.value.length, 0);			}		}		if (ret == -1) {#ifdef ENOTSUP			if (errno == ENOTSUP) {				return NT_STATUS_EAS_NOT_SUPPORTED;			}#endif			return map_nt_error_from_unix(errno);		}	}	return NT_STATUS_OK;}/**************************************************************************** Read a list of EA names from an incoming data buffer. Create an ea_list with them.****************************************************************************/static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size){	struct ea_list *ea_list_head = NULL;	size_t offset = 0;	while (offset + 2 < data_size) {		struct ea_list *tmp;		struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);		unsigned int namelen = CVAL(pdata,offset);		offset++; /* Go past the namelen byte. */		/* integer wrap paranioa. */		if ((offset + namelen < offset) || (offset + namelen < namelen) ||				(offset > data_size) || (namelen > data_size) ||				(offset + namelen >= data_size)) {			break;		}		/* Ensure the name is null terminated. */		if (pdata[offset + namelen] != '\0') {			return NULL;		}		pull_ascii_talloc(ctx, &eal->ea.name, &pdata[offset]);		if (!eal->ea.name) {			return NULL;		}		offset += (namelen + 1); /* Go past the name + terminating zero. */		DLIST_ADD_END(ea_list_head, eal, tmp);		DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name));	}	return ea_list_head;}/**************************************************************************** Read one EA list entry from the buffer.****************************************************************************/struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used){	struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);	uint16 val_len;	unsigned int namelen;	if (!eal) {		return NULL;	}	if (data_size < 6) {

⌨️ 快捷键说明

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