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

📄 proc.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 5 页
字号:
	/*	 * Trim trailing blanks for Pathworks servers	 */	while (len > 2 && qname->name[len-1] == ' ')		len--;	qname->len = 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 = server->convert(server->name_buf, SMB_MAXNAMELEN,				     qname->name, len,				     server->remote_nls, server->local_nls);	qname->name = server->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_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 = { "*.*", 3, 0 };	unsigned char *last_status;	VERBOSE("%s/%s\n", DENTRY_PATH(dir));	smb_lock_server(server);	first = 1;	entries = 0;	entries_seen = 2; /* implicit . and .. */	while (1) {		p = smb_setup_header(server, SMBsearch, 2, 0);		WSET(server->packet, smb_vwv0, entries_asked);		WSET(server->packet, smb_vwv1, aDIR);		if (first == 1) {			result = smb_simple_encode_path(server, &p, dir, &mask);			if (result < 0)				goto unlock_return;			if (p + 3 > (char*)server->packet+server->packet_size) {				result = -ENAMETOOLONG;				goto unlock_return;			}			*p++ = 5;			WSET(p, 0, 0);			p += 2;			first = 0;		} else {			if (p + 5 + SMB_STATUS_SIZE >			    (char*)server->packet + server->packet_size) {				result = -ENAMETOOLONG;				goto unlock_return;			}							*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(server, p);		result = smb_request_ok(server, SMBsearch, 1, -1);		if (result < 0) {			if ((server->rcls == ERRDOS) && 			    (server->err  == ERRnofiles))				break;			if (smb_retry(server)) {				ctl->idx = -1;	/* retry */				result = 0;			}			goto unlock_return;		}		p = SMB_VWV(server->packet);		count = WVAL(p, 0);		if (count <= 0)			break;		result = -EIO;		bcc = WVAL(p, 2);		if (bcc != count * SMB_DIRINFO_SIZE + 3)			goto unlock_return;		p += 7;		/* Make sure the response fits in the buffer. Fixed sized 		   entries means we don't have to check in the decode loop. */		last_status = SMB_BUF(server->packet) + 3 + (count - 1) *			SMB_DIRINFO_SIZE;		if (last_status + SMB_DIRINFO_SIZE >=		    server->packet + server->packet_size) {			printk(KERN_ERR "smb_proc_readdir_short: "			       "last dir entry outside buffer! "			       "%d@%p  %d@%p\n", SMB_DIRINFO_SIZE, last_status,			       server->packet_size, server->packet);			goto unlock_return;		}		/* 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);			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;unlock_return:	smb_unlock_server(server);	return result;}/* * 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){	char *result;	unsigned int len = 0;	__u16 date, time;	/*	 * 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 = date_dos2unix(server, date, time);		date = WVAL(p, 4);		time = WVAL(p, 6);		fattr->f_atime = date_dos2unix(server, date, time);		date = WVAL(p, 8);		time = WVAL(p, 10);		fattr->f_mtime = date_dos2unix(server, date, time);		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 */		qname->name = p + 94;		if (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 = DVAL(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;	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 = server->convert(server->name_buf, SMB_MAXNAMELEN,				     qname->name, len,				     server->remote_nls, server->local_nls);	qname->name = server->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_dentry;	struct smb_sb_info *server = server_from_dentry(dir);	struct qstr qname;	struct smb_fattr fattr;	unsigned char *p, *lastname;	char *mask, *param = server->temp_buf;	__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 char *resp_data = NULL;	unsigned char *resp_param = NULL;	int resp_data_len = 0;	int resp_param_len = 0;	int ff_searchcount = 0;	int ff_eos = 0;	int ff_lastname = 0;	int ff_dir_handle = 0;	int loop_count = 0;	int mask_len, i, result;	static struct qstr star = { "*", 1, 0 };	/*	 * use info level 1 for older servers that don't do 260	 */	if (server->opt.protocol < SMB_PROTOCOL_NT1)		info_level = 1;	smb_lock_server(server);	/*	 * Encode the initial path	 */	mask = param + 12;	mask_len = smb_encode_path(server, mask, SMB_MAXNAMELEN+1, dir, &star);	if (mask_len < 0) {		result = mask_len;		goto unlock_return;	}	mask_len--;	/* mask_len is strlen, not #bytes */	first = 1;	VERBOSE("starting mask_len=%d, mask=%s\n", mask_len, mask);	result = 0;	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);			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);		}		result = smb_trans2_request(server, command,					    0, NULL, 12 + mask_len + 1, param,					    &resp_data_len, &resp_data,					    &resp_param_len, &resp_param);		if (result < 0) {			if (smb_retry(server)) {				PARANOIA("error=%d, retrying\n", result);				ctl->idx = -1;	/* retry */				result = 0;				goto unlock_return;			}			PARANOIA("error=%d, breaking\n", result);			break;		}		if (server->rcls == ERRSRV && server->err == ERRerror) {			/* a damn Win95 bug - sometimes it clags if you 			   ask it too fast */			current->state = TASK_INTERRUPTIBLE;			schedule_timeout(HZ/5);			continue;                }		if (server->rcls != 0) {			result = smb_errno(server);			PARANOIA("name=%s, result=%d, rcls=%d, err=%d\n",				 mask, result, server->rcls, server->err);			break;		}		/* parse out some important return info */		if (first != 0) {			ff_dir_handle = WVAL(resp_param, 0);			ff_searchcount = WVAL(resp_param, 2);			ff_eos = WVAL(resp_param, 4);			ff_lastname = WVAL(resp_param, 8);		} else {			ff_searchcount = WVAL(resp_param, 0);			ff_eos = WVAL(resp_param, 2);			ff_lastname = WVAL(resp_param, 6);		}		if (ff_searchcount == 0)			break;		/*		 * 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		 *		 * Both are happy if we return the data they point to. So we do.		 */		mask_len = 0;		if (ff_lastname > 0 && ff_lastname < resp_data_len) {			lastname = resp_data + ff_lastname;			switch (info_level) {			case 260:				mask_len = resp_data_len - ff_lastname;				break;			case 1:				/* lastname points to a length byte */				mask_len = *lastname++;				if (ff_lastname + 1 + mask_len > resp_data_len)					mask_len = resp_data_len - ff_lastname - 1;				break;			}			/*			 * Update the mask string for the next message.			 */			if (mask_len < 0)				mask_len = 0;			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, resp_data_len, mask_len, mask);		/* Now we are ready to parse smb directory entries. */		/* point to the data bytes */		p = resp_data;		for (i = 0; i < ff_searchcount; i++) {			/* make sure we stay within the buffer */			if (p >= resp_data + resp_data_len) {				printk(KERN_ERR "smb_proc_readdir_long: "				       "dirent pointer outside buffer! "				       "%p  %d@%p  %d@%p\n",				       p, resp_data_len, resp_data,				       server->packet_size, server->packet);				result = -EIO; /* always a comm. error? */				goto unlock_return;			}			p = smb_decode_long_dirent(server, p, info_level,						   &qname, &fattr);			/* 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);		first = 0;		loop_count = 0;	}unlock_return:	smb_unlock_server(server);	return result;}intsmb_proc_readdir(struct file *filp, void *dirent, filldir_t filldir,		 struct smb_cache_control *ctl){	struct smb_sb_info *server = server_from_dentry(filp->f_dentry);	if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)		return smb_proc_readdir_long(filp, dirent, filldir, ctl);	else		return smb_proc_readdir_short(filp, dirent, filldir, ctl);}/* * This version uses the trans2 TRANSACT2_FINDFIRST message  * to get the attribute data. * Note: called with the server locked. * * Bugs Noted:

⌨️ 快捷键说明

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