]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/dpdk/lib/librte_eal/windows/include/dirent.h
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / spdk / dpdk / lib / librte_eal / windows / include / dirent.h
1 /* SPDX-License-Identifier: MIT
2 * Dirent interface for Microsoft Visual Studio
3 * Version 1.21
4 * Copyright (C) 2006-2012 Toni Ronkko
5 * https://github.com/tronkko/dirent
6 */
7
8 #ifndef DIRENT_H
9 #define DIRENT_H
10
11 /*
12 * Include windows.h without Windows Sockets 1.1 to prevent conflicts with
13 * Windows Sockets 2.0.
14 */
15 #ifndef WIN32_LEAN_AND_MEAN
16 # define WIN32_LEAN_AND_MEAN
17 #endif
18
19 #include <windows.h>
20
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <wchar.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <malloc.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <errno.h>
30
31 /* Maximum length of file name */
32 #if !defined(PATH_MAX)
33 # define PATH_MAX MAX_PATH
34 #endif
35
36 /* File type flags for d_type */
37 #define DT_UNKNOWN 0
38 #define DT_REG S_IFREG
39 #define DT_DIR S_IFDIR
40 #define DT_CHR S_IFCHR
41
42 /*
43 * File type macros. Note that block devices, sockets and links cannot be
44 * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
45 * only defined for compatibility. These macros should always return false
46 * on Windows.
47 */
48 #if !defined(S_ISDIR)
49 # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
50 #endif
51 #if !defined(S_ISREG)
52 # define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
53 #endif
54
55 /* Wide-character version */
56 struct _wdirent {
57 /* Always zero */
58 long d_ino;
59
60 /* Structure size */
61 unsigned short d_reclen;
62
63 /* Length of name without \0 */
64 size_t d_namlen;
65
66 /* File type */
67 int d_type;
68
69 /* File name */
70 wchar_t d_name[PATH_MAX];
71 };
72 typedef struct _wdirent _wdirent;
73
74 struct _WDIR {
75 /* Current directory entry */
76 struct _wdirent ent;
77
78 /* Private file data */
79 WIN32_FIND_DATAW data;
80
81 /* True if data is valid */
82 int cached;
83
84 /* Win32 search handle */
85 HANDLE handle;
86
87 /* Initial directory name */
88 wchar_t *patt;
89 };
90 typedef struct _WDIR _WDIR;
91
92 static _WDIR *_wopendir(const wchar_t *dirname);
93 static int _wclosedir(_WDIR *dirp);
94
95 /* For compatibility with Symbian */
96 #define wdirent _wdirent
97 #define WDIR _WDIR
98 #define wopendir _wopendir
99 #define wclosedir _wclosedir
100
101 /* Multi-byte character versions */
102 struct dirent {
103 /* Always zero */
104 long d_ino;
105
106 /* Structure size */
107 unsigned short d_reclen;
108
109 /* Length of name without \0 */
110 size_t d_namlen;
111
112 /* File type */
113 int d_type;
114
115 /* File name */
116 char d_name[PATH_MAX];
117 };
118 typedef struct dirent dirent;
119
120 struct DIR {
121 struct dirent ent;
122 struct _WDIR *wdirp;
123 };
124 typedef struct DIR DIR;
125
126 static DIR *opendir(const char *dirname);
127 static struct dirent *readdir(DIR *dirp);
128 static int closedir(DIR *dirp);
129
130 /* Internal utility functions */
131 static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp);
132 static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp);
133
134 static int dirent_mbstowcs_s(
135 size_t *pReturnValue,
136 wchar_t *wcstr,
137 size_t sizeInWords,
138 const char *mbstr,
139 size_t count);
140
141 static int dirent_wcstombs_s(
142 size_t *pReturnValue,
143 char *mbstr,
144 size_t sizeInBytes,
145 const wchar_t *wcstr,
146 size_t count);
147
148 static void dirent_set_errno(int error);
149
150 /*
151 * Open directory stream DIRNAME for read and return a pointer to the
152 * internal working area that is used to retrieve individual directory
153 * entries.
154 */
155 static _WDIR*
156 _wopendir(const wchar_t *dirname)
157 {
158 _WDIR *dirp = NULL;
159 int error;
160
161 /* Must have directory name */
162 if (dirname == NULL || dirname[0] == '\0') {
163 dirent_set_errno(ENOENT);
164 return NULL;
165 }
166
167 /* Allocate new _WDIR structure */
168 dirp = (_WDIR *)malloc(sizeof(struct _WDIR));
169 if (dirp != NULL) {
170 DWORD n;
171
172 /* Reset _WDIR structure */
173 dirp->handle = INVALID_HANDLE_VALUE;
174 dirp->patt = NULL;
175 dirp->cached = 0;
176
177 /* Compute the length of full path plus zero terminator
178 *
179 * Note that on WinRT there's no way to convert relative paths
180 * into absolute paths, so just assume its an absolute path.
181 */
182 #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
183 n = wcslen(dirname);
184 #else
185 n = GetFullPathNameW(dirname, 0, NULL, NULL);
186 #endif
187
188 /* Allocate room for absolute directory name and search
189 * pattern
190 */
191 dirp->patt = (wchar_t *)malloc(sizeof(wchar_t) * n + 16);
192 if (dirp->patt) {
193 /* Convert relative directory name to an
194 * absolute one. This allows rewinddir() to
195 * function correctly even when current working
196 * directory is changed between opendir()
197 * and rewinddir().
198 *
199 * Note that on WinRT there's no way to convert
200 * relative paths into absolute paths, so just
201 * assume its an absolute path.
202 */
203 #if defined(WINAPI_FAMILY) && \
204 (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
205 wcsncpy_s(dirp->patt, n + 1, dirname, n);
206 #else
207 n = GetFullPathNameW(dirname, n, dirp->patt, NULL);
208 #endif
209 if (n > 0) {
210 wchar_t *p;
211
212 /* Append search pattern \* to the directory
213 * name
214 */
215 p = dirp->patt + n;
216 if (dirp->patt < p) {
217 switch (p[-1]) {
218 case '\\':
219 case '/':
220 case ':':
221 /* Directory ends in path separator,
222 * e.g.c:\temp\
223 */
224 /*NOP*/;
225 break;
226
227 default:
228 /* Directory name doesn't end in path
229 * separator
230 */
231 *p++ = '\\';
232 }
233 }
234 *p++ = '*';
235 *p = '\0';
236
237 /* Open directory stream and retrieve the first
238 * entry
239 */
240 if (dirent_first(dirp)) {
241 /* Directory stream opened successfully */
242 error = 0;
243 } else {
244 /* Cannot retrieve first entry */
245 error = 1;
246 dirent_set_errno(ENOENT);
247 }
248
249 } else {
250 /* Cannot retrieve full path name */
251 dirent_set_errno(ENOENT);
252 error = 1;
253 }
254
255 } else {
256 /* Cannot allocate memory for search pattern */
257 error = 1;
258 }
259
260 } else {
261 /* Cannot allocate _WDIR structure */
262 error = 1;
263 }
264
265 /* Clean up in case of error */
266 if (error && dirp) {
267 _wclosedir(dirp);
268 dirp = NULL;
269 }
270
271 return dirp;
272 }
273
274 /*
275 * Close directory stream opened by opendir() function.
276 * This invalidates the DIR structure as well as any directory
277 * entry read previously by _wreaddir().
278 */
279 static int
280 _wclosedir(_WDIR *dirp)
281 {
282 int ok;
283 if (dirp) {
284
285 /* Release search handle */
286 if (dirp->handle != INVALID_HANDLE_VALUE) {
287 FindClose(dirp->handle);
288 dirp->handle = INVALID_HANDLE_VALUE;
289 }
290
291 /* Release search pattern */
292 if (dirp->patt) {
293 free(dirp->patt);
294 dirp->patt = NULL;
295 }
296
297 /* Release directory structure */
298 free(dirp);
299 ok = /*success*/0;
300
301 } else {
302 /* Invalid directory stream */
303 dirent_set_errno(EBADF);
304 ok = /*failure*/-1;
305 }
306 return ok;
307 }
308
309 /* Get first directory entry (internal) */
310 static WIN32_FIND_DATAW*
311 dirent_first(_WDIR *dirp)
312 {
313 WIN32_FIND_DATAW *datap;
314
315 /* Open directory and retrieve the first entry */
316 dirp->handle = FindFirstFileExW(
317 dirp->patt, FindExInfoStandard, &dirp->data,
318 FindExSearchNameMatch, NULL, 0);
319 if (dirp->handle != INVALID_HANDLE_VALUE) {
320
321 /* a directory entry is now waiting in memory */
322 datap = &dirp->data;
323 dirp->cached = 1;
324
325 } else {
326
327 /* Failed to re-open directory: no directory entry in memory */
328 dirp->cached = 0;
329 datap = NULL;
330
331 }
332 return datap;
333 }
334
335 /* Get next directory entry (internal) */
336 static WIN32_FIND_DATAW*
337 dirent_next(_WDIR *dirp)
338 {
339 WIN32_FIND_DATAW *p;
340
341 /* Get next directory entry */
342 if (dirp->cached != 0) {
343
344 /* A valid directory entry already in memory */
345 p = &dirp->data;
346 dirp->cached = 0;
347
348 } else if (dirp->handle != INVALID_HANDLE_VALUE) {
349
350 /* Get the next directory entry from stream */
351 if (FindNextFileW(dirp->handle, &dirp->data) != FALSE) {
352 /* Got a file */
353 p = &dirp->data;
354 } else {
355 /* The very last entry has been processed
356 *or an error occurred
357 */
358 FindClose(dirp->handle);
359 dirp->handle = INVALID_HANDLE_VALUE;
360 p = NULL;
361 }
362
363 } else {
364
365 /* End of directory stream reached */
366 p = NULL;
367
368 }
369
370 return p;
371 }
372
373 /*
374 * Open directory stream using plain old C-string.
375 */
376 static DIR*
377 opendir(const char *dirname)
378 {
379 struct DIR *dirp;
380 int error;
381
382 /* Must have directory name */
383 if (dirname == NULL || dirname[0] == '\0') {
384 dirent_set_errno(ENOENT);
385 return NULL;
386 }
387
388 /* Allocate memory for DIR structure */
389 dirp = (DIR *)malloc(sizeof(struct DIR));
390 if (dirp) {
391 wchar_t wname[PATH_MAX];
392 size_t n;
393
394 /* Convert directory name to wide-character string */
395 error = dirent_mbstowcs_s(&n, wname, PATH_MAX,
396 dirname, PATH_MAX);
397 if (!error) {
398
399 /* Open directory stream using wide-character name */
400 dirp->wdirp = _wopendir(wname);
401 if (dirp->wdirp) {
402 /* Directory stream opened */
403 error = 0;
404 } else {
405 /* Failed to open directory stream */
406 error = 1;
407 }
408
409 } else {
410 /*
411 * Cannot convert file name to wide-character string.
412 * This occurs if the string contains invalid multi-byte
413 * sequences or the output buffer is too small to
414 * contain the resulting string.
415 */
416 error = 1;
417 }
418
419 } else {
420 /* Cannot allocate DIR structure */
421 error = 1;
422 }
423
424 /* Clean up in case of error */
425 if (error && dirp) {
426 free(dirp);
427 dirp = NULL;
428 }
429
430 return dirp;
431 }
432
433 /*
434 * Read next directory entry.
435 *
436 * When working with text consoles, please note that file names
437 * returned by readdir() are represented in the default ANSI code
438 * page while any output toconsole is typically formatted on another
439 * code page. Thus, non-ASCII characters in file names will not usually
440 * display correctly on console. The problem can be fixed in two ways:
441 * (1) change the character set of console to 1252 using chcp utility
442 * and use Lucida Console font, or (2) use _cprintf function when
443 * writing to console. The _cprinf() will re-encode ANSI strings to the
444 * console code page so many non-ASCII characters will display correctly.
445 */
446 static struct dirent*
447 readdir(DIR *dirp)
448 {
449 WIN32_FIND_DATAW *datap;
450 struct dirent *entp;
451
452 /* Read next directory entry */
453 datap = dirent_next(dirp->wdirp);
454 if (datap) {
455 size_t n;
456 int error;
457
458 /* Attempt to convert file name to multi-byte string */
459 error = dirent_wcstombs_s(&n, dirp->ent.d_name,
460 PATH_MAX, datap->cFileName, PATH_MAX);
461
462 /*
463 * If the file name cannot be represented by a multi-byte
464 * string, then attempt to use old 8+3 file name.
465 * This allows traditional Unix-code to access some file
466 * names despite of unicode characters, although file names
467 * may seem unfamiliar to the user.
468 *
469 * Be ware that the code below cannot come up with a short
470 * file name unless the file system provides one. At least
471 * VirtualBox shared folders fail to do this.
472 */
473 if (error && datap->cAlternateFileName[0] != '\0') {
474 error = dirent_wcstombs_s(
475 &n, dirp->ent.d_name, PATH_MAX,
476 datap->cAlternateFileName, PATH_MAX);
477 }
478
479 if (!error) {
480 DWORD attr;
481
482 /* Initialize directory entry for return */
483 entp = &dirp->ent;
484
485 /* Length of file name excluding zero terminator */
486 entp->d_namlen = n - 1;
487
488 /* File attributes */
489 attr = datap->dwFileAttributes;
490 if ((attr & FILE_ATTRIBUTE_DEVICE) != 0)
491 entp->d_type = DT_CHR;
492 else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
493 entp->d_type = DT_DIR;
494 else
495 entp->d_type = DT_REG;
496
497 /* Reset dummy fields */
498 entp->d_ino = 0;
499 entp->d_reclen = sizeof(struct dirent);
500
501 } else {
502 /*
503 * Cannot convert file name to multi-byte string so
504 * construct an erroneous directory entry and return
505 * that. Note that we cannot return NULL as that would
506 * stop the processing of directory entries completely.
507 */
508 entp = &dirp->ent;
509 entp->d_name[0] = '?';
510 entp->d_name[1] = '\0';
511 entp->d_namlen = 1;
512 entp->d_type = DT_UNKNOWN;
513 entp->d_ino = 0;
514 entp->d_reclen = 0;
515 }
516
517 } else {
518 /* No more directory entries */
519 entp = NULL;
520 }
521
522 return entp;
523 }
524
525 /*
526 * Close directory stream.
527 */
528 static int
529 closedir(DIR *dirp)
530 {
531 int ok;
532 if (dirp) {
533
534 /* Close wide-character directory stream */
535 ok = _wclosedir(dirp->wdirp);
536 dirp->wdirp = NULL;
537
538 /* Release multi-byte character version */
539 free(dirp);
540
541 } else {
542
543 /* Invalid directory stream */
544 dirent_set_errno(EBADF);
545 ok = /*failure*/-1;
546
547 }
548 return ok;
549 }
550
551 /* Convert multi-byte string to wide character string */
552 static int
553 dirent_mbstowcs_s(
554 size_t *pReturnValue,
555 wchar_t *wcstr,
556 size_t sizeInWords,
557 const char *mbstr,
558 size_t count)
559 {
560 int error;
561
562 #if defined(_MSC_VER) && _MSC_VER >= 1400
563 /* Microsoft Visual Studio 2005 or later */
564 error = mbstowcs_s(pReturnValue, wcstr,
565 sizeInWords, mbstr, count);
566 #else
567
568 /* Older Visual Studio or non-Microsoft compiler */
569 size_t n;
570
571 /* Convert to wide-character string (or count characters) */
572 n = mbstowcs(wcstr, mbstr, sizeInWords);
573 if (!wcstr || n < count) {
574
575 /* Zero-terminate output buffer */
576 if (wcstr && sizeInWords) {
577 if (n >= sizeInWords)
578 n = sizeInWords - 1;
579 wcstr[n] = 0;
580 }
581
582 /* Length of resuting multi-byte string WITH zero
583 *terminator
584 */
585 if (pReturnValue)
586 *pReturnValue = n + 1;
587
588 /* Success */
589 error = 0;
590
591 } else {
592
593 /* Could not convert string */
594 error = 1;
595
596 }
597 #endif
598
599 return error;
600 }
601
602 /* Convert wide-character string to multi-byte string */
603 static int
604 dirent_wcstombs_s(
605 size_t *pReturnValue,
606 char *mbstr,
607 size_t sizeInBytes, /* max size of mbstr */
608 const wchar_t *wcstr,
609 size_t count)
610 {
611 int error;
612
613 #if defined(_MSC_VER) && _MSC_VER >= 1400
614 /* Microsoft Visual Studio 2005 or later */
615 error = wcstombs_s(pReturnValue, mbstr, sizeInBytes, wcstr, count);
616 #else
617 /* Older Visual Studio or non-Microsoft compiler */
618 size_t n;
619
620 /* Convert to multi-byte string
621 * (or count the number of bytes needed)
622 */
623 n = wcstombs(mbstr, wcstr, sizeInBytes);
624 if (!mbstr || n < count) {
625 /* Zero-terminate output buffer */
626 if (mbstr && sizeInBytes) {
627 if (n >= sizeInBytes)
628 n = sizeInBytes - 1;
629 mbstr[n] = '\0';
630 }
631 /* Length of resulting multi-bytes string WITH
632 *zero-terminator
633 */
634 if (pReturnValue)
635 *pReturnValue = n + 1;
636 /* Success */
637 error = 0;
638 } else {
639 /* Cannot convert string */
640 error = 1;
641 }
642 #endif
643
644 return error;
645 }
646
647 /* Set errno variable */
648 static void
649 dirent_set_errno(int error)
650 {
651 #if defined(_MSC_VER) && _MSC_VER >= 1400
652 /* Microsoft Visual Studio 2005 and later */
653 _set_errno(error);
654 #else
655
656 /* Non-Microsoft compiler or older Microsoft compiler */
657 errno = error;
658 #endif
659 }
660
661 #ifdef __cplusplus
662 }
663 #endif
664 #endif /*DIRENT_H*/