VirtualBox

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

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

lib/nt: Got fts-nt halfways working, quite a few NT interface changes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.0 KB
Line 
1/* $Id: ntdir.c 2985 2016-11-01 18:26:35Z 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 */
245int birdDirReadReentrant(BirdDir_T *pDir, BirdDirEntry_T *pEntry, BirdDirEntry_T **ppResult)
246{
247 int fSkipEntry;
248
249 *ppResult = NULL;
250
251 if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
252 return birdSetErrnoToBadFileNo();
253
254 do
255 {
256 ULONG offNext;
257 ULONG cbMinCur;
258
259 /*
260 * Read more?
261 */
262 if (!pDir->fHaveData)
263 {
264 if (birdDirReadMore(pDir) != 0)
265 return -1;
266 if (!pDir->fHaveData)
267 return 0;
268 }
269
270 /*
271 * Convert the NT data to the unixy output structure.
272 */
273 fSkipEntry = 0;
274 switch (pDir->iInfoClass)
275 {
276 case MyFileNamesInformation:
277 {
278 MY_FILE_NAMES_INFORMATION *pInfo = (MY_FILE_NAMES_INFORMATION *)&pDir->pabBuf[pDir->offBuf];
279 if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_NAMES_INFORMATION
280 || pInfo->FileNameLength >= pDir->cbBuf
281 || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_NAMES_INFORMATION > pDir->cbBuf)
282 {
283 fSkipEntry = 1;
284 pDir->fHaveData = 0;
285 continue;
286 }
287
288 memset(&pEntry->d_stat, 0, sizeof(pEntry->d_stat));
289 pEntry->d_stat.st_mode = S_IFMT;
290 pEntry->d_type = DT_UNKNOWN;
291 pEntry->d_reclen = 0;
292 pEntry->d_namlen = 0;
293 if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0)
294 fSkipEntry = 1;
295
296 cbMinCur = MIN_SIZEOF_MY_FILE_NAMES_INFORMATION + pInfo->FileNameLength;
297 offNext = pInfo->NextEntryOffset;
298 break;
299 }
300
301 case MyFileIdFullDirectoryInformation:
302 {
303 MY_FILE_ID_FULL_DIR_INFORMATION *pInfo = (MY_FILE_ID_FULL_DIR_INFORMATION *)&pDir->pabBuf[pDir->offBuf];
304 if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION
305 || pInfo->FileNameLength >= pDir->cbBuf
306 || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION > pDir->cbBuf)
307 {
308 fSkipEntry = 1;
309 pDir->fHaveData = 0;
310 continue;
311 }
312
313 pEntry->d_type = DT_UNKNOWN;
314 pEntry->d_reclen = 0;
315 pEntry->d_namlen = 0;
316 if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0)
317 fSkipEntry = 1;
318 birdStatFillFromFileIdFullDirInfo(&pEntry->d_stat, pInfo, pEntry->d_name);
319 pEntry->d_stat.st_dev = pDir->uDev;
320 switch (pEntry->d_stat.st_mode & S_IFMT)
321 {
322 case S_IFREG: pEntry->d_type = DT_REG; break;
323 case S_IFDIR: pEntry->d_type = DT_DIR; break;
324 case S_IFLNK: pEntry->d_type = DT_LNK; break;
325 case S_IFIFO: pEntry->d_type = DT_FIFO; break;
326 case S_IFCHR: pEntry->d_type = DT_CHR; break;
327 default:
328#ifndef NDEBUG
329 __debugbreak();
330#endif
331 pEntry->d_type = DT_UNKNOWN;
332 break;
333 }
334
335 cbMinCur = MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION + pInfo->FileNameLength;
336 offNext = pInfo->NextEntryOffset;
337 break;
338 }
339
340 default:
341 return birdSetErrnoToBadFileNo();
342 }
343
344 /*
345 * Advance.
346 */
347 if ( offNext >= cbMinCur
348 && offNext < pDir->cbBuf)
349 pDir->offBuf += offNext;
350 else
351 {
352 pDir->fHaveData = 0;
353 pDir->offBuf = pDir->cbBuf;
354 }
355 pDir->offPos++;
356 } while (fSkipEntry);
357
358
359 /*
360 * Successful return.
361 */
362 *ppResult = pEntry;
363 return 0;
364}
365
366
367/**
368 * Implements readdir().
369 */
370BirdDirEntry_T *birdDirRead(BirdDir_T *pDir)
371{
372 BirdDirEntry_T *pRet = NULL;
373 birdDirReadReentrant(pDir, &pDir->DirEntry, &pRet);
374 return pRet;
375}
376
377
378/**
379 * Implements telldir().
380 */
381long birdDirTell(BirdDir_T *pDir)
382{
383 if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
384 return birdSetErrnoToBadFileNo();
385 return pDir->offPos;
386}
387
388
389void birdDirSeek(BirdDir_T *pDir, long offDir);
390
391
392/**
393 * Implements closedir().
394 */
395int birdDirClose(BirdDir_T *pDir)
396{
397 if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
398 return birdSetErrnoToBadFileNo();
399
400 pDir->uMagic++;
401 if (pDir->fFlags & BIRDDIR_F_CLOSE_HANDLE)
402 birdCloseFile((HANDLE)pDir->pvHandle);
403 pDir->pvHandle = (void *)INVALID_HANDLE_VALUE;
404 birdMemFree(pDir->pabBuf);
405 pDir->pabBuf = NULL;
406 birdMemFree(pDir);
407
408 return 0;
409}
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