diff options
| author | Christoph Hellwig <[email protected]> | 2011-07-16 15:24:05 -0400 | 
|---|---|---|
| committer | Steve French <[email protected]> | 2011-07-25 21:36:44 +0000 | 
| commit | cda0ec6a86f18127d490048a46de954c03886d5e (patch) | |
| tree | 82497b560bff0119054abbf6d1c6686c09bb4842 | |
| parent | 9feed6f8fbab477b6339efb4f3119a3c22dc187e (diff) | |
cifs: introduce cifs_dirent
Introduce a generic directory entry structure, and factor the parsing
of the various on the wire structures that can represent one into
a common helper.  Switch cifs_entry_is_dot over to use it as a start.
Signed-off-by: Christoph Hellwig <[email protected]>
Reviewed-by: Jeff Layton <[email protected]>
Signed-off-by: Steve French <[email protected]>
| -rw-r--r-- | fs/cifs/readdir.c | 194 | 
1 files changed, 125 insertions, 69 deletions
| diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 04c9b9fbebb4..67fc1199699f 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -4,6 +4,7 @@   *   Directory search handling   *   *   Copyright (C) International Business Machines  Corp., 2004, 2008 + *   Copyright (C) Red Hat, Inc., 2011   *   Author(s): Steve French ([email protected])   *   *   This library is free software; you can redistribute it and/or modify @@ -290,10 +291,10 @@ error_exit:  }  /* return length of unicode string in bytes */ -static int cifs_unicode_bytelen(char *str) +static int cifs_unicode_bytelen(const char *str)  {  	int len; -	__le16 *ustr = (__le16 *)str; +	const __le16 *ustr = (const __le16 *)str;  	for (len = 0; len <= PATH_MAX; len++) {  		if (ustr[len] == 0) @@ -334,78 +335,128 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)  } +struct cifs_dirent { +	const char	*name; +	size_t		namelen; +	u32		resume_key; +	u64		ino; +}; + +static void cifs_fill_dirent_unix(struct cifs_dirent *de, +		const FILE_UNIX_INFO *info, bool is_unicode) +{ +	de->name = &info->FileName[0]; +	if (is_unicode) +		de->namelen = cifs_unicode_bytelen(de->name); +	else +		de->namelen = strnlen(de->name, PATH_MAX); +	de->resume_key = info->ResumeKey; +	de->ino = le64_to_cpu(info->basic.UniqueId); +} + +static void cifs_fill_dirent_dir(struct cifs_dirent *de, +		const FILE_DIRECTORY_INFO *info) +{ +	de->name = &info->FileName[0]; +	de->namelen = le32_to_cpu(info->FileNameLength); +	de->resume_key = info->FileIndex; +} + +static void cifs_fill_dirent_full(struct cifs_dirent *de, +		const FILE_FULL_DIRECTORY_INFO *info) +{ +	de->name = &info->FileName[0]; +	de->namelen = le32_to_cpu(info->FileNameLength); +	de->resume_key = info->FileIndex; +} + +static void cifs_fill_dirent_search(struct cifs_dirent *de, +		const SEARCH_ID_FULL_DIR_INFO *info) +{ +	de->name = &info->FileName[0]; +	de->namelen = le32_to_cpu(info->FileNameLength); +	de->resume_key = info->FileIndex; +	de->ino = le64_to_cpu(info->UniqueId); +} + +static void cifs_fill_dirent_both(struct cifs_dirent *de, +		const FILE_BOTH_DIRECTORY_INFO *info) +{ +	de->name = &info->FileName[0]; +	de->namelen = le32_to_cpu(info->FileNameLength); +	de->resume_key = info->FileIndex; +} + +static void cifs_fill_dirent_std(struct cifs_dirent *de, +		const FIND_FILE_STANDARD_INFO *info) +{ +	de->name = &info->FileName[0]; +	/* one byte length, no endianess conversion */ +	de->namelen = info->FileNameLength; +	de->resume_key = info->ResumeKey; +} + +static int cifs_fill_dirent(struct cifs_dirent *de, const void *info, +		u16 level, bool is_unicode) +{ +	memset(de, 0, sizeof(*de)); + +	switch (level) { +	case SMB_FIND_FILE_UNIX: +		cifs_fill_dirent_unix(de, info, is_unicode); +		break; +	case SMB_FIND_FILE_DIRECTORY_INFO: +		cifs_fill_dirent_dir(de, info); +		break; +	case SMB_FIND_FILE_FULL_DIRECTORY_INFO: +		cifs_fill_dirent_full(de, info); +		break; +	case SMB_FIND_FILE_ID_FULL_DIR_INFO: +		cifs_fill_dirent_search(de, info); +		break; +	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: +		cifs_fill_dirent_both(de, info); +		break; +	case SMB_FIND_FILE_INFO_STANDARD: +		cifs_fill_dirent_std(de, info); +		break; +	default: +		cFYI(1, "Unknown findfirst level %d", level); +		return -EINVAL; +	} + +	return 0; +} +  #define UNICODE_DOT cpu_to_le16(0x2e)  /* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */ -static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) +static int cifs_entry_is_dot(struct cifs_dirent *de, bool is_unicode)  {  	int rc = 0; -	char *filename = NULL; -	int len = 0; -	if (cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) { -		FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry; -		filename = &pFindData->FileName[0]; -		if (cfile->srch_inf.unicode) { -			len = cifs_unicode_bytelen(filename); -		} else { -			/* BB should we make this strnlen of PATH_MAX? */ -			len = strnlen(filename, 5); -		} -	} else if (cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) { -		FILE_DIRECTORY_INFO *pFindData = -			(FILE_DIRECTORY_INFO *)current_entry; -		filename = &pFindData->FileName[0]; -		len = le32_to_cpu(pFindData->FileNameLength); -	} else if (cfile->srch_inf.info_level == -			SMB_FIND_FILE_FULL_DIRECTORY_INFO) { -		FILE_FULL_DIRECTORY_INFO *pFindData = -			(FILE_FULL_DIRECTORY_INFO *)current_entry; -		filename = &pFindData->FileName[0]; -		len = le32_to_cpu(pFindData->FileNameLength); -	} else if (cfile->srch_inf.info_level == -			SMB_FIND_FILE_ID_FULL_DIR_INFO) { -		SEARCH_ID_FULL_DIR_INFO *pFindData = -			(SEARCH_ID_FULL_DIR_INFO *)current_entry; -		filename = &pFindData->FileName[0]; -		len = le32_to_cpu(pFindData->FileNameLength); -	} else if (cfile->srch_inf.info_level == -			SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { -		FILE_BOTH_DIRECTORY_INFO *pFindData = -			(FILE_BOTH_DIRECTORY_INFO *)current_entry; -		filename = &pFindData->FileName[0]; -		len = le32_to_cpu(pFindData->FileNameLength); -	} else if (cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) { -		FIND_FILE_STANDARD_INFO *pFindData = -			(FIND_FILE_STANDARD_INFO *)current_entry; -		filename = &pFindData->FileName[0]; -		len = pFindData->FileNameLength; -	} else { -		cFYI(1, "Unknown findfirst level %d", -			 cfile->srch_inf.info_level); -	} +	if (!de->name) +		return 0; -	if (filename) { -		if (cfile->srch_inf.unicode) { -			__le16 *ufilename = (__le16 *)filename; -			if (len == 2) { -				/* check for . */ -				if (ufilename[0] == UNICODE_DOT) -					rc = 1; -			} else if (len == 4) { -				/* check for .. */ -				if ((ufilename[0] == UNICODE_DOT) -				   && (ufilename[1] == UNICODE_DOT)) -					rc = 2; -			} -		} else /* ASCII */ { -			if (len == 1) { -				if (filename[0] == '.') -					rc = 1; -			} else if (len == 2) { -				if ((filename[0] == '.') && (filename[1] == '.')) -					rc = 2; -			} +	if (is_unicode) { +		__le16 *ufilename = (__le16 *)de->name; +		if (de->namelen == 2) { +			/* check for . */ +			if (ufilename[0] == UNICODE_DOT) +				rc = 1; +		} else if (de->namelen == 4) { +			/* check for .. */ +			if (ufilename[0] == UNICODE_DOT && +			    ufilename[1] == UNICODE_DOT) +				rc = 2; +		} +	} else /* ASCII */ { +		if (de->namelen == 1) { +			if (de->name[0] == '.') +				rc = 1; +		} else if (de->namelen == 2) { +			if (de->name[0] == '.' && de->name[1] == '.') +				rc = 2;  		}  	} @@ -687,6 +738,7 @@ static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir,  	struct cifsFileInfo *file_info = file->private_data;  	struct super_block *sb = file->f_path.dentry->d_sb;  	struct cifs_sb_info *cifs_sb = CIFS_SB(sb); +	struct cifs_dirent de = { NULL, };  	struct cifs_fattr fattr;  	struct dentry *dentry;  	struct qstr name; @@ -694,9 +746,13 @@ static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir,  	u64 inum;  	ino_t ino; +	rc = cifs_fill_dirent(&de, find_entry, file_info->srch_inf.info_level, +			      file_info->srch_inf.unicode); +	if (rc) +		return rc; +  	/* skip . and .. since we added them first */ -	rc = cifs_entry_is_dot(find_entry, file_info); -	if (rc != 0) +	if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode))  		return 0;  	name.name = scratch_buf; |