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

📄 proc.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 4 页
字号:
		goto out;	p += result;	smb_setup_bcc(server, p);	if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) {		if (smb_retry(server))			goto retry;		goto out;	}	result = 0;out:	smb_unlock_server(server);	return result;}/* * 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;	smb_lock_server(server);      retry:	p = smb_setup_header(server, command, 0, 0);	*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, command, 0, 0);	if (result < 0) {		if (smb_retry(server))			goto retry;		goto out;	}	result = 0;out:	smb_unlock_server(server);	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. * Note: called with the server locked. */static intsmb_set_rw(struct dentry *dentry,struct smb_sb_info *server){	int result;	struct smb_fattr fattr;	/* first get current attribute */	result = smb_proc_do_getattr(server, dentry, &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;	smb_lock_server(server);      retry:	p = smb_setup_header(server, SMBunlink, 1, 0);	WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);	*p++ = 4;	result = smb_encode_path(server, p, dentry, NULL);	if (result < 0)		goto out;	p += result;	smb_setup_bcc(server, p);	if ((result = smb_request_ok(server, 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;				goto retry;			}		}#endif		if (smb_retry(server))			goto retry;		goto out;	}	result = 0;out:	smb_unlock_server(server);	return result;}intsmb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length){	char *p;	int result;	smb_lock_server(server);      retry:	p = smb_setup_header(server, SMBwrite, 5, 0);	WSET(server->packet, smb_vwv0, fid);	WSET(server->packet, smb_vwv1, 0);	DSET(server->packet, smb_vwv2, length);	WSET(server->packet, smb_vwv4, 0);	*p++ = 4;	*p++ = 0;	smb_setup_bcc(server, p);	if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0) {		if (smb_retry(server))			goto retry;		goto out;	}	result = 0;out:	smb_unlock_server(server);	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_blksize = 512;}static voidsmb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr){	fattr->f_mode = server->mnt->file_mode;	if (fattr->attr & aDIR)	{		fattr->f_mode = server->mnt->dir_mode;		fattr->f_size = 512;	}	/* Check the read-only flag */	if (fattr->attr & aRONLY)		fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);	fattr->f_blocks = 0;	if ((fattr->f_blksize != 0) && (fattr->f_size != 0))	{		fattr->f_blocks =		    (fattr->f_size - 1) / fattr->f_blksize + 1;	}	return;}voidsmb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr){	smb_init_dirent(server, fattr);	fattr->attr = aDIR;	fattr->f_ino = 2; /* traditional root inode number */	fattr->f_mtime = CURRENT_TIME;	smb_finish_dirent(server, fattr);}/* * Note that we are now returning the name as a reference to avoid * an extra copy, and that the upper/lower casing is done in place. * * Bugs Noted: * (1) Pathworks servers may pad the name with extra spaces. */static __u8 *smb_decode_dirent(struct smb_sb_info *server, __u8 *p, 			struct cache_dirent *entry){	int len;	/*	 * SMB doesn't have a concept of inode numbers ...	 */	entry->ino = 0;	p += SMB_STATUS_SIZE;	/* reserved (search_status) */	entry->name = p + 9;	len = strlen(entry->name);	if (len > 12)		len = 12;	/*	 * Trim trailing blanks for Pathworks servers	 */	while (len > 2 && entry->name[len-1] == ' ')		len--;	entry->len = len;	/* 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(entry->name, len);		break;	case SMB_CASE_LOWER:		str_lower(entry->name, len);		break;	default:		break;	}	entry->len = server->convert(server->name_buf, SMB_MAXNAMELEN,				     entry->name, len,				     server->remote_nls, server->local_nls);	entry->name = server->name_buf;	DEBUG1("len=%d, name=%.*s\n", entry->len, entry->len, entry->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 smb_sb_info *server, struct dentry *dir, int fpos,		       void *cachep){	unsigned 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, pos=%d\n", DENTRY_PATH(dir), fpos);	smb_lock_server(server);	/* N.B. We need to reinitialize the cache to restart */retry:	smb_init_dircache(cachep);	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);		*p++ = 4;		if (first == 1) {			result = smb_encode_path(server, p, dir, &mask);			if (result < 0)				goto unlock_return;			p += result;			*p++ = 5;			WSET(p, 0, 0);			p += 2;			first = 0;		} else {			*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))				goto retry;			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++) {			struct cache_dirent this_ent, *entry = &this_ent;			p = smb_decode_dirent(server, p, entry);			if (entries_seen == 2 && entry->name[0] == '.') {				if (entry->len == 1)					continue;				if (entry->name[1] == '.' && entry->len == 2)					continue;			}			if (entries_seen >= fpos) {				DEBUG1("fpos=%u\n", entries_seen);				smb_add_to_cache(cachep, entry, entries_seen);				entries++;			} else {				VERBOSE("skipped, seen=%d, i=%d, fpos=%d\n",					entries_seen, i, fpos);			}			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 * * We return a reference to the name string to avoid copying, and perform * any needed upper/lower casing in place. * * 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,			struct cache_dirent *entry, int level){	char *result;	unsigned int len = 0;	/*	 * SMB doesn't have a concept of inode numbers ...	 */	entry->ino = 0;	switch (level) {	case 1:		len = *((unsigned char *) p + 22);		entry->name = p + 23;		result = p + 24 + len;		VERBOSE("info 1 at %p, len=%d, name=%.*s\n",			p, len, len, entry->name);		break;	case 260:		result = p + WVAL(p, 0);		len = DVAL(p, 60);		if (len > 255) len = 255;		/* NT4 null terminates */		entry->name = p + 94;		if (len && entry->name[len-1] == '\0')			len--;		VERBOSE("info 260 at %p, len=%d, name=%.*s\n",			p, len, len, entry->name);		break;	default:		PARANOIA("Unknown info level %d\n", level);		result = p + WVAL(p, 0);		goto out;	}	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;	}	entry->len = server->convert(server->name_buf, SMB_MAXNAMELEN,				     entry->name, len,				     server->remote_nls, server->local_nls);	entry->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 smb_sb_info *server, struct dentry *dir, int fpos,		      void *cachep){	unsigned char *p;	char *mask, *lastname, *param = server->temp_buf;	__u16 command;	int first, entries, 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);retry:	/*	 * Encode the initial path	 */	mask = param + 12;	mask_len = smb_encode_path(server, mask, dir, &star);	if (mask_len < 0) {		entries = mask_len;		goto unlock_return;	}	first = 1;	VERBOSE("starting fpos=%d, mask=%s\n", fpos, mask);	/*	 * We must reinitialize the dircache when retrying.	 */	smb_init_dircache(cachep);	entries = 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");			entries = -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);				goto retry;			}			PARANOIA("error=%d, breaking\n", result);			entries = 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) { 			PARANOIA("name=%s, entries=%d, rcls=%d, err=%d\n",				 mask, entries, server->rcls, server->err);			entries = -smb_errno(server);			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;

⌨️ 快捷键说明

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