aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2011-07-16 15:24:05 -0400
committerSteve French <sfrench@us.ibm.com>2011-07-25 17:36:44 -0400
commitcda0ec6a86f18127d490048a46de954c03886d5e (patch)
tree82497b560bff0119054abbf6d1c6686c09bb4842
parent9feed6f8fbab477b6339efb4f3119a3c22dc187e (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 <hch@lst.de> Reviewed-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r--fs/cifs/readdir.c194
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 @@
4 * Directory search handling 4 * Directory search handling
5 * 5 *
6 * Copyright (C) International Business Machines Corp., 2004, 2008 6 * Copyright (C) International Business Machines Corp., 2004, 2008
7 * Copyright (C) Red Hat, Inc., 2011
7 * Author(s): Steve French (sfrench@us.ibm.com) 8 * Author(s): Steve French (sfrench@us.ibm.com)
8 * 9 *
9 * This library is free software; you can redistribute it and/or modify 10 * This library is free software; you can redistribute it and/or modify
@@ -290,10 +291,10 @@ error_exit:
290} 291}
291 292
292/* return length of unicode string in bytes */ 293/* return length of unicode string in bytes */
293static int cifs_unicode_bytelen(char *str) 294static int cifs_unicode_bytelen(const char *str)
294{ 295{
295 int len; 296 int len;
296 __le16 *ustr = (__le16 *)str; 297 const __le16 *ustr = (const __le16 *)str;
297 298
298 for (len = 0; len <= PATH_MAX; len++) { 299 for (len = 0; len <= PATH_MAX; len++) {
299 if (ustr[len] == 0) 300 if (ustr[len] == 0)
@@ -334,78 +335,128 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
334 335
335} 336}
336 337
338struct cifs_dirent {
339 const char *name;
340 size_t namelen;
341 u32 resume_key;
342 u64 ino;
343};
344
345static 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
357static 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
365static 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
373static 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
382static 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
390static 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
399static 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
337#define UNICODE_DOT cpu_to_le16(0x2e) 431#define UNICODE_DOT cpu_to_le16(0x2e)
338 432
339/* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */ 433/* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */
340static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) 434static int cifs_entry_is_dot(struct cifs_dirent *de, bool is_unicode)
341{ 435{
342 int rc = 0; 436 int rc = 0;
343 char *filename = NULL;
344 int len = 0;
345 437
346 if (cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) { 438 if (!de->name)
347 FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry; 439 return 0;
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 }
387 440
388 if (filename) { 441 if (is_unicode) {
389 if (cfile->srch_inf.unicode) { 442 __le16 *ufilename = (__le16 *)de->name;
390 __le16 *ufilename = (__le16 *)filename; 443 if (de->namelen == 2) {
391 if (len == 2) { 444 /* check for . */
392 /* check for . */ 445 if (ufilename[0] == UNICODE_DOT)
393 if (ufilename[0] == UNICODE_DOT) 446 rc = 1;
394 rc = 1; 447 } else if (de->namelen == 4) {
395 } else if (len == 4) { 448 /* check for .. */
396 /* check for .. */ 449 if (ufilename[0] == UNICODE_DOT &&
397 if ((ufilename[0] == UNICODE_DOT) 450 ufilename[1] == UNICODE_DOT)
398 && (ufilename[1] == UNICODE_DOT)) 451 rc = 2;
399 rc = 2; 452 }
400 } 453 } else /* ASCII */ {
401 } else /* ASCII */ { 454 if (de->namelen == 1) {
402 if (len == 1) { 455 if (de->name[0] == '.')
403 if (filename[0] == '.') 456 rc = 1;
404 rc = 1; 457 } else if (de->namelen == 2) {
405 } else if (len == 2) { 458 if (de->name[0] == '.' && de->name[1] == '.')
406 if ((filename[0] == '.') && (filename[1] == '.')) 459 rc = 2;
407 rc = 2;
408 }
409 } 460 }
410 } 461 }
411 462
@@ -687,6 +738,7 @@ static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir,
687 struct cifsFileInfo *file_info = file->private_data; 738 struct cifsFileInfo *file_info = file->private_data;
688 struct super_block *sb = file->f_path.dentry->d_sb; 739 struct super_block *sb = file->f_path.dentry->d_sb;
689 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 740 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
741 struct cifs_dirent de = { NULL, };
690 struct cifs_fattr fattr; 742 struct cifs_fattr fattr;
691 struct dentry *dentry; 743 struct dentry *dentry;
692 struct qstr name; 744 struct qstr name;
@@ -694,9 +746,13 @@ static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir,
694 u64 inum; 746 u64 inum;
695 ino_t ino; 747 ino_t ino;
696 748
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
697 /* skip . and .. since we added them first */ 754 /* skip . and .. since we added them first */
698 rc = cifs_entry_is_dot(find_entry, file_info); 755 if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode))
699 if (rc != 0)
700 return 0; 756 return 0;
701 757
702 name.name = scratch_buf; 758 name.name = scratch_buf;