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

📄 proc.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 5 页
字号:
	VERBOSE("packet=%d, xmit=%d, size=%d\n",		server->packet_size, server->opt.max_xmit, size);	return size;}/* * Convert SMB error codes to -E... errno values. */intsmb_errno(struct smb_sb_info *server){	int errcls = server->rcls;	int error  = server->err;	char *class = "Unknown";	VERBOSE("errcls %d  code %d  from command 0x%x\n",		errcls, error, SMB_CMD(server->packet));	if (errcls == ERRDOS) {		switch (error) {		case ERRbadfunc:			return -EINVAL;		case ERRbadfile:		case ERRbadpath:			return -ENOENT;		case ERRnofids:			return -EMFILE;		case ERRnoaccess:			return -EACCES;		case ERRbadfid:			return -EBADF;		case ERRbadmcb:			return -EREMOTEIO;		case ERRnomem:			return -ENOMEM;		case ERRbadmem:			return -EFAULT;		case ERRbadenv:		case ERRbadformat:			return -EREMOTEIO;		case ERRbadaccess:			return -EACCES;		case ERRbaddata:			return -E2BIG;		case ERRbaddrive:			return -ENXIO;		case ERRremcd:			return -EREMOTEIO;		case ERRdiffdevice:			return -EXDEV;		case ERRnofiles:			return -ENOENT;		case ERRbadshare:			return -ETXTBSY;		case ERRlock:			return -EDEADLK;		case ERRfilexists:			return -EEXIST;		case ERROR_INVALID_PARAMETER:			return -EINVAL;		case ERROR_DISK_FULL:			return -ENOSPC;		case ERROR_INVALID_NAME:			return -ENOENT;		case ERROR_DIR_NOT_EMPTY:			return -ENOTEMPTY;		case ERROR_NOT_LOCKED:                       return -ENOLCK;		case ERROR_ALREADY_EXISTS:			return -EEXIST;		default:			class = "ERRDOS";			goto err_unknown;		}	} else if (errcls == ERRSRV) {		switch (error) {		/* N.B. This is wrong ... EIO ? */		case ERRerror:			return -ENFILE;		case ERRbadpw:			return -EINVAL;		case ERRbadtype:			return -EIO;		case ERRaccess:			return -EACCES;		/*		 * This is a fatal error, as it means the "tree ID"		 * for this connection is no longer valid. We map		 * to a special error code and get a new connection.		 */		case ERRinvnid:			return -EBADSLT;		default:			class = "ERRSRV";			goto err_unknown;		}	} else if (errcls == ERRHRD) {		switch (error) {		case ERRnowrite:			return -EROFS;		case ERRbadunit:			return -ENODEV;		case ERRnotready:			return -EUCLEAN;		case ERRbadcmd:		case ERRdata:			return -EIO;		case ERRbadreq:			return -ERANGE;		case ERRbadshare:			return -ETXTBSY;		case ERRlock:			return -EDEADLK;		case ERRdiskfull:			return -ENOSPC;		default:			class = "ERRHRD";			goto err_unknown;		}	} else if (errcls == ERRCMD) {		class = "ERRCMD";	} else if (errcls == SUCCESS) {		return 0;	/* This is the only valid 0 return */	}err_unknown:	printk(KERN_ERR "smb_errno: class %s, code %d from command 0x%x\n",	       class, error, SMB_CMD(server->packet));	return -EIO;}/* * smb_retry: This function should be called when smb_request_ok has * indicated an error. If the error was indicated because the * connection was killed, we try to reconnect. If smb_retry returns 0, * the error was indicated for another reason, so a retry would not be * of any use. * N.B. The server must be locked for this call. */static intsmb_retry(struct smb_sb_info *server){	pid_t pid = server->conn_pid;	int error, result = 0;	if (server->state == CONN_VALID || server->state == CONN_RETRYING)		goto out;	smb_close_socket(server);	if (pid == 0) {		printk(KERN_ERR "smb_retry: no connection process\n");		server->state = CONN_RETRIED;		goto out;	}	/*	 * Change state so that only one retry per server will be started.	 */	server->state = CONN_RETRYING;	/*	 * Note: use the "priv" flag, as a user process may need to reconnect.	 */	error = kill_proc(pid, SIGUSR1, 1);	if (error) {		/* FIXME: this is fatal */		printk(KERN_ERR "smb_retry: signal failed, error=%d\n", error);		goto out;	}	VERBOSE("signalled pid %d, waiting for new connection\n", pid);	/*	 * Wait for the new connection.	 */#ifdef SMB_RETRY_INTR	smb_unlock_server(server);	interruptible_sleep_on_timeout(&server->wait,  30*HZ);	smb_lock_server(server);	if (signal_pending(current))		printk(KERN_INFO "smb_retry: caught signal\n");#else	/*	 * We don't want to be interrupted. For example, what if 'current'	 * already has received a signal? sleep_on would terminate immediately	 * and smbmount would not be able to re-establish connection.	 *	 * smbmount should be able to reconnect later, but it can't because	 * it will get an -EIO on attempts to open the mountpoint!	 *	 * FIXME: go back to the interruptable version now that smbmount	 * can avoid -EIO on the mountpoint when reconnecting?	 */	smb_unlock_server(server);	sleep_on_timeout(&server->wait, 30*HZ);	smb_lock_server(server);#endif	/*	 * Check for a valid connection.	 */	if (server->state == CONN_VALID) {		/* This should be changed to VERBOSE, except many smbfs		   problems is with the userspace daemon not reconnecting. */		PARANOIA("successful, new pid=%d, generation=%d\n",			 server->conn_pid, server->generation);		result = 1;	} else if (server->state == CONN_RETRYING) {		/* allow further attempts later */		server->state = CONN_RETRIED;	}out:	return result;}/* smb_request_ok: We expect the server to be locked. Then we do the   request and check the answer completely. When smb_request_ok   returns 0, you can be quite sure that everything went well. When   the answer is <=0, the returned number is a valid unix errno. */static intsmb_request_ok(struct smb_sb_info *s, int command, int wct, int bcc){	int result = -EIO;	s->rcls = 0;	s->err = 0;	/* Make sure we have a connection */	if (s->state != CONN_VALID) {		if (!smb_retry(s))			goto out;	}	if (smb_request(s) < 0) {		DEBUG1("smb_request failed\n");		goto out;	}	if (smb_valid_packet(s->packet) != 0) {		PARANOIA("invalid packet!\n");		goto out;	}	/*	 * Check for server errors.	 */	if (s->rcls != 0) {		result = smb_errno(s);		if (!result)			printk(KERN_DEBUG "smb_request_ok: rcls=%d, err=%d mapped to 0\n",				s->rcls, s->err);		/*		 * Exit now even if the error was squashed ...		 * packet verify will fail anyway.		 */		goto out;	}	result = smb_verify(s->packet, command, wct, bcc);out:	return result;}/* * This implements the NEWCONN ioctl. It installs the server pid, * sets server->state to CONN_VALID, and wakes up the waiting process. */intsmb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt){	struct file *filp;	int error;	VERBOSE("fd=%d, pid=%d\n", opt->fd, current->pid);	smb_lock_server(server);	/*	 * Make sure we don't already have a valid connection ...	 */	error = -EINVAL;	if (server->state == CONN_VALID)		goto out;	error = -EACCES;	if (current->uid != server->mnt->mounted_uid && 	    !capable(CAP_SYS_ADMIN))		goto out;	error = -EBADF;	filp = fget(opt->fd);	if (!filp)		goto out;	if (!smb_valid_socket(filp->f_dentry->d_inode))		goto out_putf;	server->sock_file = filp;	server->conn_pid = current->pid;	smb_catch_keepalive(server);	server->opt = *opt;	server->generation += 1;	server->state = CONN_VALID;	error = 0;	/* check if we have an old smbmount that uses seconds for the 	   serverzone */	if (server->opt.serverzone > 12*60 || server->opt.serverzone < -12*60)		server->opt.serverzone /= 60;	/* now that we have an established connection we can detect the server	   type and enable bug workarounds */	if (server->opt.protocol == SMB_PROTOCOL_NT1 &&	    (server->opt.max_xmit < 0x1000) &&	    !(server->opt.capabilities & SMB_CAP_NT_SMBS)) {		server->mnt->flags |= SMB_MOUNT_WIN95;		VERBOSE("smb_newconn: detected WIN95 server\n");	}	VERBOSE("protocol=%d, max_xmit=%d, pid=%d capabilities=0x%x\n",		server->opt.protocol, server->opt.max_xmit, server->conn_pid,		server->opt.capabilities);	/* Make sure we can fit a message of the negotiated size in our	   packet buffer. */	if (server->opt.max_xmit > server->packet_size) {		int len = smb_round_length(server->opt.max_xmit);		char *buf = smb_vmalloc(len);		if (buf) {			if (server->packet)				smb_vfree(server->packet);			server->packet = buf;			server->packet_size = len;		} else {			/* else continue with the too small buffer? */			PARANOIA("Failed to allocate new packet buffer: "				 "max_xmit=%d, packet_size=%d\n",				 server->opt.max_xmit, server->packet_size);			server->opt.max_xmit = server->packet_size;		}	}out:	smb_unlock_server(server);	smb_wakeup(server);	return error;out_putf:	fput(filp);	goto out;}intsmb_wakeup(struct smb_sb_info *server){#ifdef SMB_RETRY_INTR	wake_up_interruptible(&server->wait);#else	wake_up(&server->wait);#endif	return 0;}/* smb_setup_header: We completely set up the packet. You only have to   insert the command-specific fields */__u8 *smb_setup_header(struct smb_sb_info * server, __u8 command, __u16 wct, __u16 bcc){	__u32 xmit_len = SMB_HEADER_LEN + wct * sizeof(__u16) + bcc + 2;	__u8 *p = server->packet;	__u8 *buf = server->packet;	if (xmit_len > server->packet_size)		printk(KERN_DEBUG "smb_setup_header: "		       "Aieee, xmit len > packet! len=%d, size=%d\n",		       xmit_len, server->packet_size);	p = smb_encode_smb_length(p, xmit_len - 4);	*p++ = 0xff;	*p++ = 'S';	*p++ = 'M';	*p++ = 'B';	*p++ = command;	memset(p, '\0', 19);	p += 19;	p += 8;	WSET(buf, smb_tid, server->opt.tid);	WSET(buf, smb_pid, 1);	WSET(buf, smb_uid, server->opt.server_uid);	WSET(buf, smb_mid, 1);	if (server->opt.protocol > SMB_PROTOCOL_CORE)	{		*(buf+smb_flg) = 0x8;		WSET(buf, smb_flg2, 0x3);	}	*p++ = wct;		/* wct */	p += 2 * wct;	WSET(p, 0, bcc);	return p + 2;}static voidsmb_setup_bcc(struct smb_sb_info *server, __u8 * p){	__u8 *packet = server->packet;	__u8 *pbcc = packet + SMB_HEADER_LEN + 2 * SMB_WCT(packet);	__u16 bcc = p - (pbcc + 2);	WSET(pbcc, 0, bcc);	smb_encode_smb_length(packet,			      SMB_HEADER_LEN + 2 * SMB_WCT(packet) - 2 + bcc);}/* * Called with the server locked */static intsmb_proc_seek(struct smb_sb_info *server, __u16 fileid,	      __u16 mode, off_t offset){	int result;	smb_setup_header(server, SMBlseek, 4, 0);	WSET(server->packet, smb_vwv0, fileid);	WSET(server->packet, smb_vwv1, mode);	DSET(server->packet, smb_vwv2, offset);	result = smb_request_ok(server, SMBlseek, 2, 0);	if (result < 0) {		result = 0;		goto out;	}	result = DVAL(server->packet, smb_vwv0);out:	return result;}/* * We're called with the server locked, and we leave it that way. */static intsmb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish){	struct inode *ino = dentry->d_inode;	int mode, read_write = 0x42, read_only = 0x40;	int res;	char *p;	/*	 * Attempt to open r/w, unless there are no write privileges.	 */	mode = read_write;	if (!(ino->i_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))		mode = read_only;#if 0	/* FIXME: why is this code not in? below we fix it so that a caller	   wanting RO doesn't get RW. smb_revalidate_inode does some 	   optimization based on access mode. tail -f needs it to be correct.	   We must open rw since we don't do the open if called a second time	   with different 'wish'. Is that not supported by smb servers? */	if (!(wish & (O_WRONLY | O_RDWR)))		mode = read_only;#endif      retry:	p = smb_setup_header(server, SMBopen, 2, 0);	WSET(server->packet, smb_vwv0, mode);	WSET(server->packet, smb_vwv1, aSYSTEM | aHIDDEN | aDIR);	res = smb_simple_encode_path(server, &p, dentry, NULL);	if (res < 0)		goto out;	smb_setup_bcc(server, p);	res = smb_request_ok(server, SMBopen, 7, 0);	if (res != 0) {		if (smb_retry(server))			goto retry;		if (mode == read_write &&		    (res == -EACCES || res == -ETXTBSY || res == -EROFS))		{			VERBOSE("%s/%s R/W failed, error=%d, retrying R/O\n",				DENTRY_PATH(dentry), res);			mode = read_only;			goto retry;		}		goto out;	}	/* We should now have data in vwv[0..6]. */	ino->u.smbfs_i.fileid = WVAL(server->packet, smb_vwv0);	ino->u.smbfs_i.attr   = WVAL(server->packet, smb_vwv1);	/* smb_vwv2 has mtime */	/* smb_vwv4 has size  */	ino->u.smbfs_i.access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK);	ino->u.smbfs_i.open = server->generation;out:	return res;}/* * Make sure the file is open, and check that the access * is compatible with the desired access. */intsmb_open(struct dentry *dentry, int wish){	struct inode *inode = dentry->d_inode;	int result;

⌨️ 快捷键说明

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