int main() { RTTIMESPEC Now; RTTIMESPEC Ts1; RTTIMESPEC Ts2; RTTIME T1; RTTIME T2; #ifdef RTTIME_INCL_TIMEVAL struct timeval Tv1; struct timeval Tv2; struct timespec Tsp1; struct timespec Tsp2; #endif RTTEST hTest; int rc = RTTestInitAndCreate("tstRTTimeSpec", &hTest); if (rc) return rc; /* * Simple test with current time. */ RTTestSub(hTest, "Current time (UTC)"); CHECK_NZ(RTTimeNow(&Now)); CHECK_NZ(RTTimeExplode(&T1, &Now)); RTTestIPrintf(RTTESTLVL_ALWAYS, " %RI64 ns - %s\n", RTTimeSpecGetNano(&Now), ToString(&T1)); CHECK_NZ(RTTimeImplode(&Ts1, &T1)); if (!RTTimeSpecIsEqual(&Ts1, &Now)) RTTestIFailed("%RI64 != %RI64\n", RTTimeSpecGetNano(&Ts1), RTTimeSpecGetNano(&Now)); /* * Simple test with current local time. */ RTTestSub(hTest, "Current time (local)"); CHECK_NZ(RTTimeLocalNow(&Now)); CHECK_NZ(RTTimeExplode(&T1, &Now)); RTTestIPrintf(RTTESTLVL_ALWAYS, " %RI64 ns - %s\n", RTTimeSpecGetNano(&Now), ToString(&T1)); CHECK_NZ(RTTimeImplode(&Ts1, &T1)); if (!RTTimeSpecIsEqual(&Ts1, &Now)) RTTestIFailed("%RI64 != %RI64\n", RTTimeSpecGetNano(&Ts1), RTTimeSpecGetNano(&Now)); /* * Some simple tests with fixed dates (just checking for smoke). */ RTTestSub(hTest, "Smoke"); TEST_NS(INT64_C(0)); CHECK_TIME(&T1, 1970,01,01, 00,00,00, 0, 1, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); TEST_NS(INT64_C(86400000000000)); CHECK_TIME(&T1, 1970,01,02, 00,00,00, 0, 2, 4, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); TEST_NS(INT64_C(1)); CHECK_TIME(&T1, 1970,01,01, 00,00,00, 1, 1, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); TEST_NS(INT64_C(-1)); CHECK_TIME(&T1, 1969,12,31, 23,59,59,999999999, 365, 2, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); /* * Test the limits. */ RTTestSub(hTest, "Extremes"); TEST_NS(INT64_MAX); TEST_NS(INT64_MIN); TEST_SEC(1095379198); CHECK_TIME(&T1, 2004, 9,16, 23,59,58, 0, 260, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_LEAP_YEAR); TEST_SEC(1095379199); CHECK_TIME(&T1, 2004, 9,16, 23,59,59, 0, 260, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_LEAP_YEAR); TEST_SEC(1095379200); CHECK_TIME(&T1, 2004, 9,17, 00,00,00, 0, 261, 4, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_LEAP_YEAR); TEST_SEC(1095379201); CHECK_TIME(&T1, 2004, 9,17, 00,00,01, 0, 261, 4, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_LEAP_YEAR); /* * Test normalization (UTC). */ RTTestSub(hTest, "Normalization (UTC)"); /* simple */ CHECK_NZ(RTTimeNow(&Now)); CHECK_NZ(RTTimeExplode(&T1, &Now)); T2 = T1; CHECK_NZ(RTTimeNormalize(&T1)); if (memcmp(&T1, &T2, sizeof(T1))) RTTestIFailed("simple normalization failed\n"); CHECK_NZ(RTTimeImplode(&Ts1, &T1)); CHECK_NZ(RTTimeSpecIsEqual(&Ts1, &Now)); /* a few partial dates. */ memset(&T1, 0, sizeof(T1)); SET_TIME( &T1, 1970,01,01, 00,00,00, 0, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 1970,01,01, 00,00,00, 0, 1, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 1970,00,00, 00,00,00, 1, 1, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 1970,01,01, 00,00,00, 1, 1, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 2007,12,06, 02,15,23, 1, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 2007,12,06, 02,15,23, 1, 340, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 1968,01,30, 00,19,24, 5, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 1968,01,30, 00,19,24, 5, 30, 1, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_LEAP_YEAR); SET_TIME( &T1, 1969,01,31, 00, 9, 2, 7, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 1969,01,31, 00, 9, 2, 7, 31, 4, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 1969,03,31, 00, 9, 2, 7, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 1969,03,31, 00, 9, 2, 7, 90, 0, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 1969,12,31, 00,00,00, 9, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 1969,12,31, 00,00,00, 9, 365, 2, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 1969,12,30, 00,00,00, 30, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 1969,12,30, 00,00,00, 30, 364, 1, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 1969,00,00, 00,00,00, 30, 363, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 1969,12,29, 00,00,00, 30, 363, 0, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 1969,00,00, 00,00,00, 30, 362, 6, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 1969,12,28, 00,00,00, 30, 362, 6, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 1969,12,27, 00,00,00, 30, 0, 5, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 1969,12,27, 00,00,00, 30, 361, 5, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 1969,00,00, 00,00,00, 30, 360, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 1969,12,26, 00,00,00, 30, 360, 4, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 1969,12,25, 00,00,00, 12, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 1969,12,25, 00,00,00, 12, 359, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 1969,12,24, 00,00,00, 16, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 1969,12,24, 00,00,00, 16, 358, 2, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); /* outside the year table range */ SET_TIME( &T1, 1200,01,30, 00,00,00, 2, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 1200,01,30, 00,00,00, 2, 30, 6, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_LEAP_YEAR); SET_TIME( &T1, 2555,11,29, 00,00,00, 2, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 2555,11,29, 00,00,00, 2, 333, 5, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 2555,00,00, 00,00,00, 3, 333, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 2555,11,29, 00,00,00, 3, 333, 5, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); /* time overflow */ SET_TIME( &T1, 1969,12,30, 255,255,255, UINT32_MAX, 364, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 1970,01, 9, 19,19,19,294967295, 9, 4, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); /* date overflow */ SET_TIME( &T1, 2007,11,36, 02,15,23, 1, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 2007,12,06, 02,15,23, 1, 340, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 2007,10,67, 02,15,23, 1, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 2007,12,06, 02,15,23, 1, 340, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 2007,10,98, 02,15,23, 1, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 2008,01,06, 02,15,23, 1, 6, 6, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_LEAP_YEAR); SET_TIME( &T1, 2006,24,06, 02,15,23, 1, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 2007,12,06, 02,15,23, 1, 340, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); SET_TIME( &T1, 2003,60,37, 02,15,23, 1, 0, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 2008,01,06, 02,15,23, 1, 6, 6, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_LEAP_YEAR); SET_TIME( &T1, 2003,00,00, 02,15,23, 1,1801, 0, 0, 0); CHECK_NZ(RTTimeNormalize(&T1)); CHECK_TIME(&T1, 2007,12,06, 02,15,23, 1, 340, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); /* * Conversions. */ #define CHECK_NSEC(Ts1, T2) \ do { \ RTTIMESPEC TsTmp; \ RTTESTI_CHECK_MSG( RTTimeSpecGetNano(&(Ts1)) == RTTimeSpecGetNano(RTTimeImplode(&TsTmp, &(T2))), \ ("line %d: %RI64, %RI64\n", __LINE__, \ RTTimeSpecGetNano(&(Ts1)), RTTimeSpecGetNano(RTTimeImplode(&TsTmp, &(T2)))) ); \ } while (0) RTTestSub(hTest, "Conversions, positive"); SET_TIME(&T1, 1980,01,01, 00,00,00, 0, 1, 1, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_LEAP_YEAR); RTTESTI_CHECK(RTTimeSpecSetDosSeconds(&Ts2, 0) == &Ts2); RTTESTI_CHECK(RTTimeSpecGetDosSeconds(&Ts2) == 0); CHECK_NSEC(Ts2, T1); SET_TIME(&T1, 1980,01,01, 00,00,00, 0, 1, 1, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_LEAP_YEAR); RTTESTI_CHECK(RTTimeSpecSetNtTime(&Ts2, INT64_C(119600064000000000)) == &Ts2); RTTESTI_CHECK(RTTimeSpecGetNtTime(&Ts2) == INT64_C(119600064000000000)); CHECK_NSEC(Ts2, T1); SET_TIME(&T1, 1970,01,01, 00,00,01, 0, 1, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); RTTESTI_CHECK(RTTimeSpecSetSeconds(&Ts2, 1) == &Ts2); RTTESTI_CHECK(RTTimeSpecGetSeconds(&Ts2) == 1); CHECK_NSEC(Ts2, T1); SET_TIME(&T1, 1970,01,01, 00,00,01, 0, 1, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); RTTESTI_CHECK(RTTimeSpecSetMilli(&Ts2, 1000) == &Ts2); RTTESTI_CHECK(RTTimeSpecGetMilli(&Ts2) == 1000); CHECK_NSEC(Ts2, T1); SET_TIME(&T1, 1970,01,01, 00,00,01, 0, 1, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); RTTESTI_CHECK(RTTimeSpecSetMicro(&Ts2, 1000000) == &Ts2); RTTESTI_CHECK(RTTimeSpecGetMicro(&Ts2) == 1000000); CHECK_NSEC(Ts2, T1); SET_TIME(&T1, 1970,01,01, 00,00,01, 0, 1, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); RTTESTI_CHECK(RTTimeSpecSetNano(&Ts2, 1000000000) == &Ts2); RTTESTI_CHECK(RTTimeSpecGetNano(&Ts2) == 1000000000); CHECK_NSEC(Ts2, T1); #ifdef RTTIME_INCL_TIMEVAL SET_TIME(&T1, 1970,01,01, 00,00,01, 5000, 1, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); Tv1.tv_sec = 1; Tv1.tv_usec = 5; RTTESTI_CHECK(RTTimeSpecSetTimeval(&Ts2, &Tv1) == &Ts2); RTTESTI_CHECK(RTTimeSpecGetMicro(&Ts2) == 1000005); CHECK_NSEC(Ts2, T1); RTTESTI_CHECK(RTTimeSpecGetTimeval(&Ts2, &Tv2) == &Tv2); RTTESTI_CHECK(Tv1.tv_sec == Tv2.tv_sec); RTTESTI_CHECK(Tv1.tv_usec == Tv2.tv_usec); #endif #ifdef RTTIME_INCL_TIMESPEC SET_TIME(&T1, 1970,01,01, 00,00,01, 5, 1, 3, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); Tsp1.tv_sec = 1; Tsp1.tv_nsec = 5; RTTESTI_CHECK(RTTimeSpecSetTimespec(&Ts2, &Tsp1) == &Ts2); RTTESTI_CHECK(RTTimeSpecGetNano(&Ts2) == 1000000005); CHECK_NSEC(Ts2, T1); RTTESTI_CHECK(RTTimeSpecGetTimespec(&Ts2, &Tsp2) == &Tsp2); RTTESTI_CHECK(Tsp1.tv_sec == Tsp2.tv_sec); RTTESTI_CHECK(Tsp1.tv_nsec == Tsp2.tv_nsec); #endif RTTestSub(hTest, "Conversions, negative"); #ifdef RTTIME_INCL_TIMEVAL SET_TIME(&T1, 1969,12,31, 23,59,58,999995000, 365, 2, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); Tv1.tv_sec = -2; Tv1.tv_usec = 999995; RTTESTI_CHECK(RTTimeSpecSetTimeval(&Ts2, &Tv1) == &Ts2); RTTESTI_CHECK_MSG(RTTimeSpecGetMicro(&Ts2) == -1000005, ("%RI64\n", RTTimeSpecGetMicro(&Ts2))); CHECK_NSEC(Ts2, T1); RTTESTI_CHECK(RTTimeSpecGetTimeval(&Ts2, &Tv2) == &Tv2); RTTESTI_CHECK(Tv1.tv_sec == Tv2.tv_sec); RTTESTI_CHECK(Tv1.tv_usec == Tv2.tv_usec); #endif #ifdef RTTIME_INCL_TIMESPEC SET_TIME(&T1, 1969,12,31, 23,59,58,999999995, 365, 2, 0, RTTIME_FLAGS_TYPE_UTC | RTTIME_FLAGS_COMMON_YEAR); Tsp1.tv_sec = -2; Tsp1.tv_nsec = 999999995; RTTESTI_CHECK(RTTimeSpecSetTimespec(&Ts2, &Tsp1) == &Ts2); RTTESTI_CHECK_MSG(RTTimeSpecGetNano(&Ts2) == -1000000005, ("%RI64\n", RTTimeSpecGetMicro(&Ts2))); CHECK_NSEC(Ts2, T1); RTTESTI_CHECK(RTTimeSpecGetTimespec(&Ts2, &Tsp2) == &Tsp2); RTTESTI_CHECK(Tsp1.tv_sec == Tsp2.tv_sec); RTTESTI_CHECK(Tsp1.tv_nsec == Tsp2.tv_nsec); #endif /* * Summary */ return RTTestSummaryAndDestroy(hTest); }
static NTSTATUS vbsfProcessCreate(PRX_CONTEXT RxContext, PUNICODE_STRING RemainingName, FILE_BASIC_INFORMATION *pFileBasicInfo, FILE_STANDARD_INFORMATION *pFileStandardInfo, PVOID EaBuffer, ULONG EaLength, ULONG *pulCreateAction, SHFLHANDLE *pHandle) { NTSTATUS Status = STATUS_SUCCESS; RxCaptureFcb; PMRX_VBOX_DEVICE_EXTENSION pDeviceExtension = VBoxMRxGetDeviceExtension(RxContext); PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot); int vboxRC = VINF_SUCCESS; /* Various boolean flags. */ struct { ULONG CreateDirectory :1; ULONG OpenDirectory :1; ULONG DirectoryFile :1; ULONG NonDirectoryFile :1; ULONG DeleteOnClose :1; ULONG TemporaryFile :1; } bf; ACCESS_MASK DesiredAccess; ULONG Options; UCHAR FileAttributes; ULONG ShareAccess; ULONG CreateDisposition; SHFLCREATEPARMS *pCreateParms = NULL; if (EaLength) { Log(("VBOXSF: vbsfProcessCreate: Unsupported: extended attributes!\n")); Status = STATUS_NOT_SUPPORTED; goto failure; } if (BooleanFlagOn(capFcb->FcbState, FCB_STATE_PAGING_FILE)) { Log(("VBOXSF: vbsfProcessCreate: Unsupported: paging file!\n")); Status = STATUS_NOT_IMPLEMENTED; goto failure; } Log(("VBOXSF: vbsfProcessCreate: FileAttributes = 0x%08x\n", RxContext->Create.NtCreateParameters.FileAttributes)); Log(("VBOXSF: vbsfProcessCreate: CreateOptions = 0x%08x\n", RxContext->Create.NtCreateParameters.CreateOptions)); RtlZeroMemory (&bf, sizeof (bf)); DesiredAccess = RxContext->Create.NtCreateParameters.DesiredAccess; Options = RxContext->Create.NtCreateParameters.CreateOptions & FILE_VALID_OPTION_FLAGS; FileAttributes = (UCHAR)(RxContext->Create.NtCreateParameters.FileAttributes & ~FILE_ATTRIBUTE_NORMAL); ShareAccess = RxContext->Create.NtCreateParameters.ShareAccess; /* We do not support opens by file ids. */ if (FlagOn(Options, FILE_OPEN_BY_FILE_ID)) { Log(("VBOXSF: vbsfProcessCreate: Unsupported: file open by id!\n")); Status = STATUS_NOT_IMPLEMENTED; goto failure; } /* Mask out unsupported attribute bits. */ FileAttributes &= (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE); bf.DirectoryFile = BooleanFlagOn(Options, FILE_DIRECTORY_FILE); bf.NonDirectoryFile = BooleanFlagOn(Options, FILE_NON_DIRECTORY_FILE); bf.DeleteOnClose = BooleanFlagOn(Options, FILE_DELETE_ON_CLOSE); if (bf.DeleteOnClose) Log(("VBOXSF: vbsfProcessCreate: Delete on close!\n")); CreateDisposition = RxContext->Create.NtCreateParameters.Disposition; bf.CreateDirectory = (BOOLEAN)(bf.DirectoryFile && ((CreateDisposition == FILE_CREATE) || (CreateDisposition == FILE_OPEN_IF))); bf.OpenDirectory = (BOOLEAN)(bf.DirectoryFile && ((CreateDisposition == FILE_OPEN) || (CreateDisposition == FILE_OPEN_IF))); bf.TemporaryFile = BooleanFlagOn(RxContext->Create.NtCreateParameters.FileAttributes, FILE_ATTRIBUTE_TEMPORARY); if (FlagOn(capFcb->FcbState, FCB_STATE_TEMPORARY)) bf.TemporaryFile = TRUE; Log(("VBOXSF: vbsfProcessCreate: bf.TemporaryFile %d, bf.CreateDirectory %d, bf.DirectoryFile = %d\n", (ULONG)bf.TemporaryFile, (ULONG)bf.CreateDirectory, (ULONG)bf.DirectoryFile)); /* Check consistency in specified flags. */ if (bf.TemporaryFile && bf.CreateDirectory) /* Directories with temporary flag set are not allowed! */ { Log(("VBOXSF: vbsfProcessCreate: Not allowed: Temporary directories!\n")); Status = STATUS_INVALID_PARAMETER; goto failure; } if (bf.DirectoryFile && bf.NonDirectoryFile) { Log(("VBOXSF: vbsfProcessCreate: Unsupported combination: dir && !dir\n")); Status = STATUS_INVALID_PARAMETER; goto failure; } /* Initialize create parameters. */ pCreateParms = (SHFLCREATEPARMS *)vbsfAllocNonPagedMem(sizeof(SHFLCREATEPARMS)); if (!pCreateParms) { Status = STATUS_INSUFFICIENT_RESOURCES; goto failure; } RtlZeroMemory(pCreateParms, sizeof (SHFLCREATEPARMS)); pCreateParms->Handle = SHFL_HANDLE_NIL; pCreateParms->Result = SHFL_NO_RESULT; if (bf.DirectoryFile) { if (CreateDisposition != FILE_CREATE && CreateDisposition != FILE_OPEN && CreateDisposition != FILE_OPEN_IF) { Log(("VBOXSF: vbsfProcessCreate: Invalid disposition 0x%08X for directory!\n", CreateDisposition)); Status = STATUS_INVALID_PARAMETER; goto failure; } pCreateParms->CreateFlags |= SHFL_CF_DIRECTORY; } Log(("VBOXSF: vbsfProcessCreate: CreateDisposition = 0x%08X\n", CreateDisposition)); switch (CreateDisposition) { case FILE_SUPERSEDE: pCreateParms->CreateFlags |= SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW; Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n")); break; case FILE_OPEN: pCreateParms->CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW; Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW\n")); break; case FILE_CREATE: pCreateParms->CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW; Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n")); break; case FILE_OPEN_IF: pCreateParms->CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW; Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n")); break; case FILE_OVERWRITE: pCreateParms->CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW; Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW\n")); break; case FILE_OVERWRITE_IF: pCreateParms->CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW; Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n")); break; default: Log(("VBOXSF: vbsfProcessCreate: Unexpected create disposition: 0x%08X\n", CreateDisposition)); Status = STATUS_INVALID_PARAMETER; goto failure; } Log(("VBOXSF: vbsfProcessCreate: DesiredAccess = 0x%08X\n", DesiredAccess)); Log(("VBOXSF: vbsfProcessCreate: ShareAccess = 0x%08X\n", ShareAccess)); if (DesiredAccess & FILE_READ_DATA) { Log(("VBOXSF: vbsfProcessCreate: FILE_READ_DATA\n")); pCreateParms->CreateFlags |= SHFL_CF_ACCESS_READ; } if (DesiredAccess & FILE_WRITE_DATA) { Log(("VBOXSF: vbsfProcessCreate: FILE_WRITE_DATA\n")); /* FILE_WRITE_DATA means write access regardless of FILE_APPEND_DATA bit. */ pCreateParms->CreateFlags |= SHFL_CF_ACCESS_WRITE; } else if (DesiredAccess & FILE_APPEND_DATA) { Log(("VBOXSF: vbsfProcessCreate: FILE_APPEND_DATA\n")); /* FILE_APPEND_DATA without FILE_WRITE_DATA means append only mode. * * Both write and append access flags are required for shared folders, * as on Windows FILE_APPEND_DATA implies write access. */ pCreateParms->CreateFlags |= SHFL_CF_ACCESS_WRITE | SHFL_CF_ACCESS_APPEND; } if (DesiredAccess & FILE_READ_ATTRIBUTES) pCreateParms->CreateFlags |= SHFL_CF_ACCESS_ATTR_READ; if (DesiredAccess & FILE_WRITE_ATTRIBUTES) pCreateParms->CreateFlags |= SHFL_CF_ACCESS_ATTR_WRITE; if (ShareAccess & (FILE_SHARE_READ | FILE_SHARE_WRITE)) pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYNONE; else if (ShareAccess & FILE_SHARE_READ) pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYWRITE; else if (ShareAccess & FILE_SHARE_WRITE) pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYREAD; else pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYALL; /* Set initial allocation size. */ pCreateParms->Info.cbObject = RxContext->Create.NtCreateParameters.AllocationSize.QuadPart; if (FileAttributes == 0) FileAttributes = FILE_ATTRIBUTE_NORMAL; pCreateParms->Info.Attr.fMode = NTToVBoxFileAttributes(FileAttributes); { PSHFLSTRING ParsedPath; ULONG ParsedPathSize; /* Calculate length required for parsed path. */ ParsedPathSize = sizeof(*ParsedPath) + (RemainingName->Length + sizeof(WCHAR)); Log(("VBOXSF: vbsfProcessCreate: ParsedPathSize = %d\n", ParsedPathSize)); ParsedPath = (PSHFLSTRING)vbsfAllocNonPagedMem(ParsedPathSize); if (ParsedPath == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto failure; } ShflStringInitBuffer(ParsedPath, ParsedPathSize - sizeof(SHFLSTRING)); ParsedPath->u16Size = RemainingName->Length + sizeof(WCHAR); ParsedPath->u16Length = ParsedPath->u16Size - sizeof(WCHAR); /* without terminating null */ RtlCopyMemory (ParsedPath->String.ucs2, RemainingName->Buffer, ParsedPath->u16Length); Log(("VBOXSF: ParsedPath: %.*ls\n", ParsedPath->u16Length / sizeof(WCHAR), ParsedPath->String.ucs2)); /* Call host. */ Log(("VBOXSF: vbsfProcessCreate: vboxCallCreate called.\n")); vboxRC = vboxCallCreate(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, ParsedPath, pCreateParms); vbsfFreeNonPagedMem(ParsedPath); } Log(("VBOXSF: vbsfProcessCreate: vboxCallCreate returns vboxRC = %Rrc, Result = 0x%x\n", vboxRC, pCreateParms->Result)); if (RT_FAILURE(vboxRC)) { /* Map some VBoxRC to STATUS codes expected by the system. */ switch (vboxRC) { case VERR_ALREADY_EXISTS: { *pulCreateAction = FILE_EXISTS; Status = STATUS_OBJECT_NAME_COLLISION; goto failure; } break; /* On POSIX systems, the "mkdir" command returns VERR_FILE_NOT_FOUND when doing a recursive directory create. Handle this case. */ case VERR_FILE_NOT_FOUND: { pCreateParms->Result = SHFL_PATH_NOT_FOUND; } break; default: { *pulCreateAction = FILE_DOES_NOT_EXIST; Status = VBoxErrorToNTStatus(vboxRC); goto failure; } break; } } /* * The request succeeded. Analyze host response, */ switch (pCreateParms->Result) { case SHFL_PATH_NOT_FOUND: { /* Path to object does not exist. */ Log(("VBOXSF: vbsfProcessCreate: Path not found\n")); *pulCreateAction = FILE_DOES_NOT_EXIST; Status = STATUS_OBJECT_PATH_NOT_FOUND; goto failure; } case SHFL_FILE_NOT_FOUND: { Log(("VBOXSF: vbsfProcessCreate: File not found\n")); *pulCreateAction = FILE_DOES_NOT_EXIST; if (pCreateParms->Handle == SHFL_HANDLE_NIL) { Status = STATUS_OBJECT_NAME_NOT_FOUND; goto failure; } Log(("VBOXSF: vbsfProcessCreate: File not found but have a handle!\n")); Status = STATUS_UNSUCCESSFUL; goto failure; break; } case SHFL_FILE_EXISTS: { Log(("VBOXSF: vbsfProcessCreate: File exists, Handle = 0x%RX64\n", pCreateParms->Handle)); if (pCreateParms->Handle == SHFL_HANDLE_NIL) { *pulCreateAction = FILE_EXISTS; if (CreateDisposition == FILE_CREATE) { /* File was not opened because we requested a create. */ Status = STATUS_OBJECT_NAME_COLLISION; goto failure; } /* Actually we should not go here, unless we have no rights to open the object. */ Log(("VBOXSF: vbsfProcessCreate: Existing file was not opened!\n")); Status = STATUS_ACCESS_DENIED; goto failure; } *pulCreateAction = FILE_OPENED; /* Existing file was opened. Go check flags and create FCB. */ break; } case SHFL_FILE_CREATED: { /* A new file was created. */ Assert(pCreateParms->Handle != SHFL_HANDLE_NIL); *pulCreateAction = FILE_CREATED; /* Go check flags and create FCB. */ break; } case SHFL_FILE_REPLACED: { /* Existing file was replaced or overwriting. */ Assert(pCreateParms->Handle != SHFL_HANDLE_NIL); if (CreateDisposition == FILE_SUPERSEDE) { *pulCreateAction = FILE_SUPERSEDED; } else { *pulCreateAction = FILE_OVERWRITTEN; } /* Go check flags and create FCB. */ break; } default: { Log(("VBOXSF: vbsfProcessCreate: Invalid CreateResult from host (0x%08X)\n", pCreateParms->Result)); *pulCreateAction = FILE_DOES_NOT_EXIST; Status = STATUS_OBJECT_PATH_NOT_FOUND; goto failure; } } /* Check flags. */ if (bf.NonDirectoryFile && FlagOn(pCreateParms->Info.Attr.fMode, RTFS_DOS_DIRECTORY)) { /* Caller wanted only a file, but the object is a directory. */ Log(("VBOXSF: vbsfProcessCreate: File is a directory!\n")); Status = STATUS_FILE_IS_A_DIRECTORY; goto failure; } if (bf.DirectoryFile && !FlagOn(pCreateParms->Info.Attr.fMode, RTFS_DOS_DIRECTORY)) { /* Caller wanted only a directory, but the object is not a directory. */ Log(("VBOXSF: vbsfProcessCreate: File is not a directory!\n")); Status = STATUS_NOT_A_DIRECTORY; goto failure; } *pHandle = pCreateParms->Handle; /* Translate attributes */ pFileBasicInfo->FileAttributes = VBoxToNTFileAttributes(pCreateParms->Info.Attr.fMode); /* Translate file times */ pFileBasicInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pCreateParms->Info.BirthTime); /* ridiculous name */ pFileBasicInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pCreateParms->Info.AccessTime); pFileBasicInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pCreateParms->Info.ModificationTime); pFileBasicInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pCreateParms->Info.ChangeTime); if (!FlagOn(pCreateParms->Info.Attr.fMode, RTFS_DOS_DIRECTORY)) { pFileStandardInfo->AllocationSize.QuadPart = pCreateParms->Info.cbAllocated; pFileStandardInfo->EndOfFile.QuadPart = pCreateParms->Info.cbObject; pFileStandardInfo->Directory = FALSE; Log(("VBOXSF: vbsfProcessCreate: AllocationSize = 0x%RX64, EndOfFile = 0x%RX64\n", pCreateParms->Info.cbAllocated, pCreateParms->Info.cbObject)); } else { pFileStandardInfo->AllocationSize.QuadPart = 0; pFileStandardInfo->EndOfFile.QuadPart = 0; pFileStandardInfo->Directory = TRUE; } pFileStandardInfo->NumberOfLinks = 0; pFileStandardInfo->DeletePending = FALSE; vbsfFreeNonPagedMem(pCreateParms); return Status; failure: Log(("VBOXSF: vbsfProcessCreate: Returned with status = 0x%08X\n", Status)); if (pCreateParms && pCreateParms->Handle != SHFL_HANDLE_NIL) { vboxCallClose(&pDeviceExtension->hgcmClient, &pNetRootExtension->map, pCreateParms->Handle); *pHandle = SHFL_HANDLE_NIL; } if (pCreateParms) { vbsfFreeNonPagedMem(pCreateParms); } return Status; }