VirtualBox

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

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