Skip to content

Commit cda0ec6

Browse files
Christoph HellwigSteve French
authored andcommitted
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]>
1 parent 9feed6f commit cda0ec6

File tree

1 file changed

+125
-69
lines changed

1 file changed

+125
-69
lines changed

fs/cifs/readdir.c

Lines changed: 125 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Directory search handling
55
*
66
* Copyright (C) International Business Machines Corp., 2004, 2008
7+
* Copyright (C) Red Hat, Inc., 2011
78
* Author(s): Steve French ([email protected])
89
*
910
* This library is free software; you can redistribute it and/or modify
@@ -290,10 +291,10 @@ static int initiate_cifs_search(const int xid, struct file *file)
290291
}
291292

292293
/* return length of unicode string in bytes */
293-
static int cifs_unicode_bytelen(char *str)
294+
static int cifs_unicode_bytelen(const char *str)
294295
{
295296
int len;
296-
__le16 *ustr = (__le16 *)str;
297+
const __le16 *ustr = (const __le16 *)str;
297298

298299
for (len = 0; len <= PATH_MAX; len++) {
299300
if (ustr[len] == 0)
@@ -334,78 +335,128 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
334335

335336
}
336337

338+
struct cifs_dirent {
339+
const char *name;
340+
size_t namelen;
341+
u32 resume_key;
342+
u64 ino;
343+
};
344+
345+
static void cifs_fill_dirent_unix(struct cifs_dirent *de,
346+
const FILE_UNIX_INFO *info, bool is_unicode)
347+
{
348+
de->name = &info->FileName[0];
349+
if (is_unicode)
350+
de->namelen = cifs_unicode_bytelen(de->name);
351+
else
352+
de->namelen = strnlen(de->name, PATH_MAX);
353+
de->resume_key = info->ResumeKey;
354+
de->ino = le64_to_cpu(info->basic.UniqueId);
355+
}
356+
357+
static void cifs_fill_dirent_dir(struct cifs_dirent *de,
358+
const FILE_DIRECTORY_INFO *info)
359+
{
360+
de->name = &info->FileName[0];
361+
de->namelen = le32_to_cpu(info->FileNameLength);
362+
de->resume_key = info->FileIndex;
363+
}
364+
365+
static void cifs_fill_dirent_full(struct cifs_dirent *de,
366+
const FILE_FULL_DIRECTORY_INFO *info)
367+
{
368+
de->name = &info->FileName[0];
369+
de->namelen = le32_to_cpu(info->FileNameLength);
370+
de->resume_key = info->FileIndex;
371+
}
372+
373+
static void cifs_fill_dirent_search(struct cifs_dirent *de,
374+
const SEARCH_ID_FULL_DIR_INFO *info)
375+
{
376+
de->name = &info->FileName[0];
377+
de->namelen = le32_to_cpu(info->FileNameLength);
378+
de->resume_key = info->FileIndex;
379+
de->ino = le64_to_cpu(info->UniqueId);
380+
}
381+
382+
static void cifs_fill_dirent_both(struct cifs_dirent *de,
383+
const FILE_BOTH_DIRECTORY_INFO *info)
384+
{
385+
de->name = &info->FileName[0];
386+
de->namelen = le32_to_cpu(info->FileNameLength);
387+
de->resume_key = info->FileIndex;
388+
}
389+
390+
static void cifs_fill_dirent_std(struct cifs_dirent *de,
391+
const FIND_FILE_STANDARD_INFO *info)
392+
{
393+
de->name = &info->FileName[0];
394+
/* one byte length, no endianess conversion */
395+
de->namelen = info->FileNameLength;
396+
de->resume_key = info->ResumeKey;
397+
}
398+
399+
static int cifs_fill_dirent(struct cifs_dirent *de, const void *info,
400+
u16 level, bool is_unicode)
401+
{
402+
memset(de, 0, sizeof(*de));
403+
404+
switch (level) {
405+
case SMB_FIND_FILE_UNIX:
406+
cifs_fill_dirent_unix(de, info, is_unicode);
407+
break;
408+
case SMB_FIND_FILE_DIRECTORY_INFO:
409+
cifs_fill_dirent_dir(de, info);
410+
break;
411+
case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
412+
cifs_fill_dirent_full(de, info);
413+
break;
414+
case SMB_FIND_FILE_ID_FULL_DIR_INFO:
415+
cifs_fill_dirent_search(de, info);
416+
break;
417+
case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
418+
cifs_fill_dirent_both(de, info);
419+
break;
420+
case SMB_FIND_FILE_INFO_STANDARD:
421+
cifs_fill_dirent_std(de, info);
422+
break;
423+
default:
424+
cFYI(1, "Unknown findfirst level %d", level);
425+
return -EINVAL;
426+
}
427+
428+
return 0;
429+
}
430+
337431
#define UNICODE_DOT cpu_to_le16(0x2e)
338432

339433
/* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */
340-
static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
434+
static int cifs_entry_is_dot(struct cifs_dirent *de, bool is_unicode)
341435
{
342436
int rc = 0;
343-
char *filename = NULL;
344-
int len = 0;
345437

346-
if (cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
347-
FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
348-
filename = &pFindData->FileName[0];
349-
if (cfile->srch_inf.unicode) {
350-
len = cifs_unicode_bytelen(filename);
351-
} else {
352-
/* BB should we make this strnlen of PATH_MAX? */
353-
len = strnlen(filename, 5);
354-
}
355-
} else if (cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
356-
FILE_DIRECTORY_INFO *pFindData =
357-
(FILE_DIRECTORY_INFO *)current_entry;
358-
filename = &pFindData->FileName[0];
359-
len = le32_to_cpu(pFindData->FileNameLength);
360-
} else if (cfile->srch_inf.info_level ==
361-
SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
362-
FILE_FULL_DIRECTORY_INFO *pFindData =
363-
(FILE_FULL_DIRECTORY_INFO *)current_entry;
364-
filename = &pFindData->FileName[0];
365-
len = le32_to_cpu(pFindData->FileNameLength);
366-
} else if (cfile->srch_inf.info_level ==
367-
SMB_FIND_FILE_ID_FULL_DIR_INFO) {
368-
SEARCH_ID_FULL_DIR_INFO *pFindData =
369-
(SEARCH_ID_FULL_DIR_INFO *)current_entry;
370-
filename = &pFindData->FileName[0];
371-
len = le32_to_cpu(pFindData->FileNameLength);
372-
} else if (cfile->srch_inf.info_level ==
373-
SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
374-
FILE_BOTH_DIRECTORY_INFO *pFindData =
375-
(FILE_BOTH_DIRECTORY_INFO *)current_entry;
376-
filename = &pFindData->FileName[0];
377-
len = le32_to_cpu(pFindData->FileNameLength);
378-
} else if (cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
379-
FIND_FILE_STANDARD_INFO *pFindData =
380-
(FIND_FILE_STANDARD_INFO *)current_entry;
381-
filename = &pFindData->FileName[0];
382-
len = pFindData->FileNameLength;
383-
} else {
384-
cFYI(1, "Unknown findfirst level %d",
385-
cfile->srch_inf.info_level);
386-
}
438+
if (!de->name)
439+
return 0;
387440

388-
if (filename) {
389-
if (cfile->srch_inf.unicode) {
390-
__le16 *ufilename = (__le16 *)filename;
391-
if (len == 2) {
392-
/* check for . */
393-
if (ufilename[0] == UNICODE_DOT)
394-
rc = 1;
395-
} else if (len == 4) {
396-
/* check for .. */
397-
if ((ufilename[0] == UNICODE_DOT)
398-
&& (ufilename[1] == UNICODE_DOT))
399-
rc = 2;
400-
}
401-
} else /* ASCII */ {
402-
if (len == 1) {
403-
if (filename[0] == '.')
404-
rc = 1;
405-
} else if (len == 2) {
406-
if ((filename[0] == '.') && (filename[1] == '.'))
407-
rc = 2;
408-
}
441+
if (is_unicode) {
442+
__le16 *ufilename = (__le16 *)de->name;
443+
if (de->namelen == 2) {
444+
/* check for . */
445+
if (ufilename[0] == UNICODE_DOT)
446+
rc = 1;
447+
} else if (de->namelen == 4) {
448+
/* check for .. */
449+
if (ufilename[0] == UNICODE_DOT &&
450+
ufilename[1] == UNICODE_DOT)
451+
rc = 2;
452+
}
453+
} else /* ASCII */ {
454+
if (de->namelen == 1) {
455+
if (de->name[0] == '.')
456+
rc = 1;
457+
} else if (de->namelen == 2) {
458+
if (de->name[0] == '.' && de->name[1] == '.')
459+
rc = 2;
409460
}
410461
}
411462

@@ -687,16 +738,21 @@ static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir,
687738
struct cifsFileInfo *file_info = file->private_data;
688739
struct super_block *sb = file->f_path.dentry->d_sb;
689740
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
741+
struct cifs_dirent de = { NULL, };
690742
struct cifs_fattr fattr;
691743
struct dentry *dentry;
692744
struct qstr name;
693745
int rc = 0;
694746
u64 inum;
695747
ino_t ino;
696748

749+
rc = cifs_fill_dirent(&de, find_entry, file_info->srch_inf.info_level,
750+
file_info->srch_inf.unicode);
751+
if (rc)
752+
return rc;
753+
697754
/* skip . and .. since we added them first */
698-
rc = cifs_entry_is_dot(find_entry, file_info);
699-
if (rc != 0)
755+
if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode))
700756
return 0;
701757

702758
name.name = scratch_buf;

0 commit comments

Comments
 (0)