VirtualBox

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

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

fts-nt.c: Wide char support, part 3.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 18.0 KB
Line 
1/* $Id: ntdir.c 3004 2016-11-05 23:18:51Z 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)
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 assert(pvReserved == NULL);
141 birdSetErrnoToNoMem();
142 return NULL;
143}
144
145
146static int birdDirReadMore(BirdDir_T *pDir)
147{
148 MY_NTSTATUS rcNt;
149 MY_IO_STATUS_BLOCK Ios;
150 int fFirst;
151
152 /*
153 * Retrieve the volume serial number + creation time and create the
154 * device number the first time around. Also allocate a buffer.
155 */
156 fFirst = pDir->fFirst;
157 if (fFirst)
158 {
159 union
160 {
161 MY_FILE_FS_VOLUME_INFORMATION VolInfo;
162 unsigned char abBuf[1024];
163 } uBuf;
164
165 Ios.Information = 0;
166 Ios.u.Status = -1;
167 rcNt = g_pfnNtQueryVolumeInformationFile((HANDLE)pDir->pvHandle, &Ios, &uBuf, sizeof(uBuf), MyFileFsVolumeInformation);
168 if (MY_NT_SUCCESS(rcNt))
169 rcNt = Ios.u.Status;
170 if (MY_NT_SUCCESS(rcNt))
171 pDir->uDev = uBuf.VolInfo.VolumeSerialNumber
172 | (uBuf.VolInfo.VolumeCreationTime.QuadPart << 32);
173 else
174 pDir->uDev = 0;
175
176 /*
177 * Allocate a buffer.
178 */
179 pDir->cbBuf = 0x20000;
180 pDir->pabBuf = birdMemAlloc(pDir->cbBuf);
181 if (!pDir->pabBuf)
182 return birdSetErrnoToNoMem();
183
184 pDir->fFirst = 0;
185 }
186
187 /*
188 * Read another buffer full.
189 */
190 Ios.Information = 0;
191 Ios.u.Status = -1;
192
193 rcNt = g_pfnNtQueryDirectoryFile((HANDLE)pDir->pvHandle,
194 NULL, /* hEvent */
195 NULL, /* pfnApcComplete */
196 NULL, /* pvApcCompleteCtx */
197 &Ios,
198 pDir->pabBuf,
199 pDir->cbBuf,
200 (MY_FILE_INFORMATION_CLASS)pDir->iInfoClass,
201 FALSE, /* fReturnSingleEntry */
202 NULL, /* Filter / restart pos. */
203 pDir->fFlags & BIRDDIR_F_RESTART_SCAN ? TRUE : FALSE); /* fRestartScan */
204 if (!MY_NT_SUCCESS(rcNt))
205 {
206 int rc;
207 if (rcNt == MY_STATUS_NO_MORE_FILES)
208 rc = 0;
209 else
210 rc = birdSetErrnoFromNt(rcNt);
211 pDir->fHaveData = 0;
212 pDir->offBuf = pDir->cbBuf;
213 return rc;
214 }
215
216 pDir->offBuf = 0;
217 pDir->fHaveData = 1;
218 pDir->fFlags &= ~BIRDDIR_F_RESTART_SCAN;
219
220 return 0;
221}
222
223
224static int birdDirCopyNameToEntry(WCHAR const *pwcName, ULONG cbName, BirdDirEntry_T *pEntry)
225{
226 int cchOut = WideCharToMultiByte(CP_ACP, 0,
227 pwcName, cbName / sizeof(WCHAR),
228 pEntry->d_name, sizeof(pEntry->d_name) - 1,
229 NULL, NULL);
230 if (cchOut > 0)
231 {
232 pEntry->d_name[cchOut] = '\0';
233 pEntry->d_namlen = (unsigned __int16)cchOut;
234 pEntry->d_reclen = (unsigned __int16)((size_t)&pEntry->d_name[cchOut + 1] - (size_t)pEntry);
235 return 0;
236 }
237 return -1;
238}
239
240
241
242/**
243 * Implements readdir_r().
244 *
245 * @remarks birdDirReadReentrantW is a copy of this. Keep them in sync!
246 */
247int birdDirReadReentrant(BirdDir_T *pDir, BirdDirEntry_T *pEntry, BirdDirEntry_T **ppResult)
248{
249 int fSkipEntry;
250
251 *ppResult = NULL;
252
253 if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
254 return birdSetErrnoToBadFileNo();
255
256 do
257 {
258 ULONG offNext;
259 ULONG cbMinCur;
260
261 /*
262 * Read more?
263 */
264 if (!pDir->fHaveData)
265 {
266 if (birdDirReadMore(pDir) != 0)
267 return -1;
268 if (!pDir->fHaveData)
269 return 0;
270 }
271
272 /*
273 * Convert the NT data to the unixy output structure.
274 */
275 fSkipEntry = 0;
276 switch (pDir->iInfoClass)
277 {
278 case MyFileNamesInformation:
279 {
280 MY_FILE_NAMES_INFORMATION *pInfo = (MY_FILE_NAMES_INFORMATION *)&pDir->pabBuf[pDir->offBuf];
281 if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_NAMES_INFORMATION
282 || pInfo->FileNameLength >= pDir->cbBuf
283 || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_NAMES_INFORMATION > pDir->cbBuf)
284 {
285 fSkipEntry = 1;
286 pDir->fHaveData = 0;
287 continue;
288 }
289
290 memset(&pEntry->d_stat, 0, sizeof(pEntry->d_stat));
291 pEntry->d_stat.st_mode = S_IFMT;
292 pEntry->d_type = DT_UNKNOWN;
293 pEntry->d_reclen = 0;
294 pEntry->d_namlen = 0;
295 if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0)
296 fSkipEntry = 1;
297
298 cbMinCur = MIN_SIZEOF_MY_FILE_NAMES_INFORMATION + pInfo->FileNameLength;
299 offNext = pInfo->NextEntryOffset;
300 break;
301 }
302
303 case MyFileIdFullDirectoryInformation:
304 {
305 MY_FILE_ID_FULL_DIR_INFORMATION *pInfo = (MY_FILE_ID_FULL_DIR_INFORMATION *)&pDir->pabBuf[pDir->offBuf];
306 if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION
307 || pInfo->FileNameLength >= pDir->cbBuf
308 || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION > pDir->cbBuf)
309 {
310 fSkipEntry = 1;
311 pDir->fHaveData = 0;
312 continue;
313 }
314
315 pEntry->d_type = DT_UNKNOWN;
316 pEntry->d_reclen = 0;
317 pEntry->d_namlen = 0;
318 if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0)
319 fSkipEntry = 1;
320 birdStatFillFromFileIdFullDirInfo(&pEntry->d_stat, pInfo, pEntry->d_name);
321 pEntry->d_stat.st_dev = pDir->uDev;
322 switch (pEntry->d_stat.st_mode & S_IFMT)
323 {
324 case S_IFREG: pEntry->d_type = DT_REG; break;
325 case S_IFDIR: pEntry->d_type = DT_DIR; break;
326 case S_IFLNK: pEntry->d_type = DT_LNK; break;
327 case S_IFIFO: pEntry->d_type = DT_FIFO; break;
328 case S_IFCHR: pEntry->d_type = DT_CHR; break;
329 default:
330#ifndef NDEBUG
331 __debugbreak();
332#endif
333 pEntry->d_type = DT_UNKNOWN;
334 break;
335 }
336
337 cbMinCur = MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION + pInfo->FileNameLength;
338 offNext = pInfo->NextEntryOffset;
339 break;
340 }
341
342 default:
343 return birdSetErrnoToBadFileNo();
344 }
345
346 /*
347 * Advance.
348 */
349 if ( offNext >= cbMinCur
350 && offNext < pDir->cbBuf)
351 pDir->offBuf += offNext;
352 else
353 {
354 pDir->fHaveData = 0;
355 pDir->offBuf = pDir->cbBuf;
356 }
357 pDir->offPos++;
358 } while (fSkipEntry);
359
360
361 /*
362 * Successful return.
363 */
364 *ppResult = pEntry;
365 return 0;
366}
367
368
369/**
370 * Implements readdir().
371 */
372BirdDirEntry_T *birdDirRead(BirdDir_T *pDir)
373{
374 BirdDirEntry_T *pRet = NULL;
375 birdDirReadReentrant(pDir, &pDir->u.DirEntry, &pRet);
376 return pRet;
377}
378
379
380static int birdDirCopyNameToEntryW(WCHAR const *pwcName, ULONG cbName, BirdDirEntryW_T *pEntry)
381{
382 ULONG cwcName = cbName / sizeof(wchar_t);
383 if (cwcName < sizeof(pEntry->d_name))
384 {
385 memcpy(pEntry->d_name, pwcName, cbName);
386 pEntry->d_name[cwcName] = '\0';
387 pEntry->d_namlen = (unsigned __int16)cwcName;
388 pEntry->d_reclen = (unsigned __int16)((size_t)&pEntry->d_name[cwcName + 1] - (size_t)pEntry);
389 return 0;
390 }
391 return -1;
392}
393
394
395/**
396 * Implements readdir_r(), UTF-16 version.
397 *
398 * @remarks This is a copy of birdDirReadReentrant where only the name handling
399 * and entry type differs. Remember to keep them in sync!
400 */
401int birdDirReadReentrantW(BirdDir_T *pDir, BirdDirEntryW_T *pEntry, BirdDirEntryW_T **ppResult)
402{
403 int fSkipEntry;
404
405 *ppResult = NULL;
406
407 if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
408 return birdSetErrnoToBadFileNo();
409
410 do
411 {
412 ULONG offNext;
413 ULONG cbMinCur;
414
415 /*
416 * Read more?
417 */
418 if (!pDir->fHaveData)
419 {
420 if (birdDirReadMore(pDir) != 0)
421 return -1;
422 if (!pDir->fHaveData)
423 return 0;
424 }
425
426 /*
427 * Convert the NT data to the unixy output structure.
428 */
429 fSkipEntry = 0;
430 switch (pDir->iInfoClass)
431 {
432 case MyFileNamesInformation:
433 {
434 MY_FILE_NAMES_INFORMATION *pInfo = (MY_FILE_NAMES_INFORMATION *)&pDir->pabBuf[pDir->offBuf];
435 if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_NAMES_INFORMATION
436 || pInfo->FileNameLength >= pDir->cbBuf
437 || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_NAMES_INFORMATION > pDir->cbBuf)
438 {
439 fSkipEntry = 1;
440 pDir->fHaveData = 0;
441 continue;
442 }
443
444 memset(&pEntry->d_stat, 0, sizeof(pEntry->d_stat));
445 pEntry->d_stat.st_mode = S_IFMT;
446 pEntry->d_type = DT_UNKNOWN;
447 pEntry->d_reclen = 0;
448 pEntry->d_namlen = 0;
449 if (birdDirCopyNameToEntryW(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0)
450 fSkipEntry = 1;
451
452 cbMinCur = MIN_SIZEOF_MY_FILE_NAMES_INFORMATION + pInfo->FileNameLength;
453 offNext = pInfo->NextEntryOffset;
454 break;
455 }
456
457 case MyFileIdFullDirectoryInformation:
458 {
459 MY_FILE_ID_FULL_DIR_INFORMATION *pInfo = (MY_FILE_ID_FULL_DIR_INFORMATION *)&pDir->pabBuf[pDir->offBuf];
460 if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION
461 || pInfo->FileNameLength >= pDir->cbBuf
462 || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION > pDir->cbBuf)
463 {
464 fSkipEntry = 1;
465 pDir->fHaveData = 0;
466 continue;
467 }
468
469 pEntry->d_type = DT_UNKNOWN;
470 pEntry->d_reclen = 0;
471 pEntry->d_namlen = 0;
472 if (birdDirCopyNameToEntryW(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0)
473 fSkipEntry = 1;
474 birdStatFillFromFileIdFullDirInfo(&pEntry->d_stat, pInfo, NULL);
475 pEntry->d_stat.st_dev = pDir->uDev;
476 switch (pEntry->d_stat.st_mode & S_IFMT)
477 {
478 case S_IFREG: pEntry->d_type = DT_REG; break;
479 case S_IFDIR: pEntry->d_type = DT_DIR; break;
480 case S_IFLNK: pEntry->d_type = DT_LNK; break;
481 case S_IFIFO: pEntry->d_type = DT_FIFO; break;
482 case S_IFCHR: pEntry->d_type = DT_CHR; break;
483 default:
484#ifndef NDEBUG
485 __debugbreak();
486#endif
487 pEntry->d_type = DT_UNKNOWN;
488 break;
489 }
490
491 cbMinCur = MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION + pInfo->FileNameLength;
492 offNext = pInfo->NextEntryOffset;
493 break;
494 }
495
496 default:
497 return birdSetErrnoToBadFileNo();
498 }
499
500 /*
501 * Advance.
502 */
503 if ( offNext >= cbMinCur
504 && offNext < pDir->cbBuf)
505 pDir->offBuf += offNext;
506 else
507 {
508 pDir->fHaveData = 0;
509 pDir->offBuf = pDir->cbBuf;
510 }
511 pDir->offPos++;
512 } while (fSkipEntry);
513
514
515 /*
516 * Successful return.
517 */
518 *ppResult = pEntry;
519 return 0;
520}
521
522/**
523 * Implements readdir().
524 */
525BirdDirEntryW_T *birdDirReadW(BirdDir_T *pDir)
526{
527 BirdDirEntryW_T *pRet = NULL;
528 birdDirReadReentrantW(pDir, &pDir->u.DirEntryW, &pRet);
529 return pRet;
530}
531
532
533/**
534 * Implements telldir().
535 */
536long birdDirTell(BirdDir_T *pDir)
537{
538 if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
539 return birdSetErrnoToBadFileNo();
540 return pDir->offPos;
541}
542
543
544void birdDirSeek(BirdDir_T *pDir, long offDir);
545
546
547/**
548 * Implements closedir().
549 */
550int birdDirClose(BirdDir_T *pDir)
551{
552 if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
553 return birdSetErrnoToBadFileNo();
554
555 pDir->uMagic++;
556 if (pDir->fFlags & BIRDDIR_F_CLOSE_HANDLE)
557 birdCloseFile((HANDLE)pDir->pvHandle);
558 pDir->pvHandle = (void *)INVALID_HANDLE_VALUE;
559 birdMemFree(pDir->pabBuf);
560 pDir->pabBuf = NULL;
561 birdMemFree(pDir);
562
563 return 0;
564}
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