|
4 | 4 | * Directory search handling
|
5 | 5 | *
|
6 | 6 | * Copyright (C) International Business Machines Corp., 2004, 2008
|
| 7 | + * Copyright (C) Red Hat, Inc., 2011 |
7 | 8 | * Author(s): Steve French ([email protected])
|
8 | 9 | *
|
9 | 10 | * 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)
|
290 | 291 | }
|
291 | 292 |
|
292 | 293 | /* return length of unicode string in bytes */
|
293 |
| -static int cifs_unicode_bytelen(char *str) |
| 294 | +static int cifs_unicode_bytelen(const char *str) |
294 | 295 | {
|
295 | 296 | int len;
|
296 |
| - __le16 *ustr = (__le16 *)str; |
| 297 | + const __le16 *ustr = (const __le16 *)str; |
297 | 298 |
|
298 | 299 | for (len = 0; len <= PATH_MAX; len++) {
|
299 | 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 |
|
| 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 | + |
337 | 431 | #define UNICODE_DOT cpu_to_le16(0x2e)
|
338 | 432 |
|
339 | 433 | /* 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) |
341 | 435 | {
|
342 | 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) { |
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; |
387 | 440 |
|
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; |
409 | 460 | }
|
410 | 461 | }
|
411 | 462 |
|
@@ -687,16 +738,21 @@ static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir,
|
687 | 738 | struct cifsFileInfo *file_info = file->private_data;
|
688 | 739 | struct super_block *sb = file->f_path.dentry->d_sb;
|
689 | 740 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
| 741 | + struct cifs_dirent de = { NULL, }; |
690 | 742 | struct cifs_fattr fattr;
|
691 | 743 | struct dentry *dentry;
|
692 | 744 | struct qstr name;
|
693 | 745 | int rc = 0;
|
694 | 746 | u64 inum;
|
695 | 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 | 754 | /* 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)) |
700 | 756 | return 0;
|
701 | 757 |
|
702 | 758 | name.name = scratch_buf;
|
|
0 commit comments