/*++ Copyright (c) 1991 Microsoft Corporation Module Name: tea.c Abstract: This module contains code which makes a simple ea call. Note: as an expedient, this program mixes Nt and Win32 calls on the same handle. Do not do this in production code. Author: Colin Watson (ColinW) 13-Mar-1991 Environment: Application mode Revision History: --*/ #ifdef UNICODE #undef UNICODE #pragma message("Disabling unicode"); #endif #include #include #include #include #include typedef struct _TEA_FILE_FULL_EA_INFORMATION { ULONG NextEntryOffset; UCHAR Flags; UCHAR EaNameLength; USHORT EaValueLength; CHAR EaName[2]; // 1 letter name followed by null CHAR EaValue[6]; } TEA_FILE_FULL_EA_INFORMATION, *PTEA_FILE_FULL_EA_INFORMATION; void dump( PVOID far_p, ULONG len ); VOID HexDumpLine ( PCHAR pch, ULONG len, PCHAR s, PCHAR t, USHORT flag ); VOID usage ( VOID ) { printf("usage: tea [-d][-q][-s][-c] \n"); printf(" -d specifies a directory instead of a file \n"); printf(" -p specifies attempt path based access\n"); printf(" -q specifies query the eas\n"); printf(" -s specifies set an ea\n"); printf(" -c specifies create a file with an ea \n"); printf(" is up to 128 bytes long.\n"); } int main (argc, argv) int argc; char *argv[]; { int i; CHAR Name[128]; BOOLEAN q=FALSE; BOOLEAN s=FALSE; BOOLEAN c=FALSE; BOOLEAN d=FALSE; BOOLEAN p=FALSE; HANDLE FileHandle; NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; FILE_EA_INFORMATION EaInformation; // // parse the switches // for (i=1;i sizeof(Name)-1 ) { usage(); return 1; } RtlCopyMemory ( Name, argv[i], lstrlen( argv[i] )+1); } } // Must create, set or query if ( c==FALSE && q==FALSE && s==FALSE) { usage (); return 1; } // Only allowed to set one of query, set or create if (( c==TRUE && ( q==TRUE || s==TRUE)) || ( q==TRUE && s==TRUE )) { usage (); return 1; } if ( c == TRUE ) { OBJECT_ATTRIBUTES Obja; ANSI_STRING AnsiString; UNICODE_STRING FileName; UNICODE_STRING Unicode; BOOLEAN TranslationStatus; RTL_RELATIVE_NAME RelativeName; static TEA_FILE_FULL_EA_INFORMATION NewEas[] = {{ 16, 0, 1, 6, "a", "aaaaa"}, { 0, 0, 1, 6, "b", "bbbbb"}}; printf( "Create %s\n", Name ); dump( NewEas, sizeof(NewEas) ); // Use Nt Api to add the Ea's RtlInitAnsiString(&AnsiString,Name); Status = RtlAnsiStringToUnicodeString(&Unicode,&AnsiString, TRUE); if ( !NT_SUCCESS(Status) ) { printf( "RtlAnsiStringToUnicodeString returned %X\n", Status); return 1; } TranslationStatus = RtlDosPathNameToNtPathName_U( Unicode.Buffer, &FileName, NULL, &RelativeName ); if ( !TranslationStatus ) { printf( "RtlDosPathNameToNtPathName returned FALSE\n"); return 1; } if ( RelativeName.RelativeName.Length ) { FileName = *(PUNICODE_STRING)&RelativeName.RelativeName; } else { RelativeName.ContainingDirectory = NULL; } InitializeObjectAttributes( &Obja, &FileName, OBJ_CASE_INSENSITIVE, RelativeName.ContainingDirectory, NULL ); if ( d == TRUE ) { Status = NtCreateFile( &FileHandle, FILE_LIST_DIRECTORY | SYNCHRONIZE, &Obja, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_CREATE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NewEas, sizeof(NewEas) ); } else { Status = NtCreateFile( &FileHandle, SYNCHRONIZE | GENERIC_WRITE | FILE_READ_ATTRIBUTES, &Obja, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_SUPERSEDE, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY, NewEas, sizeof(NewEas) ); } printf( "NtCreateFile on %s returned %X\n", Name, Status ); NtClose(FileHandle); } if ( s == TRUE ) { ACCESS_MASK Access = ( p == TRUE || d == TRUE ) ? SYNCHRONIZE | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA : SYNCHRONIZE | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_WRITE_DATA; OBJECT_ATTRIBUTES Obja; ANSI_STRING AnsiString; UNICODE_STRING FileName; UNICODE_STRING Unicode; BOOLEAN TranslationStatus; RTL_RELATIVE_NAME RelativeName; printf( "Create %s\n", Name ); // Use Nt Api to add the Ea's RtlInitAnsiString(&AnsiString,Name); Status = RtlAnsiStringToUnicodeString(&Unicode,&AnsiString, TRUE); if ( !NT_SUCCESS(Status) ) { printf( "RtlAnsiStringToUnicodeString returned %X\n", Status); return 1; } TranslationStatus = RtlDosPathNameToNtPathName_U( Unicode.Buffer, &FileName, NULL, &RelativeName ); if ( !TranslationStatus ) { printf( "RtlDosPathNameToNtPathName returned FALSE\n"); return 1; } if ( RelativeName.RelativeName.Length ) { FileName = *(PUNICODE_STRING)&RelativeName.RelativeName; } else { RelativeName.ContainingDirectory = NULL; } InitializeObjectAttributes( &Obja, &FileName, OBJ_CASE_INSENSITIVE, RelativeName.ContainingDirectory, NULL ); Status = NtCreateFile( &FileHandle, Access, &Obja, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_OPEN, ( d == TRUE) ? FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT : FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY, NULL, 0 ); printf( "NtCreateFile on %s returned %X\n", Name, Status ); printf( "Setting Ea on %s\n", Name ); { static TEA_FILE_FULL_EA_INFORMATION NewEas[] = {{ 16, 0, 1, 6, "a", "avalue"}, { 0, 0, 1, 6, "c", "cvalue"}}; printf( "Set Eas on %s:\n", Name ); dump( NewEas, sizeof(NewEas) ); Status=NtSetEaFile( FileHandle, &IoStatusBlock, NewEas, sizeof(NewEas) ); printf( "Set Eas returned %X\n", Status ); } NtClose( FileHandle ); } if ( q == TRUE ) { CHAR Buffer[256]; ACCESS_MASK Access = (p == TRUE ) ? SYNCHRONIZE | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | FILE_READ_EA : SYNCHRONIZE | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA; OBJECT_ATTRIBUTES Obja; ANSI_STRING AnsiString; UNICODE_STRING FileName; UNICODE_STRING Unicode; BOOLEAN TranslationStatus; RTL_RELATIVE_NAME RelativeName; printf( "Create %s\n", Name ); // Use Nt Api to add the Ea's RtlInitAnsiString(&AnsiString,Name); Status = RtlAnsiStringToUnicodeString(&Unicode,&AnsiString, TRUE); if ( !NT_SUCCESS(Status) ) { printf( "RtlAnsiStringToUnicodeString returned %X\n", Status); return 1; } TranslationStatus = RtlDosPathNameToNtPathName_U( Unicode.Buffer, &FileName, NULL, &RelativeName ); if ( !TranslationStatus ) { printf( "RtlDosPathNameToNtPathName returned FALSE\n"); return 1; } if ( RelativeName.RelativeName.Length ) { FileName = *(PUNICODE_STRING)&RelativeName.RelativeName; } else { RelativeName.ContainingDirectory = NULL; } InitializeObjectAttributes( &Obja, &FileName, OBJ_CASE_INSENSITIVE, RelativeName.ContainingDirectory, NULL ); Status = NtCreateFile( &FileHandle, Access, &Obja, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_OPEN, ( d == TRUE) ? FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT : FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY, NULL, 0 ); printf( "NtCreateFile on %s returned %X\n", Name, Status ); printf( "Query Eas on %s\n", Name ); Status=NtQueryEaFile( FileHandle, &IoStatusBlock, Buffer, sizeof(Buffer), FALSE, // ReturnSingleEntry, NULL, // EaList OPTIONAL, 0, // EaListLength, 0, // EaIndex OPTIONAL, FALSE // BOOLEAN RestartScan ); dump( Buffer, IoStatusBlock.Information ); printf( "Query All Eas on %s returned %X\n", Name, Status ); Status = NtQueryInformationFile( FileHandle, &IoStatusBlock, &EaInformation, sizeof(EaInformation), FileEaInformation); if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatusBlock.Status)) { printf("QueryEaInformation failed: %X (%X)\n", Status, IoStatusBlock.Status); exit(1); } printf("Ea information: %ld\n", EaInformation.EaSize); NtClose( FileHandle ); printf( "Create %s\n", Name ); // Use Nt Api to add the Ea's Status = NtCreateFile( &FileHandle, Access, &Obja, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_OPEN, ( d == TRUE) ? FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT : FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY, NULL, 0 ); printf( "NtCreateFile on %s returned %X\n", Name, Status ); { /* typedef struct _FILE_GET_EA_INFORMATION { ULONG NextEntryOffset; UCHAR EaNameLength; CHAR EaName[1]; } FILE_GET_EA_INFORMATION, *PFILE_GET_EA_INFORMATION; */ static FILE_GET_EA_INFORMATION RequestedEas[]= {{ 8, 1, "b"}, { 0, 1, "c"}}; Status=NtQueryEaFile( FileHandle, &IoStatusBlock, Buffer, sizeof(Buffer), FALSE, // ReturnSingleEntry, RequestedEas, sizeof(RequestedEas), 0, // EaIndex OPTIONAL, FALSE // BOOLEAN RestartScan ); printf( "Query Ea subset on %s returned %X\n", Name, Status ); dump( Buffer, IoStatusBlock.Information ); Status = NtQueryInformationFile( FileHandle, &IoStatusBlock, &EaInformation, sizeof(EaInformation), FileEaInformation); if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatusBlock.Status)) { printf("QueryEaInformation failed: %X (%X)\n", Status, IoStatusBlock.Status); exit(1); } printf("Ea information: %ld\n", EaInformation.EaSize); } NtClose( FileHandle ); } printf( "Ending Tea\n" ); return 0; } /* * ndump_core: debug routine to print core */ void dump( PVOID far_p, ULONG len ) { ULONG l; char s[80], t[80]; PCHAR far_pchar = (PCHAR)far_p; ULONG MaxDump = 256; if (len > MaxDump) len = MaxDump; while (len) { l = len < 16 ? len : 16; printf("\n%lx ", far_pchar); HexDumpLine (far_pchar, l, s, t, 0); printf("%s%.*s%s", s, 1 + ((16 - l) * 3), "", t); len -= l; far_pchar += l; } printf("\n"); } VOID HexDumpLine ( PCHAR pch, ULONG len, PCHAR s, PCHAR t, USHORT flag ) { static UCHAR rghex[] = "0123456789ABCDEF"; UCHAR c; UCHAR *hex, *asc; hex = s; asc = t; *(asc++) = '*'; while (len--) { c = *(pch++); *(hex++) = rghex [c >> 4] ; *(hex++) = rghex [c & 0x0F]; *(hex++) = ' '; *(asc++) = (c < ' ' || c > '~') ? (CHAR )'.' : c; } *(asc++) = '*'; *asc = 0; *hex = 0; flag; }