Browse Source

HADOOP-9483. Adding a file missed in previous commit r1478592

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1478633 13f79535-47bb-0310-9956-ffa450edef68
Suresh Srinivas 12 years ago
parent
commit
4b93035997
1 changed files with 224 additions and 0 deletions
  1. 224 0
      hadoop-common-project/hadoop-common/src/main/winutils/readlink.c

+ 224 - 0
hadoop-common-project/hadoop-common/src/main/winutils/readlink.c

@@ -0,0 +1,224 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include "winutils.h"
+
+
+//----------------------------------------------------------------------------
+// The Windows SDK does not include the definition of REPARSE_DATA_BUFFER. To
+// avoid adding a dependency on the WDK we define the structure here.
+// Reference: http://msdn.microsoft.com/en-us/library/ff552012.aspx
+//
+#pragma warning(push)
+#pragma warning(disable: 4201)  // nonstandard extension: nameless struct/union
+#pragma pack(push, 1)
+typedef struct _REPARSE_DATA_BUFFER {
+  ULONG  ReparseTag;
+  USHORT ReparseDataLength;
+  USHORT Reserved;
+  union {
+    struct {
+      USHORT SubstituteNameOffset;
+      USHORT SubstituteNameLength;
+      USHORT PrintNameOffset;
+      USHORT PrintNameLength;
+      ULONG  Flags;
+      WCHAR  PathBuffer[1];
+    } SymbolicLinkReparseBuffer;
+    struct {
+      USHORT SubstituteNameOffset;
+      USHORT SubstituteNameLength;
+      USHORT PrintNameOffset;
+      USHORT PrintNameLength;
+      WCHAR  PathBuffer[1];
+    } MountPointReparseBuffer;
+    struct {
+      UCHAR DataBuffer[1];
+    } GenericReparseBuffer;
+  };
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+#pragma pack(pop)
+#pragma warning(pop)
+
+
+//----------------------------------------------------------------------------
+// Function: Readlink
+//
+// Description:
+//  Prints the target of a symbolic link to stdout.
+//
+//  The return codes and output are modeled after the UNIX readlink command. 
+//  Hence no error messages are printed. Unlike the UNIX readlink, no options
+//  are accepted.
+//
+// Returns:
+//  0: on success
+//  1: on all errors
+//
+// Notes:
+//
+int Readlink(__in int argc, __in_ecount(argc) wchar_t *argv[])
+{
+  DWORD bytesReturned;
+  DWORD bufferSize = 1024;                  // Start off with a 1KB buffer.
+  HANDLE hFile = INVALID_HANDLE_VALUE;
+  PWSTR longLinkName = NULL;
+  PWCHAR printName = NULL;
+  PREPARSE_DATA_BUFFER pReparseData = NULL;
+  USHORT printNameLength;
+  USHORT printNameOffset;
+  DWORD result;
+  BOOLEAN succeeded = FALSE;
+  
+  if (argc != 2)
+  {
+    ReadlinkUsage();
+    goto Cleanup;
+  }
+
+  if (ConvertToLongPath(argv[1], &longLinkName) != ERROR_SUCCESS)
+  {
+    goto Cleanup;
+  }
+
+  // Get a handle to the link to issue the FSCTL.
+  // FILE_FLAG_BACKUP_SEMANTICS is needed to open directories.
+  // FILE_FLAG_OPEN_REPARSE_POINT disables normal reparse point processing
+  // so we can query the symlink.
+  //
+  hFile = CreateFileW(longLinkName,
+                      0,        // no rights needed to issue the FSCTL.
+                      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                      NULL,
+                      OPEN_EXISTING,
+                      FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+                      NULL);
+
+  if (hFile == INVALID_HANDLE_VALUE) 
+  {
+    goto Cleanup;
+  }
+
+  for (;;)
+  {
+    pReparseData = (PREPARSE_DATA_BUFFER) LocalAlloc(LMEM_FIXED, bufferSize);
+
+    if (pReparseData == NULL) 
+    {
+      goto Cleanup;
+    }
+
+    // Issue the FSCTL to query the link information.
+    //
+    result = DeviceIoControl(hFile,
+                             FSCTL_GET_REPARSE_POINT,
+                             NULL,
+                             0,
+                             pReparseData,
+                             bufferSize,
+                             &bytesReturned,
+                             NULL);
+
+    if (result != 0)
+    {
+      // Success!
+      //
+      break;
+    }
+    else if ((GetLastError() == ERROR_INSUFFICIENT_BUFFER) ||
+             (GetLastError() == ERROR_MORE_DATA))
+    {
+      // Retry with a larger buffer.
+      //
+      LocalFree(pReparseData);
+      bufferSize *= 2;
+    }
+    else
+    {
+      // Unrecoverable error.
+      //
+      goto Cleanup;
+    }
+  }
+
+  if (pReparseData->ReparseTag != IO_REPARSE_TAG_SYMLINK) 
+  {
+    // Doesn't look like a symlink.
+    //
+    goto Cleanup;
+  }
+
+  // MSDN does not guarantee that the embedded paths in REPARSE_DATA_BUFFER
+  // will be NULL terminated. So we copy the string to a separate buffer and
+  // NULL terminate it before printing.
+  //
+  printNameLength = pReparseData->SymbolicLinkReparseBuffer.PrintNameLength;
+  printNameOffset = pReparseData->SymbolicLinkReparseBuffer.PrintNameOffset;
+  printName = (PWCHAR) LocalAlloc(LMEM_FIXED, printNameLength + 1);
+
+  if (printName == NULL) 
+  {
+    goto Cleanup;
+  }
+
+  memcpy(
+      printName,
+      pReparseData->SymbolicLinkReparseBuffer.PathBuffer + printNameOffset,
+      printNameLength);
+
+  printName[printNameLength / sizeof(WCHAR)] = L'\0';
+
+  fwprintf(stdout, L"%ls", printName);
+  succeeded = TRUE;
+
+Cleanup:
+  if (hFile != INVALID_HANDLE_VALUE) 
+  {
+    CloseHandle(hFile);
+  }
+
+  if (printName != NULL) 
+  {
+    LocalFree(printName);
+  }
+
+  if (pReparseData != NULL)
+  {
+    LocalFree(pReparseData);
+  }
+
+  if (longLinkName != NULL)
+  {
+    LocalFree(longLinkName);
+  }
+
+  return (succeeded ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+void ReadlinkUsage()
+{
+    fwprintf(stdout, L"\
+Usage: readlink [LINKNAME]\n\
+Prints the target of a symbolic link\n\
+The output and returned error codes are similar to the UNIX\n\
+readlink command. However no options are accepted.\n\
+\n\
+0 is returned on success.\n\
+1 is returned for all errors.\n\
+\n");
+}
+