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

📄 proc.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 4 页
字号:
	smb_close_socket(server);	if (pid == 0) {		printk(KERN_ERR "smb_retry: no connection process\n");		server->state = CONN_RETRIED;		goto out;	}	/*	 * Clear the pid to enable the ioctl.	 */	server->conn_pid = 0;	/*	 * Note: use the "priv" flag, as a user process may need to reconnect.	 */	error = kill_proc(pid, SIGUSR1, 1);	if (error) {		printk(KERN_ERR "smb_retry: signal failed, error=%d\n", error);		goto out_restore;	}	VERBOSE("signalled pid %d, waiting for new connection\n", pid);	/*	 * Wait for the new connection.	 */#ifdef SMB_RETRY_INTR	interruptible_sleep_on_timeout(&server->wait,  5*HZ);	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 recieved 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!	 */	sleep_on_timeout(&server->wait, 5*HZ);#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("sucessful, new pid=%d, generation=%d\n",			 server->conn_pid, server->generation);		result = 1;	}	/*	 * Restore the original pid if we didn't get a new one.	 */out_restore:	if (!server->conn_pid)		server->conn_pid = pid;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.  The current smb_errno() routine	 * is squashing some error codes, but I don't think this is	 * correct: after a server error the packet won't be valid.	 */	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. * * Note that this must be called with the server locked, except for * the first call made after mounting the volume. The server pid * will be set to zero to indicate that smbfs is awaiting a connection. */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);	/*	 * Make sure we don't already have a pid ...	 */	error = -EINVAL;	if (server->conn_pid)		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;#ifdef SMBFS_DEBUG_VERBOSE		printk(KERN_NOTICE "smb_newconn: detected WIN95 server\n");#endif	}	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);out:#ifdef SMB_RETRY_INTR	wake_up_interruptible(&server->wait);#else	wake_up(&server->wait);#endif	return error;out_putf:	fput(filp);	goto out;}/* 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);}/* * 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. */	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);	*p++ = 4;	res = smb_encode_path(server, p, dentry, NULL);	if (res < 0)		goto out;	p += res;	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);	if (!(wish & (O_WRONLY | O_RDWR)))		ino->u.smbfs_i.access = SMB_O_RDONLY;	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;	result = -ENOENT;	if (!inode)	{		printk(KERN_ERR "smb_open: no inode for dentry %s/%s\n",		       DENTRY_PATH(dentry));		goto out;	}	if (!smb_is_open(inode))	{		struct smb_sb_info *server = SMB_SERVER(inode);		smb_lock_server(server);		result = 0;		if (!smb_is_open(inode))			result = smb_proc_open(server, dentry, wish);		smb_unlock_server(server);		if (result)		{			PARANOIA("%s/%s open failed, result=%d\n",				 DENTRY_PATH(dentry), result);			goto out;		}		/*		 * A successful open means the path is still valid ...		 */		smb_renew_times(dentry);	}	/*	 * Check whether the access is compatible with the desired mode.	 */	result = 0;	if (inode->u.smbfs_i.access != wish && 	    inode->u.smbfs_i.access != SMB_O_RDWR)	{		PARANOIA("%s/%s access denied, access=%x, wish=%x\n",			 DENTRY_PATH(dentry), inode->u.smbfs_i.access, wish);		result = -EACCES;	}out:	return result;}/* We're called with the server locked */static int smb_proc_close(struct smb_sb_info *server, __u16 fileid, __u32 mtime){	smb_setup_header(server, SMBclose, 3, 0);	WSET(server->packet, smb_vwv0, fileid);	DSET(server->packet, smb_vwv1, utc2local(server, mtime));	return smb_request_ok(server, SMBclose, 0, 0);}/* * Called with the server locked. * * Win NT 4.0 has an apparent bug in that it fails to update the * modify time when writing to a file. As a workaround, we update * both modify and access time locally, and post the times to the * server when closing the file. */static int smb_proc_close_inode(struct smb_sb_info *server, struct inode * ino){	int result = 0;	if (smb_is_open(ino))	{		/*		 * We clear the open flag in advance, in case another 		 * process observes the value while we block below.		 */		ino->u.smbfs_i.open = 0;		/*		 * Kludge alert: SMB timestamps are accurate only to		 * two seconds ... round the times to avoid needless		 * cache invalidations!		 */		if (ino->i_mtime & 1)			ino->i_mtime--;		if (ino->i_atime & 1)			ino->i_atime--;		/*		 * If the file is open with write permissions,		 * update the time stamps to sync mtime and atime.		 */		if ((server->opt.protocol >= SMB_PROTOCOL_LANMAN2) &&		    !(ino->u.smbfs_i.access == SMB_O_RDONLY))		{			struct smb_fattr fattr;			smb_get_inode_attr(ino, &fattr);			smb_proc_setattr_ext(server, ino, &fattr);		}		result = smb_proc_close(server, ino->u.smbfs_i.fileid,						ino->i_mtime);		ino->u.smbfs_i.cache_valid &= ~SMB_F_LOCALWRITE;		/*		 * Force a revalidation after closing ... some servers		 * don't post the size until the file has been closed.		 */		if (server->opt.protocol < SMB_PROTOCOL_NT1)			ino->u.smbfs_i.oldmtime = 0;		ino->u.smbfs_i.closed = jiffies;	}	return result;}intsmb_close(struct inode *ino){	int result = 0;	if (smb_is_open(ino))	{		struct smb_sb_info *server = SMB_SERVER(ino);		smb_lock_server(server);		result = smb_proc_close_inode(server, ino);		smb_unlock_server(server);	}	return result;}/* * This is used to close a file following a failed instantiate. * Since we don't have an inode, we can't use any of the above. */intsmb_close_fileid(struct dentry *dentry, __u16 fileid){	struct smb_sb_info *server = server_from_dentry(dentry);	int result;	smb_lock_server(server);	result = smb_proc_close(server, fileid, CURRENT_TIME);	smb_unlock_server(server);	return result;}/* In smb_proc_read and smb_proc_write we do not retry, because the   file-id would not be valid after a reconnection. */intsmb_proc_read(struct inode *inode, off_t offset, int count, char *data){	struct smb_sb_info *server = server_from_inode(inode);	__u16 returned_count, data_len;	unsigned char *buf;	int result;	smb_lock_server(server);	smb_setup_header(server, SMBread, 5, 0);	buf = server->packet;	WSET(buf, smb_vwv0, inode->u.smbfs_i.fileid);	WSET(buf, smb_vwv1, count);	DSET(buf, smb_vwv2, offset);	WSET(buf, smb_vwv4, 0);	result = smb_request_ok(server, SMBread, 5, -1);	if (result < 0)		goto out;	returned_count = WVAL(server->packet, smb_vwv0);	buf = SMB_BUF(server->packet);	data_len = WVAL(buf, 1);	/* we can NOT simply trust the data_len given by the server ... */	if (data_len > server->packet_size - (buf+3 - server->packet)) {		printk(KERN_ERR "smb_proc_read: invalid data length!! "		       "%d > %d - (%p - %p)\n",		       data_len, server->packet_size, buf+3, server->packet);		result = -EIO;		goto out;	}	memcpy(data, buf+3, data_len);	if (returned_count != data_len) {		printk(KERN_NOTICE "smb_proc_read: returned != data_len\n");		printk(KERN_NOTICE "smb_proc_read: ret_c=%d, data_len=%d\n",		       returned_count, data_len);	}	result = data_len;out:	VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n",		inode->ino, inode->u.smbfs_i.fileid, count, result);	smb_unlock_server(server);	return result;}intsmb_proc_write(struct inode *inode, off_t offset, int count, const char *data){	struct smb_sb_info *server = server_from_inode(inode);	int result;	__u8 *p;		VERBOSE("ino=%ld, fileid=%d, count=%d@%ld, packet_size=%d\n",		inode->ino, inode->u.smbfs_i.fileid, count, offset,		server->packet_size);	smb_lock_server(server);	p = smb_setup_header(server, SMBwrite, 5, count + 3);	WSET(server->packet, smb_vwv0, inode->u.smbfs_i.fileid);	WSET(server->packet, smb_vwv1, count);	DSET(server->packet, smb_vwv2, offset);	WSET(server->packet, smb_vwv4, 0);	*p++ = 1;	WSET(p, 0, count);	memcpy(p+2, data, count);	result = smb_request_ok(server, SMBwrite, 1, 0);	if (result >= 0)		result = WVAL(server->packet, smb_vwv0);	smb_unlock_server(server);	return result;}intsmb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid){	struct smb_sb_info *server = server_from_dentry(dentry);	char *p;	int result;	smb_lock_server(server);      retry:	p = smb_setup_header(server, SMBcreate, 3, 0);	WSET(server->packet, smb_vwv0, attr);	DSET(server->packet, smb_vwv1, utc2local(server, ctime));	*p++ = 4;	result = smb_encode_path(server, p, dentry, NULL);	if (result < 0)		goto out;	p += result;	smb_setup_bcc(server, p);	result = smb_request_ok(server, SMBcreate, 1, 0);	if (result < 0) {		if (smb_retry(server))			goto retry;		goto out;	}	*fileid = WVAL(server->packet, smb_vwv0);	result = 0;out:	smb_unlock_server(server);	return result;}intsmb_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry){	struct smb_sb_info *server = server_from_dentry(old_dentry);	char *p;	int result;	smb_lock_server(server);      retry:	p = smb_setup_header(server, SMBmv, 1, 0);	WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN | aDIR);	*p++ = 4;	result = smb_encode_path(server, p, old_dentry, NULL);	if (result < 0)		goto out;	p += result;	*p++ = 4;	result = smb_encode_path(server, p, new_dentry, NULL);	if (result < 0)

⌨️ 快捷键说明

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