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

📄 proc.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  proc.c * *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke *  Copyright (C) 1997 by Volker Lendecke * *  Please add a note about your changes to smbfs in the ChangeLog file. */#include <linux/types.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/fs.h>#include <linux/file.h>#include <linux/stat.h>#include <linux/fcntl.h>#include <linux/dcache.h>#include <linux/dirent.h>#include <linux/nls.h>#include <linux/smb_fs.h>#include <linux/smbno.h>#include <linux/smb_mount.h>#include <asm/string.h>#include <asm/div64.h>#include "smb_debug.h"#include "proto.h"/* Features. Undefine if they cause problems, this should perhaps be a   config option. */#define SMBFS_POSIX_UNLINK 1/* Allow smb_retry to be interrupted. */#define SMB_RETRY_INTR#define SMB_VWV(packet)  ((packet) + SMB_HEADER_LEN)#define SMB_CMD(packet)  (*(packet+8))#define SMB_WCT(packet)  (*(packet+SMB_HEADER_LEN - 1))#define SMB_BCC(packet)  smb_bcc(packet)#define SMB_BUF(packet)  ((packet) + SMB_HEADER_LEN + SMB_WCT(packet) * 2 + 2)#define SMB_DIRINFO_SIZE 43#define SMB_STATUS_SIZE  21#define SMB_ST_BLKSIZE	(PAGE_SIZE)#define SMB_ST_BLKSHIFT	(PAGE_SHIFT)static intsmb_proc_setattr_ext(struct smb_sb_info *, struct inode *,		     struct smb_fattr *);static intsmb_proc_setattr_core(struct smb_sb_info *server, struct dentry *dentry,                      __u16 attr);static intsmb_proc_do_getattr(struct smb_sb_info *server, struct dentry *dir,		    struct smb_fattr *fattr);static voidstr_upper(char *name, int len){	while (len--)	{		if (*name >= 'a' && *name <= 'z')			*name -= ('a' - 'A');		name++;	}}#if 0static voidstr_lower(char *name, int len){	while (len--)	{		if (*name >= 'A' && *name <= 'Z')			*name += ('a' - 'A');		name++;	}}#endif/* reverse a string inline. This is used by the dircache walking routines */static void reverse_string(char *buf, int len){	char c;	char *end = buf+len-1;	while(buf < end) {		c = *buf;		*(buf++) = *end;		*(end--) = c;	}}/* no conversion, just a wrapper for memcpy. */static int convert_memcpy(char *output, int olen,			  const char *input, int ilen,			  struct nls_table *nls_from,			  struct nls_table *nls_to){	if (olen < ilen)		return -ENAMETOOLONG;	memcpy(output, input, ilen);	return ilen;}/* convert from one "codepage" to another (possibly being utf8). */static int convert_cp(char *output, int olen,		      const char *input, int ilen,		      struct nls_table *nls_from,		      struct nls_table *nls_to){	int len = 0;	int n;	wchar_t ch;	if (!nls_from || !nls_to) {		PARANOIA("nls_from=%p, nls_to=%p\n", nls_from, nls_to);		return convert_memcpy(output, olen, input, ilen, NULL, NULL);	}	while (ilen > 0) {		/* convert by changing to unicode and back to the new cp */		n = nls_from->char2uni((unsigned char *)input, ilen, &ch);		if (n < 0)			goto fail;		input += n;		ilen -= n;		n = nls_to->uni2char(ch, output, olen);		if (n < 0)			goto fail;		output += n;		olen -= n;		len += n;	}	return len;fail:	return n;}static int setcodepage(struct nls_table **p, char *name){	struct nls_table *nls;	if (!name || !*name) {		nls = NULL;	} else if ( (nls = load_nls(name)) == NULL) {		printk (KERN_ERR "smbfs: failed to load nls '%s'\n", name);		return -EINVAL;	}	/* if already set, unload the previous one. */	if (*p)		unload_nls(*p);	*p = nls;	return 0;}/* Handles all changes to codepage settings. */int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp){	int n = 0;	smb_lock_server(server);	/* Don't load any nls_* at all, if no remote is requested */	if (!*cp->remote_name)		goto out;	n = setcodepage(&server->local_nls, cp->local_name);	if (n != 0)		goto out;	n = setcodepage(&server->remote_nls, cp->remote_name);	if (n != 0)		setcodepage(&server->local_nls, NULL);out:	if (server->local_nls != NULL && server->remote_nls != NULL)		server->convert = convert_cp;	else		server->convert = convert_memcpy;	smb_unlock_server(server);	return n;}/*****************************************************************************//*                                                                           *//*  Encoding/Decoding section                                                *//*                                                                           *//*****************************************************************************/static __u8 *smb_encode_smb_length(__u8 * p, __u32 len){	*p = 0;	*(p+1) = 0;	*(p+2) = (len & 0xFF00) >> 8;	*(p+3) = (len & 0xFF);	if (len > 0xFFFF)	{		*(p+1) = 1;	}	return p + 4;}/* * smb_build_path: build the path to entry and name storing it in buf. * The path returned will have the trailing '\0'. */static int smb_build_path(struct smb_sb_info *server, char * buf, int maxlen,			  struct dentry * entry, struct qstr * name){	char *path = buf;	int len;	if (maxlen < 2)		return -ENAMETOOLONG;	if (maxlen > SMB_MAXNAMELEN + 1)		maxlen = SMB_MAXNAMELEN + 1;	if (entry == NULL)		goto test_name_and_out;	/*	 * If IS_ROOT, we have to do no walking at all.	 */	if (IS_ROOT(entry) && !name) {		*path++ = '\\';		*path++ = '\0';		return 2;	}	/*	 * Build the path string walking the tree backward from end to ROOT	 * and store it in reversed order [see reverse_string()]	 */	while (!IS_ROOT(entry)) {		if (maxlen < 3)			return -ENAMETOOLONG;		len = server->convert(path, maxlen-2, 				      entry->d_name.name, entry->d_name.len,				      server->local_nls, server->remote_nls);		if (len < 0)			return len;		reverse_string(path, len);		path += len;		*path++ = '\\';		maxlen -= len+1;		entry = entry->d_parent;		if (IS_ROOT(entry))			break;	}	reverse_string(buf, path-buf);	/* maxlen is at least 1 */test_name_and_out:	if (name) {		if (maxlen < 3)			return -ENAMETOOLONG;		*path++ = '\\';		len = server->convert(path, maxlen-2, 				      name->name, name->len,				      server->local_nls, server->remote_nls);		if (len < 0)			return len;		path += len;		maxlen -= len+1;	}	/* maxlen is at least 1 */	*path++ = '\0';	return path-buf;}static int smb_encode_path(struct smb_sb_info *server, char *buf, int maxlen,			   struct dentry *dir, struct qstr *name){	int result;	result = smb_build_path(server, buf, maxlen, dir, name);	if (result < 0)		goto out;	if (server->opt.protocol <= SMB_PROTOCOL_COREPLUS)		str_upper(buf, result);out:	return result;}static int smb_simple_encode_path(struct smb_sb_info *server, char **p,			  struct dentry * entry, struct qstr * name){	char *s = *p;	int res;	int maxlen = ((char *)server->packet + server->packet_size) - s;	if (!maxlen)		return -ENAMETOOLONG;	*s++ = 4;	res = smb_encode_path(server, s, maxlen-1, entry, name);	if (res < 0)		return res;	*p = s + res;	return 0;}/* The following are taken directly from msdos-fs *//* Linear day numbers of the respective 1sts in non-leap years. */static int day_n[] ={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};		  /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */static time_tutc2local(struct smb_sb_info *server, time_t time){	return time - server->opt.serverzone*60;}static time_tlocal2utc(struct smb_sb_info *server, time_t time){	return time + server->opt.serverzone*60;}/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */static time_tdate_dos2unix(struct smb_sb_info *server, __u16 date, __u16 time){	int month, year;	time_t secs;	/* first subtract and mask after that... Otherwise, if	   date == 0, bad things happen */	month = ((date >> 5) - 1) & 15;	year = date >> 9;	secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + 86400 *	    ((date & 31) - 1 + day_n[month] + (year / 4) + year * 365 - ((year & 3) == 0 &&						   month < 2 ? 1 : 0) + 3653);	/* days since 1.1.70 plus 80's leap day */	return local2utc(server, secs);}/* Convert linear UNIX date to a MS-DOS time/date pair. */static voiddate_unix2dos(struct smb_sb_info *server,	      int unix_date, __u16 *date, __u16 *time){	int day, year, nl_day, month;	unix_date = utc2local(server, unix_date);	if (unix_date < 315532800)		unix_date = 315532800;	*time = (unix_date % 60) / 2 +		(((unix_date / 60) % 60) << 5) +		(((unix_date / 3600) % 24) << 11);	day = unix_date / 86400 - 3652;	year = day / 365;	if ((year + 3) / 4 + 365 * year > day)		year--;	day -= (year + 3) / 4 + 365 * year;	if (day == 59 && !(year & 3)) {		nl_day = day;		month = 2;	} else {		nl_day = (year & 3) || day <= 59 ? day : day - 1;		for (month = 0; month < 12; month++)			if (day_n[month] > nl_day)				break;	}	*date = nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9);}/* The following are taken from fs/ntfs/util.c */#define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000)/* * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units) * into Unix UTC (based 1970-01-01, in seconds). */static time_tsmb_ntutc2unixutc(u64 ntutc){	/* FIXME: what about the timezone difference? */	/* Subtract the NTFS time offset, then convert to 1s intervals. */	u64 t = ntutc - NTFS_TIME_OFFSET;	do_div(t, 10000000);	return (time_t)t;}#if 0/* Convert the Unix UTC into NT time */static u64smb_unixutc2ntutc(struct smb_sb_info *server, time_t t){	/* Note: timezone conversion is probably wrong. */	return ((u64)utc2local(server, t)) * 10000000 + NTFS_TIME_OFFSET;}#endif/*****************************************************************************//*                                                                           *//*  Support section.                                                         *//*                                                                           *//*****************************************************************************/__u32smb_len(__u8 * p){	return ((*(p+1) & 0x1) << 16L) | (*(p+2) << 8L) | *(p+3);}static __u16smb_bcc(__u8 * packet){	int pos = SMB_HEADER_LEN + SMB_WCT(packet) * sizeof(__u16);	return WVAL(packet, pos);}/* smb_valid_packet: We check if packet fulfills the basic   requirements of a smb packet */static intsmb_valid_packet(__u8 * packet){	return (packet[4] == 0xff		&& packet[5] == 'S'		&& packet[6] == 'M'		&& packet[7] == 'B'		&& (smb_len(packet) + 4 == SMB_HEADER_LEN		    + SMB_WCT(packet) * 2 + SMB_BCC(packet)));}/* smb_verify: We check if we got the answer we expected, and if we   got enough data. If bcc == -1, we don't care. */static intsmb_verify(__u8 * packet, int command, int wct, int bcc){	if (SMB_CMD(packet) != command)		goto bad_command;	if (SMB_WCT(packet) < wct)		goto bad_wct;	if (bcc != -1 && SMB_BCC(packet) < bcc)		goto bad_bcc;	return 0;bad_command:	printk(KERN_ERR "smb_verify: command=%x, SMB_CMD=%x??\n",	       command, SMB_CMD(packet));	goto fail;bad_wct:	printk(KERN_ERR "smb_verify: command=%x, wct=%d, SMB_WCT=%d??\n",	       command, wct, SMB_WCT(packet));	goto fail;bad_bcc:	printk(KERN_ERR "smb_verify: command=%x, bcc=%d, SMB_BCC=%d??\n",	       command, bcc, SMB_BCC(packet));fail:	return -EIO;}/* * Returns the maximum read or write size for the "payload". Making all of the * packet fit within the negotiated max_xmit size. * * N.B. Since this value is usually computed before locking the server, * the server's packet size must never be decreased! */static inline intsmb_get_xmitsize(struct smb_sb_info *server, int overhead){	return server->opt.max_xmit - overhead;}/* * Calculate the maximum read size */intsmb_get_rsize(struct smb_sb_info *server){	int overhead = SMB_HEADER_LEN + 5 * sizeof(__u16) + 2 + 1 + 2;	int size = smb_get_xmitsize(server, overhead);	VERBOSE("packet=%d, xmit=%d, size=%d\n",		server->packet_size, server->opt.max_xmit, size);	return size;}/* * Calculate the maximum write size */intsmb_get_wsize(struct smb_sb_info *server){	int overhead = SMB_HEADER_LEN + 5 * sizeof(__u16) + 2 + 1 + 2;	int size = smb_get_xmitsize(server, overhead);

⌨️ 快捷键说明

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