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

📄 proc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	fattr->f_mode |= LVAL(p, 84);	if ( (server->mnt->flags & SMB_MOUNT_DMODE) &&	     (S_ISDIR(fattr->f_mode)) )		fattr->f_mode = (server->mnt->dir_mode & S_IRWXUGO) | S_IFDIR;	else if ( (server->mnt->flags & SMB_MOUNT_FMODE) &&	          !(S_ISDIR(fattr->f_mode)) )		fattr->f_mode = (server->mnt->file_mode & S_IRWXUGO) |				(fattr->f_mode & S_IFMT);}/* * Interpret a long filename structure using the specified info level: *   level 1 for anything below NT1 protocol *   level 260 for NT1 protocol * * qname is filled with the decoded, and possibly translated, name * fattr receives decoded attributes. * * Bugs Noted: * (1) Win NT 4.0 appends a null byte to names and counts it in the length! */static char *smb_decode_long_dirent(struct smb_sb_info *server, char *p, int level,		       struct qstr *qname, struct smb_fattr *fattr,		       unsigned char *name_buf){	char *result;	unsigned int len = 0;	int n;	__u16 date, time;	int unicode = (server->mnt->flags & SMB_MOUNT_UNICODE);	/*	 * SMB doesn't have a concept of inode numbers ...	 */	smb_init_dirent(server, fattr);	fattr->f_ino = 0;	/* FIXME: do we need this? */	switch (level) {	case 1:		len = *((unsigned char *) p + 22);		qname->name = p + 23;		result = p + 24 + len;		date = WVAL(p, 0);		time = WVAL(p, 2);		fattr->f_ctime.tv_sec = date_dos2unix(server, date, time);		fattr->f_ctime.tv_nsec = 0;		date = WVAL(p, 4);		time = WVAL(p, 6);		fattr->f_atime.tv_sec = date_dos2unix(server, date, time);		fattr->f_atime.tv_nsec = 0;		date = WVAL(p, 8);		time = WVAL(p, 10);		fattr->f_mtime.tv_sec = date_dos2unix(server, date, time);		fattr->f_mtime.tv_nsec = 0;		fattr->f_size = DVAL(p, 12);		/* ULONG allocation size */		fattr->attr = WVAL(p, 20);		VERBOSE("info 1 at %p, len=%d, name=%.*s\n",			p, len, len, qname->name);		break;	case 260:		result = p + WVAL(p, 0);		len = DVAL(p, 60);		if (len > 255) len = 255;		/* NT4 null terminates, unless we are using unicode ... */		qname->name = p + 94;		if (!unicode && len && qname->name[len-1] == '\0')			len--;		fattr->f_ctime = smb_ntutc2unixutc(LVAL(p, 8));		fattr->f_atime = smb_ntutc2unixutc(LVAL(p, 16));		fattr->f_mtime = smb_ntutc2unixutc(LVAL(p, 24));		/* change time (32) */		fattr->f_size = LVAL(p, 40);		/* alloc size (48) */		fattr->attr = DVAL(p, 56);		VERBOSE("info 260 at %p, len=%d, name=%.*s\n",			p, len, len, qname->name);		break;	case SMB_FIND_FILE_UNIX:		result = p + WVAL(p, 0);		qname->name = p + 108;		len = strlen(qname->name);		/* FIXME: should we check the length?? */		p += 8;		smb_decode_unix_basic(fattr, server, p);		VERBOSE("info SMB_FIND_FILE_UNIX at %p, len=%d, name=%.*s\n",			p, len, len, qname->name);		break;	default:		PARANOIA("Unknown info level %d\n", level);		result = p + WVAL(p, 0);		goto out;	}	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. Remove? */	switch (server->opt.case_handling) {	case SMB_CASE_UPPER:		str_upper(qname->name, len);		break;	case SMB_CASE_LOWER:		str_lower(qname->name, len);		break;	default:		break;	}#endif	qname->len = 0;	n = server->ops->convert(name_buf, SMB_MAXNAMELEN,				 qname->name, len,				 server->remote_nls, server->local_nls);	if (n > 0) {		qname->len = n;		qname->name = name_buf;	}out:	return result;}/* findfirst/findnext flags */#define SMB_CLOSE_AFTER_FIRST (1<<0)#define SMB_CLOSE_IF_END (1<<1)#define SMB_REQUIRE_RESUME_KEY (1<<2)#define SMB_CONTINUE_BIT (1<<3)/* * Note: samba-2.0.7 (at least) has a very similar routine, cli_list, in * source/libsmb/clilist.c. When looking for smb bugs in the readdir code, * go there for advise. * * Bugs Noted: * (1) When using Info Level 1 Win NT 4.0 truncates directory listings  * for certain patterns of names and/or lengths. The breakage pattern * is completely reproducible and can be toggled by the creation of a * single file. (E.g. echo hi >foo breaks, rm -f foo works.) */static intsmb_proc_readdir_long(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;	unsigned char *p, *lastname;	char *mask, *param;	__u16 command;	int first, entries_seen;	/* Both NT and OS/2 accept info level 1 (but see note below). */	int info_level = 260;	const int max_matches = 512;	unsigned int ff_searchcount = 0;	unsigned int ff_eos = 0;	unsigned int ff_lastname = 0;	unsigned int ff_dir_handle = 0;	unsigned int loop_count = 0;	unsigned int mask_len, i;	int result;	struct smb_request *req;	unsigned char *name_buf;	static struct qstr star = {		.name	= "*",		.len	= 1,	};	lock_kernel();	/*	 * We always prefer unix style. Use info level 1 for older	 * servers that don't do 260.	 */	if (server->opt.capabilities & SMB_CAP_UNIX)		info_level = SMB_FIND_FILE_UNIX;	else if (server->opt.protocol < SMB_PROTOCOL_NT1)		info_level = 1;	result = -ENOMEM;	if (! (name_buf = kmalloc(SMB_MAXNAMELEN+2, GFP_KERNEL)))		goto out;	if (! (req = smb_alloc_request(server, server->opt.max_xmit)))		goto out_name;	param = req->rq_buffer;	/*	 * Encode the initial path	 */	mask = param + 12;	result = smb_encode_path(server, mask, SMB_MAXPATHLEN+1, dir, &star);	if (result <= 0)		goto out_free;	mask_len = result - 1;	/* mask_len is strlen, not #bytes */	result = 0;	first = 1;	VERBOSE("starting mask_len=%d, mask=%s\n", mask_len, mask);	entries_seen = 2;	ff_eos = 0;	while (ff_eos == 0) {		loop_count += 1;		if (loop_count > 10) {			printk(KERN_WARNING "smb_proc_readdir_long: "			       "Looping in FIND_NEXT??\n");			result = -EIO;			break;		}		if (first != 0) {			command = TRANSACT2_FINDFIRST;			WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);			WSET(param, 2, max_matches);	/* max count */			WSET(param, 4, SMB_CLOSE_IF_END);			WSET(param, 6, info_level);			DSET(param, 8, 0);		} else {			command = TRANSACT2_FINDNEXT;			VERBOSE("handle=0x%X, lastname=%d, mask=%.*s\n",				ff_dir_handle, ff_lastname, mask_len, mask);			WSET(param, 0, ff_dir_handle);	/* search handle */			WSET(param, 2, max_matches);	/* max count */			WSET(param, 4, info_level);			DSET(param, 6, 0);			WSET(param, 10, SMB_CONTINUE_BIT|SMB_CLOSE_IF_END);		}		req->rq_trans2_command = command;		req->rq_ldata = 0;		req->rq_data  = NULL;		req->rq_lparm = 12 + mask_len + 1;		req->rq_parm  = param;		req->rq_flags = 0;		result = smb_add_request(req);		if (result < 0) {			PARANOIA("error=%d, breaking\n", result);			break;		}		if (req->rq_rcls == ERRSRV && req->rq_err == ERRerror) {			/* a damn Win95 bug - sometimes it clags if you 			   ask it too fast */			schedule_timeout_interruptible(msecs_to_jiffies(200));			continue;                }		if (req->rq_rcls != 0) {			result = smb_errno(req);			PARANOIA("name=%s, result=%d, rcls=%d, err=%d\n",				 mask, result, req->rq_rcls, req->rq_err);			break;		}		/* parse out some important return info */		if (first != 0) {			ff_dir_handle = WVAL(req->rq_parm, 0);			ff_searchcount = WVAL(req->rq_parm, 2);			ff_eos = WVAL(req->rq_parm, 4);			ff_lastname = WVAL(req->rq_parm, 8);		} else {			ff_searchcount = WVAL(req->rq_parm, 0);			ff_eos = WVAL(req->rq_parm, 2);			ff_lastname = WVAL(req->rq_parm, 6);		}		if (ff_searchcount == 0)			break;		/* Now we are ready to parse smb directory entries. */		/* point to the data bytes */		p = req->rq_data;		for (i = 0; i < ff_searchcount; i++) {			/* make sure we stay within the buffer */			if (p >= req->rq_data + req->rq_ldata) {				printk(KERN_ERR "smb_proc_readdir_long: "				       "dirent pointer outside buffer! "				       "%p  %d@%p\n",				       p, req->rq_ldata, req->rq_data);				result = -EIO; /* always a comm. error? */				goto out_free;			}			p = smb_decode_long_dirent(server, p, info_level,						   &qname, &fattr, name_buf);			/* ignore . and .. from the server */			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++;		}		VERBOSE("received %d entries, eos=%d\n", ff_searchcount,ff_eos);		/*		 * We might need the lastname for continuations.		 *		 * Note that some servers (win95?) point to the filename and		 * others (NT4, Samba using NT1) to the dir entry. We assume		 * here that those who do not point to a filename do not need		 * this info to continue the listing.		 *		 * OS/2 needs this and talks infolevel 1.		 * NetApps want lastname with infolevel 260.		 * win2k want lastname with infolevel 260, and points to		 *       the record not to the name.		 * Samba+CifsUnixExt doesn't need lastname.		 *		 * Both are happy if we return the data they point to. So we do.		 * (FIXME: above is not true with win2k)		 */		mask_len = 0;		if (info_level != SMB_FIND_FILE_UNIX &&		    ff_lastname > 0 && ff_lastname < req->rq_ldata) {			lastname = req->rq_data + ff_lastname;			switch (info_level) {			case 260:				mask_len = req->rq_ldata - ff_lastname;				break;			case 1:				/* lastname points to a length byte */				mask_len = *lastname++;				if (ff_lastname + 1 + mask_len > req->rq_ldata)					mask_len = req->rq_ldata - ff_lastname - 1;				break;			}			/*			 * Update the mask string for the next message.			 */			if (mask_len > 255)				mask_len = 255;			if (mask_len)				strncpy(mask, lastname, mask_len);		}		mask_len = strnlen(mask, mask_len);		VERBOSE("new mask, len=%d@%d of %d, mask=%.*s\n",			mask_len, ff_lastname, req->rq_ldata, mask_len, mask);		first = 0;		loop_count = 0;	}out_free:	smb_rput(req);out_name:	kfree(name_buf);out:	unlock_kernel();	return result;}/* * This version uses the trans2 TRANSACT2_FINDFIRST message  * to get the attribute data. * * Bugs Noted: */static intsmb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry,			struct smb_fattr *fattr){	char *param, *mask;	__u16 date, time;	int mask_len, result;	struct smb_request *req;	result = -ENOMEM;	if (! (req = smb_alloc_request(server, PAGE_SIZE)))		goto out;	param = req->rq_buffer;	mask = param + 12;	mask_len = smb_encode_path(server, mask, SMB_MAXPATHLEN+1, dentry,NULL);	if (mask_len < 0) {		result = mask_len;		goto out_free;	}	VERBOSE("name=%s, len=%d\n", mask, mask_len);	WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);	WSET(param, 2, 1);	/* max count */	WSET(param, 4, 1);	/* close after this call */	WSET(param, 6, 1);	/* info_level */	DSET(param, 8, 0);	req->rq_trans2_command = TRANSACT2_FINDFIRST;	req->rq_ldata = 0;	req->rq_data  = NULL;	req->rq_lparm = 12 + mask_len;	req->rq_parm  = param;	req->rq_flags = 0;	result = smb_add_request(req);	if (result < 0)		goto out_free;	if (req->rq_rcls != 0) {		result = smb_errno(req);#ifdef SMBFS_PARANOIA		if (result != -ENOENT)			PARANOIA("error for %s, rcls=%d, err=%d\n",				 mask, req->rq_rcls, req->rq_err);#endif		goto out_free;	}	/* Make sure we got enough data ... */	result = -EINVAL;	if (req->rq_ldata < 22 || WVAL(req->rq_parm, 2) != 1) {		PARANOIA("bad result for %s, len=%d, count=%d\n",			 mask, req->rq_ldata, WVAL(req->rq_parm, 2));		goto out_free;	}	/*	 * Decode the response into the fattr ...	 */	date = WVAL(req->rq_data, 0);	time = WVAL(req->rq_data, 2);	fattr->f_ctime.tv_sec = date_dos2unix(server, date, time);	fattr->f_ctime.tv_nsec = 0;	date = WVAL(req->rq_data, 4);	time = WVAL(req->rq_data, 6);	fattr->f_atime.tv_sec = date_dos2unix(server, date, time);	fattr->f_atime.tv_nsec = 0;	date = WVAL(req->rq_data, 8);	time = WVAL(req->rq_data, 10);	fattr->f_mtime.tv_sec = date_dos2unix(server, date, time);	fattr->f_mtime.tv_nsec = 0;	VERBOSE("name=%s, date=%x, time=%x, mtime=%ld\n",		mask, date, time, fattr->f_mtime.tv_sec);	fattr->f_size = DVAL(req->rq_data, 12);	/* ULONG allocation size */	fattr->attr = WVAL(req->rq_data, 20);	result = 0;out_free:	smb_rput(req);out:	return result;}static intsmb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir,		      struct smb_fattr *fattr){	int result;	char *p;	struct smb_request *req;	result = -ENOMEM;	if (! (req = smb_alloc_request(server, PAGE_SIZE)))		goto out;	p = smb_setup_header(req, SMBgetatr, 0, 0);	result = smb_simple_encode_path(req, &p, dir, NULL);	if (result < 0) 		goto out_free;	smb_setup_bcc(req, p);	if ((result = smb_request_ok(req, SMBgetatr, 10, 0)) < 0)		goto out_free;	fattr->attr    = WVAL(req->rq_header, smb_vwv0);	fattr->f_mtime.tv_sec = local2utc(server, DVAL(req->rq_header, smb_vwv1));	fattr->f_mtime.tv_nsec = 0;	fattr->f_size  = DVAL(req->rq_header, smb_vwv3);	fattr->f_ctime = fattr->f_mtime; 	fattr->f_atime = fattr->f_mtime; #ifdef SMBFS_DEBUG_TIMESTAMP	printk("getattr_core: %s/%s, mtime=%ld\n",	       DENTRY_PATH(dir), fattr->f_mtime);#endif	result = 0;out_free:	smb_rput(req);out:	return result;}/* * Bugs Noted: * (1) Win 95 swaps the date and time fields in the standard info level. */static intsmb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,			struct smb_request *req, int infolevel){	char *p, *param;	int result;	param = req->rq_buffer;	WSET(param, 0, infolevel);	DSET(param, 2, 0);	result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, dir, NULL);	if (result < 0)		goto out;	p = param + 6 + result;	req->rq_trans2_command = TRANSACT2_QPATHINFO;	req->rq_ldata = 0;	req->rq_data  = NULL;

⌨️ 快捷键说明

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