VirtualBox

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

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

kmk: optimizations.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.2 KB
Line 
1/* $Id: ntstat.c 2850 2016-08-30 16:06:31Z 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 */
193void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf, const char *pszPath)
194{
195 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
196 NULL, &pStat->st_dirsymlink);
197 pStat->st_padding0[0] = 0;
198 pStat->st_padding0[1] = 0;
199 pStat->st_size = pBuf->EndOfFile.QuadPart;
200 birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim);
201 birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim);
202 birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim);
203 birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim);
204 pStat->st_ino = pBuf->FileId.QuadPart;
205 pStat->st_nlink = 1;
206 pStat->st_rdev = 0;
207 pStat->st_uid = 0;
208 pStat->st_gid = 0;
209 pStat->st_padding1[0] = 0;
210 pStat->st_padding1[1] = 0;
211 pStat->st_padding1[2] = 0;
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
218int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
219{
220 int rc;
221 MY_NTSTATUS rcNt;
222#if 0
223 ULONG cbAll = sizeof(MY_FILE_ALL_INFORMATION) + 0x10000;
224 MY_FILE_ALL_INFORMATION *pAll = (MY_FILE_ALL_INFORMATION *)birdTmpAlloc(cbAll);
225 if (pAll)
226 {
227 MY_IO_STATUS_BLOCK Ios;
228 Ios.Information = 0;
229 Ios.u.Status = -1;
230 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pAll, cbAll, MyFileAllInformation);
231 if (MY_NT_SUCCESS(rcNt))
232 rcNt = Ios.u.Status;
233 if (MY_NT_SUCCESS(rcNt))
234 {
235 pStat->st_mode = birdFileInfoToMode(hFile, pAll->BasicInformation.FileAttributes, pszPath,
236 &pAll->NameInformation, &pStat->st_dirsymlink);
237 pStat->st_padding0[0] = 0;
238 pStat->st_padding0[1] = 0;
239 pStat->st_size = pAll->StandardInformation.EndOfFile.QuadPart;
240 birdNtTimeToTimeSpec(pAll->BasicInformation.CreationTime.QuadPart, &pStat->st_birthtim);
241 birdNtTimeToTimeSpec(pAll->BasicInformation.ChangeTime.QuadPart, &pStat->st_ctim);
242 birdNtTimeToTimeSpec(pAll->BasicInformation.LastWriteTime.QuadPart, &pStat->st_mtim);
243 birdNtTimeToTimeSpec(pAll->BasicInformation.LastAccessTime.QuadPart, &pStat->st_atim);
244 pStat->st_ino = pAll->InternalInformation.IndexNumber.QuadPart;
245 pStat->st_nlink = pAll->StandardInformation.NumberOfLinks;
246 pStat->st_rdev = 0;
247 pStat->st_uid = 0;
248 pStat->st_gid = 0;
249 pStat->st_padding1[0] = 0;
250 pStat->st_padding1[1] = 0;
251 pStat->st_padding1[2] = 0;
252 pStat->st_blksize = 65536;
253 pStat->st_blocks = (pAll->StandardInformation.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
254 / BIRD_STAT_BLOCK_SIZE;
255
256 /* Get the serial number, reusing the buffer from above. */
257 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pAll, cbAll, MyFileFsVolumeInformation);
258 if (MY_NT_SUCCESS(rcNt))
259 rcNt = Ios.u.Status;
260 if (MY_NT_SUCCESS(rcNt))
261 {
262 MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pAll;
263 pStat->st_dev = pVolInfo->VolumeSerialNumber
264 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
265 rc = 0;
266 }
267 else
268 {
269 pStat->st_dev = 0;
270 rc = birdSetErrnoFromNt(rcNt);
271 }
272 }
273 else
274 rc = birdSetErrnoFromNt(rcNt);
275 }
276 else
277 rc = birdSetErrnoToNoMem();
278#else
279 ULONG cbNameInfo = 0;
280 MY_FILE_NAME_INFORMATION *pNameInfo = NULL;
281 MY_FILE_STANDARD_INFORMATION StdInfo;
282 MY_FILE_BASIC_INFORMATION BasicInfo;
283 MY_FILE_INTERNAL_INFORMATION InternalInfo;
284 MY_IO_STATUS_BLOCK Ios;
285
286 Ios.Information = 0;
287 Ios.u.Status = -1;
288 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &StdInfo, sizeof(StdInfo), MyFileStandardInformation);
289 if (MY_NT_SUCCESS(rcNt))
290 rcNt = Ios.u.Status;
291 if (MY_NT_SUCCESS(rcNt))
292 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation);
293 if (MY_NT_SUCCESS(rcNt))
294 rcNt = Ios.u.Status;
295 if (MY_NT_SUCCESS(rcNt))
296 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &InternalInfo, sizeof(InternalInfo), MyFileInternalInformation);
297 if (MY_NT_SUCCESS(rcNt))
298 rcNt = Ios.u.Status;
299 if (MY_NT_SUCCESS(rcNt) && !pszPath)
300 {
301 cbNameInfo = 0x10020;
302 pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
303 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileNameInformation);
304 if (MY_NT_SUCCESS(rcNt))
305 rcNt = Ios.u.Status;
306 }
307
308 if (MY_NT_SUCCESS(rcNt))
309 {
310 pStat->st_mode = birdFileInfoToMode(hFile, BasicInfo.FileAttributes, pszPath,
311 pNameInfo, &pStat->st_dirsymlink);
312 pStat->st_padding0[0] = 0;
313 pStat->st_padding0[1] = 0;
314 pStat->st_size = StdInfo.EndOfFile.QuadPart;
315 birdNtTimeToTimeSpec(BasicInfo.CreationTime.QuadPart, &pStat->st_birthtim);
316 birdNtTimeToTimeSpec(BasicInfo.ChangeTime.QuadPart, &pStat->st_ctim);
317 birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, &pStat->st_mtim);
318 birdNtTimeToTimeSpec(BasicInfo.LastAccessTime.QuadPart, &pStat->st_atim);
319 pStat->st_ino = InternalInfo.IndexNumber.QuadPart;
320 pStat->st_nlink = StdInfo.NumberOfLinks;
321 pStat->st_rdev = 0;
322 pStat->st_uid = 0;
323 pStat->st_gid = 0;
324 pStat->st_padding1[0] = 0;
325 pStat->st_padding1[1] = 0;
326 pStat->st_padding1[2] = 0;
327 pStat->st_blksize = 65536;
328 pStat->st_blocks = (StdInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
329 / BIRD_STAT_BLOCK_SIZE;
330
331 /* Get the serial number, reusing the buffer from above. */
332 if (!cbNameInfo)
333 {
334 cbNameInfo = sizeof(MY_FILE_FS_VOLUME_INFORMATION) + 1024;
335 pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
336 }
337 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileFsVolumeInformation);
338 if (MY_NT_SUCCESS(rcNt))
339 rcNt = Ios.u.Status;
340 if (MY_NT_SUCCESS(rcNt))
341 {
342 MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pNameInfo;
343 pStat->st_dev = pVolInfo->VolumeSerialNumber
344 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
345 rc = 0;
346 }
347 else
348 {
349 pStat->st_dev = 0;
350 rc = birdSetErrnoFromNt(rcNt);
351 }
352 }
353 else
354 rc = birdSetErrnoFromNt(rcNt);
355
356#endif
357 return rc;
358}
359
360
361static int birdStatInternal(const char *pszPath, BirdStat_T *pStat, int fFollow)
362{
363 int rc;
364 HANDLE hFile = birdOpenFile(pszPath,
365 FILE_READ_ATTRIBUTES,
366 FILE_ATTRIBUTE_NORMAL,
367 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
368 FILE_OPEN,
369 FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT),
370 OBJ_CASE_INSENSITIVE);
371 if (hFile != INVALID_HANDLE_VALUE)
372 {
373 rc = birdStatHandle(hFile, pStat, pszPath);
374 birdCloseFile(hFile);
375
376#if 0
377 {
378 static char s_szPrev[256];
379 size_t cchPath = strlen(pszPath);
380 if (memcmp(s_szPrev, pszPath, cchPath >= 255 ? 255 : cchPath + 1) == 0)
381 fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno);
382 else
383 memcpy(s_szPrev, pszPath, cchPath + 1);
384 }
385#endif
386 //fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno);
387 }
388 else
389 {
390 //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError());
391
392 /*
393 * On things like pagefile.sys we may get sharing violation. We fall
394 * back on directory enumeration for dealing with that.
395 */
396 if ( errno == ETXTBSY
397 && strchr(pszPath, '*') == NULL /* Serious paranoia... */
398 && strchr(pszPath, '?') == NULL)
399 {
400 MY_UNICODE_STRING NameUniStr;
401 hFile = birdOpenParentDir(pszPath,
402 FILE_READ_DATA | SYNCHRONIZE,
403 FILE_ATTRIBUTE_NORMAL,
404 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
405 FILE_OPEN,
406 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
407 OBJ_CASE_INSENSITIVE,
408 &NameUniStr);
409 if (hFile != INVALID_HANDLE_VALUE)
410 {
411 MY_FILE_ID_FULL_DIR_INFORMATION *pBuf;
412 ULONG cbBuf = sizeof(*pBuf) + NameUniStr.MaximumLength + 1024;
413 MY_IO_STATUS_BLOCK Ios;
414 MY_NTSTATUS rcNt;
415
416 pBuf = (MY_FILE_ID_FULL_DIR_INFORMATION *)alloca(cbBuf);
417 Ios.u.Status = -1;
418 Ios.Information = -1;
419 rcNt = g_pfnNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &Ios, pBuf, cbBuf,
420 MyFileIdFullDirectoryInformation, FALSE, &NameUniStr, TRUE);
421 if (MY_NT_SUCCESS(rcNt))
422 rcNt = Ios.u.Status;
423 if (MY_NT_SUCCESS(rcNt))
424 {
425 /*
426 * Convert the data.
427 */
428 birdStatFillFromFileIdFullDirInfo(pStat, pBuf, pszPath);
429
430 /* Get the serial number, reusing the buffer from above. */
431 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pBuf, cbBuf, MyFileFsVolumeInformation);
432 if (MY_NT_SUCCESS(rcNt))
433 rcNt = Ios.u.Status;
434 if (MY_NT_SUCCESS(rcNt))
435 {
436 MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pBuf;
437 pStat->st_dev = pVolInfo->VolumeSerialNumber
438 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
439 rc = 0;
440 }
441 else
442 {
443 pStat->st_dev = 0;
444 rc = birdSetErrnoFromNt(rcNt);
445 }
446 }
447
448 birdFreeNtPath(&NameUniStr);
449 birdCloseFile(hFile);
450
451 if (MY_NT_SUCCESS(rcNt))
452 return 0;
453 birdSetErrnoFromNt(rcNt);
454 }
455 }
456 rc = -1;
457 }
458
459 return rc;
460}
461
462
463/**
464 * Implements UNIX fstat().
465 */
466int birdStatOnFd(int fd, BirdStat_T *pStat)
467{
468 int rc;
469 HANDLE hFile = (HANDLE)_get_osfhandle(fd);
470 if (hFile != INVALID_HANDLE_VALUE)
471 {
472 DWORD fFileType;
473
474 birdResolveImports();
475
476 SetLastError(NO_ERROR);
477 fFileType = GetFileType(hFile) & ~FILE_TYPE_REMOTE;
478 switch (fFileType)
479 {
480 case FILE_TYPE_DISK:
481 rc = birdStatHandle(hFile, pStat, NULL);
482 break;
483
484 case FILE_TYPE_CHAR:
485 case FILE_TYPE_PIPE:
486 if (fFileType == FILE_TYPE_PIPE)
487 pStat->st_mode = S_IFIFO | 0666;
488 else
489 pStat->st_mode = S_IFCHR | 0666;
490 pStat->st_padding0[0] = 0;
491 pStat->st_padding0[1] = 0;
492 pStat->st_size = 0;
493 pStat->st_atim.tv_sec = 0;
494 pStat->st_atim.tv_nsec = 0;
495 pStat->st_mtim.tv_sec = 0;
496 pStat->st_mtim.tv_nsec = 0;
497 pStat->st_ctim.tv_sec = 0;
498 pStat->st_ctim.tv_nsec = 0;
499 pStat->st_birthtim.tv_sec = 0;
500 pStat->st_birthtim.tv_nsec = 0;
501 pStat->st_ino = 0;
502 pStat->st_dev = 0;
503 pStat->st_rdev = 0;
504 pStat->st_uid = 0;
505 pStat->st_gid = 0;
506 pStat->st_padding1[0] = 0;
507 pStat->st_padding1[1] = 0;
508 pStat->st_padding1[2] = 0;
509 pStat->st_blksize = 512;
510 pStat->st_blocks = 0;
511 if (fFileType == FILE_TYPE_PIPE)
512 {
513 DWORD cbAvail;
514 if (PeekNamedPipe(hFile, NULL, 0, NULL, &cbAvail, NULL))
515 pStat->st_size = cbAvail;
516 }
517 rc = 0;
518 break;
519
520 case FILE_TYPE_UNKNOWN:
521 default:
522 if (GetLastError() == NO_ERROR)
523 rc = birdSetErrnoToBadFileNo();
524 else
525 rc = birdSetErrnoFromWin32(GetLastError());
526 break;
527 }
528 }
529 else
530 rc = -1;
531 return rc;
532}
533
534
535/**
536 * Special case that only gets the file size and nothing else.
537 */
538int birdStatOnFdJustSize(int fd, __int64 *pcbFile)
539{
540 int rc;
541 HANDLE hFile = (HANDLE)_get_osfhandle(fd);
542 if (hFile != INVALID_HANDLE_VALUE)
543 {
544 LARGE_INTEGER cbLocal;
545 if (GetFileSizeEx(hFile, &cbLocal))
546 {
547 *pcbFile = cbLocal.QuadPart;
548 rc = 0;
549 }
550 else
551 {
552 BirdStat_T Stat;
553 rc = birdStatOnFd(fd, &Stat);
554 if (rc == 0)
555 *pcbFile = Stat.st_size;
556 }
557 }
558 else
559 rc = -1;
560 return rc;
561}
562
563
564/**
565 * Implements UNIX stat().
566 */
567int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat)
568{
569 return birdStatInternal(pszPath, pStat, 1 /*fFollow*/);
570}
571
572
573/**
574 * Implements UNIX lstat().
575 */
576int birdStatOnLink(const char *pszPath, BirdStat_T *pStat)
577{
578 return birdStatInternal(pszPath, pStat, 0 /*fFollow*/);
579}
580
581
582/**
583 * Internal worker for birdStatModTimeOnly.
584 */
585static int birdStatOnlyInternal(const char *pszPath, int fFollowLink, MY_FILE_BASIC_INFORMATION *pBasicInfo)
586{
587 int rc;
588 HANDLE hFile = birdOpenFile(pszPath,
589 FILE_READ_ATTRIBUTES,
590 FILE_ATTRIBUTE_NORMAL,
591 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
592 FILE_OPEN,
593 FILE_OPEN_FOR_BACKUP_INTENT | (fFollowLink ? 0 : FILE_OPEN_REPARSE_POINT),
594 OBJ_CASE_INSENSITIVE);
595 if (hFile != INVALID_HANDLE_VALUE)
596 {
597 MY_NTSTATUS rcNt = 0;
598 MY_IO_STATUS_BLOCK Ios;
599 Ios.Information = 0;
600 Ios.u.Status = -1;
601
602 if (pBasicInfo)
603 {
604 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pBasicInfo, sizeof(*pBasicInfo), MyFileBasicInformation);
605 if (MY_NT_SUCCESS(rcNt))
606 rcNt = Ios.u.Status;
607 }
608 birdCloseFile(hFile);
609
610 if (!MY_NT_SUCCESS(rcNt))
611 birdSetErrnoFromNt(rcNt);
612 }
613 else
614 {
615 //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError());
616
617 /* On things like pagefile.sys we may get sharing violation. */
618 if (GetLastError() == ERROR_SHARING_VIOLATION)
619 {
620 /** @todo Fall back on the parent directory enum if we run into a sharing
621 * violation. */
622 }
623 rc = -1;
624 }
625 return rc;
626}
627
628
629/**
630 * Special function for getting the modification time.
631 */
632int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink)
633{
634 MY_FILE_BASIC_INFORMATION BasicInfo;
635 int rc = birdStatOnlyInternal(pszPath, fFollowLink, &BasicInfo);
636 if (!rc)
637 birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, pTimeSpec);
638 return rc;
639}
640
641
642
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