dirent.h (26800B)
1/* 2 * Dirent interface for Microsoft Visual Studio 3 * 4 * Copyright (C) 1998-2019 Toni Ronkko 5 * This file is part of dirent. Dirent may be freely distributed 6 * under the MIT license. For all details and documentation, see 7 * https://github.com/tronkko/dirent 8 */ 9#ifndef DIRENT_H 10#define DIRENT_H 11 12/* Hide warnings about unreferenced local functions */ 13#if defined(__clang__) 14# pragma clang diagnostic ignored "-Wunused-function" 15#elif defined(_MSC_VER) 16# pragma warning(disable:4505) 17#elif defined(__GNUC__) 18# pragma GCC diagnostic ignored "-Wunused-function" 19#endif 20 21/* 22 * Include windows.h without Windows Sockets 1.1 to prevent conflicts with 23 * Windows Sockets 2.0. 24 */ 25#ifndef WIN32_LEAN_AND_MEAN 26# define WIN32_LEAN_AND_MEAN 27#endif 28#include <windows.h> 29 30#include <stdio.h> 31#include <stdarg.h> 32#include <wchar.h> 33#include <string.h> 34#include <stdlib.h> 35#include <malloc.h> 36#include <sys/types.h> 37#include <sys/stat.h> 38#include <errno.h> 39 40/* Indicates that d_type field is available in dirent structure */ 41#define _DIRENT_HAVE_D_TYPE 42 43/* Indicates that d_namlen field is available in dirent structure */ 44#define _DIRENT_HAVE_D_NAMLEN 45 46/* Entries missing from MSVC 6.0 */ 47#if !defined(FILE_ATTRIBUTE_DEVICE) 48# define FILE_ATTRIBUTE_DEVICE 0x40 49#endif 50 51/* File type and permission flags for stat(), general mask */ 52#if !defined(S_IFMT) 53# define S_IFMT _S_IFMT 54#endif 55 56/* Directory bit */ 57#if !defined(S_IFDIR) 58# define S_IFDIR _S_IFDIR 59#endif 60 61/* Character device bit */ 62#if !defined(S_IFCHR) 63# define S_IFCHR _S_IFCHR 64#endif 65 66/* Pipe bit */ 67#if !defined(S_IFFIFO) 68# define S_IFFIFO _S_IFFIFO 69#endif 70 71/* Regular file bit */ 72#if !defined(S_IFREG) 73# define S_IFREG _S_IFREG 74#endif 75 76/* Read permission */ 77#if !defined(S_IREAD) 78# define S_IREAD _S_IREAD 79#endif 80 81/* Write permission */ 82#if !defined(S_IWRITE) 83# define S_IWRITE _S_IWRITE 84#endif 85 86/* Execute permission */ 87#if !defined(S_IEXEC) 88# define S_IEXEC _S_IEXEC 89#endif 90 91/* Pipe */ 92#if !defined(S_IFIFO) 93# define S_IFIFO _S_IFIFO 94#endif 95 96/* Block device */ 97#if !defined(S_IFBLK) 98# define S_IFBLK 0 99#endif 100 101/* Link */ 102#if !defined(S_IFLNK) 103# define S_IFLNK 0 104#endif 105 106/* Socket */ 107#if !defined(S_IFSOCK) 108# define S_IFSOCK 0 109#endif 110 111/* Read user permission */ 112#if !defined(S_IRUSR) 113# define S_IRUSR S_IREAD 114#endif 115 116/* Write user permission */ 117#if !defined(S_IWUSR) 118# define S_IWUSR S_IWRITE 119#endif 120 121/* Execute user permission */ 122#if !defined(S_IXUSR) 123# define S_IXUSR 0 124#endif 125 126/* Read group permission */ 127#if !defined(S_IRGRP) 128# define S_IRGRP 0 129#endif 130 131/* Write group permission */ 132#if !defined(S_IWGRP) 133# define S_IWGRP 0 134#endif 135 136/* Execute group permission */ 137#if !defined(S_IXGRP) 138# define S_IXGRP 0 139#endif 140 141/* Read others permission */ 142#if !defined(S_IROTH) 143# define S_IROTH 0 144#endif 145 146/* Write others permission */ 147#if !defined(S_IWOTH) 148# define S_IWOTH 0 149#endif 150 151/* Execute others permission */ 152#if !defined(S_IXOTH) 153# define S_IXOTH 0 154#endif 155 156/* Maximum length of file name */ 157#if !defined(PATH_MAX) 158# define PATH_MAX MAX_PATH 159#endif 160#if !defined(FILENAME_MAX) 161# define FILENAME_MAX MAX_PATH 162#endif 163#if !defined(NAME_MAX) 164# define NAME_MAX FILENAME_MAX 165#endif 166 167/* File type flags for d_type */ 168#define DT_UNKNOWN 0 169#define DT_REG S_IFREG 170#define DT_DIR S_IFDIR 171#define DT_FIFO S_IFIFO 172#define DT_SOCK S_IFSOCK 173#define DT_CHR S_IFCHR 174#define DT_BLK S_IFBLK 175#define DT_LNK S_IFLNK 176 177/* Macros for converting between st_mode and d_type */ 178#define IFTODT(mode) ((mode) & S_IFMT) 179#define DTTOIF(type) (type) 180 181/* 182 * File type macros. Note that block devices, sockets and links cannot be 183 * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are 184 * only defined for compatibility. These macros should always return false 185 * on Windows. 186 */ 187#if !defined(S_ISFIFO) 188# define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) 189#endif 190#if !defined(S_ISDIR) 191# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) 192#endif 193#if !defined(S_ISREG) 194# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) 195#endif 196#if !defined(S_ISLNK) 197# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) 198#endif 199#if !defined(S_ISSOCK) 200# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) 201#endif 202#if !defined(S_ISCHR) 203# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) 204#endif 205#if !defined(S_ISBLK) 206# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) 207#endif 208 209/* Return the exact length of the file name without zero terminator */ 210#define _D_EXACT_NAMLEN(p) ((p)->d_namlen) 211 212/* Return the maximum size of a file name */ 213#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1) 214 215 216#ifdef __cplusplus 217extern "C" { 218#endif 219 220 221/* Wide-character version */ 222struct _wdirent { 223 /* Always zero */ 224 long d_ino; 225 226 /* File position within stream */ 227 long d_off; 228 229 /* Structure size */ 230 unsigned short d_reclen; 231 232 /* Length of name without \0 */ 233 size_t d_namlen; 234 235 /* File type */ 236 int d_type; 237 238 /* File name */ 239 wchar_t d_name[PATH_MAX+1]; 240}; 241typedef struct _wdirent _wdirent; 242 243struct _WDIR { 244 /* Current directory entry */ 245 struct _wdirent ent; 246 247 /* Private file data */ 248 WIN32_FIND_DATAW data; 249 250 /* True if data is valid */ 251 int cached; 252 253 /* Win32 search handle */ 254 HANDLE handle; 255 256 /* Initial directory name */ 257 wchar_t *patt; 258}; 259typedef struct _WDIR _WDIR; 260 261/* Multi-byte character version */ 262struct dirent { 263 /* Always zero */ 264 long d_ino; 265 266 /* File position within stream */ 267 long d_off; 268 269 /* Structure size */ 270 unsigned short d_reclen; 271 272 /* Length of name without \0 */ 273 size_t d_namlen; 274 275 /* File type */ 276 int d_type; 277 278 /* File name */ 279 char d_name[PATH_MAX+1]; 280}; 281typedef struct dirent dirent; 282 283struct DIR { 284 struct dirent ent; 285 struct _WDIR *wdirp; 286}; 287typedef struct DIR DIR; 288 289 290/* Dirent functions */ 291static DIR *opendir (const char *dirname); 292static _WDIR *_wopendir (const wchar_t *dirname); 293 294static struct dirent *readdir (DIR *dirp); 295static struct _wdirent *_wreaddir (_WDIR *dirp); 296 297static int readdir_r( 298 DIR *dirp, struct dirent *entry, struct dirent **result); 299static int _wreaddir_r( 300 _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result); 301 302static int closedir (DIR *dirp); 303static int _wclosedir (_WDIR *dirp); 304 305static void rewinddir (DIR* dirp); 306static void _wrewinddir (_WDIR* dirp); 307 308static int scandir (const char *dirname, struct dirent ***namelist, 309 int (*filter)(const struct dirent*), 310 int (*compare)(const struct dirent**, const struct dirent**)); 311 312static int alphasort (const struct dirent **a, const struct dirent **b); 313 314static int versionsort (const struct dirent **a, const struct dirent **b); 315 316 317/* For compatibility with Symbian */ 318#define wdirent _wdirent 319#define WDIR _WDIR 320#define wopendir _wopendir 321#define wreaddir _wreaddir 322#define wclosedir _wclosedir 323#define wrewinddir _wrewinddir 324 325 326/* Internal utility functions */ 327static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp); 328static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp); 329 330static int dirent_mbstowcs_s( 331 size_t *pReturnValue, 332 wchar_t *wcstr, 333 size_t sizeInWords, 334 const char *mbstr, 335 size_t count); 336 337static int dirent_wcstombs_s( 338 size_t *pReturnValue, 339 char *mbstr, 340 size_t sizeInBytes, 341 const wchar_t *wcstr, 342 size_t count); 343 344static void dirent_set_errno (int error); 345 346 347/* 348 * Open directory stream DIRNAME for read and return a pointer to the 349 * internal working area that is used to retrieve individual directory 350 * entries. 351 */ 352static _WDIR* 353_wopendir( 354 const wchar_t *dirname) 355{ 356 _WDIR *dirp; 357 DWORD n; 358 wchar_t *p; 359 360 /* Must have directory name */ 361 if (dirname == NULL || dirname[0] == '\0') { 362 dirent_set_errno (ENOENT); 363 return NULL; 364 } 365 366 /* Allocate new _WDIR structure */ 367 dirp = (_WDIR*) malloc (sizeof (struct _WDIR)); 368 if (!dirp) { 369 return NULL; 370 } 371 372 /* Reset _WDIR structure */ 373 dirp->handle = INVALID_HANDLE_VALUE; 374 dirp->patt = NULL; 375 dirp->cached = 0; 376 377 /* 378 * Compute the length of full path plus zero terminator 379 * 380 * Note that on WinRT there's no way to convert relative paths 381 * into absolute paths, so just assume it is an absolute path. 382 */ 383#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 384 /* Desktop */ 385 n = GetFullPathNameW (dirname, 0, NULL, NULL); 386#else 387 /* WinRT */ 388 n = wcslen (dirname); 389#endif 390 391 /* Allocate room for absolute directory name and search pattern */ 392 dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); 393 if (dirp->patt == NULL) { 394 goto exit_closedir; 395 } 396 397 /* 398 * Convert relative directory name to an absolute one. This 399 * allows rewinddir() to function correctly even when current 400 * working directory is changed between opendir() and rewinddir(). 401 * 402 * Note that on WinRT there's no way to convert relative paths 403 * into absolute paths, so just assume it is an absolute path. 404 */ 405#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 406 /* Desktop */ 407 n = GetFullPathNameW (dirname, n, dirp->patt, NULL); 408 if (n <= 0) { 409 goto exit_closedir; 410 } 411#else 412 /* WinRT */ 413 wcsncpy_s (dirp->patt, n+1, dirname, n); 414#endif 415 416 /* Append search pattern \* to the directory name */ 417 p = dirp->patt + n; 418 switch (p[-1]) { 419 case '\\': 420 case '/': 421 case ':': 422 /* Directory ends in path separator, e.g. c:\temp\ */ 423 /*NOP*/; 424 break; 425 426 default: 427 /* Directory name doesn't end in path separator */ 428 *p++ = '\\'; 429 } 430 *p++ = '*'; 431 *p = '\0'; 432 433 /* Open directory stream and retrieve the first entry */ 434 if (!dirent_first (dirp)) { 435 goto exit_closedir; 436 } 437 438 /* Success */ 439 return dirp; 440 441 /* Failure */ 442exit_closedir: 443 _wclosedir (dirp); 444 return NULL; 445} 446 447/* 448 * Read next directory entry. 449 * 450 * Returns pointer to static directory entry which may be overwritten by 451 * subsequent calls to _wreaddir(). 452 */ 453static struct _wdirent* 454_wreaddir( 455 _WDIR *dirp) 456{ 457 struct _wdirent *entry; 458 459 /* 460 * Read directory entry to buffer. We can safely ignore the return value 461 * as entry will be set to NULL in case of error. 462 */ 463 (void) _wreaddir_r (dirp, &dirp->ent, &entry); 464 465 /* Return pointer to statically allocated directory entry */ 466 return entry; 467} 468 469/* 470 * Read next directory entry. 471 * 472 * Returns zero on success. If end of directory stream is reached, then sets 473 * result to NULL and returns zero. 474 */ 475static int 476_wreaddir_r( 477 _WDIR *dirp, 478 struct _wdirent *entry, 479 struct _wdirent **result) 480{ 481 WIN32_FIND_DATAW *datap; 482 483 /* Read next directory entry */ 484 datap = dirent_next (dirp); 485 if (datap) { 486 size_t n; 487 DWORD attr; 488 489 /* 490 * Copy file name as wide-character string. If the file name is too 491 * long to fit in to the destination buffer, then truncate file name 492 * to PATH_MAX characters and zero-terminate the buffer. 493 */ 494 n = 0; 495 while (n < PATH_MAX && datap->cFileName[n] != 0) { 496 entry->d_name[n] = datap->cFileName[n]; 497 n++; 498 } 499 entry->d_name[n] = 0; 500 501 /* Length of file name excluding zero terminator */ 502 entry->d_namlen = n; 503 504 /* File type */ 505 attr = datap->dwFileAttributes; 506 if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { 507 entry->d_type = DT_CHR; 508 } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { 509 entry->d_type = DT_DIR; 510 } else { 511 entry->d_type = DT_REG; 512 } 513 514 /* Reset dummy fields */ 515 entry->d_ino = 0; 516 entry->d_off = 0; 517 entry->d_reclen = sizeof (struct _wdirent); 518 519 /* Set result address */ 520 *result = entry; 521 522 } else { 523 524 /* Return NULL to indicate end of directory */ 525 *result = NULL; 526 527 } 528 529 return /*OK*/0; 530} 531 532/* 533 * Close directory stream opened by opendir() function. This invalidates the 534 * DIR structure as well as any directory entry read previously by 535 * _wreaddir(). 536 */ 537static int 538_wclosedir( 539 _WDIR *dirp) 540{ 541 int ok; 542 if (dirp) { 543 544 /* Release search handle */ 545 if (dirp->handle != INVALID_HANDLE_VALUE) { 546 FindClose (dirp->handle); 547 } 548 549 /* Release search pattern */ 550 free (dirp->patt); 551 552 /* Release directory structure */ 553 free (dirp); 554 ok = /*success*/0; 555 556 } else { 557 558 /* Invalid directory stream */ 559 dirent_set_errno (EBADF); 560 ok = /*failure*/-1; 561 562 } 563 return ok; 564} 565 566/* 567 * Rewind directory stream such that _wreaddir() returns the very first 568 * file name again. 569 */ 570static void 571_wrewinddir( 572 _WDIR* dirp) 573{ 574 if (dirp) { 575 /* Release existing search handle */ 576 if (dirp->handle != INVALID_HANDLE_VALUE) { 577 FindClose (dirp->handle); 578 } 579 580 /* Open new search handle */ 581 dirent_first (dirp); 582 } 583} 584 585/* Get first directory entry (internal) */ 586static WIN32_FIND_DATAW* 587dirent_first( 588 _WDIR *dirp) 589{ 590 WIN32_FIND_DATAW *datap; 591 DWORD error; 592 593 /* Open directory and retrieve the first entry */ 594 dirp->handle = FindFirstFileExW( 595 dirp->patt, FindExInfoStandard, &dirp->data, 596 FindExSearchNameMatch, NULL, 0); 597 if (dirp->handle != INVALID_HANDLE_VALUE) { 598 599 /* a directory entry is now waiting in memory */ 600 datap = &dirp->data; 601 dirp->cached = 1; 602 603 } else { 604 605 /* Failed to open directory: no directory entry in memory */ 606 dirp->cached = 0; 607 datap = NULL; 608 609 /* Set error code */ 610 error = GetLastError (); 611 switch (error) { 612 case ERROR_ACCESS_DENIED: 613 /* No read access to directory */ 614 dirent_set_errno (EACCES); 615 break; 616 617 case ERROR_DIRECTORY: 618 /* Directory name is invalid */ 619 dirent_set_errno (ENOTDIR); 620 break; 621 622 case ERROR_PATH_NOT_FOUND: 623 default: 624 /* Cannot find the file */ 625 dirent_set_errno (ENOENT); 626 } 627 628 } 629 return datap; 630} 631 632/* 633 * Get next directory entry (internal). 634 * 635 * Returns 636 */ 637static WIN32_FIND_DATAW* 638dirent_next( 639 _WDIR *dirp) 640{ 641 WIN32_FIND_DATAW *p; 642 643 /* Get next directory entry */ 644 if (dirp->cached != 0) { 645 646 /* A valid directory entry already in memory */ 647 p = &dirp->data; 648 dirp->cached = 0; 649 650 } else if (dirp->handle != INVALID_HANDLE_VALUE) { 651 652 /* Get the next directory entry from stream */ 653 if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) { 654 /* Got a file */ 655 p = &dirp->data; 656 } else { 657 /* The very last entry has been processed or an error occurred */ 658 FindClose (dirp->handle); 659 dirp->handle = INVALID_HANDLE_VALUE; 660 p = NULL; 661 } 662 663 } else { 664 665 /* End of directory stream reached */ 666 p = NULL; 667 668 } 669 670 return p; 671} 672 673/* 674 * Open directory stream using plain old C-string. 675 */ 676static DIR* 677opendir( 678 const char *dirname) 679{ 680 struct DIR *dirp; 681 682 /* Must have directory name */ 683 if (dirname == NULL || dirname[0] == '\0') { 684 dirent_set_errno (ENOENT); 685 return NULL; 686 } 687 688 /* Allocate memory for DIR structure */ 689 dirp = (DIR*) malloc (sizeof (struct DIR)); 690 if (!dirp) { 691 return NULL; 692 } 693 { 694 int error; 695 wchar_t wname[PATH_MAX + 1]; 696 size_t n; 697 698 /* Convert directory name to wide-character string */ 699 error = dirent_mbstowcs_s( 700 &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1); 701 if (error) { 702 /* 703 * Cannot convert file name to wide-character string. This 704 * occurs if the string contains invalid multi-byte sequences or 705 * the output buffer is too small to contain the resulting 706 * string. 707 */ 708 goto exit_free; 709 } 710 711 712 /* Open directory stream using wide-character name */ 713 dirp->wdirp = _wopendir (wname); 714 if (!dirp->wdirp) { 715 goto exit_free; 716 } 717 718 } 719 720 /* Success */ 721 return dirp; 722 723 /* Failure */ 724exit_free: 725 free (dirp); 726 return NULL; 727} 728 729/* 730 * Read next directory entry. 731 */ 732static struct dirent* 733readdir( 734 DIR *dirp) 735{ 736 struct dirent *entry; 737 738 /* 739 * Read directory entry to buffer. We can safely ignore the return value 740 * as entry will be set to NULL in case of error. 741 */ 742 (void) readdir_r (dirp, &dirp->ent, &entry); 743 744 /* Return pointer to statically allocated directory entry */ 745 return entry; 746} 747 748/* 749 * Read next directory entry into called-allocated buffer. 750 * 751 * Returns zero on success. If the end of directory stream is reached, then 752 * sets result to NULL and returns zero. 753 */ 754static int 755readdir_r( 756 DIR *dirp, 757 struct dirent *entry, 758 struct dirent **result) 759{ 760 WIN32_FIND_DATAW *datap; 761 762 /* Read next directory entry */ 763 datap = dirent_next (dirp->wdirp); 764 if (datap) { 765 size_t n; 766 int error; 767 768 /* Attempt to convert file name to multi-byte string */ 769 error = dirent_wcstombs_s( 770 &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1); 771 772 /* 773 * If the file name cannot be represented by a multi-byte string, 774 * then attempt to use old 8+3 file name. This allows traditional 775 * Unix-code to access some file names despite of unicode 776 * characters, although file names may seem unfamiliar to the user. 777 * 778 * Be ware that the code below cannot come up with a short file 779 * name unless the file system provides one. At least 780 * VirtualBox shared folders fail to do this. 781 */ 782 if (error && datap->cAlternateFileName[0] != '\0') { 783 error = dirent_wcstombs_s( 784 &n, entry->d_name, PATH_MAX + 1, 785 datap->cAlternateFileName, PATH_MAX + 1); 786 } 787 788 if (!error) { 789 DWORD attr; 790 791 /* Length of file name excluding zero terminator */ 792 entry->d_namlen = n - 1; 793 794 /* File attributes */ 795 attr = datap->dwFileAttributes; 796 if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { 797 entry->d_type = DT_CHR; 798 } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { 799 entry->d_type = DT_DIR; 800 } else { 801 entry->d_type = DT_REG; 802 } 803 804 /* Reset dummy fields */ 805 entry->d_ino = 0; 806 entry->d_off = 0; 807 entry->d_reclen = sizeof (struct dirent); 808 809 } else { 810 811 /* 812 * Cannot convert file name to multi-byte string so construct 813 * an erroneous directory entry and return that. Note that 814 * we cannot return NULL as that would stop the processing 815 * of directory entries completely. 816 */ 817 entry->d_name[0] = '?'; 818 entry->d_name[1] = '\0'; 819 entry->d_namlen = 1; 820 entry->d_type = DT_UNKNOWN; 821 entry->d_ino = 0; 822 entry->d_off = -1; 823 entry->d_reclen = 0; 824 825 } 826 827 /* Return pointer to directory entry */ 828 *result = entry; 829 830 } else { 831 832 /* No more directory entries */ 833 *result = NULL; 834 835 } 836 837 return /*OK*/0; 838} 839 840/* 841 * Close directory stream. 842 */ 843static int 844closedir( 845 DIR *dirp) 846{ 847 int ok; 848 if (dirp) { 849 850 /* Close wide-character directory stream */ 851 ok = _wclosedir (dirp->wdirp); 852 dirp->wdirp = NULL; 853 854 /* Release multi-byte character version */ 855 free (dirp); 856 857 } else { 858 859 /* Invalid directory stream */ 860 dirent_set_errno (EBADF); 861 ok = /*failure*/-1; 862 863 } 864 return ok; 865} 866 867/* 868 * Rewind directory stream to beginning. 869 */ 870static void 871rewinddir( 872 DIR* dirp) 873{ 874 /* Rewind wide-character string directory stream */ 875 _wrewinddir (dirp->wdirp); 876} 877 878/* 879 * Scan directory for entries. 880 */ 881static int 882scandir( 883 const char *dirname, 884 struct dirent ***namelist, 885 int (*filter)(const struct dirent*), 886 int (*compare)(const struct dirent**, const struct dirent**)) 887{ 888 struct dirent **files = NULL; 889 size_t size = 0; 890 size_t allocated = 0; 891 const size_t init_size = 1; 892 DIR *dir = NULL; 893 struct dirent *entry; 894 struct dirent *tmp = NULL; 895 size_t i; 896 int result = 0; 897 898 /* Open directory stream */ 899 dir = opendir (dirname); 900 if (dir) { 901 902 /* Read directory entries to memory */ 903 while (1) { 904 905 /* Enlarge pointer table to make room for another pointer */ 906 if (size >= allocated) { 907 void *p; 908 size_t num_entries; 909 910 /* Compute number of entries in the enlarged pointer table */ 911 if (size < init_size) { 912 /* Allocate initial pointer table */ 913 num_entries = init_size; 914 } else { 915 /* Double the size */ 916 num_entries = size * 2; 917 } 918 919 /* Allocate first pointer table or enlarge existing table */ 920 p = realloc (files, sizeof (void*) * num_entries); 921 if (p != NULL) { 922 /* Got the memory */ 923 files = (dirent**) p; 924 allocated = num_entries; 925 } else { 926 /* Out of memory */ 927 result = -1; 928 break; 929 } 930 931 } 932 933 /* Allocate room for temporary directory entry */ 934 if (tmp == NULL) { 935 tmp = (struct dirent*) malloc (sizeof (struct dirent)); 936 if (tmp == NULL) { 937 /* Cannot allocate temporary directory entry */ 938 result = -1; 939 break; 940 } 941 } 942 943 /* Read directory entry to temporary area */ 944 if (readdir_r (dir, tmp, &entry) == /*OK*/0) { 945 946 /* Did we get an entry? */ 947 if (entry != NULL) { 948 int pass; 949 950 /* Determine whether to include the entry in result */ 951 if (filter) { 952 /* Let the filter function decide */ 953 pass = filter (tmp); 954 } else { 955 /* No filter function, include everything */ 956 pass = 1; 957 } 958 959 if (pass) { 960 /* Store the temporary entry to pointer table */ 961 files[size++] = tmp; 962 tmp = NULL; 963 964 /* Keep up with the number of files */ 965 result++; 966 } 967 968 } else { 969 970 /* 971 * End of directory stream reached => sort entries and 972 * exit. 973 */ 974 qsort (files, size, sizeof (void*), 975 (int (*) (const void*, const void*)) compare); 976 break; 977 978 } 979 980 } else { 981 /* Error reading directory entry */ 982 result = /*Error*/ -1; 983 break; 984 } 985 986 } 987 988 } else { 989 /* Cannot open directory */ 990 result = /*Error*/ -1; 991 } 992 993 /* Release temporary directory entry */ 994 free (tmp); 995 996 /* Release allocated memory on error */ 997 if (result < 0) { 998 for (i = 0; i < size; i++) { 999 free (files[i]); 1000 } 1001 free (files); 1002 files = NULL; 1003 } 1004 1005 /* Close directory stream */ 1006 if (dir) { 1007 closedir (dir); 1008 } 1009 1010 /* Pass pointer table to caller */ 1011 if (namelist) { 1012 *namelist = files; 1013 } 1014 return result; 1015} 1016 1017/* Alphabetical sorting */ 1018static int 1019alphasort( 1020 const struct dirent **a, const struct dirent **b) 1021{ 1022 return strcoll ((*a)->d_name, (*b)->d_name); 1023} 1024 1025/* Sort versions */ 1026static int 1027versionsort( 1028 const struct dirent **a, const struct dirent **b) 1029{ 1030 /* FIXME: implement strverscmp and use that */ 1031 return alphasort (a, b); 1032} 1033 1034/* Convert multi-byte string to wide character string */ 1035static int 1036dirent_mbstowcs_s( 1037 size_t *pReturnValue, 1038 wchar_t *wcstr, 1039 size_t sizeInWords, 1040 const char *mbstr, 1041 size_t count) 1042{ 1043 int error; 1044 1045#if defined(_MSC_VER) && _MSC_VER >= 1400 1046 1047 /* Microsoft Visual Studio 2005 or later */ 1048 error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count); 1049 1050#else 1051 1052 /* Older Visual Studio or non-Microsoft compiler */ 1053 size_t n; 1054 1055 /* Convert to wide-character string (or count characters) */ 1056 n = mbstowcs (wcstr, mbstr, sizeInWords); 1057 if (!wcstr || n < count) { 1058 1059 /* Zero-terminate output buffer */ 1060 if (wcstr && sizeInWords) { 1061 if (n >= sizeInWords) { 1062 n = sizeInWords - 1; 1063 } 1064 wcstr[n] = 0; 1065 } 1066 1067 /* Length of resulting multi-byte string WITH zero terminator */ 1068 if (pReturnValue) { 1069 *pReturnValue = n + 1; 1070 } 1071 1072 /* Success */ 1073 error = 0; 1074 1075 } else { 1076 1077 /* Could not convert string */ 1078 error = 1; 1079 1080 } 1081 1082#endif 1083 return error; 1084} 1085 1086/* Convert wide-character string to multi-byte string */ 1087static int 1088dirent_wcstombs_s( 1089 size_t *pReturnValue, 1090 char *mbstr, 1091 size_t sizeInBytes, /* max size of mbstr */ 1092 const wchar_t *wcstr, 1093 size_t count) 1094{ 1095 int error; 1096 1097#if defined(_MSC_VER) && _MSC_VER >= 1400 1098 1099 /* Microsoft Visual Studio 2005 or later */ 1100 error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count); 1101 1102#else 1103 1104 /* Older Visual Studio or non-Microsoft compiler */ 1105 size_t n; 1106 1107 /* Convert to multi-byte string (or count the number of bytes needed) */ 1108 n = wcstombs (mbstr, wcstr, sizeInBytes); 1109 if (!mbstr || n < count) { 1110 1111 /* Zero-terminate output buffer */ 1112 if (mbstr && sizeInBytes) { 1113 if (n >= sizeInBytes) { 1114 n = sizeInBytes - 1; 1115 } 1116 mbstr[n] = '\0'; 1117 } 1118 1119 /* Length of resulting multi-bytes string WITH zero-terminator */ 1120 if (pReturnValue) { 1121 *pReturnValue = n + 1; 1122 } 1123 1124 /* Success */ 1125 error = 0; 1126 1127 } else { 1128 1129 /* Cannot convert string */ 1130 error = 1; 1131 1132 } 1133 1134#endif 1135 return error; 1136} 1137 1138/* Set errno variable */ 1139static void 1140dirent_set_errno( 1141 int error) 1142{ 1143#if defined(_MSC_VER) && _MSC_VER >= 1400 1144 1145 /* Microsoft Visual Studio 2005 and later */ 1146 _set_errno (error); 1147 1148#else 1149 1150 /* Non-Microsoft compiler or older Microsoft compiler */ 1151 errno = error; 1152 1153#endif 1154} 1155 1156 1157#ifdef __cplusplus 1158} 1159#endif 1160#endif /*DIRENT_H*/