VirtualBox

source: kBuild/trunk/src/lib/nt/ntdir.c@ 3372

Last change on this file since 3372 was 3007, checked in by bird, 8 years ago

lib/nt: Deal better with NTFS mount points.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 21.6 KB
Line 
1/* $Id: ntdir.c 3007 2016-11-06 16:46:43Z bird $ */
2/** @file
3 * MSC + NT opendir, readdir, telldir, seekdir, and closedir.
4 */
5
6/*
7 * Copyright (c) 2005-2016 knut st. osmundsen <[email protected]>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 * IN THE SOFTWARE.
26 *
27 * Alternatively, the content of this file may be used under the terms of the
28 * GPL version 2 or later, or LGPL version 2.1 or later.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include <stdio.h>
36#include <errno.h>
37#include <malloc.h>
38#include <assert.h>
39
40#include "ntstuff.h"
41#include "nthlp.h"
42#include "ntdir.h"
43
44
45/**
46 * Implements opendir.
47 */
48BirdDir_T *birdDirOpen(const char *pszPath)
49{
50 HANDLE hDir = birdOpenFile(pszPath,
51 FILE_READ_DATA | SYNCHRONIZE,
52 FILE_ATTRIBUTE_NORMAL,
53 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
54 FILE_OPEN,
55 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
56 OBJ_CASE_INSENSITIVE);
57 if (hDir != INVALID_HANDLE_VALUE)
58 {
59 BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, NULL, BIRDDIR_F_CLOSE_HANDLE);
60 if (pDir)
61 return pDir;
62 birdCloseFile(hDir);
63 }
64 return NULL;
65}
66
67
68/**
69 * Alternative opendir, with extra stat() info returned by readdir().
70 */
71BirdDir_T *birdDirOpenExtraInfo(const char *pszPath)
72{
73 HANDLE hDir = birdOpenFile(pszPath,
74 FILE_READ_DATA | SYNCHRONIZE,
75 FILE_ATTRIBUTE_NORMAL,
76 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
77 FILE_OPEN,
78 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
79 OBJ_CASE_INSENSITIVE);
80 if (hDir != INVALID_HANDLE_VALUE)
81 {
82 BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, NULL, BIRDDIR_F_CLOSE_HANDLE | BIRDDIR_F_EXTRA_INFO);
83 if (pDir)
84 return pDir;
85 birdCloseFile(hDir);
86 }
87 return NULL;
88}
89
90
91BirdDir_T *birdDirOpenExW(void *hRoot, const wchar_t *pwszPath, const wchar_t *pwszFilter, unsigned fFlags)
92{
93 HANDLE hDir = birdOpenFileExW((HANDLE)hRoot,
94 pwszPath,
95 FILE_READ_DATA | SYNCHRONIZE,
96 FILE_ATTRIBUTE_NORMAL,
97 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
98 FILE_OPEN,
99 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
100 OBJ_CASE_INSENSITIVE);
101 if (hDir != INVALID_HANDLE_VALUE)
102 {
103 BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, pwszFilter, fFlags | BIRDDIR_F_CLOSE_HANDLE);
104 if (pDir)
105 return pDir;
106 birdCloseFile(hDir);
107 }
108 return NULL;
109}
110
111
112/**
113 * Internal worker for birdStatModTimeOnly.
114 */
115BirdDir_T *birdDirOpenFromHandle(void *pvHandle, const void *pvReserved, unsigned fFlags)
116{
117 if (!pvReserved && !(fFlags & BIRDDIR_F_STATIC_ALLOC))
118 {
119 /*
120 * Allocate and initialize the directory enum handle.
121 */
122 BirdDir_T *pDir = (BirdDir_T *)birdMemAlloc(sizeof(*pDir));
123 if (pDir)
124 {
125 pDir->uMagic = BIRD_DIR_MAGIC;
126 pDir->fFlags = fFlags;
127 pDir->pvHandle = pvHandle;
128 pDir->uDev = 0;
129 pDir->offPos = 0;
130 pDir->fHaveData = 0;
131 pDir->fFirst = 1;
132 pDir->iInfoClass = fFlags & BIRDDIR_F_EXTRA_INFO ? MyFileIdFullDirectoryInformation : MyFileNamesInformation;
133 pDir->offBuf = 0;
134 pDir->cbBuf = 0;
135 pDir->pabBuf = NULL;
136 return pDir;
137 }
138 }
139 else
140 {
141 assert(!(fFlags & BIRDDIR_F_STATIC_ALLOC));
142 assert(pvReserved == NULL);
143 }
144 birdSetErrnoToInvalidArg();
145 return NULL;
146}
147
148
149/**
150 * Special API that takes a preallocated BirdDir_T and can be called again
151 * without involving birdDirClose.
152 *
153 *
154 */
155BirdDir_T *birdDirOpenFromHandleWithReuse(BirdDir_T *pDir, void *pvHandle, const void *pvReserved, unsigned fFlags)
156{
157 if (!pvReserved)
158 {
159 /*
160 * Allocate and initialize the directory enum handle.
161 */
162 if (pDir)
163 {
164 if (pDir->uMagic == BIRD_DIR_MAGIC)
165 {
166 if ( (pDir->fFlags & BIRDDIR_F_CLOSE_HANDLE)
167 && pDir->pvHandle != INVALID_HANDLE_VALUE)
168 birdCloseFile((HANDLE)pDir->pvHandle);
169 }
170 else
171 {
172 pDir->cbBuf = 0;
173 pDir->pabBuf = NULL;
174 pDir->uMagic = BIRD_DIR_MAGIC;
175 }
176 pDir->pvHandle = pvHandle;
177 pDir->fFlags = fFlags;
178 pDir->uDev = 0;
179 pDir->offPos = 0;
180 pDir->fHaveData = 0;
181 pDir->fFirst = 1;
182 pDir->iInfoClass = fFlags & BIRDDIR_F_EXTRA_INFO ? MyFileIdFullDirectoryInformation : MyFileNamesInformation;
183 pDir->offBuf = 0;
184 return pDir;
185 }
186 }
187 else
188 assert(pvReserved == NULL);
189 birdSetErrnoToInvalidArg();
190 return NULL;
191}
192
193
194static int birdDirReadMore(BirdDir_T *pDir)
195{
196 MY_NTSTATUS rcNt;
197 MY_IO_STATUS_BLOCK Ios;
198 int fFirst;
199
200 /*
201 * Retrieve the volume serial number + creation time and create the
202 * device number the first time around. Also allocate a buffer.
203 */
204 fFirst = pDir->fFirst;
205 if (fFirst)
206 {
207 union
208 {
209 MY_FILE_FS_VOLUME_INFORMATION VolInfo;
210 unsigned char abBuf[1024];
211 } uBuf;
212
213 Ios.Information = 0;
214 Ios.u.Status = -1;
215 rcNt = g_pfnNtQueryVolumeInformationFile((HANDLE)pDir->pvHandle, &Ios, &uBuf, sizeof(uBuf), MyFileFsVolumeInformation);
216 if (MY_NT_SUCCESS(rcNt))
217 rcNt = Ios.u.Status;
218 if (MY_NT_SUCCESS(rcNt))
219 pDir->uDev = uBuf.VolInfo.VolumeSerialNumber
220 | (uBuf.VolInfo.VolumeCreationTime.QuadPart << 32);
221 else
222 pDir->uDev = 0;
223
224 if (!pDir->pabBuf)
225 {
226 /*
227 * Allocate a buffer.
228 *
229 * Better not exceed 64KB or CIFS may throw a fit. Also, on win10/64
230 * here there is a noticable speedup when going one byte below 64KB.
231 */
232 pDir->cbBuf = 0xffe0;
233 pDir->pabBuf = birdMemAlloc(pDir->cbBuf);
234 if (!pDir->pabBuf)
235 return birdSetErrnoToNoMem();
236 }
237
238 pDir->fFirst = 0;
239 }
240
241 /*
242 * Read another buffer full.
243 */
244 Ios.Information = 0;
245 Ios.u.Status = -1;
246
247 rcNt = g_pfnNtQueryDirectoryFile((HANDLE)pDir->pvHandle,
248 NULL, /* hEvent */
249 NULL, /* pfnApcComplete */
250 NULL, /* pvApcCompleteCtx */
251 &Ios,
252 pDir->pabBuf,
253 pDir->cbBuf,
254 (MY_FILE_INFORMATION_CLASS)pDir->iInfoClass,
255 FALSE, /* fReturnSingleEntry */
256 NULL, /* Filter / restart pos. */
257 pDir->fFlags & BIRDDIR_F_RESTART_SCAN ? TRUE : FALSE); /* fRestartScan */
258 if (!MY_NT_SUCCESS(rcNt))
259 {
260 int rc;
261 if (rcNt == MY_STATUS_NO_MORE_FILES)
262 rc = 0;
263 else
264 rc = birdSetErrnoFromNt(rcNt);
265 pDir->fHaveData = 0;
266 pDir->offBuf = pDir->cbBuf;
267 return rc;
268 }
269
270 pDir->offBuf = 0;
271 pDir->fHaveData = 1;
272 pDir->fFlags &= ~BIRDDIR_F_RESTART_SCAN;
273
274 return 0;
275}
276
277
278static int birdDirCopyNameToEntry(WCHAR const *pwcName, ULONG cbName, BirdDirEntry_T *pEntry)
279{
280 int cchOut = WideCharToMultiByte(CP_ACP, 0,
281 pwcName, cbName / sizeof(WCHAR),
282 pEntry->d_name, sizeof(pEntry->d_name) - 1,
283 NULL, NULL);
284 if (cchOut > 0)
285 {
286 pEntry->d_name[cchOut] = '\0';
287 pEntry->d_namlen = (unsigned __int16)cchOut;
288 pEntry->d_reclen = (unsigned __int16)((size_t)&pEntry->d_name[cchOut + 1] - (size_t)pEntry);
289 return 0;
290 }
291 return -1;
292}
293
294
295/**
296 * Deals with mount points.
297 *
298 * @param pDir The directory handle.
299 * @param pInfo The NT entry information.
300 * @param pEntryStat The stats for the mount point directory that needs
301 * updating (a d_stat member).
302 */
303static void birdDirUpdateMountPointInfo(BirdDir_T *pDir, MY_FILE_ID_FULL_DIR_INFORMATION *pInfo,
304 BirdStat_T *pEntryStat)
305{
306 /*
307 * Try open the root directory of the mount.
308 * (Can't use birdStatAtW here because the name isn't terminated.)
309 */
310 HANDLE hRoot = INVALID_HANDLE_VALUE;
311 MY_NTSTATUS rcNt;
312 MY_UNICODE_STRING Name;
313 Name.Buffer = pInfo->FileName;
314 Name.Length = Name.MaximumLength = (USHORT)pInfo->FileNameLength;
315
316 rcNt = birdOpenFileUniStr((HANDLE)pDir->pvHandle, &Name,
317 FILE_READ_ATTRIBUTES,
318 FILE_ATTRIBUTE_NORMAL,
319 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
320 FILE_OPEN,
321 FILE_OPEN_FOR_BACKUP_INTENT,
322 OBJ_CASE_INSENSITIVE,
323 &hRoot);
324 if (MY_NT_SUCCESS(rcNt))
325 {
326 int iSavedErrno = errno;
327 BirdStat_T RootStat;
328 if (birdStatHandle(hRoot, &RootStat, NULL) == 0)
329 {
330 RootStat.st_ismountpoint = 2;
331 *pEntryStat = RootStat;
332 }
333 birdCloseFile(hRoot);
334 errno = iSavedErrno;
335 }
336 /* else: don't mind failures, we've got some info. */
337}
338
339
340/**
341 * Implements readdir_r().
342 *
343 * @remarks birdDirReadReentrantW is a copy of this. Keep them in sync!
344 */
345int birdDirReadReentrant(BirdDir_T *pDir, BirdDirEntry_T *pEntry, BirdDirEntry_T **ppResult)
346{
347 int fSkipEntry;
348
349 *ppResult = NULL;
350
351 if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
352 return birdSetErrnoToBadFileNo();
353
354 do
355 {
356 ULONG offNext;
357 ULONG cbMinCur;
358
359 /*
360 * Read more?
361 */
362 if (!pDir->fHaveData)
363 {
364 if (birdDirReadMore(pDir) != 0)
365 return -1;
366 if (!pDir->fHaveData)
367 return 0;
368 }
369
370 /*
371 * Convert the NT data to the unixy output structure.
372 */
373 fSkipEntry = 0;
374 switch (pDir->iInfoClass)
375 {
376 case MyFileNamesInformation:
377 {
378 MY_FILE_NAMES_INFORMATION *pInfo = (MY_FILE_NAMES_INFORMATION *)&pDir->pabBuf[pDir->offBuf];
379 if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_NAMES_INFORMATION
380 || pInfo->FileNameLength >= pDir->cbBuf
381 || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_NAMES_INFORMATION > pDir->cbBuf)
382 {
383 fSkipEntry = 1;
384 pDir->fHaveData = 0;
385 continue;
386 }
387
388 memset(&pEntry->d_stat, 0, sizeof(pEntry->d_stat));
389 pEntry->d_stat.st_mode = S_IFMT;
390 pEntry->d_type = DT_UNKNOWN;
391 pEntry->d_reclen = 0;
392 pEntry->d_namlen = 0;
393 if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0)
394 fSkipEntry = 1;
395
396 cbMinCur = MIN_SIZEOF_MY_FILE_NAMES_INFORMATION + pInfo->FileNameLength;
397 offNext = pInfo->NextEntryOffset;
398 break;
399 }
400
401 case MyFileIdFullDirectoryInformation:
402 {
403 MY_FILE_ID_FULL_DIR_INFORMATION *pInfo = (MY_FILE_ID_FULL_DIR_INFORMATION *)&pDir->pabBuf[pDir->offBuf];
404 if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION
405 || pInfo->FileNameLength >= pDir->cbBuf
406 || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION > pDir->cbBuf)
407 {
408 fSkipEntry = 1;
409 pDir->fHaveData = 0;
410 continue;
411 }
412
413 pEntry->d_type = DT_UNKNOWN;
414 pEntry->d_reclen = 0;
415 pEntry->d_namlen = 0;
416 if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0)
417 fSkipEntry = 1;
418 birdStatFillFromFileIdFullDirInfo(&pEntry->d_stat, pInfo);
419 pEntry->d_stat.st_dev = pDir->uDev;
420 switch (pEntry->d_stat.st_mode & S_IFMT)
421 {
422 case S_IFREG: pEntry->d_type = DT_REG; break;
423 case S_IFDIR: pEntry->d_type = DT_DIR; break;
424 case S_IFLNK: pEntry->d_type = DT_LNK; break;
425 case S_IFIFO: pEntry->d_type = DT_FIFO; break;
426 case S_IFCHR: pEntry->d_type = DT_CHR; break;
427 default:
428#ifndef NDEBUG
429 __debugbreak();
430#endif
431 pEntry->d_type = DT_UNKNOWN;
432 break;
433 }
434
435 if (pEntry->d_stat.st_ismountpoint != 1)
436 { /* likely. */ }
437 else
438 birdDirUpdateMountPointInfo(pDir, pInfo, &pEntry->d_stat);
439
440 cbMinCur = MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION + pInfo->FileNameLength;
441 offNext = pInfo->NextEntryOffset;
442 break;
443 }
444
445 default:
446 return birdSetErrnoToBadFileNo();
447 }
448
449 /*
450 * Advance.
451 */
452 if ( offNext >= cbMinCur
453 && offNext < pDir->cbBuf)
454 pDir->offBuf += offNext;
455 else
456 {
457 pDir->fHaveData = 0;
458 pDir->offBuf = pDir->cbBuf;
459 }
460 pDir->offPos++;
461 } while (fSkipEntry);
462
463
464 /*
465 * Successful return.
466 */
467 *ppResult = pEntry;
468 return 0;
469}
470
471
472/**
473 * Implements readdir().
474 */
475BirdDirEntry_T *birdDirRead(BirdDir_T *pDir)
476{
477 BirdDirEntry_T *pRet = NULL;
478 birdDirReadReentrant(pDir, &pDir->u.DirEntry, &pRet);
479 return pRet;
480}
481
482
483static int birdDirCopyNameToEntryW(WCHAR const *pwcName, ULONG cbName, BirdDirEntryW_T *pEntry)
484{
485 ULONG cwcName = cbName / sizeof(wchar_t);
486 if (cwcName < sizeof(pEntry->d_name))
487 {
488 memcpy(pEntry->d_name, pwcName, cbName);
489 pEntry->d_name[cwcName] = '\0';
490 pEntry->d_namlen = (unsigned __int16)cwcName;
491 pEntry->d_reclen = (unsigned __int16)((size_t)&pEntry->d_name[cwcName + 1] - (size_t)pEntry);
492 return 0;
493 }
494 return -1;
495}
496
497
498/**
499 * Implements readdir_r(), UTF-16 version.
500 *
501 * @remarks This is a copy of birdDirReadReentrant where only the name handling
502 * and entry type differs. Remember to keep them in sync!
503 */
504int birdDirReadReentrantW(BirdDir_T *pDir, BirdDirEntryW_T *pEntry, BirdDirEntryW_T **ppResult)
505{
506 int fSkipEntry;
507
508 *ppResult = NULL;
509
510 if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
511 return birdSetErrnoToBadFileNo();
512
513 do
514 {
515 ULONG offNext;
516 ULONG cbMinCur;
517
518 /*
519 * Read more?
520 */
521 if (!pDir->fHaveData)
522 {
523 if (birdDirReadMore(pDir) != 0)
524 return -1;
525 if (!pDir->fHaveData)
526 return 0;
527 }
528
529 /*
530 * Convert the NT data to the unixy output structure.
531 */
532 fSkipEntry = 0;
533 switch (pDir->iInfoClass)
534 {
535 case MyFileNamesInformation:
536 {
537 MY_FILE_NAMES_INFORMATION *pInfo = (MY_FILE_NAMES_INFORMATION *)&pDir->pabBuf[pDir->offBuf];
538 if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_NAMES_INFORMATION
539 || pInfo->FileNameLength >= pDir->cbBuf
540 || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_NAMES_INFORMATION > pDir->cbBuf)
541 {
542 fSkipEntry = 1;
543 pDir->fHaveData = 0;
544 continue;
545 }
546
547 memset(&pEntry->d_stat, 0, sizeof(pEntry->d_stat));
548 pEntry->d_stat.st_mode = S_IFMT;
549 pEntry->d_type = DT_UNKNOWN;
550 pEntry->d_reclen = 0;
551 pEntry->d_namlen = 0;
552 if (birdDirCopyNameToEntryW(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0)
553 fSkipEntry = 1;
554
555 cbMinCur = MIN_SIZEOF_MY_FILE_NAMES_INFORMATION + pInfo->FileNameLength;
556 offNext = pInfo->NextEntryOffset;
557 break;
558 }
559
560 case MyFileIdFullDirectoryInformation:
561 {
562 MY_FILE_ID_FULL_DIR_INFORMATION *pInfo = (MY_FILE_ID_FULL_DIR_INFORMATION *)&pDir->pabBuf[pDir->offBuf];
563 if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION
564 || pInfo->FileNameLength >= pDir->cbBuf
565 || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION > pDir->cbBuf)
566 {
567 fSkipEntry = 1;
568 pDir->fHaveData = 0;
569 continue;
570 }
571
572 pEntry->d_type = DT_UNKNOWN;
573 pEntry->d_reclen = 0;
574 pEntry->d_namlen = 0;
575 if (birdDirCopyNameToEntryW(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0)
576 fSkipEntry = 1;
577 birdStatFillFromFileIdFullDirInfo(&pEntry->d_stat, pInfo);
578 pEntry->d_stat.st_dev = pDir->uDev;
579 switch (pEntry->d_stat.st_mode & S_IFMT)
580 {
581 case S_IFREG: pEntry->d_type = DT_REG; break;
582 case S_IFDIR: pEntry->d_type = DT_DIR; break;
583 case S_IFLNK: pEntry->d_type = DT_LNK; break;
584 case S_IFIFO: pEntry->d_type = DT_FIFO; break;
585 case S_IFCHR: pEntry->d_type = DT_CHR; break;
586 default:
587#ifndef NDEBUG
588 __debugbreak();
589#endif
590 pEntry->d_type = DT_UNKNOWN;
591 break;
592 }
593
594 if (pEntry->d_stat.st_ismountpoint != 1)
595 { /* likely. */ }
596 else
597 birdDirUpdateMountPointInfo(pDir, pInfo, &pEntry->d_stat);
598
599 cbMinCur = MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION + pInfo->FileNameLength;
600 offNext = pInfo->NextEntryOffset;
601 break;
602 }
603
604 default:
605 return birdSetErrnoToBadFileNo();
606 }
607
608 /*
609 * Advance.
610 */
611 if ( offNext >= cbMinCur
612 && offNext < pDir->cbBuf)
613 pDir->offBuf += offNext;
614 else
615 {
616 pDir->fHaveData = 0;
617 pDir->offBuf = pDir->cbBuf;
618 }
619 pDir->offPos++;
620 } while (fSkipEntry);
621
622
623 /*
624 * Successful return.
625 */
626 *ppResult = pEntry;
627 return 0;
628}
629
630/**
631 * Implements readdir().
632 */
633BirdDirEntryW_T *birdDirReadW(BirdDir_T *pDir)
634{
635 BirdDirEntryW_T *pRet = NULL;
636 birdDirReadReentrantW(pDir, &pDir->u.DirEntryW, &pRet);
637 return pRet;
638}
639
640
641/**
642 * Implements telldir().
643 */
644long birdDirTell(BirdDir_T *pDir)
645{
646 if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
647 return birdSetErrnoToBadFileNo();
648 return pDir->offPos;
649}
650
651
652void birdDirSeek(BirdDir_T *pDir, long offDir);
653
654
655/**
656 * Implements closedir().
657 */
658int birdDirClose(BirdDir_T *pDir)
659{
660 if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
661 return birdSetErrnoToBadFileNo();
662
663 pDir->uMagic++;
664 if (pDir->fFlags & BIRDDIR_F_CLOSE_HANDLE)
665 birdCloseFile((HANDLE)pDir->pvHandle);
666 pDir->pvHandle = (void *)INVALID_HANDLE_VALUE;
667 birdMemFree(pDir->pabBuf);
668 pDir->pabBuf = NULL;
669 if (!(pDir->fFlags & BIRDDIR_F_STATIC_ALLOC))
670 birdMemFree(pDir);
671
672 return 0;
673}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette