VirtualBox

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

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

updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.1 KB
Line 
1/* $Id: ntstat.c 2858 2016-09-01 15:12:24Z 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
178static void birdNtTimeToTimeSpec(__int64 iNtTime, BirdTimeSpec_T *pTimeSpec)
179{
180 iNtTime -= BIRD_NT_EPOCH_OFFSET_UNIX_100NS;
181 pTimeSpec->tv_sec = iNtTime / 10000000;
182 pTimeSpec->tv_nsec = (iNtTime % 10000000) * 100;
183}
184
185
186/**
187 * Fills in a stat structure from an MY_FILE_ID_FULL_DIR_INFORMATION entry.
188 *
189 * @param pStat The stat structure.
190 * @param pBuf The MY_FILE_ID_FULL_DIR_INFORMATION entry.
191 * @param pszPath Optionally, the path for X bit checks.
192 * @remarks Caller sets st_dev.
193 */
194void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf, const char *pszPath)
195{
196 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
197 NULL, &pStat->st_dirsymlink);
198 pStat->st_padding0[0] = 0;
199 pStat->st_padding0[1] = 0;
200 pStat->st_size = pBuf->EndOfFile.QuadPart;
201 birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim);
202 birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim);
203 birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim);
204 birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim);
205 pStat->st_ino = pBuf->FileId.QuadPart;
206 pStat->st_nlink = 1;
207 pStat->st_rdev = 0;
208 pStat->st_uid = 0;
209 pStat->st_gid = 0;
210 pStat->st_padding1 = 0;
211 pStat->st_attribs = pBuf->FileAttributes;
212 pStat->st_blksize = 65536;
213 pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
214 / BIRD_STAT_BLOCK_SIZE;
215}
216
217
218/**
219 * Fills in a stat structure from an MY_FILE_ID_BOTH_DIR_INFORMATION entry.
220 *
221 * @param pStat The stat structure.
222 * @param pBuf The MY_FILE_ID_BOTH_DIR_INFORMATION entry.
223 * @param pszPath Optionally, the path for X bit checks.
224 * @remarks Caller sets st_dev.
225 */
226void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath)
227{
228 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
229 NULL, &pStat->st_dirsymlink);
230 pStat->st_padding0[0] = 0;
231 pStat->st_padding0[1] = 0;
232 pStat->st_size = pBuf->EndOfFile.QuadPart;
233 birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim);
234 birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim);
235 birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim);
236 birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim);
237 pStat->st_ino = pBuf->FileId.QuadPart;
238 pStat->st_nlink = 1;
239 pStat->st_rdev = 0;
240 pStat->st_uid = 0;
241 pStat->st_gid = 0;
242 pStat->st_padding1 = 0;
243 pStat->st_attribs = pBuf->FileAttributes;
244 pStat->st_blksize = 65536;
245 pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
246 / BIRD_STAT_BLOCK_SIZE;
247}
248
249
250/**
251 * Fills in a stat structure from an MY_FILE_BOTH_DIR_INFORMATION entry.
252 *
253 * @param pStat The stat structure.
254 * @param pBuf The MY_FILE_BOTH_DIR_INFORMATION entry.
255 * @param pszPath Optionally, the path for X bit checks.
256 * @remarks Caller sets st_dev.
257 */
258void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath)
259{
260 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
261 NULL, &pStat->st_dirsymlink);
262 pStat->st_padding0[0] = 0;
263 pStat->st_padding0[1] = 0;
264 pStat->st_size = pBuf->EndOfFile.QuadPart;
265 birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim);
266 birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim);
267 birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim);
268 birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim);
269 pStat->st_ino = 0;
270 pStat->st_nlink = 1;
271 pStat->st_rdev = 0;
272 pStat->st_uid = 0;
273 pStat->st_gid = 0;
274 pStat->st_padding1 = 0;
275 pStat->st_attribs = pBuf->FileAttributes;
276 pStat->st_blksize = 65536;
277 pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
278 / BIRD_STAT_BLOCK_SIZE;
279}
280
281
282int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
283{
284 int rc;
285 MY_NTSTATUS rcNt;
286#if 0
287 ULONG cbAll = sizeof(MY_FILE_ALL_INFORMATION) + 0x10000;
288 MY_FILE_ALL_INFORMATION *pAll = (MY_FILE_ALL_INFORMATION *)birdTmpAlloc(cbAll);
289 if (pAll)
290 {
291 MY_IO_STATUS_BLOCK Ios;
292 Ios.Information = 0;
293 Ios.u.Status = -1;
294 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pAll, cbAll, MyFileAllInformation);
295 if (MY_NT_SUCCESS(rcNt))
296 rcNt = Ios.u.Status;
297 if (MY_NT_SUCCESS(rcNt))
298 {
299 pStat->st_mode = birdFileInfoToMode(hFile, pAll->BasicInformation.FileAttributes, pszPath,
300 &pAll->NameInformation, &pStat->st_dirsymlink);
301 pStat->st_padding0[0] = 0;
302 pStat->st_padding0[1] = 0;
303 pStat->st_size = pAll->StandardInformation.EndOfFile.QuadPart;
304 birdNtTimeToTimeSpec(pAll->BasicInformation.CreationTime.QuadPart, &pStat->st_birthtim);
305 birdNtTimeToTimeSpec(pAll->BasicInformation.ChangeTime.QuadPart, &pStat->st_ctim);
306 birdNtTimeToTimeSpec(pAll->BasicInformation.LastWriteTime.QuadPart, &pStat->st_mtim);
307 birdNtTimeToTimeSpec(pAll->BasicInformation.LastAccessTime.QuadPart, &pStat->st_atim);
308 pStat->st_ino = pAll->InternalInformation.IndexNumber.QuadPart;
309 pStat->st_nlink = pAll->StandardInformation.NumberOfLinks;
310 pStat->st_rdev = 0;
311 pStat->st_uid = 0;
312 pStat->st_gid = 0;
313 pStat->st_padding1 = 0;
314 pStat->st_attribs = pAll->StandardInformation.FileAttributes;
315 pStat->st_blksize = 65536;
316 pStat->st_blocks = (pAll->StandardInformation.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
317 / BIRD_STAT_BLOCK_SIZE;
318
319 /* Get the serial number, reusing the buffer from above. */
320 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pAll, cbAll, MyFileFsVolumeInformation);
321 if (MY_NT_SUCCESS(rcNt))
322 rcNt = Ios.u.Status;
323 if (MY_NT_SUCCESS(rcNt))
324 {
325 MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pAll;
326 pStat->st_dev = pVolInfo->VolumeSerialNumber
327 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
328 rc = 0;
329 }
330 else
331 {
332 pStat->st_dev = 0;
333 rc = birdSetErrnoFromNt(rcNt);
334 }
335 }
336 else
337 rc = birdSetErrnoFromNt(rcNt);
338 }
339 else
340 rc = birdSetErrnoToNoMem();
341#else
342 ULONG cbNameInfo = 0;
343 MY_FILE_NAME_INFORMATION *pNameInfo = NULL;
344 MY_FILE_STANDARD_INFORMATION StdInfo;
345 MY_FILE_BASIC_INFORMATION BasicInfo;
346 MY_FILE_INTERNAL_INFORMATION InternalInfo;
347 MY_IO_STATUS_BLOCK Ios;
348
349 Ios.Information = 0;
350 Ios.u.Status = -1;
351 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &StdInfo, sizeof(StdInfo), MyFileStandardInformation);
352 if (MY_NT_SUCCESS(rcNt))
353 rcNt = Ios.u.Status;
354 if (MY_NT_SUCCESS(rcNt))
355 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation);
356 if (MY_NT_SUCCESS(rcNt))
357 rcNt = Ios.u.Status;
358 if (MY_NT_SUCCESS(rcNt))
359 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &InternalInfo, sizeof(InternalInfo), MyFileInternalInformation);
360 if (MY_NT_SUCCESS(rcNt))
361 rcNt = Ios.u.Status;
362 if (MY_NT_SUCCESS(rcNt) && !pszPath)
363 {
364 cbNameInfo = 0x10020;
365 pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
366 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileNameInformation);
367 if (MY_NT_SUCCESS(rcNt))
368 rcNt = Ios.u.Status;
369 }
370
371 if (MY_NT_SUCCESS(rcNt))
372 {
373 pStat->st_mode = birdFileInfoToMode(hFile, BasicInfo.FileAttributes, pszPath,
374 pNameInfo, &pStat->st_dirsymlink);
375 pStat->st_padding0[0] = 0;
376 pStat->st_padding0[1] = 0;
377 pStat->st_size = StdInfo.EndOfFile.QuadPart;
378 birdNtTimeToTimeSpec(BasicInfo.CreationTime.QuadPart, &pStat->st_birthtim);
379 birdNtTimeToTimeSpec(BasicInfo.ChangeTime.QuadPart, &pStat->st_ctim);
380 birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, &pStat->st_mtim);
381 birdNtTimeToTimeSpec(BasicInfo.LastAccessTime.QuadPart, &pStat->st_atim);
382 pStat->st_ino = InternalInfo.IndexNumber.QuadPart;
383 pStat->st_nlink = StdInfo.NumberOfLinks;
384 pStat->st_rdev = 0;
385 pStat->st_uid = 0;
386 pStat->st_gid = 0;
387 pStat->st_padding1 = 0;
388 pStat->st_attribs = BasicInfo.FileAttributes;
389 pStat->st_blksize = 65536;
390 pStat->st_blocks = (StdInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
391 / BIRD_STAT_BLOCK_SIZE;
392
393 /* Get the serial number, reusing the buffer from above. */
394 if (!cbNameInfo)
395 {
396 cbNameInfo = sizeof(MY_FILE_FS_VOLUME_INFORMATION) + 1024;
397 pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
398 }
399 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileFsVolumeInformation);
400 if (MY_NT_SUCCESS(rcNt))
401 rcNt = Ios.u.Status;
402 if (MY_NT_SUCCESS(rcNt))
403 {
404 MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pNameInfo;
405 pStat->st_dev = pVolInfo->VolumeSerialNumber
406 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
407 rc = 0;
408 }
409 else
410 {
411 pStat->st_dev = 0;
412 rc = birdSetErrnoFromNt(rcNt);
413 }
414 }
415 else
416 rc = birdSetErrnoFromNt(rcNt);
417
418#endif
419 return rc;
420}
421
422
423/**
424 * Generates a device number from the volume information.
425 *
426 * @returns Device number.
427 * @param pVolInfo Volume information.
428 */
429unsigned __int64 birdVolumeInfoToDeviceNumber(const MY_FILE_FS_VOLUME_INFORMATION *pVolInfo)
430{
431 return pVolInfo->VolumeSerialNumber
432 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
433}
434
435
436/**
437 * Quries the volume information and generates a device number from it.
438 *
439 * @returns NT status code.
440 * @param hFile The file/dir/whatever to query the volume info
441 * and device number for.
442 * @param pVolInfo User provided buffer for volume information.
443 * @param cbVolInfo The size of the buffer.
444 * @param puDevNo Where to return the device number. This is set
445 * to zero on failure.
446 */
447MY_NTSTATUS birdQueryVolumeDeviceNumber(HANDLE hFile, MY_FILE_FS_VOLUME_INFORMATION *pVolInfo, size_t cbVolInfo,
448 unsigned __int64 *puDevNo)
449{
450 MY_IO_STATUS_BLOCK Ios;
451 MY_NTSTATUS rcNt;
452
453 Ios.u.Status = -1;
454 Ios.Information = -1;
455
456 pVolInfo->VolumeSerialNumber = 0;
457 pVolInfo->VolumeCreationTime.QuadPart = 0;
458
459 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pVolInfo, (LONG)cbVolInfo, MyFileFsVolumeInformation);
460 if (MY_NT_SUCCESS(rcNt))
461 {
462 *puDevNo = birdVolumeInfoToDeviceNumber(pVolInfo);
463 return Ios.u.Status;
464 }
465 *puDevNo = 0;
466 return rcNt;
467}
468
469
470static int birdStatInternal(const char *pszPath, BirdStat_T *pStat, int fFollow)
471{
472 int rc;
473 HANDLE hFile = birdOpenFile(pszPath,
474 FILE_READ_ATTRIBUTES,
475 FILE_ATTRIBUTE_NORMAL,
476 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
477 FILE_OPEN,
478 FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT),
479 OBJ_CASE_INSENSITIVE);
480 if (hFile != INVALID_HANDLE_VALUE)
481 {
482 rc = birdStatHandle(hFile, pStat, pszPath);
483 birdCloseFile(hFile);
484
485#if 0
486 {
487 static char s_szPrev[256];
488 size_t cchPath = strlen(pszPath);
489 if (memcmp(s_szPrev, pszPath, cchPath >= 255 ? 255 : cchPath + 1) == 0)
490 fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno);
491 else
492 memcpy(s_szPrev, pszPath, cchPath + 1);
493 }
494#endif
495 //fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno);
496 }
497 else
498 {
499 //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError());
500
501 /*
502 * On things like pagefile.sys we may get sharing violation. We fall
503 * back on directory enumeration for dealing with that.
504 */
505 if ( errno == ETXTBSY
506 && strchr(pszPath, '*') == NULL /* Serious paranoia... */
507 && strchr(pszPath, '?') == NULL)
508 {
509 MY_UNICODE_STRING NameUniStr;
510 hFile = birdOpenParentDir(pszPath,
511 FILE_READ_DATA | SYNCHRONIZE,
512 FILE_ATTRIBUTE_NORMAL,
513 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
514 FILE_OPEN,
515 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
516 OBJ_CASE_INSENSITIVE,
517 &NameUniStr);
518 if (hFile != INVALID_HANDLE_VALUE)
519 {
520 MY_FILE_ID_FULL_DIR_INFORMATION *pBuf;
521 ULONG cbBuf = sizeof(*pBuf) + NameUniStr.MaximumLength + 1024;
522 MY_IO_STATUS_BLOCK Ios;
523 MY_NTSTATUS rcNt;
524
525 pBuf = (MY_FILE_ID_FULL_DIR_INFORMATION *)alloca(cbBuf);
526 Ios.u.Status = -1;
527 Ios.Information = -1;
528 rcNt = g_pfnNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &Ios, pBuf, cbBuf,
529 MyFileIdFullDirectoryInformation, FALSE, &NameUniStr, TRUE);
530 if (MY_NT_SUCCESS(rcNt))
531 rcNt = Ios.u.Status;
532 if (MY_NT_SUCCESS(rcNt))
533 {
534 /*
535 * Convert the data.
536 */
537 birdStatFillFromFileIdFullDirInfo(pStat, pBuf, pszPath);
538
539 /* Get the serial number, reusing the buffer from above. */
540 rcNt = birdQueryVolumeDeviceNumber(hFile, (MY_FILE_FS_VOLUME_INFORMATION *)pBuf, cbBuf, &pStat->st_dev);
541 if (MY_NT_SUCCESS(rcNt))
542 rc = 0;
543 else
544 rc = birdSetErrnoFromNt(rcNt);
545 }
546
547 birdFreeNtPath(&NameUniStr);
548 birdCloseFile(hFile);
549
550 if (MY_NT_SUCCESS(rcNt))
551 return 0;
552 birdSetErrnoFromNt(rcNt);
553 }
554 }
555 rc = -1;
556 }
557
558 return rc;
559}
560
561
562/**
563 * Implements UNIX fstat().
564 */
565int birdStatOnFd(int fd, BirdStat_T *pStat)
566{
567 int rc;
568 HANDLE hFile = (HANDLE)_get_osfhandle(fd);
569 if (hFile != INVALID_HANDLE_VALUE)
570 {
571 DWORD fFileType;
572
573 birdResolveImports();
574
575 SetLastError(NO_ERROR);
576 fFileType = GetFileType(hFile) & ~FILE_TYPE_REMOTE;
577 switch (fFileType)
578 {
579 case FILE_TYPE_DISK:
580 rc = birdStatHandle(hFile, pStat, NULL);
581 break;
582
583 case FILE_TYPE_CHAR:
584 case FILE_TYPE_PIPE:
585 if (fFileType == FILE_TYPE_PIPE)
586 pStat->st_mode = S_IFIFO | 0666;
587 else
588 pStat->st_mode = S_IFCHR | 0666;
589 pStat->st_padding0[0] = 0;
590 pStat->st_padding0[1] = 0;
591 pStat->st_size = 0;
592 pStat->st_atim.tv_sec = 0;
593 pStat->st_atim.tv_nsec = 0;
594 pStat->st_mtim.tv_sec = 0;
595 pStat->st_mtim.tv_nsec = 0;
596 pStat->st_ctim.tv_sec = 0;
597 pStat->st_ctim.tv_nsec = 0;
598 pStat->st_birthtim.tv_sec = 0;
599 pStat->st_birthtim.tv_nsec = 0;
600 pStat->st_ino = 0;
601 pStat->st_dev = 0;
602 pStat->st_rdev = 0;
603 pStat->st_uid = 0;
604 pStat->st_gid = 0;
605 pStat->st_padding1 = 0;
606 pStat->st_attribs = fFileType == FILE_TYPE_PIPE ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_DEVICE;
607 pStat->st_blksize = 512;
608 pStat->st_blocks = 0;
609 if (fFileType == FILE_TYPE_PIPE)
610 {
611 DWORD cbAvail;
612 if (PeekNamedPipe(hFile, NULL, 0, NULL, &cbAvail, NULL))
613 pStat->st_size = cbAvail;
614 }
615 rc = 0;
616 break;
617
618 case FILE_TYPE_UNKNOWN:
619 default:
620 if (GetLastError() == NO_ERROR)
621 rc = birdSetErrnoToBadFileNo();
622 else
623 rc = birdSetErrnoFromWin32(GetLastError());
624 break;
625 }
626 }
627 else
628 rc = -1;
629 return rc;
630}
631
632
633/**
634 * Special case that only gets the file size and nothing else.
635 */
636int birdStatOnFdJustSize(int fd, __int64 *pcbFile)
637{
638 int rc;
639 HANDLE hFile = (HANDLE)_get_osfhandle(fd);
640 if (hFile != INVALID_HANDLE_VALUE)
641 {
642 LARGE_INTEGER cbLocal;
643 if (GetFileSizeEx(hFile, &cbLocal))
644 {
645 *pcbFile = cbLocal.QuadPart;
646 rc = 0;
647 }
648 else
649 {
650 BirdStat_T Stat;
651 rc = birdStatOnFd(fd, &Stat);
652 if (rc == 0)
653 *pcbFile = Stat.st_size;
654 }
655 }
656 else
657 rc = -1;
658 return rc;
659}
660
661
662/**
663 * Implements UNIX stat().
664 */
665int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat)
666{
667 return birdStatInternal(pszPath, pStat, 1 /*fFollow*/);
668}
669
670
671/**
672 * Implements UNIX lstat().
673 */
674int birdStatOnLink(const char *pszPath, BirdStat_T *pStat)
675{
676 return birdStatInternal(pszPath, pStat, 0 /*fFollow*/);
677}
678
679
680/**
681 * Internal worker for birdStatModTimeOnly.
682 */
683static int birdStatOnlyInternal(const char *pszPath, int fFollowLink, MY_FILE_BASIC_INFORMATION *pBasicInfo)
684{
685 int rc;
686 HANDLE hFile = birdOpenFile(pszPath,
687 FILE_READ_ATTRIBUTES,
688 FILE_ATTRIBUTE_NORMAL,
689 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
690 FILE_OPEN,
691 FILE_OPEN_FOR_BACKUP_INTENT | (fFollowLink ? 0 : FILE_OPEN_REPARSE_POINT),
692 OBJ_CASE_INSENSITIVE);
693 if (hFile != INVALID_HANDLE_VALUE)
694 {
695 MY_NTSTATUS rcNt = 0;
696 MY_IO_STATUS_BLOCK Ios;
697 Ios.Information = 0;
698 Ios.u.Status = -1;
699
700 if (pBasicInfo)
701 {
702 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pBasicInfo, sizeof(*pBasicInfo), MyFileBasicInformation);
703 if (MY_NT_SUCCESS(rcNt))
704 rcNt = Ios.u.Status;
705 }
706 birdCloseFile(hFile);
707
708 if (!MY_NT_SUCCESS(rcNt))
709 birdSetErrnoFromNt(rcNt);
710 }
711 else
712 {
713 //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError());
714
715 /* On things like pagefile.sys we may get sharing violation. */
716 if (GetLastError() == ERROR_SHARING_VIOLATION)
717 {
718 /** @todo Fall back on the parent directory enum if we run into a sharing
719 * violation. */
720 }
721 rc = -1;
722 }
723 return rc;
724}
725
726
727/**
728 * Special function for getting the modification time.
729 */
730int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink)
731{
732 MY_FILE_BASIC_INFORMATION BasicInfo;
733 int rc = birdStatOnlyInternal(pszPath, fFollowLink, &BasicInfo);
734 if (!rc)
735 birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, pTimeSpec);
736 return rc;
737}
738
739
740
Note: See TracBrowser for help on using the repository browser.

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