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

📄 proc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Code common to mkdir and rmdir. */static intsmb_proc_generic_command(struct dentry *dentry, __u8 command){	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, command, 0, 0);	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, command, 0, 0);	if (result < 0)		goto out_free;	result = 0;out_free:	smb_rput(req);out:	return result;}intsmb_proc_mkdir(struct dentry *dentry){	return smb_proc_generic_command(dentry, SMBmkdir);}intsmb_proc_rmdir(struct dentry *dentry){	return smb_proc_generic_command(dentry, SMBrmdir);}#if SMBFS_POSIX_UNLINK/* * Removes readonly attribute from a file. Used by unlink to give posix * semantics. */static intsmb_set_rw(struct dentry *dentry,struct smb_sb_info *server){	int result;	struct smb_fattr fattr;	/* FIXME: cifsUE should allow removing a readonly file. */	/* first get current attribute */	smb_init_dirent(server, &fattr);	result = server->ops->getattr(server, dentry, &fattr);	smb_finish_dirent(server, &fattr);	if (result < 0)		return result;	/* if RONLY attribute is set, remove it */	if (fattr.attr & aRONLY) {  /* read only attribute is set */		fattr.attr &= ~aRONLY;		result = smb_proc_setattr_core(server, dentry, fattr.attr);	}	return result;}#endifintsmb_proc_unlink(struct dentry *dentry){	struct smb_sb_info *server = server_from_dentry(dentry);	int flag = 0;	char *p;	int result;	struct smb_request *req;	result = -ENOMEM;	if (! (req = smb_alloc_request(server, PAGE_SIZE)))		goto out;      retry:	p = smb_setup_header(req, SMBunlink, 1, 0);	WSET(req->rq_header, smb_vwv0, aSYSTEM | aHIDDEN);	result = smb_simple_encode_path(req, &p, dentry, NULL);	if (result < 0)		goto out_free;	smb_setup_bcc(req, p);	if ((result = smb_request_ok(req, SMBunlink, 0, 0)) < 0) {#if SMBFS_POSIX_UNLINK		if (result == -EACCES && !flag) {			/* Posix semantics is for the read-only state			   of a file to be ignored in unlink(). In the			   SMB world a unlink() is refused on a			   read-only file. To make things easier for			   unix users we try to override the files			   permission if the unlink fails with the			   right error.			   This introduces a race condition that could			   lead to a file being written by someone who			   shouldn't have access, but as far as I can			   tell that is unavoidable */			/* remove RONLY attribute and try again */			result = smb_set_rw(dentry,server);			if (result == 0) {				flag = 1;				req->rq_flags = 0;				goto retry;			}		}#endif		goto out_free;	}	result = 0;out_free:	smb_rput(req);out:	return result;}intsmb_proc_flush(struct smb_sb_info *server, __u16 fileid){	int result;	struct smb_request *req;	result = -ENOMEM;	if (! (req = smb_alloc_request(server, 0)))		goto out;	smb_setup_header(req, SMBflush, 1, 0);	WSET(req->rq_header, smb_vwv0, fileid);	req->rq_flags |= SMB_REQ_NORETRY;	result = smb_request_ok(req, SMBflush, 0, 0);	smb_rput(req);out:	return result;}static intsmb_proc_trunc32(struct inode *inode, loff_t length){	/*	 * Writing 0bytes is old-SMB magic for truncating files.	 * MAX_NON_LFS should prevent this from being called with a too	 * large offset.	 */	return smb_proc_write(inode, length, 0, NULL);}static intsmb_proc_trunc64(struct inode *inode, loff_t length){	struct smb_sb_info *server = server_from_inode(inode);	int result;	char *param;	char *data;	struct smb_request *req;	result = -ENOMEM;	if (! (req = smb_alloc_request(server, 14)))		goto out;	param = req->rq_buffer;	data = req->rq_buffer + 6;	/* FIXME: must we also set allocation size? winNT seems to do that */	WSET(param, 0, SMB_I(inode)->fileid);	WSET(param, 2, SMB_SET_FILE_END_OF_FILE_INFO);	WSET(param, 4, 0);	LSET(data, 0, length);	req->rq_trans2_command = TRANSACT2_SETFILEINFO;	req->rq_ldata = 8;	req->rq_data  = data;	req->rq_lparm = 6;	req->rq_parm  = param;	req->rq_flags |= SMB_REQ_NORETRY;	result = smb_add_request(req);	if (result < 0)		goto out_free;	result = 0;	if (req->rq_rcls != 0)		result = smb_errno(req);out_free:	smb_rput(req);out:	return result;}static intsmb_proc_trunc95(struct inode *inode, loff_t length){	struct smb_sb_info *server = server_from_inode(inode);	int result = smb_proc_trunc32(inode, length); 	/*	 * win9x doesn't appear to update the size immediately.	 * It will return the old file size after the truncate,	 * confusing smbfs. So we force an update.	 *	 * FIXME: is this still necessary?	 */	smb_proc_flush(server, SMB_I(inode)->fileid);	return result;}static voidsmb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr){	memset(fattr, 0, sizeof(*fattr));	fattr->f_nlink = 1;	fattr->f_uid = server->mnt->uid;	fattr->f_gid = server->mnt->gid;	fattr->f_unix = 0;}static voidsmb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr){	if (fattr->f_unix)		return;	fattr->f_mode = server->mnt->file_mode;	if (fattr->attr & aDIR) {		fattr->f_mode = server->mnt->dir_mode;		fattr->f_size = SMB_ST_BLKSIZE;	}	/* Check the read-only flag */	if (fattr->attr & aRONLY)		fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);	/* How many 512 byte blocks do we need for this file? */	fattr->f_blocks = 0;	if (fattr->f_size != 0)		fattr->f_blocks = 1 + ((fattr->f_size-1) >> 9);	return;}voidsmb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr,		     struct super_block *sb){	smb_init_dirent(server, fattr);	fattr->attr = aDIR;	fattr->f_ino = 2; /* traditional root inode number */	fattr->f_mtime = current_fs_time(sb);	smb_finish_dirent(server, fattr);}/* * Decode a dirent for old protocols * * qname is filled with the decoded, and possibly translated, name. * fattr receives decoded attributes * * Bugs Noted: * (1) Pathworks servers may pad the name with extra spaces. */static char *smb_decode_short_dirent(struct smb_sb_info *server, char *p,			struct qstr *qname, struct smb_fattr *fattr,			unsigned char *name_buf){	int len;	/*	 * SMB doesn't have a concept of inode numbers ...	 */	smb_init_dirent(server, fattr);	fattr->f_ino = 0;	/* FIXME: do we need this? */	p += SMB_STATUS_SIZE;	/* reserved (search_status) */	fattr->attr = *p;	fattr->f_mtime.tv_sec = date_dos2unix(server, WVAL(p, 3), WVAL(p, 1));	fattr->f_mtime.tv_nsec = 0;	fattr->f_size = DVAL(p, 5);	fattr->f_ctime = fattr->f_mtime;	fattr->f_atime = fattr->f_mtime;	qname->name = p + 9;	len = strnlen(qname->name, 12);	/*	 * Trim trailing blanks for Pathworks servers	 */	while (len > 2 && qname->name[len-1] == ' ')		len--;	smb_finish_dirent(server, fattr);#if 0	/* FIXME: These only work for ascii chars, and recent smbmount doesn't	   allow the flag to be set anyway. It kills const. Remove? */	switch (server->opt.case_handling) {	case SMB_CASE_UPPER:		str_upper(entry->name, len);		break;	case SMB_CASE_LOWER:		str_lower(entry->name, len);		break;	default:		break;	}#endif	qname->len = 0;	len = server->ops->convert(name_buf, SMB_MAXNAMELEN,				   qname->name, len,				   server->remote_nls, server->local_nls);	if (len > 0) {		qname->len = len;		qname->name = name_buf;		DEBUG1("len=%d, name=%.*s\n",qname->len,qname->len,qname->name);	}	return p + 22;}/* * This routine is used to read in directory entries from the network. * Note that it is for short directory name seeks, i.e.: protocol < * SMB_PROTOCOL_LANMAN2 */static intsmb_proc_readdir_short(struct file *filp, void *dirent, filldir_t filldir,		       struct smb_cache_control *ctl){	struct dentry *dir = filp->f_path.dentry;	struct smb_sb_info *server = server_from_dentry(dir);	struct qstr qname;	struct smb_fattr fattr;	char *p;	int result;	int i, first, entries_seen, entries;	int entries_asked = (server->opt.max_xmit - 100) / SMB_DIRINFO_SIZE;	__u16 bcc;	__u16 count;	char status[SMB_STATUS_SIZE];	static struct qstr mask = {		.name	= "*.*",		.len	= 3,	};	unsigned char *last_status;	struct smb_request *req;	unsigned char *name_buf;	VERBOSE("%s/%s\n", DENTRY_PATH(dir));	lock_kernel();	result = -ENOMEM;	if (! (name_buf = kmalloc(SMB_MAXNAMELEN, GFP_KERNEL)))		goto out;	first = 1;	entries = 0;	entries_seen = 2; /* implicit . and .. */	result = -ENOMEM;	if (! (req = smb_alloc_request(server, server->opt.max_xmit)))		goto out_name;	while (1) {		p = smb_setup_header(req, SMBsearch, 2, 0);		WSET(req->rq_header, smb_vwv0, entries_asked);		WSET(req->rq_header, smb_vwv1, aDIR);		if (first == 1) {			result = smb_simple_encode_path(req, &p, dir, &mask);			if (result < 0)				goto out_free;			if (p + 3 > (char *)req->rq_buffer + req->rq_bufsize) {				result = -ENAMETOOLONG;				goto out_free;			}			*p++ = 5;			WSET(p, 0, 0);			p += 2;			first = 0;		} else {			if (p + 5 + SMB_STATUS_SIZE >			    (char *)req->rq_buffer + req->rq_bufsize) {				result = -ENAMETOOLONG;				goto out_free;			}							*p++ = 4;			*p++ = 0;			*p++ = 5;			WSET(p, 0, SMB_STATUS_SIZE);			p += 2;			memcpy(p, status, SMB_STATUS_SIZE);			p += SMB_STATUS_SIZE;		}		smb_setup_bcc(req, p);		result = smb_request_ok(req, SMBsearch, 1, -1);		if (result < 0) {			if ((req->rq_rcls == ERRDOS) && 			    (req->rq_err  == ERRnofiles))				break;			goto out_free;		}		count = WVAL(req->rq_header, smb_vwv0);		if (count <= 0)			break;		result = -EIO;		bcc = smb_bcc(req->rq_header);		if (bcc != count * SMB_DIRINFO_SIZE + 3)			goto out_free;		p = req->rq_buffer + 3;		/* Make sure the response fits in the buffer. Fixed sized 		   entries means we don't have to check in the decode loop. */		last_status = req->rq_buffer + 3 + (count-1) * SMB_DIRINFO_SIZE;		if (last_status + SMB_DIRINFO_SIZE >=		    req->rq_buffer + req->rq_bufsize) {			printk(KERN_ERR "smb_proc_readdir_short: "			       "last dir entry outside buffer! "			       "%d@%p  %d@%p\n", SMB_DIRINFO_SIZE, last_status,			       req->rq_bufsize, req->rq_buffer);			goto out_free;		}		/* Read the last entry into the status field. */		memcpy(status, last_status, SMB_STATUS_SIZE);		/* Now we are ready to parse smb directory entries. */		for (i = 0; i < count; i++) {			p = smb_decode_short_dirent(server, p, 						    &qname, &fattr, name_buf);			if (qname.len == 0)				continue;			if (entries_seen == 2 && qname.name[0] == '.') {				if (qname.len == 1)					continue;				if (qname.name[1] == '.' && qname.len == 2)					continue;			}			if (!smb_fill_cache(filp, dirent, filldir, ctl, 					    &qname, &fattr))				;	/* stop reading? */			entries_seen++;		}	}	result = entries;out_free:	smb_rput(req);out_name:	kfree(name_buf);out:	unlock_kernel();	return result;}static void smb_decode_unix_basic(struct smb_fattr *fattr, struct smb_sb_info *server, char *p){	u64 size, disk_bytes;	/* FIXME: verify nls support. all is sent as utf8? */	fattr->f_unix = 1;	fattr->f_mode = 0;	/* FIXME: use the uniqueID from the remote instead? */	/* 0 L file size in bytes */	/* 8 L file size on disk in bytes (block count) */	/* 40 L uid */	/* 48 L gid */	/* 56 W file type */	/* 60 L devmajor */	/* 68 L devminor */	/* 76 L unique ID (inode) */	/* 84 L permissions */	/* 92 L link count */	size = LVAL(p, 0);	disk_bytes = LVAL(p, 8);	/*	 * Some samba versions round up on-disk byte usage	 * to 1MB boundaries, making it useless. When seeing	 * that, use the size instead.	 */	if (!(disk_bytes & 0xfffff))		disk_bytes = size+511;	fattr->f_size = size;	fattr->f_blocks = disk_bytes >> 9;	fattr->f_ctime = smb_ntutc2unixutc(LVAL(p, 16));	fattr->f_atime = smb_ntutc2unixutc(LVAL(p, 24));	fattr->f_mtime = smb_ntutc2unixutc(LVAL(p, 32));	if (server->mnt->flags & SMB_MOUNT_UID)		fattr->f_uid = server->mnt->uid;	else		fattr->f_uid = LVAL(p, 40);	if (server->mnt->flags & SMB_MOUNT_GID)		fattr->f_gid = server->mnt->gid;	else		fattr->f_gid = LVAL(p, 48);	fattr->f_mode |= smb_filetype_to_mode(WVAL(p, 56));	if (S_ISBLK(fattr->f_mode) || S_ISCHR(fattr->f_mode)) {		__u64 major = LVAL(p, 60);		__u64 minor = LVAL(p, 68);		fattr->f_rdev = MKDEV(major & 0xffffffff, minor & 0xffffffff);		if (MAJOR(fattr->f_rdev) != (major & 0xffffffff) ||	    	MINOR(fattr->f_rdev) != (minor & 0xffffffff))			fattr->f_rdev = 0;	}

⌨️ 快捷键说明

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