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

📄 proc.c

📁 linux 内核源代码
💻 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/capability.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/smp_lock.h>#include <linux/net.h>#include <linux/vfs.h>#include <linux/smb_fs.h>#include <linux/smbno.h>#include <linux/smb_mount.h>#include <net/sock.h>#include <asm/string.h>#include <asm/div64.h>#include "smb_debug.h"#include "proto.h"#include "request.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_DIRINFO_SIZE 43#define SMB_STATUS_SIZE  21#define SMB_ST_BLKSIZE	(PAGE_SIZE)#define SMB_ST_BLKSHIFT	(PAGE_SHIFT)static struct smb_ops smb_ops_core;static struct smb_ops smb_ops_os2;static struct smb_ops smb_ops_win95;static struct smb_ops smb_ops_winNT;static struct smb_ops smb_ops_unix;static struct smb_ops smb_ops_null;static voidsmb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr);static voidsmb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr);static intsmb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir,		      struct smb_fattr *fattr);static intsmb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry,		    struct smb_fattr *fattr);static intsmb_proc_setattr_core(struct smb_sb_info *server, struct dentry *dentry,		      u16 attr);static intsmb_proc_setattr_ext(struct smb_sb_info *server,		     struct inode *inode, struct smb_fattr *fattr);static intsmb_proc_query_cifsunix(struct smb_sb_info *server);static voidinstall_ops(struct smb_ops *dst, struct smb_ops *src);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(unsigned char *output, int olen,			  const unsigned 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;}static inline int write_char(unsigned char ch, char *output, int olen){	if (olen < 4)		return -ENAMETOOLONG;	sprintf(output, ":x%02x", ch);	return 4;}static inline int write_unichar(wchar_t ch, char *output, int olen){	if (olen < 5)		return -ENAMETOOLONG;	sprintf(output, ":%04x", ch);	return 5;}/* convert from one "codepage" to another (possibly being utf8). */static int convert_cp(unsigned char *output, int olen,		      const unsigned char *input, int ilen,		      struct nls_table *nls_from,		      struct nls_table *nls_to){	int len = 0;	int n;	wchar_t ch;	while (ilen > 0) {		/* convert by changing to unicode and back to the new cp */		n = nls_from->char2uni(input, ilen, &ch);		if (n == -EINVAL) {			ilen--;			n = write_char(*input++, output, olen);			if (n < 0)				goto fail;			output += n;			olen -= n;			len += n;			continue;		} else if (n < 0)			goto fail;		input += n;		ilen -= n;		n = nls_to->uni2char(ch, output, olen);		if (n == -EINVAL)			n = write_unichar(ch, output, olen);		if (n < 0)			goto fail;		output += n;		olen -= n;		len += n;	}	return len;fail:	return n;}/* ----------------------------------------------------------- *//* * nls_unicode * * This encodes/decodes little endian unicode format */static int uni2char(wchar_t uni, unsigned char *out, int boundlen){	if (boundlen < 2)		return -EINVAL;	*out++ = uni & 0xff;	*out++ = uni >> 8;	return 2;}static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni){	if (boundlen < 2)		return -EINVAL;	*uni = (rawstring[1] << 8) | rawstring[0];	return 2;}static struct nls_table unicode_table = {	.charset	= "unicode",	.uni2char	= uni2char,	.char2uni	= char2uni,};/* ----------------------------------------------------------- */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 && *p != &unicode_table)		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;	/* local */	n = setcodepage(&server->local_nls, cp->local_name);	if (n != 0)		goto out;	/* remote */	if (!strcmp(cp->remote_name, "unicode")) {		server->remote_nls = &unicode_table;	} else {		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->ops->convert = convert_cp;	else		server->ops->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, unsigned char *buf,			  int maxlen,			  struct dentry *entry, struct qstr *name){	unsigned char *path = buf;	int len;	int unicode = (server->mnt->flags & SMB_MOUNT_UNICODE) != 0;	if (maxlen < (2<<unicode))		return -ENAMETOOLONG;	if (maxlen > SMB_MAXPATHLEN + 1)		maxlen = SMB_MAXPATHLEN + 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++ = '\\';		if (unicode) *path++ = '\0';		*path++ = '\0';		if (unicode) *path++ = '\0';		return path-buf;	}	/*	 * Build the path string walking the tree backward from end to ROOT	 * and store it in reversed order [see reverse_string()]	 */	dget(entry);	spin_lock(&entry->d_lock);	while (!IS_ROOT(entry)) {		struct dentry *parent;		if (maxlen < (3<<unicode)) {			spin_unlock(&entry->d_lock);			dput(entry);			return -ENAMETOOLONG;		}		len = server->ops->convert(path, maxlen-2, 				      entry->d_name.name, entry->d_name.len,				      server->local_nls, server->remote_nls);		if (len < 0) {			spin_unlock(&entry->d_lock);			dput(entry);			return len;		}		reverse_string(path, len);		path += len;		if (unicode) {			/* Note: reverse order */			*path++ = '\0';			maxlen--;		}		*path++ = '\\';		maxlen -= len+1;		parent = entry->d_parent;		dget(parent);		spin_unlock(&entry->d_lock);		dput(entry);		entry = parent;		spin_lock(&entry->d_lock);	}	spin_unlock(&entry->d_lock);	dput(entry);	reverse_string(buf, path-buf);	/* maxlen has space for at least one char */test_name_and_out:	if (name) {		if (maxlen < (3<<unicode))			return -ENAMETOOLONG;		*path++ = '\\';		if (unicode) {			*path++ = '\0';			maxlen--;		}		len = server->ops->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 has space for at least one char */	*path++ = '\0';	if (unicode) *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;}/* encode_path for non-trans2 request SMBs */static int smb_simple_encode_path(struct smb_request *req, char **p,				  struct dentry * entry, struct qstr * name){	struct smb_sb_info *server = req->rq_server;	char *s = *p;	int res;	int maxlen = ((char *)req->rq_buffer + req->rq_bufsize) - s;	int unicode = (server->mnt->flags & SMB_MOUNT_UNICODE);	if (!maxlen)		return -ENAMETOOLONG;	*s++ = 4;	/* ASCII data format */	/*	 * SMB Unicode strings must be 16bit aligned relative the start of the	 * packet. If they are not they must be padded with 0.	 */	if (unicode) {		int align = s - (char *)req->rq_buffer;		if (!(align & 1)) {			*s++ = '\0';			maxlen--;		}	}	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 struct timespecsmb_ntutc2unixutc(u64 ntutc){	struct timespec ts;	/* FIXME: what about the timezone difference? */	/* Subtract the NTFS time offset, then convert to 1s intervals. */	u64 t = ntutc - NTFS_TIME_OFFSET;

⌨️ 快捷键说明

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