www.delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2010/09/10/20:13:15

X-Recipient: archive-cygwin AT delorie DOT com
X-SWARE-Spam-Status: No, hits=0.0 required=5.0 tests=AWL,BAYES_50,RCVD_IN_DNSWL_NONE,TW_CP
X-Spam-Check-By: sourceware.org
X-USANET-Received: from gateout02.mbox.net [127.0.0.1] by gateout02.mbox.net via mtad (C8.MAIN.3.65C) with ESMTP id 323oikamr7024Mo2; Sat, 11 Sep 2010 00:12:43 -0000
X-USANET-Source: 165.212.120.254 IN aeolus AT electric-cloud DOT com s1hub3.EXCHPROD.USA.NET
X-USANET-MsgId: XID192oikamr5574Xo2
From: John Carey <aeolus AT electric-cloud DOT com>
To: "cygwin AT cygwin DOT com" <cygwin AT cygwin DOT com>
Date: Sat, 11 Sep 2010 00:12:42 +0000
Subject: RE: 1.7.5: Occasional failure of CreatePipe or signal handing due to thread-unsafe code in cwdstuff::set
Message-ID: <3C031C390CBF1E4A8CE1F74DE7ECAF3A158EDA704C@MBX8.EXCHPROD.USA.NET>
References: <3C031C390CBF1E4A8CE1F74DE7ECAF3A140684F0AA AT MBX8 DOT EXCHPROD DOT USA DOT NET> <20100811084926 DOT GC26152 AT calimero DOT vinschen DOT de> <3C031C390CBF1E4A8CE1F74DE7ECAF3A140684F0B0 AT MBX8 DOT EXCHPROD DOT USA DOT NET> <AANLkTimpBCKzUioEarGiKMQbTjN+6s9iDYm_zzZ2Lxr9 AT mail DOT gmail DOT com> <20100812081151 DOT GT14202 AT calimero DOT vinschen DOT de> <3C031C390CBF1E4A8CE1F74DE7ECAF3A158EDA702A AT MBX8 DOT EXCHPROD DOT USA DOT NET> <20100903073740 DOT GA1749 AT calimero DOT vinschen DOT de> <3C031C390CBF1E4A8CE1F74DE7ECAF3A158EDA702D AT MBX8 DOT EXCHPROD DOT USA DOT NET>,<20100904092626 DOT GE16534 AT calimero DOT vinschen DOT de>
In-Reply-To: <20100904092626.GE16534@calimero.vinschen.de>
MIME-Version: 1.0
X-IsSubscribed: yes
Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Id: <cygwin.cygwin.com>
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
Sender: cygwin-owner AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
Delivered-To: mailing list cygwin AT cygwin DOT com

--_002_3C031C390CBF1E4A8CE1F74DE7ECAF3A158EDA704CMBX8EXCHPRODU_
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable

On Sep 04 02:26 Corinna Vinschen wrote:
> On Sep  3 16:18, John Carey wrote:
> > On Sep 03 12:37 Corinna Vinschen wrote:
> > > On Sep  2 23:32, John Carey wrote:
> > > > In Aug 17 10:15, Corinna Vinschen wrote:
> > > > > I just released 1.7.6-1.
> > > > ...
> > > > > What changed since Cygwin 1.7.5:
> > > > > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> > > > >
> > > > > - Cygwin handles the current working directory entirely on its ow=
n.  The
> > > > >   Win32 current working directory is set to an invalid path to be=
 out of
> > > > >   the way.  This affects calls to the Win32 file API (CreateFile,=
 etc.).
> > > > >   See http://cygwin.com/htdocs/cygwin-ug-net/using.html#pathnames=
-win32-api
> > > >
> > > > Thank you very much for the fix!
> > > >
> > > > I've been running tests against Cygwin 1.7.6, and then 1.7.7,
> > > > and those sporadic, non-deterministic failures in CreatePipe
> > > > did stop after the 1.7.6 upgrade, and are still gone in 1.7.7.
> > > > I think it's been long enough to conclude that it is not just
> > > > the non-determinism--it really is fixed, as expected.
> > > >
> > > > I understand that this issue opened a can of worms;
> > > > thanks again for your efforts to overcome those difficulties.
> > >
> > > I still don't like the final workaround, which is, to set the Win32 C=
WD
> > > to the Cygwin CWD.  It would be nice if we could revert that change to
> > > the pre-1.7.6 behaviour in a Vista-friendly way.  If you ever find out
> > > how to make sure that the new handle in the PEB's user parameter block
> > > is used even on Vista and later, pray tell me.
> >
> > Thus far the only ideas I have come up with are somewhat
> > shaky and go well beyond the documented Win32 API.
> > (If only there was the equivalent of dup2(), but for Win32
> > handles!!!)
>
> ACK.
>
> > Just how much undocumented behavior is
> > tolerable, do you think?
>
> Up to XP/2K3, we can simply set the handle in the user parameter block
> and be done with it, just as in 1.7.5, but without the Vista workaround.
>
> The problem only starts with Vista.  I have no objections to use
> undocumented features, if they work.  If there's any way to replace the
> cwd handle with our own *and* keep the Win32 API happy, I'll take it.

I think I've found a way to open the directory handle for backup intent
on Vista and later versions.  Essentially, I emulate the new things that
SetCurrentDirectory() is doing, but in order to get the necessary
addresses, I have to do some very ugly hacks.

The proof-of-concept code follows (and is also attached).  It includes
an analysis of what is going on--to the extent that I know what is going
on, of course.  Please let me know what you think.

  - - - - - - BEGIN INCLUSION - - - - - - -

// Compile with Cygwin G++, and include a '-I' argument that
// specifies the "winsup" directory of the Cygwin source tree.
//
// Run with two arguments:
//
//   1. An absolute Windows path to a directory (can use forward slashes).
//
//   2. The relative name of a file within that directory.
//
// The purpose of this source code is to discuss Win32 CWD
// issues and to compile into a proof-of-concept program.
// Please read the interleaved comments.

#include <w32api/include/windows.h>
#include <w32api/include/ntdef.h>
#include <w32api/include/winnt.h>
#include <cygwin/ntdll.h>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <locale>
#include <string>

using namespace std;

/****************************************

Primary research was on Windows 7 x64, but there appears to be
at least superficial similarity on Windows 2008 (x32 and x64)
and Windows Vista (x32 and x64).

Let "Params" be an alias for *NtCurrentTeb ()->Peb->ProcessParameters.

Let "HeapHandle" be an alias for *(PVOID*)((char*)NtCurrentTeb ()->Peb + 0x=
18)
(which is the second 32-bit word after ProcessParameters.)

Let "DismountCount" be an alias for the user space mapping of
KUSER_SHARED_DATA::DismountCount: namely, *(ULONG*)0x7ffe02dc.
See: http://www.nirsoft.net/kernel_struct/vista/KUSER_SHARED_DATA.html

In the implementation of SetCurrentDirectory (),
Params.CurrentDirectoryName.MaximumLength is read but NOT modified.
Its value determines the sizes of various buffers, including the
new buffer that will hold the new current directory pathname.

The constant value we have observed for
Params.CurrentDirectoryName.MaximumLength
is 520, which is sizeof(wchar_t [MAX_PATH]).

In addition to the PEB, there is an allocated memory block describing
the current directory.  Its lifetime is controlled by thread-safe
reference counting.  Call its type "VistaCwd"; more details follow.

The PEB does NOT seem to point to any VistaCwd instances.  Instead,
there is a global pointer outside of the PEB, which we call "Cwd",
and it is protected by a critical section, which we call "CwdCS",
which is also outside of the PEB.  Apparently these globals are
in the ntdll.dll data space, but their symbols are not exported.
Later we will discuss how to compute their addresses.

NOTE: The SetCurrentDirectory () implementation appears to update the
Win32 CWD *without* locking the PEB as such.  It locks CwdCS instead.

Structure:

****************************************/

  struct VistaCwd {
    // Use bus-locked increment/decrement to adjust this reference count.
    // When the reference count drops to zero, destroy and deallocate.

    volatile LONG ReferenceCount;

    // The open handle to the current directory.

    HANDLE DirectoryHandle;

    // A snapshot of the global DismountCount, updated at various
    // times during the lifetime of this struct.  It appears that
    // reads of and writes to this member are locked by CwdCS,
    // except for initialization (see below).
    //
    // What is this member for?  Following things in a debugger,
    // it seems likely that whenever the current VistaCwd is used,
    // its current value of OldDismountCount is compared against the
    // current (or perhaps slightly stale?) value of DismountCount,
    // and if it does not match then some extra action is taken.
    // Such extra action seems to include checking if the volume
    // is mounted.
    //
    // Presumably the global DismountCount increases monotonically.
    // Reads of the global DismountCount appear to be unlocked.
    // If a stale value is stored in OldDismountCount, then it
    // may be harmless in the sense that it just fails to prevent
    // unnecessary computation later.  But a stale read during
    // a comparison with OldDismountCount could prevent the extra
    // actions, which could be more serious.  At a guess, that
    // problem is prevented by the following code structure,
    // observed in at least one place that uses the CWD setting:
    // the value of OldDismountCount is read under a CwdCS lock,
    // and only *after* that lock is released is the global
    // DismountCount read.  The lock-unlock probably flushes
    // writes to the global DismountCount.

    ULONG OldDismountCount;

    // The path of the current directory.  Always ends in a backslash;
    // one is appended if the given path did not already end in one.
    //
    // The "MaximumLength" and "Buffer" members always specify the size
    // and starting address of the "Buffer" sibling member (see below).

    UNICODE_STRING Path;

    // The actual size of this member, and therefore of the struct as
    // a whole, is computed dynamically so that this member has the
    // same size as the previous value of
    //
    //   Params.CurrentDirectoryName.MaximumLength
    //
    // But since SetCurrentDirectory () never seems to modify that
    // PEB datum, in practice the dimension is always MAX_PATH.

    wchar_t Buffer[MAX_PATH];
  };

/****************************************

Allocation:

Before modifying the PEB data, the implementation
of SetCurrentDirectory () allocates a new instance
of VistaCwd, as follows:

    RtlAllocateHeap (HeapHandle, 0,
      offsetof (VistaCwd, Buffer) + Params.CurrentDirectoryName.MaximumLeng=
th);

Initialization:

The SetCurrentDirectory () implementation
then initializes that instance as follows:

  // Read DismountCount before calling NtOpenFile().
  // If the relative order matters at all, then it is
  // probably following the general principle that
  // a stale value copied from DismountCount to the
  // OldDismountCount member (see below) just causes
  // extra work but is otherwise harmless, whereas
  // a too-recent value might prevent necessary work.

  ULONG DismountCountBeforeNtOpenFile =3D DismountCount;

  ReferenceCount =3D 1;

  DirectoryHandle =3D NtOpenFile (...);

  // NOTE: There is no locking around this initialization.
  // But the SetCurrentDirectory () implementation locks CwdCS
  // while updating Cwd to point to new instances of VistaCwd,
  // and presumably that suffices to flush this initialization
  // to other CPUs.  Other threads would not see the new VistaCwd
  // instance before that point.  As mentioned before, copying of
  // a stale value of the global DismountCount is probably harmless,
  // in that it would merely trigger an unnecessary update.

  OldDismountCount =3D DismountCountBeforeNtOpenFile;

  // The length of the path in bytes, not counting the terminator.

  Path.Length =3D ...;

  // As mentioned before, in practice this is sizeof(wchar_t [MAX_PATH]).

  Path.MaximumLength =3D Params.CurrentDirectoryName.MaximumLength;

  Path.Buffer =3D Buffer;

  // The wide path for the directory; if necessary a backslash is
  // appended so that the final character (before the terminator)
  // is always a backslash.

  memcpy (Buffer, ...);
  Buffer[Path.Length / sizeof(wchar_t)] =3D L'\0';

Usage:

After creating the new VistaCwd instance; call it newCwd, the
SetCurrentDirectory () implementation modifies the PEB and Cwd
under a lock on CwdCS, as follows:

  Params.CurrentDirectoryHandle =3D newCwd.DirectoryHandle;

  Params.CurrentDirectoryName.Buffer =3D newCwd.Path.Buffer;

  Params.CurrentDirectoryName.Length =3D newCwd.Path.Length;

  VistaCwd *oldCwd =3D Cwd;

  Cwd =3D newCwd;

Note that as mentioned before,
Params.CurrentDirectoryName.MaximumLength
is NOT modified.

Cleanup:

After the SetCurrentDirectory () implementation releases
its lock on CwdCS, it performs a bus-locked decrement on
oldCwd->ReferenceCount (unless oldCwd =3D=3D NULL).  If the
result is zero, it then destroys and deallocates the
old VistaCwd instance as follows:

  NtClose (oldCwd->DirectoryHandle);

  RtlFreeHeap (HeapHandle, 0, oldCwd);

Addresses of Cwd and CwdCS:

In order to imitate the way in which SetCurrentDirectory () updates
the Win32 CWD data, we must learn the addresses of Cwd and CwdCS.

The following program performs code analysis to discover those.
It then changes the Win32 CWD directly and tests the result
with a relative CreateFile ().  It is intended as
a quick-and-dirty stand-alone proof-of-concept program;
final code to be included in cygwin1.dll would differ greatly.

****************************************/

typedef unsigned char code_t;

unsigned peek32 (const unsigned char *p)
{
  return p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
}

void badCode ()
{
  cerr << "Code looks different than expected; bailing out." << endl;
  exit (1);
}

ostream& winError (ostream& os, DWORD code =3D GetLastError())
{
  LPSTR msg =3D 0;
  if (FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM
                      | FORMAT_MESSAGE_ALLOCATE_BUFFER,
                      0,
                      code,
                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                      (LPSTR)&msg,
                      1,
                      NULL)) {
    os << "error " << code << ": " << msg;
    LocalFree (msg);
  } else {
    os << "???";
  }
  return os;
}

#define DDKAPI __stdcall

typedef CONST char *PCSZ;

typedef
NTSTATUS
DDKAPI
(* NtClose_t)(
  /*IN*/ HANDLE  Handle);

typedef
NTSTATUS
DDKAPI
(* NtOpenFile_t) (
  /*OUT*/ PHANDLE  FileHandle,
  /*IN*/ ACCESS_MASK  DesiredAccess,
  /*IN*/ POBJECT_ATTRIBUTES  ObjectAttributes,
  /*OUT*/ PIO_STATUS_BLOCK  IoStatusBlock,
  /*IN*/ ULONG  ShareAccess,
  /*IN*/ ULONG  OpenOptions);

typedef
PVOID
NTAPI
(* RtlAllocateHeap_t) (
  /*IN*/ HANDLE  HeapHandle,
  /*IN*/ ULONG   Flags,
  /*IN*/ ULONG   Size
);

typedef
BOOLEAN
NTAPI
(* RtlFreeHeap_t) (
  /*IN*/ HANDLE  HeapHandle,
  /*IN*/ ULONG   Flags,
  /*IN*/ PVOID   P
);

typedef
VOID
DDKAPI
(* RtlInitString_t) (
  /*IN OUT*/ PSTRING  DestinationString,
  /*IN*/ PCSZ  SourceString);

typedef
NTSTATUS
DDKAPI
(* RtlAnsiStringToUnicodeString_t) (
  /*IN OUT*/ PUNICODE_STRING  DestinationString,
  /*IN*/ PANSI_STRING  SourceString,
  /*IN*/ BOOLEAN  AllocateDestinationString);

typedef
VOID
DDKAPI
(* RtlFreeUnicodeString_t) (
  /*IN*/ PUNICODE_STRING  UnicodeString);

typedef
NTSTATUS
DDKAPI
(* RtlUnicodeStringToAnsiString_t)(
  /*IN OUT*/ PANSI_STRING  DestinationString,
  /*IN*/ PUNICODE_STRING  SourceString,
  /*IN*/ BOOLEAN  AllocateDestinationString);

typedef
VOID
DDKAPI
(* RtlFreeAnsiString_t)(
  /*IN*/ PANSI_STRING  AnsiString);

#define NTFUNC_DECL(F) F ## _t _ ## F

struct NtFuncs
{
  NTFUNC_DECL(NtClose);
  NTFUNC_DECL(NtOpenFile);
  NTFUNC_DECL(RtlAllocateHeap);
  NTFUNC_DECL(RtlFreeHeap);
  NTFUNC_DECL(RtlInitString);
  NTFUNC_DECL(RtlAnsiStringToUnicodeString);
  NTFUNC_DECL(RtlFreeUnicodeString);
  NTFUNC_DECL(RtlUnicodeStringToAnsiString);
  NTFUNC_DECL(RtlFreeAnsiString);

  NtFuncs(HMODULE module);
};

#define NTFUNC_BIND(M, F) _ ## F =3D (F ## _t) GetProcAddress(M, # F)

NtFuncs::NtFuncs(HMODULE module)
{
  NTFUNC_BIND(module, NtClose);
  NTFUNC_BIND(module, NtOpenFile);
  NTFUNC_BIND(module, RtlAllocateHeap);
  NTFUNC_BIND(module, RtlFreeHeap);
  NTFUNC_BIND(module, RtlInitString);
  NTFUNC_BIND(module, RtlAnsiStringToUnicodeString);
  NTFUNC_BIND(module, RtlFreeUnicodeString);
  NTFUNC_BIND(module, RtlUnicodeStringToAnsiString);
  NTFUNC_BIND(module, RtlFreeAnsiString);
}

void modifiedSetCurrentDirectory (
    const NtFuncs& nt,
    CRITICAL_SECTION *CwdCS,
    VistaCwd **Cwd,
    UNICODE_STRING& upath)
{
  // The real SetCurrentDirectory () implementation calls
  // a non-exported function that appears to expand relative
  // paths to absolute paths and convert / to \.  It might
  // also do other things.
  //
  // There appear to be no locks on the PEB or Cwd that
  // persist between this conversion and the actual Win32
  // CWD change, so presumably the following race is possible:
  //
  //   1. Thread A calls SetCurrentDirectory("C:\\a\\b").
  //
  //   2. Thread A creates Thread B.
  //
  //   3. Thread A starts calling SetCurrentDirectory("..")
  //      and gets through relative-to-absolute conversion,
  //      yielding "C:\\a" as the desired CWD.
  //
  //   4. Thread B calls SetCurrentDirectory("C:\\d\\e").
  //
  //   5. Thread A acquires CwdCS and sets Cwd to a new
  //      VistaCwd instance that specifies "C:\\a".
  //
  // Holding a lock between (3) and (5) would force
  // (4) to come either before (3) or after (5), but
  // there would still be a race: if (4) comes first,
  // then the final CWD is "C:\\d", whereas if (4)
  // comes last, then the final CWD is "C:\\d\\e".
  // Probably that is why no lock is held: it would
  // increase contention but not eliminate races.
  //
  // On the other hand, it appears that at least some
  // other versions of Windows that do not use the
  // VistaCwd mechanism, such as Windows Server 2003 R2 x64,
  // might actually acquire a lock before relative-to-absolute
  // path conversion.  Perhaps Microsoft rethought the races
  // when they changed to the newer mechanism?
  //
  // Anyway, the output of relative-to-absolute conversion
  // is run through another, non-exported path conversion
  // function that prefixes \??\ and presumably does
  // other normalizations appropriate to such paths.
  // However, that special form is used only as an argument
  // to NtOpenFile()--it does NOT get put into the new
  // VistaCwd instance.  Instead, the VistaCwd instance
  // gets a separate copy of the output of the
  // relative-to-absolute conversion, and in this copy only,
  // a backslash is appended if the absolute path did not
  // already end in a backslash.
  //
  // In this implementation we do not bother to perform
  // the relative-to-absolute path conversion; instead
  // we just warn if the path is not absolute.
  // But we do convert / to \.

  replace (upath.Buffer, upath.Buffer + upath.Length / sizeof(wchar_t),
           L'/', L'\\');
  if (upath.Length < 3 || upath.Buffer[1] !=3D L':' || upath.Buffer[2] !=3D=
 L'\\'){
    cerr << "Relative paths not implemented." << endl;
    exit (1);
  }

  // Prefix \??\ to the path before passing it to NtOpenFile().
  if (upath.Length > (MAX_PATH - 5) * sizeof(wchar_t)) {
    cerr << "Path too long." << endl;
    exit(1);
  }
  wchar_t ntupath_buf[MAX_PATH];
  UNICODE_STRING ntupath;
  ntupath.Length =3D upath.Length + 4 * sizeof(wchar_t);
  ntupath.MaximumLength =3D sizeof ntupath_buf;
  ntupath.Buffer =3D ntupath_buf;
  memcpy(ntupath_buf, L"\\??\\", 4 * sizeof(wchar_t));
  memcpy(ntupath_buf + 4, upath.Buffer, upath.Length);
  ntupath_buf[4 + (upath.Length / sizeof(wchar_t))] =3D L'\0';

  RTL_USER_PROCESS_PARAMETERS& Params
    =3D *NtCurrentTeb ()->Peb->ProcessParameters;

  PVOID HeapHandle =3D *(PVOID*)((char*)NtCurrentTeb ()->Peb + 0x18);

  volatile ULONG& DismountCount =3D *(volatile ULONG*)0x7ffe02dc;

  // Do this before the NtOpenFile, just in case that order matters.

  ULONG DismountCountBeforeNtOpenFile =3D DismountCount;

  HANDLE h;
  NTSTATUS status;
  IO_STATUS_BLOCK io;
  OBJECT_ATTRIBUTES attr;

  InitializeObjectAttributes (&attr, &ntupath,
                              OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
                              NULL, NULL);
  status =3D nt._NtOpenFile (&h, SYNCHRONIZE | FILE_TRAVERSE, &attr, &io,
                           FILE_SHARE_VALID_FLAGS,
                           FILE_DIRECTORY_FILE
                           | FILE_SYNCHRONOUS_IO_NONALERT
                           | FILE_OPEN_FOR_BACKUP_INTENT);
  if (!NT_SUCCESS (status))
  {
    ANSI_STRING narrow;
    nt._RtlUnicodeStringToAnsiString(&narrow, &ntupath, TRUE);

    cerr << "Failed to open directory '";
    cerr.write(narrow.Buffer, narrow.Length);
    cerr << "': NTSTATUS " << showbase << hex << status << endl;

    nt._RtlFreeAnsiString(&narrow);

    exit(1);
  }

  // As mentioned before, in practice this is sizeof (wchar_t [MAX_PATH]).

  USHORT MaximumLength =3D Params.CurrentDirectoryName.MaximumLength;

  VistaCwd *newCwd =3D (VistaCwd *) nt._RtlAllocateHeap (HeapHandle, 0,
      offsetof (VistaCwd, Buffer) + MaximumLength);

  newCwd->ReferenceCount =3D 1;

  newCwd->DirectoryHandle =3D h;

  newCwd->OldDismountCount =3D DismountCountBeforeNtOpenFile;

  newCwd->Path.Length =3D upath.Length;

  newCwd->Path.MaximumLength =3D MaximumLength;

  newCwd->Path.Buffer =3D newCwd->Buffer;

  memcpy (newCwd->Buffer, upath.Buffer, upath.Length);
  newCwd->Buffer[upath.Length / sizeof(wchar_t)] =3D L'\0';

  // In new VistaCwd instance, ensure that the final path character is L'\\=
':

  if (newCwd->Buffer[(upath.Length / sizeof(wchar_t)) - 1] !=3D L'\\') {
    if (upath.Length > newCwd->Path.MaximumLength - (2 * sizeof(wchar_t))) {
      cerr << "Path too long." << endl;
      exit(1);
    }
    newCwd->Buffer[upath.Length / sizeof(wchar_t)] =3D L'\\';
    newCwd->Buffer[(upath.Length / sizeof(wchar_t)) + 1] =3D L'\0';
    upath.Length +=3D sizeof(wchar_t);
  }

  // NOTE: We never acquire the PEB lock, only the Vista++ CWD lock:

  EnterCriticalSection(CwdCS);

  Params.CurrentDirectoryHandle =3D newCwd->DirectoryHandle;

  Params.CurrentDirectoryName.Buffer =3D newCwd->Path.Buffer;

  Params.CurrentDirectoryName.Length =3D newCwd->Path.Length;

  VistaCwd *oldCwd =3D *Cwd;

  *Cwd =3D newCwd;

  LeaveCriticalSection(CwdCS);

  if (InterlockedDecrement(&oldCwd->ReferenceCount) =3D=3D 0) {
    nt._NtClose (oldCwd->DirectoryHandle);

    nt._RtlFreeHeap (HeapHandle, 0, oldCwd);
  }
}

int main (int argc, char **argv)
{
  HMODULE module =3D GetModuleHandle ("ntdll.dll");

  // Reading the CWD is simpler than writing the CWD,
  // which makes it easier to find the addresses we need,
  // and might also tend to make code changes less frequent.
  const code_t *get_dir =3D (const code_t*) GetProcAddress
    (module, "RtlGetCurrentDirectory_U");

  const code_t *ent_crit =3D (const code_t*) GetProcAddress
    (module, "RtlEnterCriticalSection");

  // Find first relative call instruction.
  const code_t *rcall =3D (const code_t *) memchr (get_dir, 0xE8, 32);
  if (! rcall) {
    badCode ();
  }

  // Compute the address, use_cwd, of the function being called.
  // This function actually fetches the current VistaCwd instance
  // and performs actions conditioned upon the freshness of its
  // OldDismountCount member.
  ptrdiff_t offset =3D peek32 (rcall + 1);
  const code_t *use_cwd =3D rcall + 5 + offset;

  // Find the first "push edi" instruction...
  const code_t *movedi =3D (const code_t *) memchr (use_cwd, 0x57, 32);
  ++movedi;
  // ...which should be followed by "mov edi, crit-sect-addr" then "push ed=
i".
  // (Ideally we should not depend upon %EDI being the register,
  // but this is a proof of concept, and even with more flexibility
  // we are still depending heavily upon code structure here.)
  if (movedi[0] !=3D 0xBF || movedi[5] !=3D 0x57) {
    badCode ();
  }
  // Get the address of the critical section for the CWD.
  CRITICAL_SECTION *CwdCS =3D (CRITICAL_SECTION *) peek32 (movedi + 1);

  // To check we are seeing the right code, we check our expectation that
  // the next instruction is a relative call into RtlEnterCriticalSection.
  rcall =3D movedi + 6;
  if (rcall[0] !=3D 0xe8) {
    badCode ();
  }
  offset =3D peek32 (rcall + 1);
  if (rcall + 5 + offset !=3D ent_crit) {
    badCode ();
  }

  // After locking the critical section, the code should read the
  // global CWD block pointer that is guarded by that critical section.
  const code_t *movesi =3D rcall + 5;
  if (movesi[0] !=3D 0x8b) {
    badCode ();
  }
  VistaCwd **Cwd =3D (VistaCwd **) peek32 (movesi + 2);

  cout << showbase << hex << (size_t)CwdCS
       << "  <=3D=3D critical section" << endl;
  cout << showbase << hex << (size_t)Cwd
       << "  <=3D=3D Vista++ CWD struct pointer" << endl;

  if (argc >=3D 2) {
    NtFuncs nt(module);

    STRING npath;
    nt._RtlInitString (&npath, argv[1]);

    UNICODE_STRING upath;
    nt._RtlAnsiStringToUnicodeString (&upath, &npath, TRUE);

    modifiedSetCurrentDirectory (nt, CwdCS, Cwd, upath);

    nt._RtlFreeUnicodeString (&upath);

    cout << "Changed directory." << endl;
  }

  if (argc >=3D 3) {
    HANDLE h =3D CreateFile (argv[2], GENERIC_READ, 0, NULL, OPEN_EXISTING,
                           FILE_ATTRIBUTE_NORMAL, NULL);
    if (h =3D=3D INVALID_HANDLE_VALUE) {
      winError(cerr << "Failed to open file: ") << endl;
      return 1;
    }

    cout << "Successfully opened file." << endl;
    if (! CloseHandle (h)) {
      winError(cerr << "Failed to close file: ") << endl;
      return 1;
    }
  }

  return 0;
}

--_002_3C031C390CBF1E4A8CE1F74DE7ECAF3A158EDA704CMBX8EXCHPRODU_
Content-Type: text/x-c++src; name="vistachdir.cc"
Content-Description: vistachdir.cc
Content-Disposition: attachment; filename="vistachdir.cc"; size=20349;
	creation-date="Sat, 11 Sep 2010 00:12:29 GMT";
	modification-date="Sat, 11 Sep 2010 00:12:29 GMT"
Content-Transfer-Encoding: base64

Ly8gQ29tcGlsZSB3aXRoIEN5Z3dpbiBHKyssIGFuZCBpbmNsdWRlIGEgJy1J
JyBhcmd1bWVudCB0aGF0Ci8vIHNwZWNpZmllcyB0aGUgIndpbnN1cCIgZGly
ZWN0b3J5IG9mIHRoZSBDeWd3aW4gc291cmNlIHRyZWUuCi8vCi8vIFJ1biB3
aXRoIHR3byBhcmd1bWVudHM6Ci8vCi8vICAgMS4gQW4gYWJzb2x1dGUgV2lu
ZG93cyBwYXRoIHRvIGEgZGlyZWN0b3J5IChjYW4gdXNlIGZvcndhcmQgc2xh
c2hlcykuCi8vCi8vICAgMi4gVGhlIHJlbGF0aXZlIG5hbWUgb2YgYSBmaWxl
IHdpdGhpbiB0aGF0IGRpcmVjdG9yeS4KLy8KLy8gVGhlIHB1cnBvc2Ugb2Yg
dGhpcyBzb3VyY2UgY29kZSBpcyB0byBkaXNjdXNzIFdpbjMyIENXRAovLyBp
c3N1ZXMgYW5kIHRvIGNvbXBpbGUgaW50byBhIHByb29mLW9mLWNvbmNlcHQg
cHJvZ3JhbS4KLy8gUGxlYXNlIHJlYWQgdGhlIGludGVybGVhdmVkIGNvbW1l
bnRzLgoKI2luY2x1ZGUgPHczMmFwaS9pbmNsdWRlL3dpbmRvd3MuaD4KI2lu
Y2x1ZGUgPHczMmFwaS9pbmNsdWRlL250ZGVmLmg+CiNpbmNsdWRlIDx3MzJh
cGkvaW5jbHVkZS93aW5udC5oPgojaW5jbHVkZSA8Y3lnd2luL250ZGxsLmg+
CiNpbmNsdWRlIDxhbGdvcml0aG0+CiNpbmNsdWRlIDxjc3RkbGliPgojaW5j
bHVkZSA8Y3N0cmluZz4KI2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8
bG9jYWxlPgojaW5jbHVkZSA8c3RyaW5nPgoKdXNpbmcgbmFtZXNwYWNlIHN0
ZDsKCi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq
CgpQcmltYXJ5IHJlc2VhcmNoIHdhcyBvbiBXaW5kb3dzIDcgeDY0LCBidXQg
dGhlcmUgYXBwZWFycyB0byBiZQphdCBsZWFzdCBzdXBlcmZpY2lhbCBzaW1p
bGFyaXR5IG9uIFdpbmRvd3MgMjAwOCAoeDMyIGFuZCB4NjQpCmFuZCBXaW5k
b3dzIFZpc3RhICh4MzIgYW5kIHg2NCkuCgpMZXQgIlBhcmFtcyIgYmUgYW4g
YWxpYXMgZm9yICpOdEN1cnJlbnRUZWIgKCktPlBlYi0+UHJvY2Vzc1BhcmFt
ZXRlcnMuCgpMZXQgIkhlYXBIYW5kbGUiIGJlIGFuIGFsaWFzIGZvciAqKFBW
T0lEKikoKGNoYXIqKU50Q3VycmVudFRlYiAoKS0+UGViICsgMHgxOCkKKHdo
aWNoIGlzIHRoZSBzZWNvbmQgMzItYml0IHdvcmQgYWZ0ZXIgUHJvY2Vzc1Bh
cmFtZXRlcnMuKQoKTGV0ICJEaXNtb3VudENvdW50IiBiZSBhbiBhbGlhcyBm
b3IgdGhlIHVzZXIgc3BhY2UgbWFwcGluZyBvZgpLVVNFUl9TSEFSRURfREFU
QTo6RGlzbW91bnRDb3VudDogbmFtZWx5LCAqKFVMT05HKikweDdmZmUwMmRj
LgpTZWU6IGh0dHA6Ly93d3cubmlyc29mdC5uZXQva2VybmVsX3N0cnVjdC92
aXN0YS9LVVNFUl9TSEFSRURfREFUQS5odG1sCgpJbiB0aGUgaW1wbGVtZW50
YXRpb24gb2YgU2V0Q3VycmVudERpcmVjdG9yeSAoKSwKUGFyYW1zLkN1cnJl
bnREaXJlY3RvcnlOYW1lLk1heGltdW1MZW5ndGggaXMgcmVhZCBidXQgTk9U
IG1vZGlmaWVkLgpJdHMgdmFsdWUgZGV0ZXJtaW5lcyB0aGUgc2l6ZXMgb2Yg
dmFyaW91cyBidWZmZXJzLCBpbmNsdWRpbmcgdGhlCm5ldyBidWZmZXIgdGhh
dCB3aWxsIGhvbGQgdGhlIG5ldyBjdXJyZW50IGRpcmVjdG9yeSBwYXRobmFt
ZS4KClRoZSBjb25zdGFudCB2YWx1ZSB3ZSBoYXZlIG9ic2VydmVkIGZvcgpQ
YXJhbXMuQ3VycmVudERpcmVjdG9yeU5hbWUuTWF4aW11bUxlbmd0aAppcyA1
MjAsIHdoaWNoIGlzIHNpemVvZih3Y2hhcl90IFtNQVhfUEFUSF0pLgoKSW4g
YWRkaXRpb24gdG8gdGhlIFBFQiwgdGhlcmUgaXMgYW4gYWxsb2NhdGVkIG1l
bW9yeSBibG9jayBkZXNjcmliaW5nCnRoZSBjdXJyZW50IGRpcmVjdG9yeS4g
IEl0cyBsaWZldGltZSBpcyBjb250cm9sbGVkIGJ5IHRocmVhZC1zYWZlCnJl
ZmVyZW5jZSBjb3VudGluZy4gIENhbGwgaXRzIHR5cGUgIlZpc3RhQ3dkIjsg
bW9yZSBkZXRhaWxzIGZvbGxvdy4KClRoZSBQRUIgZG9lcyBOT1Qgc2VlbSB0
byBwb2ludCB0byBhbnkgVmlzdGFDd2QgaW5zdGFuY2VzLiAgSW5zdGVhZCwK
dGhlcmUgaXMgYSBnbG9iYWwgcG9pbnRlciBvdXRzaWRlIG9mIHRoZSBQRUIs
IHdoaWNoIHdlIGNhbGwgIkN3ZCIsCmFuZCBpdCBpcyBwcm90ZWN0ZWQgYnkg
YSBjcml0aWNhbCBzZWN0aW9uLCB3aGljaCB3ZSBjYWxsICJDd2RDUyIsCndo
aWNoIGlzIGFsc28gb3V0c2lkZSBvZiB0aGUgUEVCLiAgQXBwYXJlbnRseSB0
aGVzZSBnbG9iYWxzIGFyZQppbiB0aGUgbnRkbGwuZGxsIGRhdGEgc3BhY2Us
IGJ1dCB0aGVpciBzeW1ib2xzIGFyZSBub3QgZXhwb3J0ZWQuCkxhdGVyIHdl
IHdpbGwgZGlzY3VzcyBob3cgdG8gY29tcHV0ZSB0aGVpciBhZGRyZXNzZXMu
CgpOT1RFOiBUaGUgU2V0Q3VycmVudERpcmVjdG9yeSAoKSBpbXBsZW1lbnRh
dGlvbiBhcHBlYXJzIHRvIHVwZGF0ZSB0aGUKV2luMzIgQ1dEICp3aXRob3V0
KiBsb2NraW5nIHRoZSBQRUIgYXMgc3VjaC4gIEl0IGxvY2tzIEN3ZENTIGlu
c3RlYWQuCgpTdHJ1Y3R1cmU6CgoqKioqKioqKioqKioqKioqKioqKioqKioq
KioqKioqKioqKioqKioqLwoKICBzdHJ1Y3QgVmlzdGFDd2QgewogICAgLy8g
VXNlIGJ1cy1sb2NrZWQgaW5jcmVtZW50L2RlY3JlbWVudCB0byBhZGp1c3Qg
dGhpcyByZWZlcmVuY2UgY291bnQuCiAgICAvLyBXaGVuIHRoZSByZWZlcmVu
Y2UgY291bnQgZHJvcHMgdG8gemVybywgZGVzdHJveSBhbmQgZGVhbGxvY2F0
ZS4KCiAgICB2b2xhdGlsZSBMT05HIFJlZmVyZW5jZUNvdW50OwoKICAgIC8v
IFRoZSBvcGVuIGhhbmRsZSB0byB0aGUgY3VycmVudCBkaXJlY3RvcnkuCgog
ICAgSEFORExFIERpcmVjdG9yeUhhbmRsZTsKCiAgICAvLyBBIHNuYXBzaG90
IG9mIHRoZSBnbG9iYWwgRGlzbW91bnRDb3VudCwgdXBkYXRlZCBhdCB2YXJp
b3VzCiAgICAvLyB0aW1lcyBkdXJpbmcgdGhlIGxpZmV0aW1lIG9mIHRoaXMg
c3RydWN0LiAgSXQgYXBwZWFycyB0aGF0CiAgICAvLyByZWFkcyBvZiBhbmQg
d3JpdGVzIHRvIHRoaXMgbWVtYmVyIGFyZSBsb2NrZWQgYnkgQ3dkQ1MsCiAg
ICAvLyBleGNlcHQgZm9yIGluaXRpYWxpemF0aW9uIChzZWUgYmVsb3cpLgog
ICAgLy8KICAgIC8vIFdoYXQgaXMgdGhpcyBtZW1iZXIgZm9yPyAgRm9sbG93
aW5nIHRoaW5ncyBpbiBhIGRlYnVnZ2VyLAogICAgLy8gaXQgc2VlbXMgbGlr
ZWx5IHRoYXQgd2hlbmV2ZXIgdGhlIGN1cnJlbnQgVmlzdGFDd2QgaXMgdXNl
ZCwKICAgIC8vIGl0cyBjdXJyZW50IHZhbHVlIG9mIE9sZERpc21vdW50Q291
bnQgaXMgY29tcGFyZWQgYWdhaW5zdCB0aGUKICAgIC8vIGN1cnJlbnQgKG9y
IHBlcmhhcHMgc2xpZ2h0bHkgc3RhbGU/KSB2YWx1ZSBvZiBEaXNtb3VudENv
dW50LAogICAgLy8gYW5kIGlmIGl0IGRvZXMgbm90IG1hdGNoIHRoZW4gc29t
ZSBleHRyYSBhY3Rpb24gaXMgdGFrZW4uCiAgICAvLyBTdWNoIGV4dHJhIGFj
dGlvbiBzZWVtcyB0byBpbmNsdWRlIGNoZWNraW5nIGlmIHRoZSB2b2x1bWUK
ICAgIC8vIGlzIG1vdW50ZWQuCiAgICAvLwogICAgLy8gUHJlc3VtYWJseSB0
aGUgZ2xvYmFsIERpc21vdW50Q291bnQgaW5jcmVhc2VzIG1vbm90b25pY2Fs
bHkuCiAgICAvLyBSZWFkcyBvZiB0aGUgZ2xvYmFsIERpc21vdW50Q291bnQg
YXBwZWFyIHRvIGJlIHVubG9ja2VkLgogICAgLy8gSWYgYSBzdGFsZSB2YWx1
ZSBpcyBzdG9yZWQgaW4gT2xkRGlzbW91bnRDb3VudCwgdGhlbiBpdAogICAg
Ly8gbWF5IGJlIGhhcm1sZXNzIGluIHRoZSBzZW5zZSB0aGF0IGl0IGp1c3Qg
ZmFpbHMgdG8gcHJldmVudAogICAgLy8gdW5uZWNlc3NhcnkgY29tcHV0YXRp
b24gbGF0ZXIuICBCdXQgYSBzdGFsZSByZWFkIGR1cmluZwogICAgLy8gYSBj
b21wYXJpc29uIHdpdGggT2xkRGlzbW91bnRDb3VudCBjb3VsZCBwcmV2ZW50
IHRoZSBleHRyYQogICAgLy8gYWN0aW9ucywgd2hpY2ggY291bGQgYmUgbW9y
ZSBzZXJpb3VzLiAgQXQgYSBndWVzcywgdGhhdAogICAgLy8gcHJvYmxlbSBp
cyBwcmV2ZW50ZWQgYnkgdGhlIGZvbGxvd2luZyBjb2RlIHN0cnVjdHVyZSwK
ICAgIC8vIG9ic2VydmVkIGluIGF0IGxlYXN0IG9uZSBwbGFjZSB0aGF0IHVz
ZXMgdGhlIENXRCBzZXR0aW5nOgogICAgLy8gdGhlIHZhbHVlIG9mIE9sZERp
c21vdW50Q291bnQgaXMgcmVhZCB1bmRlciBhIEN3ZENTIGxvY2ssCiAgICAv
LyBhbmQgb25seSAqYWZ0ZXIqIHRoYXQgbG9jayBpcyByZWxlYXNlZCBpcyB0
aGUgZ2xvYmFsCiAgICAvLyBEaXNtb3VudENvdW50IHJlYWQuICBUaGUgbG9j
ay11bmxvY2sgcHJvYmFibHkgZmx1c2hlcwogICAgLy8gd3JpdGVzIHRvIHRo
ZSBnbG9iYWwgRGlzbW91bnRDb3VudC4KCiAgICBVTE9ORyBPbGREaXNtb3Vu
dENvdW50OwoKICAgIC8vIFRoZSBwYXRoIG9mIHRoZSBjdXJyZW50IGRpcmVj
dG9yeS4gIEFsd2F5cyBlbmRzIGluIGEgYmFja3NsYXNoOwogICAgLy8gb25l
IGlzIGFwcGVuZGVkIGlmIHRoZSBnaXZlbiBwYXRoIGRpZCBub3QgYWxyZWFk
eSBlbmQgaW4gb25lLgogICAgLy8KICAgIC8vIFRoZSAiTWF4aW11bUxlbmd0
aCIgYW5kICJCdWZmZXIiIG1lbWJlcnMgYWx3YXlzIHNwZWNpZnkgdGhlIHNp
emUKICAgIC8vIGFuZCBzdGFydGluZyBhZGRyZXNzIG9mIHRoZSAiQnVmZmVy
IiBzaWJsaW5nIG1lbWJlciAoc2VlIGJlbG93KS4KCiAgICBVTklDT0RFX1NU
UklORyBQYXRoOwoKICAgIC8vIFRoZSBhY3R1YWwgc2l6ZSBvZiB0aGlzIG1l
bWJlciwgYW5kIHRoZXJlZm9yZSBvZiB0aGUgc3RydWN0IGFzCiAgICAvLyBh
IHdob2xlLCBpcyBjb21wdXRlZCBkeW5hbWljYWxseSBzbyB0aGF0IHRoaXMg
bWVtYmVyIGhhcyB0aGUKICAgIC8vIHNhbWUgc2l6ZSBhcyB0aGUgcHJldmlv
dXMgdmFsdWUgb2YKICAgIC8vCiAgICAvLyAgIFBhcmFtcy5DdXJyZW50RGly
ZWN0b3J5TmFtZS5NYXhpbXVtTGVuZ3RoCiAgICAvLwogICAgLy8gQnV0IHNp
bmNlIFNldEN1cnJlbnREaXJlY3RvcnkgKCkgbmV2ZXIgc2VlbXMgdG8gbW9k
aWZ5IHRoYXQKICAgIC8vIFBFQiBkYXR1bSwgaW4gcHJhY3RpY2UgdGhlIGRp
bWVuc2lvbiBpcyBhbHdheXMgTUFYX1BBVEguCgogICAgd2NoYXJfdCBCdWZm
ZXJbTUFYX1BBVEhdOwogIH07CgovKioqKioqKioqKioqKioqKioqKioqKioq
KioqKioqKioqKioqKioqKgoKQWxsb2NhdGlvbjoKCkJlZm9yZSBtb2RpZnlp
bmcgdGhlIFBFQiBkYXRhLCB0aGUgaW1wbGVtZW50YXRpb24Kb2YgU2V0Q3Vy
cmVudERpcmVjdG9yeSAoKSBhbGxvY2F0ZXMgYSBuZXcgaW5zdGFuY2UKb2Yg
VmlzdGFDd2QsIGFzIGZvbGxvd3M6CgogICAgUnRsQWxsb2NhdGVIZWFwIChI
ZWFwSGFuZGxlLCAwLAogICAgICBvZmZzZXRvZiAoVmlzdGFDd2QsIEJ1ZmZl
cikgKyBQYXJhbXMuQ3VycmVudERpcmVjdG9yeU5hbWUuTWF4aW11bUxlbmd0
aCk7CgpJbml0aWFsaXphdGlvbjoKClRoZSBTZXRDdXJyZW50RGlyZWN0b3J5
ICgpIGltcGxlbWVudGF0aW9uCnRoZW4gaW5pdGlhbGl6ZXMgdGhhdCBpbnN0
YW5jZSBhcyBmb2xsb3dzOgoKICAvLyBSZWFkIERpc21vdW50Q291bnQgYmVm
b3JlIGNhbGxpbmcgTnRPcGVuRmlsZSgpLgogIC8vIElmIHRoZSByZWxhdGl2
ZSBvcmRlciBtYXR0ZXJzIGF0IGFsbCwgdGhlbiBpdCBpcwogIC8vIHByb2Jh
Ymx5IGZvbGxvd2luZyB0aGUgZ2VuZXJhbCBwcmluY2lwbGUgdGhhdAogIC8v
IGEgc3RhbGUgdmFsdWUgY29waWVkIGZyb20gRGlzbW91bnRDb3VudCB0byB0
aGUKICAvLyBPbGREaXNtb3VudENvdW50IG1lbWJlciAoc2VlIGJlbG93KSBq
dXN0IGNhdXNlcwogIC8vIGV4dHJhIHdvcmsgYnV0IGlzIG90aGVyd2lzZSBo
YXJtbGVzcywgd2hlcmVhcwogIC8vIGEgdG9vLXJlY2VudCB2YWx1ZSBtaWdo
dCBwcmV2ZW50IG5lY2Vzc2FyeSB3b3JrLgoKICBVTE9ORyBEaXNtb3VudENv
dW50QmVmb3JlTnRPcGVuRmlsZSA9IERpc21vdW50Q291bnQ7CgogIFJlZmVy
ZW5jZUNvdW50ID0gMTsKCiAgRGlyZWN0b3J5SGFuZGxlID0gTnRPcGVuRmls
ZSAoLi4uKTsKCiAgLy8gTk9URTogVGhlcmUgaXMgbm8gbG9ja2luZyBhcm91
bmQgdGhpcyBpbml0aWFsaXphdGlvbi4KICAvLyBCdXQgdGhlIFNldEN1cnJl
bnREaXJlY3RvcnkgKCkgaW1wbGVtZW50YXRpb24gbG9ja3MgQ3dkQ1MKICAv
LyB3aGlsZSB1cGRhdGluZyBDd2QgdG8gcG9pbnQgdG8gbmV3IGluc3RhbmNl
cyBvZiBWaXN0YUN3ZCwKICAvLyBhbmQgcHJlc3VtYWJseSB0aGF0IHN1ZmZp
Y2VzIHRvIGZsdXNoIHRoaXMgaW5pdGlhbGl6YXRpb24KICAvLyB0byBvdGhl
ciBDUFVzLiAgT3RoZXIgdGhyZWFkcyB3b3VsZCBub3Qgc2VlIHRoZSBuZXcg
VmlzdGFDd2QKICAvLyBpbnN0YW5jZSBiZWZvcmUgdGhhdCBwb2ludC4gIEFz
IG1lbnRpb25lZCBiZWZvcmUsIGNvcHlpbmcgb2YKICAvLyBhIHN0YWxlIHZh
bHVlIG9mIHRoZSBnbG9iYWwgRGlzbW91bnRDb3VudCBpcyBwcm9iYWJseSBo
YXJtbGVzcywKICAvLyBpbiB0aGF0IGl0IHdvdWxkIG1lcmVseSB0cmlnZ2Vy
IGFuIHVubmVjZXNzYXJ5IHVwZGF0ZS4KCiAgT2xkRGlzbW91bnRDb3VudCA9
IERpc21vdW50Q291bnRCZWZvcmVOdE9wZW5GaWxlOwoKICAvLyBUaGUgbGVu
Z3RoIG9mIHRoZSBwYXRoIGluIGJ5dGVzLCBub3QgY291bnRpbmcgdGhlIHRl
cm1pbmF0b3IuCgogIFBhdGguTGVuZ3RoID0gLi4uOwoKICAvLyBBcyBtZW50
aW9uZWQgYmVmb3JlLCBpbiBwcmFjdGljZSB0aGlzIGlzIHNpemVvZih3Y2hh
cl90IFtNQVhfUEFUSF0pLgoKICBQYXRoLk1heGltdW1MZW5ndGggPSBQYXJh
bXMuQ3VycmVudERpcmVjdG9yeU5hbWUuTWF4aW11bUxlbmd0aDsKCiAgUGF0
aC5CdWZmZXIgPSBCdWZmZXI7CgogIC8vIFRoZSB3aWRlIHBhdGggZm9yIHRo
ZSBkaXJlY3Rvcnk7IGlmIG5lY2Vzc2FyeSBhIGJhY2tzbGFzaCBpcwogIC8v
IGFwcGVuZGVkIHNvIHRoYXQgdGhlIGZpbmFsIGNoYXJhY3RlciAoYmVmb3Jl
IHRoZSB0ZXJtaW5hdG9yKQogIC8vIGlzIGFsd2F5cyBhIGJhY2tzbGFzaC4K
CiAgbWVtY3B5IChCdWZmZXIsIC4uLik7CiAgQnVmZmVyW1BhdGguTGVuZ3Ro
IC8gc2l6ZW9mKHdjaGFyX3QpXSA9IEwnXDAnOwoKVXNhZ2U6CgpBZnRlciBj
cmVhdGluZyB0aGUgbmV3IFZpc3RhQ3dkIGluc3RhbmNlOyBjYWxsIGl0IG5l
d0N3ZCwgdGhlClNldEN1cnJlbnREaXJlY3RvcnkgKCkgaW1wbGVtZW50YXRp
b24gbW9kaWZpZXMgdGhlIFBFQiBhbmQgQ3dkCnVuZGVyIGEgbG9jayBvbiBD
d2RDUywgYXMgZm9sbG93czoKCiAgUGFyYW1zLkN1cnJlbnREaXJlY3RvcnlI
YW5kbGUgPSBuZXdDd2QuRGlyZWN0b3J5SGFuZGxlOwoKICBQYXJhbXMuQ3Vy
cmVudERpcmVjdG9yeU5hbWUuQnVmZmVyID0gbmV3Q3dkLlBhdGguQnVmZmVy
OwoKICBQYXJhbXMuQ3VycmVudERpcmVjdG9yeU5hbWUuTGVuZ3RoID0gbmV3
Q3dkLlBhdGguTGVuZ3RoOwoKICBWaXN0YUN3ZCAqb2xkQ3dkID0gQ3dkOwoK
ICBDd2QgPSBuZXdDd2Q7CgpOb3RlIHRoYXQgYXMgbWVudGlvbmVkIGJlZm9y
ZSwKUGFyYW1zLkN1cnJlbnREaXJlY3RvcnlOYW1lLk1heGltdW1MZW5ndGgK
aXMgTk9UIG1vZGlmaWVkLgoKQ2xlYW51cDoKCkFmdGVyIHRoZSBTZXRDdXJy
ZW50RGlyZWN0b3J5ICgpIGltcGxlbWVudGF0aW9uIHJlbGVhc2VzCml0cyBs
b2NrIG9uIEN3ZENTLCBpdCBwZXJmb3JtcyBhIGJ1cy1sb2NrZWQgZGVjcmVt
ZW50IG9uCm9sZEN3ZC0+UmVmZXJlbmNlQ291bnQgKHVubGVzcyBvbGRDd2Qg
PT0gTlVMTCkuICBJZiB0aGUKcmVzdWx0IGlzIHplcm8sIGl0IHRoZW4gZGVz
dHJveXMgYW5kIGRlYWxsb2NhdGVzIHRoZQpvbGQgVmlzdGFDd2QgaW5zdGFu
Y2UgYXMgZm9sbG93czoKCiAgTnRDbG9zZSAob2xkQ3dkLT5EaXJlY3RvcnlI
YW5kbGUpOwoKICBSdGxGcmVlSGVhcCAoSGVhcEhhbmRsZSwgMCwgb2xkQ3dk
KTsKCkFkZHJlc3NlcyBvZiBDd2QgYW5kIEN3ZENTOgoKSW4gb3JkZXIgdG8g
aW1pdGF0ZSB0aGUgd2F5IGluIHdoaWNoIFNldEN1cnJlbnREaXJlY3Rvcnkg
KCkgdXBkYXRlcwp0aGUgV2luMzIgQ1dEIGRhdGEsIHdlIG11c3QgbGVhcm4g
dGhlIGFkZHJlc3NlcyBvZiBDd2QgYW5kIEN3ZENTLgoKVGhlIGZvbGxvd2lu
ZyBwcm9ncmFtIHBlcmZvcm1zIGNvZGUgYW5hbHlzaXMgdG8gZGlzY292ZXIg
dGhvc2UuCkl0IHRoZW4gY2hhbmdlcyB0aGUgV2luMzIgQ1dEIGRpcmVjdGx5
IGFuZCB0ZXN0cyB0aGUgcmVzdWx0CndpdGggYSByZWxhdGl2ZSBDcmVhdGVG
aWxlICgpLiAgSXQgaXMgaW50ZW5kZWQgYXMKYSBxdWljay1hbmQtZGlydHkg
c3RhbmQtYWxvbmUgcHJvb2Ytb2YtY29uY2VwdCBwcm9ncmFtOwpmaW5hbCBj
b2RlIHRvIGJlIGluY2x1ZGVkIGluIGN5Z3dpbjEuZGxsIHdvdWxkIGRpZmZl
ciBncmVhdGx5LgoKKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq
KioqKioqKi8KCnR5cGVkZWYgdW5zaWduZWQgY2hhciBjb2RlX3Q7Cgp1bnNp
Z25lZCBwZWVrMzIgKGNvbnN0IHVuc2lnbmVkIGNoYXIgKnApCnsKICByZXR1
cm4gcFswXSArIChwWzFdIDw8IDgpICsgKHBbMl0gPDwgMTYpICsgKHBbM10g
PDwgMjQpOwp9Cgp2b2lkIGJhZENvZGUgKCkKewogIGNlcnIgPDwgIkNvZGUg
bG9va3MgZGlmZmVyZW50IHRoYW4gZXhwZWN0ZWQ7IGJhaWxpbmcgb3V0LiIg
PDwgZW5kbDsKICBleGl0ICgxKTsKfQoKb3N0cmVhbSYgd2luRXJyb3IgKG9z
dHJlYW0mIG9zLCBEV09SRCBjb2RlID0gR2V0TGFzdEVycm9yKCkpCnsKICBM
UFNUUiBtc2cgPSAwOwogIGlmIChGb3JtYXRNZXNzYWdlQSAoRk9STUFUX01F
U1NBR0VfRlJPTV9TWVNURU0KICAgICAgICAgICAgICAgICAgICAgIHwgRk9S
TUFUX01FU1NBR0VfQUxMT0NBVEVfQlVGRkVSLAogICAgICAgICAgICAgICAg
ICAgICAgMCwKICAgICAgICAgICAgICAgICAgICAgIGNvZGUsCiAgICAgICAg
ICAgICAgICAgICAgICBNQUtFTEFOR0lEKExBTkdfTkVVVFJBTCwgU1VCTEFO
R19ERUZBVUxUKSwKICAgICAgICAgICAgICAgICAgICAgIChMUFNUUikmbXNn
LAogICAgICAgICAgICAgICAgICAgICAgMSwKICAgICAgICAgICAgICAgICAg
ICAgIE5VTEwpKSB7CiAgICBvcyA8PCAiZXJyb3IgIiA8PCBjb2RlIDw8ICI6
ICIgPDwgbXNnOwogICAgTG9jYWxGcmVlIChtc2cpOwogIH0gZWxzZSB7CiAg
ICBvcyA8PCAiPz8/IjsKICB9CiAgcmV0dXJuIG9zOwp9CgojZGVmaW5lIERE
S0FQSSBfX3N0ZGNhbGwKCnR5cGVkZWYgQ09OU1QgY2hhciAqUENTWjsKCnR5
cGVkZWYKTlRTVEFUVVMKRERLQVBJCigqIE50Q2xvc2VfdCkoCiAgLypJTiov
IEhBTkRMRSAgSGFuZGxlKTsKCnR5cGVkZWYKTlRTVEFUVVMKRERLQVBJCigq
IE50T3BlbkZpbGVfdCkgKAogIC8qT1VUKi8gUEhBTkRMRSAgRmlsZUhhbmRs
ZSwKICAvKklOKi8gQUNDRVNTX01BU0sgIERlc2lyZWRBY2Nlc3MsCiAgLypJ
TiovIFBPQkpFQ1RfQVRUUklCVVRFUyAgT2JqZWN0QXR0cmlidXRlcywKICAv
Kk9VVCovIFBJT19TVEFUVVNfQkxPQ0sgIElvU3RhdHVzQmxvY2ssCiAgLypJ
TiovIFVMT05HICBTaGFyZUFjY2VzcywKICAvKklOKi8gVUxPTkcgIE9wZW5P
cHRpb25zKTsKCnR5cGVkZWYKUFZPSUQKTlRBUEkKKCogUnRsQWxsb2NhdGVI
ZWFwX3QpICgKICAvKklOKi8gSEFORExFICBIZWFwSGFuZGxlLAogIC8qSU4q
LyBVTE9ORyAgIEZsYWdzLAogIC8qSU4qLyBVTE9ORyAgIFNpemUKKTsKCnR5
cGVkZWYKQk9PTEVBTgpOVEFQSQooKiBSdGxGcmVlSGVhcF90KSAoCiAgLypJ
TiovIEhBTkRMRSAgSGVhcEhhbmRsZSwKICAvKklOKi8gVUxPTkcgICBGbGFn
cywKICAvKklOKi8gUFZPSUQgICBQCik7Cgp0eXBlZGVmClZPSUQKRERLQVBJ
CigqIFJ0bEluaXRTdHJpbmdfdCkgKAogIC8qSU4gT1VUKi8gUFNUUklORyAg
RGVzdGluYXRpb25TdHJpbmcsCiAgLypJTiovIFBDU1ogIFNvdXJjZVN0cmlu
Zyk7Cgp0eXBlZGVmCk5UU1RBVFVTCkRES0FQSQooKiBSdGxBbnNpU3RyaW5n
VG9Vbmljb2RlU3RyaW5nX3QpICgKICAvKklOIE9VVCovIFBVTklDT0RFX1NU
UklORyAgRGVzdGluYXRpb25TdHJpbmcsCiAgLypJTiovIFBBTlNJX1NUUklO
RyAgU291cmNlU3RyaW5nLAogIC8qSU4qLyBCT09MRUFOICBBbGxvY2F0ZURl
c3RpbmF0aW9uU3RyaW5nKTsKCnR5cGVkZWYKVk9JRApEREtBUEkKKCogUnRs
RnJlZVVuaWNvZGVTdHJpbmdfdCkgKAogIC8qSU4qLyBQVU5JQ09ERV9TVFJJ
TkcgIFVuaWNvZGVTdHJpbmcpOwoKdHlwZWRlZgpOVFNUQVRVUwpEREtBUEkK
KCogUnRsVW5pY29kZVN0cmluZ1RvQW5zaVN0cmluZ190KSgKICAvKklOIE9V
VCovIFBBTlNJX1NUUklORyAgRGVzdGluYXRpb25TdHJpbmcsCiAgLypJTiov
IFBVTklDT0RFX1NUUklORyAgU291cmNlU3RyaW5nLAogIC8qSU4qLyBCT09M
RUFOICBBbGxvY2F0ZURlc3RpbmF0aW9uU3RyaW5nKTsKCnR5cGVkZWYKVk9J
RApEREtBUEkKKCogUnRsRnJlZUFuc2lTdHJpbmdfdCkoCiAgLypJTiovIFBB
TlNJX1NUUklORyAgQW5zaVN0cmluZyk7CgojZGVmaW5lIE5URlVOQ19ERUNM
KEYpIEYgIyMgX3QgXyAjIyBGCgpzdHJ1Y3QgTnRGdW5jcwp7CiAgTlRGVU5D
X0RFQ0woTnRDbG9zZSk7CiAgTlRGVU5DX0RFQ0woTnRPcGVuRmlsZSk7CiAg
TlRGVU5DX0RFQ0woUnRsQWxsb2NhdGVIZWFwKTsKICBOVEZVTkNfREVDTChS
dGxGcmVlSGVhcCk7CiAgTlRGVU5DX0RFQ0woUnRsSW5pdFN0cmluZyk7CiAg
TlRGVU5DX0RFQ0woUnRsQW5zaVN0cmluZ1RvVW5pY29kZVN0cmluZyk7CiAg
TlRGVU5DX0RFQ0woUnRsRnJlZVVuaWNvZGVTdHJpbmcpOwogIE5URlVOQ19E
RUNMKFJ0bFVuaWNvZGVTdHJpbmdUb0Fuc2lTdHJpbmcpOwogIE5URlVOQ19E
RUNMKFJ0bEZyZWVBbnNpU3RyaW5nKTsKCiAgTnRGdW5jcyhITU9EVUxFIG1v
ZHVsZSk7Cn07CgojZGVmaW5lIE5URlVOQ19CSU5EKE0sIEYpIF8gIyMgRiA9
IChGICMjIF90KSBHZXRQcm9jQWRkcmVzcyhNLCAjIEYpCgpOdEZ1bmNzOjpO
dEZ1bmNzKEhNT0RVTEUgbW9kdWxlKQp7CiAgTlRGVU5DX0JJTkQobW9kdWxl
LCBOdENsb3NlKTsKICBOVEZVTkNfQklORChtb2R1bGUsIE50T3BlbkZpbGUp
OwogIE5URlVOQ19CSU5EKG1vZHVsZSwgUnRsQWxsb2NhdGVIZWFwKTsKICBO
VEZVTkNfQklORChtb2R1bGUsIFJ0bEZyZWVIZWFwKTsKICBOVEZVTkNfQklO
RChtb2R1bGUsIFJ0bEluaXRTdHJpbmcpOwogIE5URlVOQ19CSU5EKG1vZHVs
ZSwgUnRsQW5zaVN0cmluZ1RvVW5pY29kZVN0cmluZyk7CiAgTlRGVU5DX0JJ
TkQobW9kdWxlLCBSdGxGcmVlVW5pY29kZVN0cmluZyk7CiAgTlRGVU5DX0JJ
TkQobW9kdWxlLCBSdGxVbmljb2RlU3RyaW5nVG9BbnNpU3RyaW5nKTsKICBO
VEZVTkNfQklORChtb2R1bGUsIFJ0bEZyZWVBbnNpU3RyaW5nKTsKfQoKdm9p
ZCBtb2RpZmllZFNldEN1cnJlbnREaXJlY3RvcnkgKAogICAgY29uc3QgTnRG
dW5jcyYgbnQsCiAgICBDUklUSUNBTF9TRUNUSU9OICpDd2RDUywKICAgIFZp
c3RhQ3dkICoqQ3dkLAogICAgVU5JQ09ERV9TVFJJTkcmIHVwYXRoKQp7CiAg
Ly8gVGhlIHJlYWwgU2V0Q3VycmVudERpcmVjdG9yeSAoKSBpbXBsZW1lbnRh
dGlvbiBjYWxscwogIC8vIGEgbm9uLWV4cG9ydGVkIGZ1bmN0aW9uIHRoYXQg
YXBwZWFycyB0byBleHBhbmQgcmVsYXRpdmUKICAvLyBwYXRocyB0byBhYnNv
bHV0ZSBwYXRocyBhbmQgY29udmVydCAvIHRvIFwuICBJdCBtaWdodAogIC8v
IGFsc28gZG8gb3RoZXIgdGhpbmdzLgogIC8vCiAgLy8gVGhlcmUgYXBwZWFy
IHRvIGJlIG5vIGxvY2tzIG9uIHRoZSBQRUIgb3IgQ3dkIHRoYXQKICAvLyBw
ZXJzaXN0IGJldHdlZW4gdGhpcyBjb252ZXJzaW9uIGFuZCB0aGUgYWN0dWFs
IFdpbjMyCiAgLy8gQ1dEIGNoYW5nZSwgc28gcHJlc3VtYWJseSB0aGUgZm9s
bG93aW5nIHJhY2UgaXMgcG9zc2libGU6CiAgLy8KICAvLyAgIDEuIFRocmVh
ZCBBIGNhbGxzIFNldEN1cnJlbnREaXJlY3RvcnkoIkM6XFxhXFxiIikuCiAg
Ly8KICAvLyAgIDIuIFRocmVhZCBBIGNyZWF0ZXMgVGhyZWFkIEIuCiAgLy8K
ICAvLyAgIDMuIFRocmVhZCBBIHN0YXJ0cyBjYWxsaW5nIFNldEN1cnJlbnRE
aXJlY3RvcnkoIi4uIikKICAvLyAgICAgIGFuZCBnZXRzIHRocm91Z2ggcmVs
YXRpdmUtdG8tYWJzb2x1dGUgY29udmVyc2lvbiwKICAvLyAgICAgIHlpZWxk
aW5nICJDOlxcYSIgYXMgdGhlIGRlc2lyZWQgQ1dELgogIC8vCiAgLy8gICA0
LiBUaHJlYWQgQiBjYWxscyBTZXRDdXJyZW50RGlyZWN0b3J5KCJDOlxcZFxc
ZSIpLgogIC8vCiAgLy8gICA1LiBUaHJlYWQgQSBhY3F1aXJlcyBDd2RDUyBh
bmQgc2V0cyBDd2QgdG8gYSBuZXcKICAvLyAgICAgIFZpc3RhQ3dkIGluc3Rh
bmNlIHRoYXQgc3BlY2lmaWVzICJDOlxcYSIuCiAgLy8KICAvLyBIb2xkaW5n
IGEgbG9jayBiZXR3ZWVuICgzKSBhbmQgKDUpIHdvdWxkIGZvcmNlCiAgLy8g
KDQpIHRvIGNvbWUgZWl0aGVyIGJlZm9yZSAoMykgb3IgYWZ0ZXIgKDUpLCBi
dXQKICAvLyB0aGVyZSB3b3VsZCBzdGlsbCBiZSBhIHJhY2U6IGlmICg0KSBj
b21lcyBmaXJzdCwKICAvLyB0aGVuIHRoZSBmaW5hbCBDV0QgaXMgIkM6XFxk
Iiwgd2hlcmVhcyBpZiAoNCkKICAvLyBjb21lcyBsYXN0LCB0aGVuIHRoZSBm
aW5hbCBDV0QgaXMgIkM6XFxkXFxlIi4KICAvLyBQcm9iYWJseSB0aGF0IGlz
IHdoeSBubyBsb2NrIGlzIGhlbGQ6IGl0IHdvdWxkCiAgLy8gaW5jcmVhc2Ug
Y29udGVudGlvbiBidXQgbm90IGVsaW1pbmF0ZSByYWNlcy4KICAvLwogIC8v
IE9uIHRoZSBvdGhlciBoYW5kLCBpdCBhcHBlYXJzIHRoYXQgYXQgbGVhc3Qg
c29tZQogIC8vIG90aGVyIHZlcnNpb25zIG9mIFdpbmRvd3MgdGhhdCBkbyBu
b3QgdXNlIHRoZQogIC8vIFZpc3RhQ3dkIG1lY2hhbmlzbSwgc3VjaCBhcyBX
aW5kb3dzIFNlcnZlciAyMDAzIFIyIHg2NCwKICAvLyBtaWdodCBhY3R1YWxs
eSBhY3F1aXJlIGEgbG9jayBiZWZvcmUgcmVsYXRpdmUtdG8tYWJzb2x1dGUK
ICAvLyBwYXRoIGNvbnZlcnNpb24uICBQZXJoYXBzIE1pY3Jvc29mdCByZXRo
b3VnaHQgdGhlIHJhY2VzCiAgLy8gd2hlbiB0aGV5IGNoYW5nZWQgdG8gdGhl
IG5ld2VyIG1lY2hhbmlzbT8KICAvLwogIC8vIEFueXdheSwgdGhlIG91dHB1
dCBvZiByZWxhdGl2ZS10by1hYnNvbHV0ZSBjb252ZXJzaW9uCiAgLy8gaXMg
cnVuIHRocm91Z2ggYW5vdGhlciwgbm9uLWV4cG9ydGVkIHBhdGggY29udmVy
c2lvbgogIC8vIGZ1bmN0aW9uIHRoYXQgcHJlZml4ZXMgXD8/XCBhbmQgcHJl
c3VtYWJseSBkb2VzCiAgLy8gb3RoZXIgbm9ybWFsaXphdGlvbnMgYXBwcm9w
cmlhdGUgdG8gc3VjaCBwYXRocy4KICAvLyBIb3dldmVyLCB0aGF0IHNwZWNp
YWwgZm9ybSBpcyB1c2VkIG9ubHkgYXMgYW4gYXJndW1lbnQKICAvLyB0byBO
dE9wZW5GaWxlKCktLWl0IGRvZXMgTk9UIGdldCBwdXQgaW50byB0aGUgbmV3
CiAgLy8gVmlzdGFDd2QgaW5zdGFuY2UuICBJbnN0ZWFkLCB0aGUgVmlzdGFD
d2QgaW5zdGFuY2UKICAvLyBnZXRzIGEgc2VwYXJhdGUgY29weSBvZiB0aGUg
b3V0cHV0IG9mIHRoZQogIC8vIHJlbGF0aXZlLXRvLWFic29sdXRlIGNvbnZl
cnNpb24sIGFuZCBpbiB0aGlzIGNvcHkgb25seSwKICAvLyBhIGJhY2tzbGFz
aCBpcyBhcHBlbmRlZCBpZiB0aGUgYWJzb2x1dGUgcGF0aCBkaWQgbm90CiAg
Ly8gYWxyZWFkeSBlbmQgaW4gYSBiYWNrc2xhc2guCiAgLy8KICAvLyBJbiB0
aGlzIGltcGxlbWVudGF0aW9uIHdlIGRvIG5vdCBib3RoZXIgdG8gcGVyZm9y
bQogIC8vIHRoZSByZWxhdGl2ZS10by1hYnNvbHV0ZSBwYXRoIGNvbnZlcnNp
b247IGluc3RlYWQKICAvLyB3ZSBqdXN0IHdhcm4gaWYgdGhlIHBhdGggaXMg
bm90IGFic29sdXRlLgogIC8vIEJ1dCB3ZSBkbyBjb252ZXJ0IC8gdG8gXC4K
CiAgcmVwbGFjZSAodXBhdGguQnVmZmVyLCB1cGF0aC5CdWZmZXIgKyB1cGF0
aC5MZW5ndGggLyBzaXplb2Yod2NoYXJfdCksCiAgICAgICAgICAgTCcvJywg
TCdcXCcpOwogIGlmICh1cGF0aC5MZW5ndGggPCAzIHx8IHVwYXRoLkJ1ZmZl
clsxXSAhPSBMJzonIHx8IHVwYXRoLkJ1ZmZlclsyXSAhPSBMJ1xcJyl7CiAg
ICBjZXJyIDw8ICJSZWxhdGl2ZSBwYXRocyBub3QgaW1wbGVtZW50ZWQuIiA8
PCBlbmRsOwogICAgZXhpdCAoMSk7CiAgfQoKICAvLyBQcmVmaXggXD8/XCB0
byB0aGUgcGF0aCBiZWZvcmUgcGFzc2luZyBpdCB0byBOdE9wZW5GaWxlKCku
CiAgaWYgKHVwYXRoLkxlbmd0aCA+IChNQVhfUEFUSCAtIDUpICogc2l6ZW9m
KHdjaGFyX3QpKSB7CiAgICBjZXJyIDw8ICJQYXRoIHRvbyBsb25nLiIgPDwg
ZW5kbDsKICAgIGV4aXQoMSk7CiAgfQogIHdjaGFyX3QgbnR1cGF0aF9idWZb
TUFYX1BBVEhdOwogIFVOSUNPREVfU1RSSU5HIG50dXBhdGg7CiAgbnR1cGF0
aC5MZW5ndGggPSB1cGF0aC5MZW5ndGggKyA0ICogc2l6ZW9mKHdjaGFyX3Qp
OwogIG50dXBhdGguTWF4aW11bUxlbmd0aCA9IHNpemVvZiBudHVwYXRoX2J1
ZjsKICBudHVwYXRoLkJ1ZmZlciA9IG50dXBhdGhfYnVmOwogIG1lbWNweShu
dHVwYXRoX2J1ZiwgTCJcXD8/XFwiLCA0ICogc2l6ZW9mKHdjaGFyX3QpKTsK
ICBtZW1jcHkobnR1cGF0aF9idWYgKyA0LCB1cGF0aC5CdWZmZXIsIHVwYXRo
Lkxlbmd0aCk7CiAgbnR1cGF0aF9idWZbNCArICh1cGF0aC5MZW5ndGggLyBz
aXplb2Yod2NoYXJfdCkpXSA9IEwnXDAnOwoKICBSVExfVVNFUl9QUk9DRVNT
X1BBUkFNRVRFUlMmIFBhcmFtcwogICAgPSAqTnRDdXJyZW50VGViICgpLT5Q
ZWItPlByb2Nlc3NQYXJhbWV0ZXJzOwoKICBQVk9JRCBIZWFwSGFuZGxlID0g
KihQVk9JRCopKChjaGFyKilOdEN1cnJlbnRUZWIgKCktPlBlYiArIDB4MTgp
OwoKICB2b2xhdGlsZSBVTE9ORyYgRGlzbW91bnRDb3VudCA9ICoodm9sYXRp
bGUgVUxPTkcqKTB4N2ZmZTAyZGM7CgogIC8vIERvIHRoaXMgYmVmb3JlIHRo
ZSBOdE9wZW5GaWxlLCBqdXN0IGluIGNhc2UgdGhhdCBvcmRlciBtYXR0ZXJz
LgoKICBVTE9ORyBEaXNtb3VudENvdW50QmVmb3JlTnRPcGVuRmlsZSA9IERp
c21vdW50Q291bnQ7CgogIEhBTkRMRSBoOwogIE5UU1RBVFVTIHN0YXR1czsK
ICBJT19TVEFUVVNfQkxPQ0sgaW87CiAgT0JKRUNUX0FUVFJJQlVURVMgYXR0
cjsKCiAgSW5pdGlhbGl6ZU9iamVjdEF0dHJpYnV0ZXMgKCZhdHRyLCAmbnR1
cGF0aCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT0JKX0NBU0Vf
SU5TRU5TSVRJVkUgfCBPQkpfSU5IRVJJVCwKICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgTlVMTCwgTlVMTCk7CiAgc3RhdHVzID0gbnQuX050T3Bl
bkZpbGUgKCZoLCBTWU5DSFJPTklaRSB8IEZJTEVfVFJBVkVSU0UsICZhdHRy
LCAmaW8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgIEZJTEVfU0hBUkVf
VkFMSURfRkxBR1MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIEZJTEVf
RElSRUNUT1JZX0ZJTEUKICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBG
SUxFX1NZTkNIUk9OT1VTX0lPX05PTkFMRVJUCiAgICAgICAgICAgICAgICAg
ICAgICAgICAgIHwgRklMRV9PUEVOX0ZPUl9CQUNLVVBfSU5URU5UKTsKICBp
ZiAoIU5UX1NVQ0NFU1MgKHN0YXR1cykpCiAgewogICAgQU5TSV9TVFJJTkcg
bmFycm93OwogICAgbnQuX1J0bFVuaWNvZGVTdHJpbmdUb0Fuc2lTdHJpbmco
Jm5hcnJvdywgJm50dXBhdGgsIFRSVUUpOwoKICAgIGNlcnIgPDwgIkZhaWxl
ZCB0byBvcGVuIGRpcmVjdG9yeSAnIjsKICAgIGNlcnIud3JpdGUobmFycm93
LkJ1ZmZlciwgbmFycm93Lkxlbmd0aCk7CiAgICBjZXJyIDw8ICInOiBOVFNU
QVRVUyAiIDw8IHNob3diYXNlIDw8IGhleCA8PCBzdGF0dXMgPDwgZW5kbDsK
CiAgICBudC5fUnRsRnJlZUFuc2lTdHJpbmcoJm5hcnJvdyk7CgogICAgZXhp
dCgxKTsKICB9CgogIC8vIEFzIG1lbnRpb25lZCBiZWZvcmUsIGluIHByYWN0
aWNlIHRoaXMgaXMgc2l6ZW9mICh3Y2hhcl90IFtNQVhfUEFUSF0pLgoKICBV
U0hPUlQgTWF4aW11bUxlbmd0aCA9IFBhcmFtcy5DdXJyZW50RGlyZWN0b3J5
TmFtZS5NYXhpbXVtTGVuZ3RoOwoKICBWaXN0YUN3ZCAqbmV3Q3dkID0gKFZp
c3RhQ3dkICopIG50Ll9SdGxBbGxvY2F0ZUhlYXAgKEhlYXBIYW5kbGUsIDAs
CiAgICAgIG9mZnNldG9mIChWaXN0YUN3ZCwgQnVmZmVyKSArIE1heGltdW1M
ZW5ndGgpOwoKICBuZXdDd2QtPlJlZmVyZW5jZUNvdW50ID0gMTsKCiAgbmV3
Q3dkLT5EaXJlY3RvcnlIYW5kbGUgPSBoOwoKICBuZXdDd2QtPk9sZERpc21v
dW50Q291bnQgPSBEaXNtb3VudENvdW50QmVmb3JlTnRPcGVuRmlsZTsKCiAg
bmV3Q3dkLT5QYXRoLkxlbmd0aCA9IHVwYXRoLkxlbmd0aDsKCiAgbmV3Q3dk
LT5QYXRoLk1heGltdW1MZW5ndGggPSBNYXhpbXVtTGVuZ3RoOwoKICBuZXdD
d2QtPlBhdGguQnVmZmVyID0gbmV3Q3dkLT5CdWZmZXI7CgogIG1lbWNweSAo
bmV3Q3dkLT5CdWZmZXIsIHVwYXRoLkJ1ZmZlciwgdXBhdGguTGVuZ3RoKTsK
ICBuZXdDd2QtPkJ1ZmZlclt1cGF0aC5MZW5ndGggLyBzaXplb2Yod2NoYXJf
dCldID0gTCdcMCc7CgogIC8vIEluIG5ldyBWaXN0YUN3ZCBpbnN0YW5jZSwg
ZW5zdXJlIHRoYXQgdGhlIGZpbmFsIHBhdGggY2hhcmFjdGVyIGlzIEwnXFwn
OgoKICBpZiAobmV3Q3dkLT5CdWZmZXJbKHVwYXRoLkxlbmd0aCAvIHNpemVv
Zih3Y2hhcl90KSkgLSAxXSAhPSBMJ1xcJykgewogICAgaWYgKHVwYXRoLkxl
bmd0aCA+IG5ld0N3ZC0+UGF0aC5NYXhpbXVtTGVuZ3RoIC0gKDIgKiBzaXpl
b2Yod2NoYXJfdCkpKSB7CiAgICAgIGNlcnIgPDwgIlBhdGggdG9vIGxvbmcu
IiA8PCBlbmRsOwogICAgICBleGl0KDEpOwogICAgfQogICAgbmV3Q3dkLT5C
dWZmZXJbdXBhdGguTGVuZ3RoIC8gc2l6ZW9mKHdjaGFyX3QpXSA9IEwnXFwn
OwogICAgbmV3Q3dkLT5CdWZmZXJbKHVwYXRoLkxlbmd0aCAvIHNpemVvZih3
Y2hhcl90KSkgKyAxXSA9IEwnXDAnOwogICAgdXBhdGguTGVuZ3RoICs9IHNp
emVvZih3Y2hhcl90KTsKICB9CgogIC8vIE5PVEU6IFdlIG5ldmVyIGFjcXVp
cmUgdGhlIFBFQiBsb2NrLCBvbmx5IHRoZSBWaXN0YSsrIENXRCBsb2NrOgoK
ICBFbnRlckNyaXRpY2FsU2VjdGlvbihDd2RDUyk7CgogIFBhcmFtcy5DdXJy
ZW50RGlyZWN0b3J5SGFuZGxlID0gbmV3Q3dkLT5EaXJlY3RvcnlIYW5kbGU7
CgogIFBhcmFtcy5DdXJyZW50RGlyZWN0b3J5TmFtZS5CdWZmZXIgPSBuZXdD
d2QtPlBhdGguQnVmZmVyOwoKICBQYXJhbXMuQ3VycmVudERpcmVjdG9yeU5h
bWUuTGVuZ3RoID0gbmV3Q3dkLT5QYXRoLkxlbmd0aDsKCiAgVmlzdGFDd2Qg
Km9sZEN3ZCA9ICpDd2Q7CgogICpDd2QgPSBuZXdDd2Q7CgogIExlYXZlQ3Jp
dGljYWxTZWN0aW9uKEN3ZENTKTsKCiAgaWYgKEludGVybG9ja2VkRGVjcmVt
ZW50KCZvbGRDd2QtPlJlZmVyZW5jZUNvdW50KSA9PSAwKSB7CiAgICBudC5f
TnRDbG9zZSAob2xkQ3dkLT5EaXJlY3RvcnlIYW5kbGUpOwoKICAgIG50Ll9S
dGxGcmVlSGVhcCAoSGVhcEhhbmRsZSwgMCwgb2xkQ3dkKTsKICB9Cn0KCmlu
dCBtYWluIChpbnQgYXJnYywgY2hhciAqKmFyZ3YpCnsKICBITU9EVUxFIG1v
ZHVsZSA9IEdldE1vZHVsZUhhbmRsZSAoIm50ZGxsLmRsbCIpOwoKICAvLyBS
ZWFkaW5nIHRoZSBDV0QgaXMgc2ltcGxlciB0aGFuIHdyaXRpbmcgdGhlIENX
RCwKICAvLyB3aGljaCBtYWtlcyBpdCBlYXNpZXIgdG8gZmluZCB0aGUgYWRk
cmVzc2VzIHdlIG5lZWQsCiAgLy8gYW5kIG1pZ2h0IGFsc28gdGVuZCB0byBt
YWtlIGNvZGUgY2hhbmdlcyBsZXNzIGZyZXF1ZW50LgogIGNvbnN0IGNvZGVf
dCAqZ2V0X2RpciA9IChjb25zdCBjb2RlX3QqKSBHZXRQcm9jQWRkcmVzcwog
ICAgKG1vZHVsZSwgIlJ0bEdldEN1cnJlbnREaXJlY3RvcnlfVSIpOwoKICBj
b25zdCBjb2RlX3QgKmVudF9jcml0ID0gKGNvbnN0IGNvZGVfdCopIEdldFBy
b2NBZGRyZXNzCiAgICAobW9kdWxlLCAiUnRsRW50ZXJDcml0aWNhbFNlY3Rp
b24iKTsKCiAgLy8gRmluZCBmaXJzdCByZWxhdGl2ZSBjYWxsIGluc3RydWN0
aW9uLgogIGNvbnN0IGNvZGVfdCAqcmNhbGwgPSAoY29uc3QgY29kZV90ICop
IG1lbWNociAoZ2V0X2RpciwgMHhFOCwgMzIpOwogIGlmICghIHJjYWxsKSB7
CiAgICBiYWRDb2RlICgpOwogIH0KCiAgLy8gQ29tcHV0ZSB0aGUgYWRkcmVz
cywgdXNlX2N3ZCwgb2YgdGhlIGZ1bmN0aW9uIGJlaW5nIGNhbGxlZC4KICAv
LyBUaGlzIGZ1bmN0aW9uIGFjdHVhbGx5IGZldGNoZXMgdGhlIGN1cnJlbnQg
VmlzdGFDd2QgaW5zdGFuY2UKICAvLyBhbmQgcGVyZm9ybXMgYWN0aW9ucyBj
b25kaXRpb25lZCB1cG9uIHRoZSBmcmVzaG5lc3Mgb2YgaXRzCiAgLy8gT2xk
RGlzbW91bnRDb3VudCBtZW1iZXIuCiAgcHRyZGlmZl90IG9mZnNldCA9IHBl
ZWszMiAocmNhbGwgKyAxKTsKICBjb25zdCBjb2RlX3QgKnVzZV9jd2QgPSBy
Y2FsbCArIDUgKyBvZmZzZXQ7CgogIC8vIEZpbmQgdGhlIGZpcnN0ICJwdXNo
IGVkaSIgaW5zdHJ1Y3Rpb24uLi4KICBjb25zdCBjb2RlX3QgKm1vdmVkaSA9
IChjb25zdCBjb2RlX3QgKikgbWVtY2hyICh1c2VfY3dkLCAweDU3LCAzMik7
CiAgKyttb3ZlZGk7CiAgLy8gLi4ud2hpY2ggc2hvdWxkIGJlIGZvbGxvd2Vk
IGJ5ICJtb3YgZWRpLCBjcml0LXNlY3QtYWRkciIgdGhlbiAicHVzaCBlZGki
LgogIC8vIChJZGVhbGx5IHdlIHNob3VsZCBub3QgZGVwZW5kIHVwb24gJUVE
SSBiZWluZyB0aGUgcmVnaXN0ZXIsCiAgLy8gYnV0IHRoaXMgaXMgYSBwcm9v
ZiBvZiBjb25jZXB0LCBhbmQgZXZlbiB3aXRoIG1vcmUgZmxleGliaWxpdHkK
ICAvLyB3ZSBhcmUgc3RpbGwgZGVwZW5kaW5nIGhlYXZpbHkgdXBvbiBjb2Rl
IHN0cnVjdHVyZSBoZXJlLikKICBpZiAobW92ZWRpWzBdICE9IDB4QkYgfHwg
bW92ZWRpWzVdICE9IDB4NTcpIHsKICAgIGJhZENvZGUgKCk7CiAgfQogIC8v
IEdldCB0aGUgYWRkcmVzcyBvZiB0aGUgY3JpdGljYWwgc2VjdGlvbiBmb3Ig
dGhlIENXRC4KICBDUklUSUNBTF9TRUNUSU9OICpDd2RDUyA9IChDUklUSUNB
TF9TRUNUSU9OICopIHBlZWszMiAobW92ZWRpICsgMSk7CgogIC8vIFRvIGNo
ZWNrIHdlIGFyZSBzZWVpbmcgdGhlIHJpZ2h0IGNvZGUsIHdlIGNoZWNrIG91
ciBleHBlY3RhdGlvbiB0aGF0CiAgLy8gdGhlIG5leHQgaW5zdHJ1Y3Rpb24g
aXMgYSByZWxhdGl2ZSBjYWxsIGludG8gUnRsRW50ZXJDcml0aWNhbFNlY3Rp
b24uCiAgcmNhbGwgPSBtb3ZlZGkgKyA2OwogIGlmIChyY2FsbFswXSAhPSAw
eGU4KSB7CiAgICBiYWRDb2RlICgpOwogIH0KICBvZmZzZXQgPSBwZWVrMzIg
KHJjYWxsICsgMSk7CiAgaWYgKHJjYWxsICsgNSArIG9mZnNldCAhPSBlbnRf
Y3JpdCkgewogICAgYmFkQ29kZSAoKTsKICB9CgogIC8vIEFmdGVyIGxvY2tp
bmcgdGhlIGNyaXRpY2FsIHNlY3Rpb24sIHRoZSBjb2RlIHNob3VsZCByZWFk
IHRoZQogIC8vIGdsb2JhbCBDV0QgYmxvY2sgcG9pbnRlciB0aGF0IGlzIGd1
YXJkZWQgYnkgdGhhdCBjcml0aWNhbCBzZWN0aW9uLgogIGNvbnN0IGNvZGVf
dCAqbW92ZXNpID0gcmNhbGwgKyA1OwogIGlmIChtb3Zlc2lbMF0gIT0gMHg4
YikgewogICAgYmFkQ29kZSAoKTsKICB9CiAgVmlzdGFDd2QgKipDd2QgPSAo
VmlzdGFDd2QgKiopIHBlZWszMiAobW92ZXNpICsgMik7CgogIGNvdXQgPDwg
c2hvd2Jhc2UgPDwgaGV4IDw8IChzaXplX3QpQ3dkQ1MKICAgICAgIDw8ICIg
IDw9PSBjcml0aWNhbCBzZWN0aW9uIiA8PCBlbmRsOwogIGNvdXQgPDwgc2hv
d2Jhc2UgPDwgaGV4IDw8IChzaXplX3QpQ3dkCiAgICAgICA8PCAiICA8PT0g
VmlzdGErKyBDV0Qgc3RydWN0IHBvaW50ZXIiIDw8IGVuZGw7CgogIGlmIChh
cmdjID49IDIpIHsKICAgIE50RnVuY3MgbnQobW9kdWxlKTsKCiAgICBTVFJJ
TkcgbnBhdGg7CiAgICBudC5fUnRsSW5pdFN0cmluZyAoJm5wYXRoLCBhcmd2
WzFdKTsKCiAgICBVTklDT0RFX1NUUklORyB1cGF0aDsKICAgIG50Ll9SdGxB
bnNpU3RyaW5nVG9Vbmljb2RlU3RyaW5nICgmdXBhdGgsICZucGF0aCwgVFJV
RSk7CgogICAgbW9kaWZpZWRTZXRDdXJyZW50RGlyZWN0b3J5IChudCwgQ3dk
Q1MsIEN3ZCwgdXBhdGgpOwoKICAgIG50Ll9SdGxGcmVlVW5pY29kZVN0cmlu
ZyAoJnVwYXRoKTsKCiAgICBjb3V0IDw8ICJDaGFuZ2VkIGRpcmVjdG9yeS4i
IDw8IGVuZGw7CiAgfQoKICBpZiAoYXJnYyA+PSAzKSB7CiAgICBIQU5ETEUg
aCA9IENyZWF0ZUZpbGUgKGFyZ3ZbMl0sIEdFTkVSSUNfUkVBRCwgMCwgTlVM
TCwgT1BFTl9FWElTVElORywKICAgICAgICAgICAgICAgICAgICAgICAgICAg
RklMRV9BVFRSSUJVVEVfTk9STUFMLCBOVUxMKTsKICAgIGlmIChoID09IElO
VkFMSURfSEFORExFX1ZBTFVFKSB7CiAgICAgIHdpbkVycm9yKGNlcnIgPDwg
IkZhaWxlZCB0byBvcGVuIGZpbGU6ICIpIDw8IGVuZGw7CiAgICAgIHJldHVy
biAxOwogICAgfQoKICAgIGNvdXQgPDwgIlN1Y2Nlc3NmdWxseSBvcGVuZWQg
ZmlsZS4iIDw8IGVuZGw7CiAgICBpZiAoISBDbG9zZUhhbmRsZSAoaCkpIHsK
ICAgICAgd2luRXJyb3IoY2VyciA8PCAiRmFpbGVkIHRvIGNsb3NlIGZpbGU6
ICIpIDw8IGVuZGw7CiAgICAgIHJldHVybiAxOwogICAgfQogIH0KCiAgcmV0
dXJuIDA7Cn0K


--_002_3C031C390CBF1E4A8CE1F74DE7ECAF3A158EDA704CMBX8EXCHPRODU_
Content-Type: text/plain; charset=us-ascii

--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
--_002_3C031C390CBF1E4A8CE1F74DE7ECAF3A158EDA704CMBX8EXCHPRODU_--

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019