summaryrefslogtreecommitdiffstats
path: root/private/nw/rdr/convert.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/rdr/convert.c')
-rw-r--r--private/nw/rdr/convert.c732
1 files changed, 732 insertions, 0 deletions
diff --git a/private/nw/rdr/convert.c b/private/nw/rdr/convert.c
new file mode 100644
index 000000000..4caf5372a
--- /dev/null
+++ b/private/nw/rdr/convert.c
@@ -0,0 +1,732 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ Convert.c
+
+Abstract:
+
+ This module implements conversion routine to map NT formats to
+ Netware and vice versa.
+
+Author:
+
+ Manny Weiser [MannyW] 3-Mar-1993
+
+Revision History:
+
+--*/
+
+#include "Procs.h"
+
+typedef union _NCP_DATE {
+ USHORT Ushort;
+ struct {
+ USHORT Day : 5;
+ USHORT Month : 4;
+ USHORT Year : 7;
+ } Struct;
+} NCP_DATE;
+
+typedef union _NCP_TIME {
+ USHORT Ushort;
+ struct {
+ USHORT TwoSeconds : 5;
+ USHORT Minutes : 6;
+ USHORT Hours : 5;
+ } Struct;
+} NCP_TIME;
+
+#define BASE_DOS_ERROR ((NTSTATUS )0xC0010000L)
+
+
+struct {
+ UCHAR NetError;
+ NTSTATUS ResultingStatus;
+} Error_Map[] = {
+ // NetWare specific error mappings
+ { 1, STATUS_DISK_FULL },
+ {128, STATUS_SHARING_VIOLATION },
+ {129, STATUS_INSUFF_SERVER_RESOURCES },
+ {130, STATUS_ACCESS_DENIED },
+ {131, STATUS_DATA_ERROR },
+ {132, STATUS_ACCESS_DENIED },
+ {133, STATUS_OBJECT_NAME_COLLISION },
+ {134, STATUS_OBJECT_NAME_COLLISION },
+ {135, STATUS_OBJECT_NAME_INVALID },
+ {136, STATUS_INVALID_HANDLE },
+ {137, STATUS_ACCESS_DENIED },
+ {138, STATUS_ACCESS_DENIED },
+ {139, STATUS_ACCESS_DENIED },
+ {140, STATUS_ACCESS_DENIED },
+ {141, STATUS_SHARING_VIOLATION },
+ {142, STATUS_SHARING_VIOLATION },
+ {143, STATUS_ACCESS_DENIED },
+ {144, STATUS_ACCESS_DENIED },
+ {145, STATUS_OBJECT_NAME_COLLISION },
+ {146, STATUS_OBJECT_NAME_COLLISION },
+ {147, STATUS_ACCESS_DENIED },
+ {148, STATUS_ACCESS_DENIED },
+ {149, STATUS_ACCESS_DENIED },
+ {150, STATUS_INSUFF_SERVER_RESOURCES },
+ {151, STATUS_NO_SPOOL_SPACE },
+ {152, STATUS_NO_SUCH_DEVICE },
+ {153, STATUS_DISK_FULL },
+ {154, STATUS_NOT_SAME_DEVICE },
+ {155, STATUS_INVALID_HANDLE },
+ {156, STATUS_OBJECT_PATH_NOT_FOUND },
+ {157, STATUS_INSUFF_SERVER_RESOURCES },
+ {158, STATUS_OBJECT_PATH_INVALID },
+ {159, STATUS_SHARING_VIOLATION },
+ {160, STATUS_DIRECTORY_NOT_EMPTY },
+ {161, STATUS_DATA_ERROR },
+ {162, STATUS_FILE_LOCK_CONFLICT },
+ {165, STATUS_OBJECT_NAME_NOT_FOUND },
+ {191, STATUS_OBJECT_NAME_INVALID }, // Name space not loaded
+ {192, STATUS_ACCESS_DENIED},
+ {193, STATUS_ACCOUNT_RESTRICTION },
+ {194, STATUS_ACCOUNT_RESTRICTION },
+ {195, STATUS_ACCOUNT_DISABLED},
+ {197, STATUS_ACCOUNT_DISABLED },
+ {198, STATUS_ACCESS_DENIED },
+ {211, STATUS_ACCESS_DENIED },
+ {212, STATUS_PRINT_QUEUE_FULL },
+ {213, STATUS_PRINT_CANCELLED },
+ {214, STATUS_ACCESS_DENIED },
+ {215, STATUS_PASSWORD_RESTRICTION },
+ {216, STATUS_PASSWORD_RESTRICTION },
+#ifdef QFE_BUILD
+ {217, STATUS_ACCOUNT_RESTRICTION },
+ {218, STATUS_ACCOUNT_RESTRICTION },
+ {219, STATUS_ACCOUNT_RESTRICTION },
+#else
+ {217, STATUS_CONNECTION_COUNT_LIMIT },
+ {218, STATUS_LOGIN_TIME_RESTRICTION },
+ {219, STATUS_LOGIN_WKSTA_RESTRICTION },
+#endif
+ {220, STATUS_ACCOUNT_DISABLED },
+ {222, STATUS_PASSWORD_EXPIRED },
+ {223, NWRDR_PASSWORD_HAS_EXPIRED },
+ {231, STATUS_REMOTE_SESSION_LIMIT },
+ {236, STATUS_UNEXPECTED_NETWORK_ERROR },
+ {251, STATUS_INVALID_PARAMETER },
+ {252, STATUS_NO_MORE_ENTRIES },
+ {253, STATUS_FILE_LOCK_CONFLICT },
+ {254, STATUS_FILE_LOCK_CONFLICT },
+ {255, STATUS_UNSUCCESSFUL},
+
+ // DOS error mappings
+ //{ ERROR_INVALID_FUNCTION, STATUS_NOT_IMPLEMENTED },
+ { ERROR_FILE_NOT_FOUND, STATUS_NO_SUCH_FILE },
+ { ERROR_PATH_NOT_FOUND, STATUS_OBJECT_PATH_NOT_FOUND },
+ { ERROR_TOO_MANY_OPEN_FILES, STATUS_TOO_MANY_OPENED_FILES },
+ { ERROR_ACCESS_DENIED, STATUS_ACCESS_DENIED },
+ { ERROR_INVALID_HANDLE, STATUS_INVALID_HANDLE },
+ { ERROR_NOT_ENOUGH_MEMORY, STATUS_INSUFFICIENT_RESOURCES },
+ { ERROR_INVALID_ACCESS, STATUS_ACCESS_DENIED },
+ { ERROR_INVALID_DATA, STATUS_DATA_ERROR },
+
+ { ERROR_CURRENT_DIRECTORY, STATUS_DIRECTORY_NOT_EMPTY },
+ { ERROR_NOT_SAME_DEVICE, STATUS_NOT_SAME_DEVICE },
+ { ERROR_NO_MORE_FILES, STATUS_NO_MORE_FILES },
+/* */
+/* These are the universal int 24 mappings for the old INT 24 set of errors */
+/* */
+ { ERROR_WRITE_PROTECT, STATUS_MEDIA_WRITE_PROTECTED},
+ { ERROR_BAD_UNIT, STATUS_UNSUCCESSFUL}, // ***
+ { ERROR_NOT_READY, STATUS_DEVICE_NOT_READY },
+ { ERROR_BAD_COMMAND, STATUS_UNSUCCESSFUL}, // ***
+ { ERROR_CRC, STATUS_CRC_ERROR },
+ { ERROR_BAD_LENGTH, STATUS_DATA_ERROR },
+ { ERROR_SEEK, STATUS_UNSUCCESSFUL },// ***
+ { ERROR_NOT_DOS_DISK, STATUS_DISK_CORRUPT_ERROR }, //***
+ { ERROR_SECTOR_NOT_FOUND, STATUS_NONEXISTENT_SECTOR },
+ { ERROR_OUT_OF_PAPER, STATUS_DEVICE_PAPER_EMPTY},
+ { ERROR_WRITE_FAULT, STATUS_UNSUCCESSFUL}, // ***
+ { ERROR_READ_FAULT, STATUS_UNSUCCESSFUL}, // ***
+ { ERROR_GEN_FAILURE, STATUS_UNSUCCESSFUL }, // ***
+/* */
+/* These are the new 3.0 error codes reported through INT 24 */
+/* */
+ { ERROR_SHARING_VIOLATION, STATUS_SHARING_VIOLATION },
+ { ERROR_LOCK_VIOLATION, STATUS_FILE_LOCK_CONFLICT },
+ { ERROR_WRONG_DISK, STATUS_WRONG_VOLUME },
+// { ERROR_FCB_UNAVAILABLE, },
+// { ERROR_SHARING_BUFFER_EXCEEDED, },
+/* */
+/* New OEM network-related errors are 50-79 */
+/* */
+ { ERROR_NOT_SUPPORTED, STATUS_NOT_SUPPORTED },
+ { ERROR_REM_NOT_LIST, STATUS_REMOTE_NOT_LISTENING },
+ { ERROR_DUP_NAME, STATUS_DUPLICATE_NAME },
+ { ERROR_BAD_NETPATH, STATUS_BAD_NETWORK_PATH },
+ { ERROR_NETWORK_BUSY, STATUS_NETWORK_BUSY },
+ { ERROR_DEV_NOT_EXIST, STATUS_DEVICE_DOES_NOT_EXIST },
+ { ERROR_TOO_MANY_CMDS, STATUS_TOO_MANY_COMMANDS },
+ { ERROR_ADAP_HDW_ERR, STATUS_ADAPTER_HARDWARE_ERROR },
+ { ERROR_BAD_NET_RESP, STATUS_INVALID_NETWORK_RESPONSE },
+ { ERROR_UNEXP_NET_ERR, STATUS_UNEXPECTED_NETWORK_ERROR },
+ { ERROR_BAD_REM_ADAP, STATUS_BAD_REMOTE_ADAPTER },
+ { ERROR_PRINTQ_FULL, STATUS_PRINT_QUEUE_FULL },
+ { ERROR_NO_SPOOL_SPACE, STATUS_NO_SPOOL_SPACE },
+ { ERROR_PRINT_CANCELLED, STATUS_PRINT_CANCELLED },
+ { ERROR_NETNAME_DELETED, STATUS_NETWORK_NAME_DELETED },
+ { ERROR_NETWORK_ACCESS_DENIED, STATUS_NETWORK_ACCESS_DENIED },
+ { ERROR_BAD_DEV_TYPE, STATUS_BAD_DEVICE_TYPE },
+ { ERROR_BAD_NET_NAME, STATUS_BAD_NETWORK_NAME },
+ { ERROR_TOO_MANY_NAMES, STATUS_TOO_MANY_NAMES },
+ { ERROR_TOO_MANY_SESS, STATUS_REMOTE_SESSION_LIMIT },
+ { ERROR_SHARING_PAUSED, STATUS_SHARING_PAUSED },
+ { ERROR_REQ_NOT_ACCEP, STATUS_REQUEST_NOT_ACCEPTED },
+ { ERROR_REDIR_PAUSED, STATUS_REDIRECTOR_PAUSED },
+/* */
+/* End of INT 24 reportable errors */
+/* */
+ { ERROR_FILE_EXISTS, STATUS_OBJECT_NAME_COLLISION },
+// { ERROR_DUP_FCB, },
+// { ERROR_CANNOT_MAKE, },
+// { ERROR_FAIL_I24, },
+/* */
+/* New 3.0 network related error codes */
+/* */
+// { ERROR_OUT_OF_STRUCTURES, },
+// { ERROR_ALREADY_ASSIGNED, },
+ { ERROR_INVALID_PASSWORD, STATUS_WRONG_PASSWORD },
+ { ERROR_INVALID_PARAMETER, STATUS_INVALID_PARAMETER },
+ { ERROR_NET_WRITE_FAULT, STATUS_NET_WRITE_FAULT },
+/* */
+/* New error codes for 4.0 */
+/* */
+// { ERROR_NO_PROC_SLOTS, },
+// { ERROR_NOT_FROZEN, },
+// { ERR_TSTOVFL, },
+// { ERR_TSTDUP, },
+// { ERROR_NO_ITEMS, },
+// { ERROR_INTERRUPT, },
+
+// { ERROR_TOO_MANY_SEMAPHORES, },
+// { ERROR_EXCL_SEM_ALREADY_OWNED, },
+// { ERROR_SEM_IS_SET, },
+// { ERROR_TOO_MANY_SEM_REQUESTS, },
+// { ERROR_INVALID_AT_INTERRUPT_TIME, },
+
+// { ERROR_SEM_OWNER_DIED, },
+// { ERROR_SEM_USER_LIMIT, },
+// { ERROR_DISK_CHANGE, },
+// { ERROR_DRIVE_LOCKED, },
+ { ERROR_BROKEN_PIPE, STATUS_PIPE_BROKEN },
+/* */
+/* New error codes for 5.0 */
+/* */
+ //
+ // NOTE: ERROR_OPEN_FAILED is handled specially.
+ //
+
+ //
+ // The mapping of ERROR_OPEN_FAILED is context sensitive. If the
+ // disposition requested in the Open_AndX SMB is FILE_CREATE, this
+ // error means that the file already existed. If the disposition
+ // is FILE_OPEN, it means that the file does NOT exist!
+ //
+
+ { ERROR_OPEN_FAILED, STATUS_OPEN_FAILED },
+// { ERROR_BUFFER_OVERFLOW, },
+ { ERROR_DISK_FULL, STATUS_DISK_FULL },
+// { ERROR_NO_MORE_SEARCH_HANDLES, },
+// { ERROR_INVALID_TARGET_HANDLE, },
+// { ERROR_PROTECTION_VIOLATION, STATUS_ACCESS_VIOLATION },
+// { ERROR_VIOKBD_REQUEST, },
+// { ERROR_INVALID_CATEGORY, },
+// { ERROR_INVALID_VERIFY_SWITCH, },
+// { ERROR_BAD_DRIVER_LEVEL, },
+// { ERROR_CALL_NOT_IMPLEMENTED, },
+ { ERROR_SEM_TIMEOUT, STATUS_IO_TIMEOUT },
+ { ERROR_INSUFFICIENT_BUFFER, STATUS_BUFFER_TOO_SMALL },
+ { ERROR_INVALID_NAME, STATUS_OBJECT_NAME_INVALID },
+ { ERROR_INVALID_LEVEL, STATUS_INVALID_LEVEL },
+// { ERROR_NO_VOLUME_LABEL, },
+
+/* NOTE: DosQFSInfo no longer returns the above error; it is still here for */
+/* api\d_qfsinf.asm. */
+
+// { ERROR_MOD_NOT_FOUND, },
+// { ERROR_PROC_NOT_FOUND, },
+
+// { ERROR_WAIT_NO_CHILDREN, },
+
+// { ERROR_CHILD_NOT_COMPLETE, },
+
+// { ERROR_DIRECT_ACCESS_HANDLE, },
+ /* for direct disk access */
+ /* handles */
+// { ERROR_NEGATIVE_SEEK, },
+ /* with negitive offset */
+// { ERROR_SEEK_ON_DEVICE, },
+ /* on device or pipe */
+ { ERROR_BAD_PATHNAME, STATUS_OBJECT_PATH_INVALID }, //*
+
+/*
+ * Error codes 230 - 249 are reserved for MS Networks
+ */
+ { ERROR_BAD_PIPE, STATUS_INVALID_PARAMETER },
+ { ERROR_PIPE_BUSY, STATUS_PIPE_NOT_AVAILABLE },
+ { ERROR_NO_DATA, STATUS_PIPE_EMPTY },
+ { ERROR_PIPE_NOT_CONNECTED, STATUS_PIPE_DISCONNECTED },
+ { ERROR_MORE_DATA, STATUS_BUFFER_OVERFLOW },
+
+ { ERROR_VC_DISCONNECTED, STATUS_VIRTUAL_CIRCUIT_CLOSED },
+};
+
+#define NUM_ERRORS sizeof(Error_Map) / sizeof(Error_Map[0])
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_CONVERT)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( PAGE, NtToNwShareFlags )
+#pragma alloc_text( PAGE, NtAttributesToNwAttributes )
+
+#ifndef QFE_BUILD
+#pragma alloc_text( PAGE1, pNwErrorToNtStatus )
+#pragma alloc_text( PAGE1, NwBurstResultToNtStatus )
+#pragma alloc_text( PAGE1, NwConnectionStatusToNtStatus )
+#pragma alloc_text( PAGE1, NwDateTimeToNtTime )
+#pragma alloc_text( PAGE1, NwNtTimeToNwDateTime )
+#endif
+
+#endif
+
+#if 0 // Not pageable
+
+// see ifndef QFE_BUILD above
+
+#endif
+
+UCHAR
+NtToNwShareFlags(
+ ULONG DesiredAccess,
+ ULONG NtShareFlags
+ )
+/*++
+
+Routine Description:
+
+ This routine maps a NT desired/share access to Netware share flag bits.
+
+Arguments:
+
+ DesiredAccess - Desired access for open as specified in the read IRP.
+ NtShareFlags - The NT share flags from the create IRP.
+
+Return Value:
+
+ Netware share mode.
+
+--*/
+{
+ UCHAR NwShareFlags = 0;
+ ULONG lDesiredAccess;
+
+ PAGED_CODE();
+
+ //
+ // Ignore share delete, since we can't do anything with it.
+ //
+
+ switch ( NtShareFlags & (FILE_SHARE_READ | FILE_SHARE_WRITE) ) {
+
+ case 0:
+ NwShareFlags = NW_OPEN_EXCLUSIVE;
+ break;
+
+ case FILE_SHARE_READ:
+ NwShareFlags = NW_DENY_WRITE;
+ break;
+
+ case FILE_SHARE_WRITE:
+ NwShareFlags = NW_DENY_READ;
+ break;
+
+ case FILE_SHARE_WRITE | FILE_SHARE_READ:
+ NwShareFlags = 0;
+
+ }
+
+ //
+ // Treat append the same as write.
+ //
+
+ if ( DesiredAccess & FILE_APPEND_DATA) {
+
+ lDesiredAccess = DesiredAccess | FILE_WRITE_DATA;
+
+ } else {
+
+ lDesiredAccess = DesiredAccess;
+
+ }
+
+ switch ( lDesiredAccess & (FILE_EXECUTE | FILE_WRITE_DATA | FILE_READ_DATA) ) {
+
+ case (FILE_EXECUTE | FILE_WRITE_DATA | FILE_READ_DATA):
+ case (FILE_EXECUTE | FILE_WRITE_DATA):
+ NwShareFlags |= NW_OPEN_EXCLUSIVE | NW_OPEN_FOR_WRITE | NW_OPEN_FOR_READ;
+ break;
+
+ case (FILE_EXECUTE | FILE_READ_DATA):
+ case (FILE_EXECUTE):
+ NwShareFlags |= NW_OPEN_EXCLUSIVE | NW_OPEN_FOR_READ;
+ break;
+
+ case (FILE_WRITE_DATA | FILE_READ_DATA):
+ NwShareFlags |= NW_OPEN_FOR_WRITE | NW_OPEN_FOR_READ;
+ break;
+
+ case (FILE_WRITE_DATA):
+ NwShareFlags |= NW_OPEN_FOR_WRITE;
+ break;
+
+ default:
+ NwShareFlags |= NW_OPEN_FOR_READ;
+ break;
+ }
+
+ if (NwShareFlags & NW_OPEN_EXCLUSIVE) {
+
+ //
+ // Remove the NW_DENY_* flags if exclusive is already specified since
+ // this interferes with the shareable flag.
+ //
+
+ return( NwShareFlags & ~(NW_DENY_READ | NW_DENY_WRITE) );
+ }
+
+ return( NwShareFlags );
+}
+
+
+UCHAR
+NtAttributesToNwAttributes(
+ ULONG FileAttributes
+ )
+/*++
+
+Routine Description:
+
+ This routine maps a NT attributes mask to a Netware mask.
+
+Arguments:
+
+ DesiredAccess - Desired access for open as specified in the read IRP.
+
+Return Value:
+
+ Netware share mode.
+
+--*/
+{
+ return( (UCHAR)FileAttributes & 0x3F );
+}
+
+NTSTATUS
+pNwErrorToNtStatus(
+ UCHAR NwError
+ )
+/*++
+
+Routine Description:
+
+ This routine converts a Netware error code to an NT status code.
+
+Arguments:
+
+ NwError - The netware error.
+
+Return Value:
+
+ NTSTATUS - The converted status.
+
+--*/
+
+{
+ int i;
+
+ ASSERT(NwError != 0);
+
+ //
+ // Errors 2 through 127 are mapped as DOS errors.
+ //
+
+ if ( NwError > 1 && NwError < 128 ) {
+ return( BASE_DOS_ERROR + NwError );
+ }
+
+ //
+ // For other errors, search the table for the matching error number.
+ //
+
+ for ( i = 0; i < NUM_ERRORS; i++ ) {
+ if ( Error_Map[i].NetError == NwError ) {
+ return( Error_Map[i].ResultingStatus );
+ }
+ }
+
+ DebugTrace( 0, 0, "No error mapping for error %d\n", NwError );
+
+#ifdef NWDBG
+ Error( EVENT_NWRDR_NETWORK_ERROR, (NTSTATUS)0xC0010000 | NwError, NULL, 0, 0 );
+#endif
+
+ return( (NTSTATUS)0xC0010000 | NwError );
+}
+
+NTSTATUS
+NwBurstResultToNtStatus(
+ ULONG Result
+ )
+/*++
+
+Routine Description:
+
+ This routine converts a Netware burst result code to an NT status code.
+
+Arguments:
+
+ Result - The netware burst result.
+
+Return Value:
+
+ NTSTATUS - The converted status.
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ //
+ // the 3 high order bits should not be set. but if they are,
+ // we return an error.
+ //
+ if (Result & 0xFFFFFF00)
+ return( STATUS_UNEXPECTED_NETWORK_ERROR );
+
+ switch ( Result ) {
+
+ case 0:
+ case 3: // No data
+ Status = STATUS_SUCCESS;
+ break;
+
+ case 1:
+ Status = STATUS_DISK_FULL;
+ break;
+
+ case 2: // I/O error
+ Status = STATUS_UNEXPECTED_IO_ERROR;
+ break;
+
+ default:
+ Status = NwErrorToNtStatus( (UCHAR)Result );
+ break;
+ }
+
+ return( Status );
+}
+
+NTSTATUS
+NwConnectionStatusToNtStatus(
+ UCHAR NwStatus
+ )
+/*++
+
+Routine Description:
+
+ This routine converts a Netware connection status code to an NT
+ status code.
+
+Arguments:
+
+ NwStatus - The netware connection status.
+
+Return Value:
+
+ NTSTATUS - The converted status.
+
+--*/
+
+{
+ if ( (NwStatus & 1) == 0 ) {
+ return STATUS_SUCCESS;
+ } else {
+ return STATUS_REMOTE_DISCONNECT;
+ }
+}
+
+LARGE_INTEGER
+NwDateTimeToNtTime (
+ IN USHORT UDate,
+ IN USHORT UTime
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts an NCP time to an NT time structure.
+
+Arguments:
+
+ Time - Supplies the time of day to convert
+ Date - Supplies the day of the year to convert
+
+Return Value:
+
+ LARGE_INTEGER - Time structure describing input time.
+
+--*/
+
+{
+ TIME_FIELDS TimeFields;
+ LARGE_INTEGER OutputTime;
+ NCP_DATE Date = *(NCP_DATE *)&UDate;
+ NCP_TIME Time = *(NCP_TIME *)&UTime;
+
+ if ( Date.Ushort == 0 && Time.Ushort == 0 ) {
+
+ //
+ // The file time stamp is zero. Do not return a file time of
+ // zero, since this will be biased to a negative time (due to
+ // time zone fixup), and no one will be able to display it
+ // correctly. Instead, we "randomly" pick Jan 01, 1980 @ 12:00am
+ // as the file time.
+ //
+ // We assume that the netware server is in our time zone.
+
+ RtlSecondsSince1980ToTime(0, &OutputTime);
+
+ } else {
+
+ TimeFields.Year = Date.Struct.Year + (USHORT )1980;
+ TimeFields.Month = Date.Struct.Month;
+ TimeFields.Day = Date.Struct.Day;
+
+ TimeFields.Hour = Time.Struct.Hours;
+ TimeFields.Minute = Time.Struct.Minutes;
+ TimeFields.Second = Time.Struct.TwoSeconds*(USHORT )2;
+ TimeFields.Milliseconds = 0;
+
+ //
+ // Make sure that the times specified in the packet are reasonable
+ // before converting them.
+ //
+
+ if (TimeFields.Year < 1601) {
+ TimeFields.Year = 1601;
+ }
+
+ if (TimeFields.Month > 12) {
+ TimeFields.Month = 12;
+ }
+
+ if (TimeFields.Hour >= 24) {
+ TimeFields.Hour = 23;
+ }
+
+ if (TimeFields.Minute >= 60) {
+ TimeFields.Minute = 59;
+ }
+
+ if (TimeFields.Second >= 60) {
+ TimeFields.Second = 59;
+ }
+
+ if (!RtlTimeFieldsToTime(&TimeFields, &OutputTime)) {
+
+ OutputTime.QuadPart = 0;
+ return OutputTime;
+ }
+
+ }
+
+ // Convert to UTC for the system.
+ ExLocalTimeToSystemTime(&OutputTime, &OutputTime);
+ return OutputTime;
+
+}
+
+NTSTATUS
+NwNtTimeToNwDateTime (
+ IN LARGE_INTEGER NtTime,
+ IN PUSHORT NwDate,
+ IN PUSHORT NwTime
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts an NT time structure to an NCP time.
+
+Arguments:
+
+ NtTime - Supplies to NT Time to convert.
+
+ NwDate - Returns the Netware format date.
+
+ NwTime - Returns the Netware format time.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+ TIME_FIELDS TimeFields;
+ NCP_DATE Date;
+ NCP_TIME Time;
+
+ if (NtTime.QuadPart == 0) {
+
+ Time.Ushort = Date.Ushort = 0;
+
+ } else {
+
+ LARGE_INTEGER LocalTime;
+
+ // We assume that the netware server is in our time zone.
+
+ ExSystemTimeToLocalTime( &NtTime, &LocalTime );
+ RtlTimeToTimeFields( &LocalTime, &TimeFields );
+
+ if (TimeFields.Year < 1980 || TimeFields.Year > (1980 + 127) ) {
+ return( STATUS_INVALID_PARAMETER );
+ }
+
+ Date.Struct.Year = (USHORT )(TimeFields.Year - 1980);
+ Date.Struct.Month = TimeFields.Month;
+ Date.Struct.Day = TimeFields.Day;
+
+ Time.Struct.Hours = TimeFields.Hour;
+ Time.Struct.Minutes = TimeFields.Minute;
+
+ //
+ // When converting from a higher granularity time to a lesser
+ // granularity time (seconds to 2 seconds), always round up
+ // the time, don't round down.
+ //
+
+ Time.Struct.TwoSeconds = TimeFields.Second / 2;
+
+ }
+
+ *NwDate = *( USHORT *)&Date;
+ *NwTime = *( USHORT *)&Time;
+ return( STATUS_SUCCESS );
+}
+