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

📄 proc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	result = -ENOMEM;	if (! (req = smb_alloc_request(server, 0)))		goto out;	smb_setup_header(req, SMBlseek, 4, 0);	WSET(req->rq_header, smb_vwv0, fileid);	WSET(req->rq_header, smb_vwv1, mode);	DSET(req->rq_header, smb_vwv2, offset);	req->rq_flags |= SMB_REQ_NORETRY;	result = smb_request_ok(req, SMBlseek, 2, 0);	if (result < 0) {		result = 0;		goto out_free;	}	result = DVAL(req->rq_header, smb_vwv0);out_free:	smb_rput(req);out:	return result;}static intsmb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish){	struct inode *ino = dentry->d_inode;	struct smb_inode_info *ei = SMB_I(ino);	int mode, read_write = 0x42, read_only = 0x40;	int res;	char *p;	struct smb_request *req;	/*	 * 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	res = -ENOMEM;	if (! (req = smb_alloc_request(server, PAGE_SIZE)))		goto out;      retry:	p = smb_setup_header(req, SMBopen, 2, 0);	WSET(req->rq_header, smb_vwv0, mode);	WSET(req->rq_header, smb_vwv1, aSYSTEM | aHIDDEN | aDIR);	res = smb_simple_encode_path(req, &p, dentry, NULL);	if (res < 0)		goto out_free;	smb_setup_bcc(req, p);	res = smb_request_ok(req, SMBopen, 7, 0);	if (res != 0) {		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;			req->rq_flags = 0;			goto retry;		}		goto out_free;	}	/* We should now have data in vwv[0..6]. */	ei->fileid = WVAL(req->rq_header, smb_vwv0);	ei->attr   = WVAL(req->rq_header, smb_vwv1);	/* smb_vwv2 has mtime */	/* smb_vwv4 has size  */	ei->access = (WVAL(req->rq_header, smb_vwv6) & SMB_ACCMASK);	ei->open = server->generation;out_free:	smb_rput(req);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;	__u16 access;	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 = server_from_inode(inode);		result = 0;		if (!smb_is_open(inode))			result = smb_proc_open(server, dentry, wish);		if (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;	access = SMB_I(inode)->access;	if (access != wish && access != SMB_O_RDWR) {		PARANOIA("%s/%s access denied, access=%x, wish=%x\n",			 DENTRY_PATH(dentry), access, wish);		result = -EACCES;	}out:	return result;}static int smb_proc_close(struct smb_sb_info *server, __u16 fileid, __u32 mtime){	struct smb_request *req;	int result = -ENOMEM;	if (! (req = smb_alloc_request(server, 0)))		goto out;	smb_setup_header(req, SMBclose, 3, 0);	WSET(req->rq_header, smb_vwv0, fileid);	DSET(req->rq_header, smb_vwv1, utc2local(server, mtime));	req->rq_flags |= SMB_REQ_NORETRY;	result = smb_request_ok(req, SMBclose, 0, 0);	smb_rput(req);out:	return result;}/* * 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){	struct smb_inode_info *ei = SMB_I(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.		 */		ei->open = 0;		/*		 * Kludge alert: SMB timestamps are accurate only to		 * two seconds ... round the times to avoid needless		 * cache invalidations!		 */		if (ino->i_mtime.tv_sec & 1) { 			ino->i_mtime.tv_sec--;			ino->i_mtime.tv_nsec = 0; 		}		if (ino->i_atime.tv_sec & 1) {			ino->i_atime.tv_sec--;			ino->i_atime.tv_nsec = 0;		}		/*		 * If the file is open with write permissions,		 * update the time stamps to sync mtime and atime.		 */		if ((server->opt.capabilities & SMB_CAP_UNIX) == 0 &&		    (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) &&		    !(ei->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, ei->fileid, ino->i_mtime.tv_sec);		/*		 * 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)			ei->oldmtime = 0;		ei->closed = jiffies;	}	return result;}intsmb_close(struct inode *ino){	int result = 0;	if (smb_is_open(ino)) {		struct smb_sb_info *server = server_from_inode(ino);		result = smb_proc_close_inode(server, ino);	}	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;	result = smb_proc_close(server, fileid, get_seconds());	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. */static voidsmb_proc_read_data(struct smb_request *req){	req->rq_iov[0].iov_base = req->rq_buffer;	req->rq_iov[0].iov_len  = 3;	req->rq_iov[1].iov_base = req->rq_page;	req->rq_iov[1].iov_len  = req->rq_rsize;	req->rq_iovlen = 2;	req->rq_rlen = smb_len(req->rq_header) + 4 - req->rq_bytes_recvd;}static intsmb_proc_read(struct inode *inode, loff_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;	struct smb_request *req;	u8 rbuf[4];	result = -ENOMEM;	if (! (req = smb_alloc_request(server, 0)))		goto out;	smb_setup_header(req, SMBread, 5, 0);	buf = req->rq_header;	WSET(buf, smb_vwv0, SMB_I(inode)->fileid);	WSET(buf, smb_vwv1, count);	DSET(buf, smb_vwv2, offset);	WSET(buf, smb_vwv4, 0);	req->rq_page = data;	req->rq_rsize = count;	req->rq_callback = smb_proc_read_data;	req->rq_buffer = rbuf;	req->rq_flags |= SMB_REQ_NORETRY | SMB_REQ_STATIC;	result = smb_request_ok(req, SMBread, 5, -1);	if (result < 0)		goto out_free;	returned_count = WVAL(req->rq_header, smb_vwv0);	data_len = WVAL(rbuf, 1);	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_free:	smb_rput(req);out:	VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n",		inode->i_ino, SMB_I(inode)->fileid, count, result);	return result;}static intsmb_proc_write(struct inode *inode, loff_t offset, int count, const char *data){	struct smb_sb_info *server = server_from_inode(inode);	int result;	u16 fileid = SMB_I(inode)->fileid;	u8 buf[4];	struct smb_request *req;	result = -ENOMEM;	if (! (req = smb_alloc_request(server, 0)))		goto out;	VERBOSE("ino=%ld, fileid=%d, count=%d@%Ld\n",		inode->i_ino, fileid, count, offset);	smb_setup_header(req, SMBwrite, 5, count + 3);	WSET(req->rq_header, smb_vwv0, fileid);	WSET(req->rq_header, smb_vwv1, count);	DSET(req->rq_header, smb_vwv2, offset);	WSET(req->rq_header, smb_vwv4, 0);	buf[0] = 1;	WSET(buf, 1, count);	/* yes, again ... */	req->rq_iov[1].iov_base = buf;	req->rq_iov[1].iov_len = 3;	req->rq_iov[2].iov_base = (char *) data;	req->rq_iov[2].iov_len = count;	req->rq_iovlen = 3;	req->rq_flags |= SMB_REQ_NORETRY;	result = smb_request_ok(req, SMBwrite, 1, 0);	if (result >= 0)		result = WVAL(req->rq_header, smb_vwv0);	smb_rput(req);out:	return result;}/* * In smb_proc_readX and smb_proc_writeX we do not retry, because the * file-id would not be valid after a reconnection. */#define SMB_READX_MAX_PAD      64static voidsmb_proc_readX_data(struct smb_request *req){	/* header length, excluding the netbios length (-4) */	int hdrlen = SMB_HEADER_LEN + req->rq_resp_wct*2 - 2;	int data_off = WVAL(req->rq_header, smb_vwv6);	/*	 * Some genius made the padding to the data bytes arbitrary.	 * So we must first calculate the amount of padding used by the server.	 */	data_off -= hdrlen;	if (data_off > SMB_READX_MAX_PAD || data_off < 0) {		PARANOIA("offset is larger than SMB_READX_MAX_PAD or negative!\n");		PARANOIA("%d > %d || %d < 0\n", data_off, SMB_READX_MAX_PAD, data_off);		req->rq_rlen = req->rq_bufsize + 1;		return;	}	req->rq_iov[0].iov_base = req->rq_buffer;	req->rq_iov[0].iov_len  = data_off;	req->rq_iov[1].iov_base = req->rq_page;	req->rq_iov[1].iov_len  = req->rq_rsize;	req->rq_iovlen = 2;	req->rq_rlen = smb_len(req->rq_header) + 4 - req->rq_bytes_recvd;}static intsmb_proc_readX(struct inode *inode, loff_t offset, int count, char *data){	struct smb_sb_info *server = server_from_inode(inode);	unsigned char *buf;	int result;	struct smb_request *req;	static char pad[SMB_READX_MAX_PAD];	result = -ENOMEM;	if (! (req = smb_alloc_request(server, 0)))		goto out;	smb_setup_header(req, SMBreadX, 12, 0);	buf = req->rq_header;	WSET(buf, smb_vwv0, 0x00ff);	WSET(buf, smb_vwv1, 0);	WSET(buf, smb_vwv2, SMB_I(inode)->fileid);	DSET(buf, smb_vwv3, (u32)offset);               /* low 32 bits */	WSET(buf, smb_vwv5, count);	WSET(buf, smb_vwv6, 0);	DSET(buf, smb_vwv7, 0);	WSET(buf, smb_vwv9, 0);	DSET(buf, smb_vwv10, (u32)(offset >> 32));      /* high 32 bits */	WSET(buf, smb_vwv11, 0);	req->rq_page = data;	req->rq_rsize = count;	req->rq_callback = smb_proc_readX_data;	req->rq_buffer = pad;	req->rq_bufsize = SMB_READX_MAX_PAD;	req->rq_flags |= SMB_REQ_STATIC | SMB_REQ_NORETRY;	result = smb_request_ok(req, SMBreadX, 12, -1);	if (result < 0)		goto out_free;	result = WVAL(req->rq_header, smb_vwv5);out_free:	smb_rput(req);out:	VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n",		inode->i_ino, SMB_I(inode)->fileid, count, result);	return result;}static intsmb_proc_writeX(struct inode *inode, loff_t offset, int count, const char *data){	struct smb_sb_info *server = server_from_inode(inode);	int result;	u8 *p;	static u8 pad[4];	struct smb_request *req;	result = -ENOMEM;	if (! (req = smb_alloc_request(server, 0)))		goto out;	VERBOSE("ino=%ld, fileid=%d, count=%d@%Ld\n",		inode->i_ino, SMB_I(inode)->fileid, count, offset);	p = smb_setup_header(req, SMBwriteX, 14, count + 1);	WSET(req->rq_header, smb_vwv0, 0x00ff);	WSET(req->rq_header, smb_vwv1, 0);	WSET(req->rq_header, smb_vwv2, SMB_I(inode)->fileid);	DSET(req->rq_header, smb_vwv3, (u32)offset);	/* low 32 bits */	DSET(req->rq_header, smb_vwv5, 0);	WSET(req->rq_header, smb_vwv7, 0);		/* write mode */	WSET(req->rq_header, smb_vwv8, 0);	WSET(req->rq_header, smb_vwv9, 0);	WSET(req->rq_header, smb_vwv10, count);		/* data length */	WSET(req->rq_header, smb_vwv11, smb_vwv12 + 2 + 1);	DSET(req->rq_header, smb_vwv12, (u32)(offset >> 32));	req->rq_iov[1].iov_base = pad;	req->rq_iov[1].iov_len = 1;	req->rq_iov[2].iov_base = (char *) data;	req->rq_iov[2].iov_len = count;	req->rq_iovlen = 3;	req->rq_flags |= SMB_REQ_NORETRY;	result = smb_request_ok(req, SMBwriteX, 6, 0); 	if (result >= 0)		result = WVAL(req->rq_header, smb_vwv2);	smb_rput(req);out:	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;	struct smb_request *req;	result = -ENOMEM;	if (! (req = smb_alloc_request(server, PAGE_SIZE)))		goto out;	p = smb_setup_header(req, SMBcreate, 3, 0);	WSET(req->rq_header, smb_vwv0, attr);	DSET(req->rq_header, smb_vwv1, utc2local(server, ctime));	result = smb_simple_encode_path(req, &p, dentry, NULL);	if (result < 0)		goto out_free;	smb_setup_bcc(req, p);	result = smb_request_ok(req, SMBcreate, 1, 0);	if (result < 0)		goto out_free;	*fileid = WVAL(req->rq_header, smb_vwv0);	result = 0;out_free:	smb_rput(req);out:	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;	struct smb_request *req;	result = -ENOMEM;	if (! (req = smb_alloc_request(server, PAGE_SIZE)))		goto out;	p = smb_setup_header(req, SMBmv, 1, 0);	WSET(req->rq_header, smb_vwv0, aSYSTEM | aHIDDEN | aDIR);	result = smb_simple_encode_path(req, &p, old_dentry, NULL);	if (result < 0)		goto out_free;	result = smb_simple_encode_path(req, &p, new_dentry, NULL);	if (result < 0)		goto out_free;	smb_setup_bcc(req, p);	if ((result = smb_request_ok(req, SMBmv, 0, 0)) < 0)		goto out_free;	result = 0;out_free:	smb_rput(req);out:	return result;}

⌨️ 快捷键说明

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