VirtualBox

source: kBuild/trunk/src/lib/nt/ntstat.c@ 2940

Last change on this file since 2940 was 2880, checked in by bird, 9 years ago

bugfix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.0 KB
Line 
1/* $Id: ntstat.c 2880 2016-09-05 20:36:26Z bird $ */
2/** @file
3 * MSC + NT stat, lstat and fstat.
4 */
5
6/*
7 * Copyright (c) 2005-2013 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
39#include "ntstuff.h"
40#include "nthlp.h"
41#include "ntstat.h"
42
43
44#undef stat
45
46static int birdIsExecutableExtension(const char *pszExt)
47{
48 return !strcmp(pszExt, "exe")
49 || !strcmp(pszExt, "cmd")
50 || !strcmp(pszExt, "bat")
51 || !strcmp(pszExt, "vbs")
52 || !strcmp(pszExt, "com")
53 ;
54}
55
56
57static int birdIsFileExecutable(const char *pszName)
58{
59 const char *pszExt = NULL;
60 char szExt[8];
61 size_t cchExt;
62 unsigned i;
63 char ch;
64
65 /* Look for a 3 char extension. */
66 ch = *pszName++;
67 if (!ch)
68 return 0;
69
70 while ((ch = *pszName++) != '\0')
71 if (ch == '.')
72 pszExt = pszName;
73
74 if (!pszExt)
75 return 0;
76 pszExt++;
77 cchExt = pszName - pszExt;
78 if (cchExt != 3)
79 return 0;
80
81 /* Copy the extension out and lower case it. */
82 for (i = 0; i < cchExt; i++, pszExt++)
83 {
84 ch = *pszExt;
85 if (ch >= 'A' && ch <= 'Z')
86 ch += 'a' - 'A';
87 szExt[i] = ch;
88 }
89 szExt[i] = '\0';
90
91 return birdIsExecutableExtension(szExt);
92}
93
94
95static int birdIsFileExecutableW(WCHAR const *pwcName, ULONG cwcName)
96{
97 char szExt[8];
98 unsigned cchExt;
99 unsigned i;
100 WCHAR const *pwc;
101
102 /* Look for a 3 char extension. */
103 if (cwcName > 2 && pwcName[cwcName - 2] == '.')
104 return 0;
105 else if (cwcName > 3 && pwcName[cwcName - 3] == '.')
106 return 0;
107 else if (cwcName > 4 && pwcName[cwcName - 4] == '.')
108 cchExt = 3;
109 else
110 return 0;
111
112 /* Copy the extension out and lower case it. */
113 pwc = &pwcName[cwcName - cchExt];
114 for (i = 0; i < cchExt; i++, pwc++)
115 {
116 WCHAR wc = *pwc;
117 if (wc >= 'A' && wc <= 'Z')
118 wc += 'a' - 'A';
119 else if (wc > 255)
120 wc = 255;
121 szExt[i] = (char)wc;
122 }
123 szExt[i] = '\0';
124
125 return birdIsExecutableExtension(szExt);
126}
127
128
129static unsigned short birdFileInfoToMode(HANDLE hFile, ULONG fAttribs, const char *pszName,
130 MY_FILE_NAME_INFORMATION *pNameInfo, __int16 *pfIsDirSymlink)
131{
132 unsigned short fMode;
133
134 /* File type. */
135 if ( (fAttribs & FILE_ATTRIBUTE_REPARSE_POINT)
136 && hFile != INVALID_HANDLE_VALUE)
137 {
138 MY_FILE_ATTRIBUTE_TAG_INFORMATION TagInfo;
139 MY_IO_STATUS_BLOCK Ios;
140 MY_NTSTATUS rcNt;
141 Ios.Information = 0;
142 Ios.u.Status = -1;
143 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &TagInfo, sizeof(TagInfo), MyFileAttributeTagInformation);
144 if ( !MY_NT_SUCCESS(rcNt)
145 || !MY_NT_SUCCESS(Ios.u.Status)
146 || TagInfo.ReparseTag != IO_REPARSE_TAG_SYMLINK)
147 fAttribs &= ~FILE_ATTRIBUTE_REPARSE_POINT;
148 }
149
150 if (fAttribs & FILE_ATTRIBUTE_REPARSE_POINT)
151 {
152 *pfIsDirSymlink = !!(fAttribs & FILE_ATTRIBUTE_DIRECTORY);
153 fMode = S_IFLNK;
154 }
155 else
156 {
157 *pfIsDirSymlink = 0;
158 if (fAttribs & FILE_ATTRIBUTE_DIRECTORY)
159 fMode = S_IFDIR;
160 else
161 fMode = S_IFREG;
162 }
163
164 /* Access mask. */
165 fMode |= S_IROTH | S_IRGRP | S_IRUSR;
166 if (!(fAttribs & FILE_ATTRIBUTE_READONLY))
167 fMode |= S_IWOTH | S_IWGRP | S_IWUSR;
168 if ( (fAttribs & FILE_ATTRIBUTE_DIRECTORY)
169 || (pszName
170 ? birdIsFileExecutable(pszName)
171 : birdIsFileExecutableW(pNameInfo->FileName, pNameInfo->FileNameLength)) )
172 fMode |= S_IXOTH | S_IXGRP | S_IXUSR;
173
174 return fMode;
175}
176
177
178/**
179 * Fills in a stat structure from an MY_FILE_ID_FULL_DIR_INFORMATION entry.
180 *
181 * @param pStat The stat structure.
182 * @param pBuf The MY_FILE_ID_FULL_DIR_INFORMATION entry.
183 * @param pszPath Optionally, the path for X bit checks.
184 * @remarks Caller sets st_dev.
185 */
186void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf, const char *pszPath)
187{
188 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
189 NULL, &pStat->st_dirsymlink);
190 pStat->st_padding0[0] = 0;
191 pStat->st_padding0[1] = 0;
192 pStat->st_size = pBuf->EndOfFile.QuadPart;
193 birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim);
194 birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim);
195 birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim);
196 birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim);
197 pStat->st_ino = pBuf->FileId.QuadPart;
198 pStat->st_nlink = 1;
199 pStat->st_rdev = 0;
200 pStat->st_uid = 0;
201 pStat->st_gid = 0;
202 pStat->st_padding1 = 0;
203 pStat->st_attribs = pBuf->FileAttributes;
204 pStat->st_blksize = 65536;
205 pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
206 / BIRD_STAT_BLOCK_SIZE;
207}
208
209
210/**
211 * Fills in a stat structure from an MY_FILE_ID_BOTH_DIR_INFORMATION entry.
212 *
213 * @param pStat The stat structure.
214 * @param pBuf The MY_FILE_ID_BOTH_DIR_INFORMATION entry.
215 * @param pszPath Optionally, the path for X bit checks.
216 * @remarks Caller sets st_dev.
217 */
218void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath)
219{
220 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
221 NULL, &pStat->st_dirsymlink);
222 pStat->st_padding0[0] = 0;
223 pStat->st_padding0[1] = 0;
224 pStat->st_size = pBuf->EndOfFile.QuadPart;
225 birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim);
226 birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim);
227 birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim);
228 birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim);
229 pStat->st_ino = pBuf->FileId.QuadPart;
230 pStat->st_nlink = 1;
231 pStat->st_rdev = 0;
232 pStat->st_uid = 0;
233 pStat->st_gid = 0;
234 pStat->st_padding1 = 0;
235 pStat->st_attribs = pBuf->FileAttributes;
236 pStat->st_blksize = 65536;
237 pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
238 / BIRD_STAT_BLOCK_SIZE;
239}
240
241
242/**
243 * Fills in a stat structure from an MY_FILE_BOTH_DIR_INFORMATION entry.
244 *
245 * @param pStat The stat structure.
246 * @param pBuf The MY_FILE_BOTH_DIR_INFORMATION entry.
247 * @param pszPath Optionally, the path for X bit checks.
248 * @remarks Caller sets st_dev.
249 */
250void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath)
251{
252 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
253 NULL, &pStat->st_dirsymlink);
254 pStat->st_padding0[0] = 0;
255 pStat->st_padding0[1] = 0;
256 pStat->st_size = pBuf->EndOfFile.QuadPart;
257 birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim);
258 birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim);
259 birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim);
260 birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim);
261 pStat->st_ino = 0;
262 pStat->st_nlink = 1;
263 pStat->st_rdev = 0;
264 pStat->st_uid = 0;
265 pStat->st_gid = 0;
266 pStat->st_padding1 = 0;
267 pStat->st_attribs = pBuf->FileAttributes;
268 pStat->st_blksize = 65536;
269 pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
270 / BIRD_STAT_BLOCK_SIZE;
271}
272
273
274int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
275{
276 int rc;
277 MY_NTSTATUS rcNt;
278#if 0
279 ULONG cbAll = sizeof(MY_FILE_ALL_INFORMATION) + 0x10000;
280 MY_FILE_ALL_INFORMATION *pAll = (MY_FILE_ALL_INFORMATION *)birdTmpAlloc(cbAll);
281 if (pAll)
282 {
283 MY_IO_STATUS_BLOCK Ios;
284 Ios.Information = 0;
285 Ios.u.Status = -1;
286 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pAll, cbAll, MyFileAllInformation);
287 if (MY_NT_SUCCESS(rcNt))
288 rcNt = Ios.u.Status;
289 if (MY_NT_SUCCESS(rcNt))
290 {
291 pStat->st_mode = birdFileInfoToMode(hFile, pAll->BasicInformation.FileAttributes, pszPath,
292 &pAll->NameInformation, &pStat->st_dirsymlink);
293 pStat->st_padding0[0] = 0;
294 pStat->st_padding0[1] = 0;
295 pStat->st_size = pAll->StandardInformation.EndOfFile.QuadPart;
296 birdNtTimeToTimeSpec(pAll->BasicInformation.CreationTime.QuadPart, &pStat->st_birthtim);
297 birdNtTimeToTimeSpec(pAll->BasicInformation.ChangeTime.QuadPart, &pStat->st_ctim);
298 birdNtTimeToTimeSpec(pAll->BasicInformation.LastWriteTime.QuadPart, &pStat->st_mtim);
299 birdNtTimeToTimeSpec(pAll->BasicInformation.LastAccessTime.QuadPart, &pStat->st_atim);
300 pStat->st_ino = pAll->InternalInformation.IndexNumber.QuadPart;
301 pStat->st_nlink = pAll->StandardInformation.NumberOfLinks;
302 pStat->st_rdev = 0;
303 pStat->st_uid = 0;
304 pStat->st_gid = 0;
305 pStat->st_padding1 = 0;
306 pStat->st_attribs = pAll->StandardInformation.FileAttributes;
307 pStat->st_blksize = 65536;
308 pStat->st_blocks = (pAll->StandardInformation.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
309 / BIRD_STAT_BLOCK_SIZE;
310
311 /* Get the serial number, reusing the buffer from above. */
312 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pAll, cbAll, MyFileFsVolumeInformation);
313 if (MY_NT_SUCCESS(rcNt))
314 rcNt = Ios.u.Status;
315 if (MY_NT_SUCCESS(rcNt))
316 {
317 MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pAll;
318 pStat->st_dev = pVolInfo->VolumeSerialNumber
319 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
320 rc = 0;
321 }
322 else
323 {
324 pStat->st_dev = 0;
325 rc = birdSetErrnoFromNt(rcNt);
326 }
327 }
328 else
329 rc = birdSetErrnoFromNt(rcNt);
330 }
331 else
332 rc = birdSetErrnoToNoMem();
333#else
334 ULONG cbNameInfo = 0;
335 MY_FILE_NAME_INFORMATION *pNameInfo = NULL;
336 MY_FILE_STANDARD_INFORMATION StdInfo;
337 MY_FILE_BASIC_INFORMATION BasicInfo;
338 MY_FILE_INTERNAL_INFORMATION InternalInfo;
339 MY_IO_STATUS_BLOCK Ios;
340
341 Ios.Information = 0;
342 Ios.u.Status = -1;
343 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &StdInfo, sizeof(StdInfo), MyFileStandardInformation);
344 if (MY_NT_SUCCESS(rcNt))
345 rcNt = Ios.u.Status;
346 if (MY_NT_SUCCESS(rcNt))
347 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation);
348 if (MY_NT_SUCCESS(rcNt))
349 rcNt = Ios.u.Status;
350 if (MY_NT_SUCCESS(rcNt))
351 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &InternalInfo, sizeof(InternalInfo), MyFileInternalInformation);
352 if (MY_NT_SUCCESS(rcNt))
353 rcNt = Ios.u.Status;
354 if (MY_NT_SUCCESS(rcNt) && !pszPath)
355 {
356 cbNameInfo = 0x10020;
357 pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
358 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileNameInformation);
359 if (MY_NT_SUCCESS(rcNt))
360 rcNt = Ios.u.Status;
361 }
362
363 if (MY_NT_SUCCESS(rcNt))
364 {
365 pStat->st_mode = birdFileInfoToMode(hFile, BasicInfo.FileAttributes, pszPath,
366 pNameInfo, &pStat->st_dirsymlink);
367 pStat->st_padding0[0] = 0;
368 pStat->st_padding0[1] = 0;
369 pStat->st_size = StdInfo.EndOfFile.QuadPart;
370 birdNtTimeToTimeSpec(BasicInfo.CreationTime.QuadPart, &pStat->st_birthtim);
371 birdNtTimeToTimeSpec(BasicInfo.ChangeTime.QuadPart, &pStat->st_ctim);
372 birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, &pStat->st_mtim);
373 birdNtTimeToTimeSpec(BasicInfo.LastAccessTime.QuadPart, &pStat->st_atim);
374 pStat->st_ino = InternalInfo.IndexNumber.QuadPart;
375 pStat->st_nlink = StdInfo.NumberOfLinks;
376 pStat->st_rdev = 0;
377 pStat->st_uid = 0;
378 pStat->st_gid = 0;
379 pStat->st_padding1 = 0;
380 pStat->st_attribs = BasicInfo.FileAttributes;
381 pStat->st_blksize = 65536;
382 pStat->st_blocks = (StdInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
383 / BIRD_STAT_BLOCK_SIZE;
384
385 /* Get the serial number, reusing the buffer from above. */
386 if (!cbNameInfo)
387 {
388 cbNameInfo = sizeof(MY_FILE_FS_VOLUME_INFORMATION) + 1024;
389 pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
390 }
391 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileFsVolumeInformation);
392 if (MY_NT_SUCCESS(rcNt))
393 rcNt = Ios.u.Status;
394 if (MY_NT_SUCCESS(rcNt))
395 {
396 MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pNameInfo;
397 pStat->st_dev = pVolInfo->VolumeSerialNumber
398 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
399 rc = 0;
400 }
401 else
402 {
403 pStat->st_dev = 0;
404 rc = birdSetErrnoFromNt(rcNt);
405 }
406 }
407 else
408 rc = birdSetErrnoFromNt(rcNt);
409
410#endif
411 return rc;
412}
413
414
415/**
416 * Generates a device number from the volume information.
417 *
418 * @returns Device number.
419 * @param pVolInfo Volume information.
420 */
421unsigned __int64 birdVolumeInfoToDeviceNumber(const MY_FILE_FS_VOLUME_INFORMATION *pVolInfo)
422{
423 return pVolInfo->VolumeSerialNumber
424 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
425}
426
427
428/**
429 * Quries the volume information and generates a device number from it.
430 *
431 * @returns NT status code.
432 * @param hFile The file/dir/whatever to query the volume info
433 * and device number for.
434 * @param pVolInfo User provided buffer for volume information.
435 * @param cbVolInfo The size of the buffer.
436 * @param puDevNo Where to return the device number. This is set
437 * to zero on failure.
438 */
439MY_NTSTATUS birdQueryVolumeDeviceNumber(HANDLE hFile, MY_FILE_FS_VOLUME_INFORMATION *pVolInfo, size_t cbVolInfo,
440 unsigned __int64 *puDevNo)
441{
442 MY_IO_STATUS_BLOCK Ios;
443 MY_NTSTATUS rcNt;
444
445 Ios.u.Status = -1;
446 Ios.Information = -1;
447
448 pVolInfo->VolumeSerialNumber = 0;
449 pVolInfo->VolumeCreationTime.QuadPart = 0;
450
451 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pVolInfo, (LONG)cbVolInfo, MyFileFsVolumeInformation);
452 if (MY_NT_SUCCESS(rcNt))
453 {
454 *puDevNo = birdVolumeInfoToDeviceNumber(pVolInfo);
455 return Ios.u.Status;
456 }
457 *puDevNo = 0;
458 return rcNt;
459}
460
461
462static int birdStatInternal(const char *pszPath, BirdStat_T *pStat, int fFollow)
463{
464 int rc;
465 HANDLE hFile = birdOpenFile(pszPath,
466 FILE_READ_ATTRIBUTES,
467 FILE_ATTRIBUTE_NORMAL,
468 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
469 FILE_OPEN,
470 FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT),
471 OBJ_CASE_INSENSITIVE);
472 if (hFile != INVALID_HANDLE_VALUE)
473 {
474 rc = birdStatHandle(hFile, pStat, pszPath);
475 birdCloseFile(hFile);
476
477#if 0
478 {
479 static char s_szPrev[256];
480 size_t cchPath = strlen(pszPath);
481 if (memcmp(s_szPrev, pszPath, cchPath >= 255 ? 255 : cchPath + 1) == 0)
482 fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno);
483 else
484 memcpy(s_szPrev, pszPath, cchPath + 1);
485 }
486#endif
487 //fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno);
488 }
489 else
490 {
491 //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError());
492
493 /*
494 * On things like pagefile.sys we may get sharing violation. We fall
495 * back on directory enumeration for dealing with that.
496 */
497 if ( errno == ETXTBSY
498 && strchr(pszPath, '*') == NULL /* Serious paranoia... */
499 && strchr(pszPath, '?') == NULL)
500 {
501 MY_UNICODE_STRING NameUniStr;
502 hFile = birdOpenParentDir(pszPath,
503 FILE_READ_DATA | SYNCHRONIZE,
504 FILE_ATTRIBUTE_NORMAL,
505 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
506 FILE_OPEN,
507 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
508 OBJ_CASE_INSENSITIVE,
509 &NameUniStr);
510 if (hFile != INVALID_HANDLE_VALUE)
511 {
512 MY_FILE_ID_FULL_DIR_INFORMATION *pBuf;
513 ULONG cbBuf = sizeof(*pBuf) + NameUniStr.MaximumLength + 1024;
514 MY_IO_STATUS_BLOCK Ios;
515 MY_NTSTATUS rcNt;
516
517 pBuf = (MY_FILE_ID_FULL_DIR_INFORMATION *)alloca(cbBuf);
518 Ios.u.Status = -1;
519 Ios.Information = -1;
520 rcNt = g_pfnNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &Ios, pBuf, cbBuf,
521 MyFileIdFullDirectoryInformation, FALSE, &NameUniStr, TRUE);
522 if (MY_NT_SUCCESS(rcNt))
523 rcNt = Ios.u.Status;
524 if (MY_NT_SUCCESS(rcNt))
525 {
526 /*
527 * Convert the data.
528 */
529 birdStatFillFromFileIdFullDirInfo(pStat, pBuf, pszPath);
530
531 /* Get the serial number, reusing the buffer from above. */
532 rcNt = birdQueryVolumeDeviceNumber(hFile, (MY_FILE_FS_VOLUME_INFORMATION *)pBuf, cbBuf, &pStat->st_dev);
533 if (MY_NT_SUCCESS(rcNt))
534 rc = 0;
535 else
536 rc = birdSetErrnoFromNt(rcNt);
537 }
538
539 birdFreeNtPath(&NameUniStr);
540 birdCloseFile(hFile);
541
542 if (MY_NT_SUCCESS(rcNt))
543 return 0;
544 birdSetErrnoFromNt(rcNt);
545 }
546 }
547 rc = -1;
548 }
549
550 return rc;
551}
552
553
554/**
555 * Implements UNIX fstat().
556 */
557int birdStatOnFd(int fd, BirdStat_T *pStat)
558{
559 int rc;
560 HANDLE hFile = (HANDLE)_get_osfhandle(fd);
561 if (hFile != INVALID_HANDLE_VALUE)
562 {
563 DWORD fFileType;
564
565 birdResolveImports();
566
567 SetLastError(NO_ERROR);
568 fFileType = GetFileType(hFile) & ~FILE_TYPE_REMOTE;
569 switch (fFileType)
570 {
571 case FILE_TYPE_DISK:
572 rc = birdStatHandle(hFile, pStat, NULL);
573 break;
574
575 case FILE_TYPE_CHAR:
576 case FILE_TYPE_PIPE:
577 if (fFileType == FILE_TYPE_PIPE)
578 pStat->st_mode = S_IFIFO | 0666;
579 else
580 pStat->st_mode = S_IFCHR | 0666;
581 pStat->st_padding0[0] = 0;
582 pStat->st_padding0[1] = 0;
583 pStat->st_size = 0;
584 pStat->st_atim.tv_sec = 0;
585 pStat->st_atim.tv_nsec = 0;
586 pStat->st_mtim.tv_sec = 0;
587 pStat->st_mtim.tv_nsec = 0;
588 pStat->st_ctim.tv_sec = 0;
589 pStat->st_ctim.tv_nsec = 0;
590 pStat->st_birthtim.tv_sec = 0;
591 pStat->st_birthtim.tv_nsec = 0;
592 pStat->st_ino = 0;
593 pStat->st_dev = 0;
594 pStat->st_rdev = 0;
595 pStat->st_uid = 0;
596 pStat->st_gid = 0;
597 pStat->st_padding1 = 0;
598 pStat->st_attribs = fFileType == FILE_TYPE_PIPE ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_DEVICE;
599 pStat->st_blksize = 512;
600 pStat->st_blocks = 0;
601 if (fFileType == FILE_TYPE_PIPE)
602 {
603 DWORD cbAvail;
604 if (PeekNamedPipe(hFile, NULL, 0, NULL, &cbAvail, NULL))
605 pStat->st_size = cbAvail;
606 }
607 rc = 0;
608 break;
609
610 case FILE_TYPE_UNKNOWN:
611 default:
612 if (GetLastError() == NO_ERROR)
613 rc = birdSetErrnoToBadFileNo();
614 else
615 rc = birdSetErrnoFromWin32(GetLastError());
616 break;
617 }
618 }
619 else
620 rc = -1;
621 return rc;
622}
623
624
625/**
626 * Special case that only gets the file size and nothing else.
627 */
628int birdStatOnFdJustSize(int fd, __int64 *pcbFile)
629{
630 int rc;
631 HANDLE hFile = (HANDLE)_get_osfhandle(fd);
632 if (hFile != INVALID_HANDLE_VALUE)
633 {
634 LARGE_INTEGER cbLocal;
635 if (GetFileSizeEx(hFile, &cbLocal))
636 {
637 *pcbFile = cbLocal.QuadPart;
638 rc = 0;
639 }
640 else
641 {
642 BirdStat_T Stat;
643 rc = birdStatOnFd(fd, &Stat);
644 if (rc == 0)
645 *pcbFile = Stat.st_size;
646 }
647 }
648 else
649 rc = -1;
650 return rc;
651}
652
653
654/**
655 * Implements UNIX stat().
656 */
657int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat)
658{
659 return birdStatInternal(pszPath, pStat, 1 /*fFollow*/);
660}
661
662
663/**
664 * Implements UNIX lstat().
665 */
666int birdStatOnLink(const char *pszPath, BirdStat_T *pStat)
667{
668 return birdStatInternal(pszPath, pStat, 0 /*fFollow*/);
669}
670
671
672/**
673 * Internal worker for birdStatModTimeOnly.
674 */
675static int birdStatOnlyInternal(const char *pszPath, int fFollowLink, MY_FILE_BASIC_INFORMATION *pBasicInfo)
676{
677 int rc;
678 HANDLE hFile = birdOpenFile(pszPath,
679 FILE_READ_ATTRIBUTES,
680 FILE_ATTRIBUTE_NORMAL,
681 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
682 FILE_OPEN,
683 FILE_OPEN_FOR_BACKUP_INTENT | (fFollowLink ? 0 : FILE_OPEN_REPARSE_POINT),
684 OBJ_CASE_INSENSITIVE);
685 if (hFile != INVALID_HANDLE_VALUE)
686 {
687 MY_NTSTATUS rcNt = 0;
688 MY_IO_STATUS_BLOCK Ios;
689 Ios.Information = 0;
690 Ios.u.Status = -1;
691
692 if (pBasicInfo)
693 {
694 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pBasicInfo, sizeof(*pBasicInfo), MyFileBasicInformation);
695 if (MY_NT_SUCCESS(rcNt))
696 rcNt = Ios.u.Status;
697 }
698 birdCloseFile(hFile);
699
700 if (MY_NT_SUCCESS(rcNt))
701 rc = 0;
702 else
703 {
704 birdSetErrnoFromNt(rcNt);
705 rc = -1;
706 }
707 }
708 else
709 {
710 //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError());
711
712 /* On things like pagefile.sys we may get sharing violation. */
713 if (GetLastError() == ERROR_SHARING_VIOLATION)
714 {
715 /** @todo Fall back on the parent directory enum if we run into a sharing
716 * violation. */
717 }
718 rc = -1;
719 }
720 return rc;
721}
722
723
724/**
725 * Special function for getting the modification time.
726 */
727int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink)
728{
729 MY_FILE_BASIC_INFORMATION BasicInfo;
730 int rc = birdStatOnlyInternal(pszPath, fFollowLink, &BasicInfo);
731 if (!rc)
732 birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, pTimeSpec);
733 return rc;
734}
735
736
737
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