/*++

Copyright (c) 1990  Microsoft Corporation

Module Name:

    setlink.c

Abstract:

    Utility to display or change the value of a symbolic link.

Author:

    Darryl E. Havens    (DarrylH)   9-Nov-1990

Revision History:


--*/

#include <nt.h>
#include <ntrtl.h>
#include <stdio.h>

BOOLEAN
_CRTAPI1 main(
    IN ULONG argc,
    IN PCHAR argv[]
    )
{
    NTSTATUS Status;
    STRING AnsiString;
    UNICODE_STRING LinkName;
    UNICODE_STRING LinkValue;
    HANDLE Handle;
    OBJECT_ATTRIBUTES ObjectAttributes;
    WCHAR Buffer[256];
    PWSTR s;
    ULONG ReturnedLength;

    //
    // Check to see whether or not this utility was invoked with the correct
    // number of parameters.  If not, bail out now.
    //

    ConvertAppToOem( argc, argv );
    if (argc < 2 || argc > 3) {
        printf( "Useage:  setlink symbolic-link-name [symbolic-link-value]\n" );
        return FALSE;
    }

    //
    // Begin by attempting to open the existing symbolic link name specified.
    //

    RtlInitString( &AnsiString, argv[1] );
    Status = RtlAnsiStringToUnicodeString( &LinkName,
                                           &AnsiString,
                                           TRUE );
    ASSERT( NT_SUCCESS( Status ) );
    InitializeObjectAttributes( &ObjectAttributes,
                                &LinkName,
                                OBJ_CASE_INSENSITIVE,
                                (HANDLE) NULL,
                                (PSECURITY_DESCRIPTOR) NULL );
    Status = NtOpenSymbolicLinkObject( &Handle,
                                       argc == 2 ? SYMBOLIC_LINK_QUERY :
                                                   SYMBOLIC_LINK_ALL_ACCESS,
                                       &ObjectAttributes );

    //
    // Determine what should be done based on the number of parameters that
    // were given to the program.
    //

    if (argc == 2) {

        //
        // Only one parameter was specified, so display the value of the
        // symbolic link if it exists.
        //

        if (!NT_SUCCESS( Status )) {
            printf( "Symbolic link %wZ does not exist\n", &LinkName );
            return FALSE;
        } else {
            LinkValue.Length = 0;
            LinkValue.MaximumLength = sizeof( Buffer );
            LinkValue.Buffer = Buffer;
            ReturnedLength = 0;
            Status = NtQuerySymbolicLinkObject( Handle,
                                                &LinkValue,
                                                &ReturnedLength
                                              );
            NtClose( Handle );
            if (!NT_SUCCESS( Status )) {
                printf( "Error reading symbolic link %wZ\n", &LinkName );
                printf( "Error status was:  %X\n", Status );
                return FALSE;
            } else {
                printf( "Value of %wZ => %wZ", &LinkName, &LinkValue );
                s = LinkValue.Buffer + ((LinkValue.Length / sizeof( WCHAR )) + 1);
                while (ReturnedLength > LinkValue.MaximumLength) {
                    printf( " ; %ws", s );
                    while (*s++) {
                        ReturnedLength -= 2;
                        }
                    ReturnedLength -= 2;
                    }
                printf( "\n", s );
                return TRUE;
            }
        }

    } else {

        //
        // Three parameters were supplied, so assign a new value to the
        // symbolic link if it exists by first deleting the existing link
        // (mark it temporary and close the handle).  If it doesn't exist
        // yet, then it will simply be created.
        //

        if (NT_SUCCESS( Status )) {
            Status = NtMakeTemporaryObject( Handle );
            if (NT_SUCCESS( Status )) {
                NtClose( Handle );
            }
        }
    }

    //
    // Create a new value for the link.
    //

    ObjectAttributes.Attributes |= OBJ_PERMANENT;
    RtlInitString( &AnsiString, argv[2] );
    Status = RtlAnsiStringToUnicodeString( &LinkValue,
                                           &AnsiString,
                                           TRUE );
    Status = NtCreateSymbolicLinkObject( &Handle,
                                         SYMBOLIC_LINK_ALL_ACCESS,
                                         &ObjectAttributes,
                                         &LinkValue );
    if (!NT_SUCCESS( Status )) {
        printf( "Error creating symbolic link %wZ => %wZ\n",
                 &LinkName,
                 &LinkValue );
        printf( "Error status was:  %X\n", Status );
    } else {
        NtClose( Handle );
    }

    return TRUE;
}