You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by su...@apache.org on 2013/03/06 20:15:22 UTC

svn commit: r1453486 [4/7] - in /hadoop/common/trunk/hadoop-common-project/hadoop-common: ./ src/main/bin/ src/main/conf/ src/main/docs/src/documentation/content/xdocs/ src/main/java/ src/main/java/org/apache/hadoop/fs/ src/main/java/org/apache/hadoop/...

Added: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/chmod.c
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/chmod.c?rev=1453486&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/chmod.c (added)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/chmod.c Wed Mar  6 19:15:18 2013
@@ -0,0 +1,893 @@
+/**
+* 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"
+#include <errno.h>
+
+enum CHMOD_WHO
+{
+  CHMOD_WHO_NONE  =    0,
+  CHMOD_WHO_OTHER =   07,
+  CHMOD_WHO_GROUP =  070,
+  CHMOD_WHO_USER  = 0700,
+  CHMOD_WHO_ALL   = CHMOD_WHO_OTHER | CHMOD_WHO_GROUP | CHMOD_WHO_USER
+};
+
+enum CHMOD_OP
+{
+  CHMOD_OP_INVALID,
+  CHMOD_OP_PLUS,
+  CHMOD_OP_MINUS,
+  CHMOD_OP_EQUAL,
+};
+
+enum CHMOD_PERM
+{
+  CHMOD_PERM_NA =  00,
+  CHMOD_PERM_R  =  01,
+  CHMOD_PERM_W  =  02,
+  CHMOD_PERM_X  =  04,
+  CHMOD_PERM_LX = 010,
+};
+
+/*
+ * We use the following struct to build a linked list of mode change actions.
+ * The mode is described by the following grammar:
+ *  mode         ::= clause [, clause ...]
+ *  clause       ::= [who ...] [action ...]
+ *  action       ::= op [perm ...] | op [ref]
+ *  who          ::= a | u | g | o
+ *  op           ::= + | - | =
+ *  perm         ::= r | w | x | X
+ *  ref          ::= u | g | o
+ */
+typedef struct _MODE_CHANGE_ACTION
+{
+  USHORT who;
+  USHORT op;
+  USHORT perm;
+  USHORT ref;
+  struct _MODE_CHANGE_ACTION *next_action;
+} MODE_CHANGE_ACTION, *PMODE_CHANGE_ACTION;
+
+const MODE_CHANGE_ACTION INIT_MODE_CHANGE_ACTION = {
+  CHMOD_WHO_NONE, CHMOD_OP_INVALID, CHMOD_PERM_NA, CHMOD_WHO_NONE, NULL
+};
+
+static BOOL ParseOctalMode(LPCWSTR tsMask, INT *uMask);
+
+static BOOL ParseMode(LPCWSTR modeString, PMODE_CHANGE_ACTION *actions);
+
+static BOOL FreeActions(PMODE_CHANGE_ACTION actions);
+
+static BOOL ParseCommandLineArguments(__in int argc, __in wchar_t *argv[],
+  __out BOOL *rec, __out_opt INT *mask,
+  __out_opt PMODE_CHANGE_ACTION *actions, __out LPCWSTR *path);
+
+static BOOL ChangeFileModeByActions(__in LPCWSTR path,
+  PMODE_CHANGE_ACTION actions);
+
+static BOOL ChangeFileMode(__in LPCWSTR path, __in_opt INT mode,
+  __in_opt PMODE_CHANGE_ACTION actions);
+
+static BOOL ChangeFileModeRecursively(__in LPCWSTR path, __in_opt INT mode,
+  __in_opt PMODE_CHANGE_ACTION actions);
+
+
+//----------------------------------------------------------------------------
+// Function: Chmod
+//
+// Description:
+//  The main method for chmod command
+//
+// Returns:
+//  0: on success
+//
+// Notes:
+//
+int Chmod(int argc, wchar_t *argv[])
+{
+  LPWSTR pathName = NULL;
+  LPWSTR longPathName = NULL;
+
+  BOOL recursive = FALSE;
+
+  PMODE_CHANGE_ACTION actions = NULL;
+
+  INT unixAccessMask = 0;
+
+  DWORD dwRtnCode = 0;
+
+  int ret = EXIT_FAILURE;
+
+  // Parsing chmod arguments
+  //
+  if (!ParseCommandLineArguments(argc, argv,
+    &recursive, &unixAccessMask, &actions, &pathName))
+  {
+    fwprintf(stderr, L"Incorrect command line arguments.\n\n");
+    ChmodUsage(argv[0]);
+    return EXIT_FAILURE;
+  }
+
+  // Convert the path the the long path
+  //
+  dwRtnCode = ConvertToLongPath(pathName, &longPathName);
+  if (dwRtnCode != ERROR_SUCCESS)
+  {
+    ReportErrorCode(L"ConvertToLongPath", dwRtnCode);
+    goto ChmodEnd;
+  }
+
+  if (!recursive)
+  {
+    if (ChangeFileMode(longPathName, unixAccessMask, actions))
+    {
+      ret = EXIT_SUCCESS;
+    }
+  }
+  else
+  {
+    if (ChangeFileModeRecursively(longPathName, unixAccessMask, actions))
+    {
+      ret = EXIT_SUCCESS;
+    }
+  }
+
+ChmodEnd:
+  FreeActions(actions);
+  LocalFree(longPathName);
+
+  return ret;
+}
+
+//----------------------------------------------------------------------------
+// Function: ChangeFileMode
+//
+// Description:
+//  Wrapper function for change file mode. Choose either change by action or by
+//  access mask.
+//
+// Returns:
+//  TRUE: on success
+//  FALSE: otherwise
+//
+// Notes:
+//
+static BOOL ChangeFileMode(__in LPCWSTR path, __in_opt INT unixAccessMask,
+  __in_opt PMODE_CHANGE_ACTION actions)
+{
+  if (actions != NULL)
+    return ChangeFileModeByActions(path, actions);
+  else
+  {
+    DWORD dwRtnCode = ChangeFileModeByMask(path, unixAccessMask);
+    if (dwRtnCode != ERROR_SUCCESS)
+    {
+      ReportErrorCode(L"ChangeFileModeByMask", dwRtnCode);
+      return FALSE;
+    }
+    return TRUE;
+  }
+}
+
+//----------------------------------------------------------------------------
+// Function: ChangeFileModeRecursively
+//
+// Description:
+//  Travel the directory recursively to change the permissions.
+//
+// Returns:
+//  TRUE: on success
+//  FALSE: otherwise
+//
+// Notes:
+//  The recursion works in the following way:
+//    - If the path is not a directory, change its mode and return.
+//      Symbolic links and junction points are not considered as directories.
+//    - Otherwise, call the method on all its children, then change its mode.
+//
+static BOOL ChangeFileModeRecursively(__in LPCWSTR path, __in_opt INT mode,
+  __in_opt PMODE_CHANGE_ACTION actions)
+{
+  BOOL isDir = FALSE;
+  BOOL isSymlink = FALSE;
+  LPWSTR dir = NULL;
+
+  size_t pathSize = 0;
+  size_t dirSize = 0;
+
+  HANDLE hFind = INVALID_HANDLE_VALUE;
+  WIN32_FIND_DATA ffd;
+  DWORD dwRtnCode = ERROR_SUCCESS;
+  BOOL ret = FALSE;
+
+  if ((dwRtnCode = DirectoryCheck(path, &isDir)) != ERROR_SUCCESS)
+  {
+    ReportErrorCode(L"IsDirectory", dwRtnCode);
+    return FALSE;
+  }
+  if ((dwRtnCode = SymbolicLinkCheck(path, &isSymlink)) != ERROR_SUCCESS)
+  {
+    ReportErrorCode(L"IsSymbolicLink", dwRtnCode);
+    return FALSE;
+  }
+
+  if (isSymlink || !isDir)
+  {
+     if (ChangeFileMode(path, mode, actions))
+       return TRUE;
+     else
+       return FALSE;
+  }
+
+  if (FAILED(StringCchLengthW(path, STRSAFE_MAX_CCH - 3, &pathSize)))
+  {
+    return FALSE;
+  }
+  dirSize = pathSize + 3;
+  dir = (LPWSTR)LocalAlloc(LPTR, dirSize * sizeof(WCHAR));
+  if (dir == NULL)
+  {
+    ReportErrorCode(L"LocalAlloc", GetLastError());
+    goto ChangeFileModeRecursivelyEnd;
+  }
+
+  if (FAILED(StringCchCopyW(dir, dirSize, path)) ||
+    FAILED(StringCchCatW(dir, dirSize, L"\\*")))
+  {
+    goto ChangeFileModeRecursivelyEnd;
+  }
+
+  hFind = FindFirstFile(dir, &ffd);
+  if (hFind == INVALID_HANDLE_VALUE)
+  {
+    ReportErrorCode(L"FindFirstFile", GetLastError());
+    goto ChangeFileModeRecursivelyEnd;
+  }
+
+  do
+  {
+    LPWSTR filename = NULL;
+    LPWSTR longFilename = NULL;
+    size_t filenameSize = 0;
+
+    if (wcscmp(ffd.cFileName, L".") == 0 ||
+      wcscmp(ffd.cFileName, L"..") == 0)
+      continue;
+
+    filenameSize = pathSize + wcslen(ffd.cFileName) + 2;
+    filename = (LPWSTR)LocalAlloc(LPTR, filenameSize * sizeof(WCHAR));
+    if (filename == NULL)
+    {
+      ReportErrorCode(L"LocalAlloc", GetLastError());
+      goto ChangeFileModeRecursivelyEnd;
+    }
+
+    if (FAILED(StringCchCopyW(filename, filenameSize, path)) ||
+      FAILED(StringCchCatW(filename, filenameSize, L"\\")) ||
+      FAILED(StringCchCatW(filename, filenameSize, ffd.cFileName)))
+    {
+      LocalFree(filename);
+      goto ChangeFileModeRecursivelyEnd;
+    }
+     
+    // The child fileanme is not prepended with long path prefix.
+    // Convert the filename to long path format.
+    //
+    dwRtnCode = ConvertToLongPath(filename, &longFilename);
+    LocalFree(filename);
+    if (dwRtnCode != ERROR_SUCCESS)
+    {
+      ReportErrorCode(L"ConvertToLongPath", dwRtnCode);
+      LocalFree(longFilename);
+      goto ChangeFileModeRecursivelyEnd;
+    }
+
+    if(!ChangeFileModeRecursively(longFilename, mode, actions))
+    {
+      LocalFree(longFilename);
+      goto ChangeFileModeRecursivelyEnd;
+    }
+
+    LocalFree(longFilename);
+
+  } while (FindNextFileW(hFind, &ffd));
+
+  if (!ChangeFileMode(path, mode, actions))
+  {
+    goto ChangeFileModeRecursivelyEnd;
+  }
+
+  ret = TRUE;
+
+ChangeFileModeRecursivelyEnd:
+  LocalFree(dir);
+
+  return ret;
+}
+
+//----------------------------------------------------------------------------
+// Function: ParseCommandLineArguments
+//
+// Description:
+//  Parse command line arguments for chmod.
+//
+// Returns:
+//  TRUE: on success
+//  FALSE: otherwise
+//
+// Notes:
+//	1. Recursive is only set on directories
+//  2. 'actions' is NULL if the mode is octal
+//
+static BOOL ParseCommandLineArguments(__in int argc, __in wchar_t *argv[],
+  __out BOOL *rec,
+  __out_opt INT *mask,
+  __out_opt PMODE_CHANGE_ACTION *actions,
+  __out LPCWSTR *path)
+{
+  LPCWSTR maskString;
+  BY_HANDLE_FILE_INFORMATION fileInfo;
+  DWORD dwRtnCode = ERROR_SUCCESS;
+
+  assert(path != NULL);
+
+  if (argc != 3 && argc != 4)
+    return FALSE;
+
+  *rec = FALSE;
+  if (argc == 4)
+  {
+    maskString = argv[2];
+    *path = argv[3];
+
+    if (wcscmp(argv[1], L"-R") == 0)
+    {
+      // Check if the given path name is a file or directory
+      // Only set recursive flag if the given path is a directory
+      //
+      dwRtnCode = GetFileInformationByName(*path, FALSE, &fileInfo);
+      if (dwRtnCode != ERROR_SUCCESS)
+      {
+        ReportErrorCode(L"GetFileInformationByName", dwRtnCode);
+        return FALSE;
+      }
+
+      if (IsDirFileInfo(&fileInfo))
+      {
+        *rec = TRUE;
+      }
+    }
+    else
+      return FALSE;
+  }
+  else
+  {
+    maskString = argv[1];
+    *path = argv[2];
+  }
+
+  if (ParseOctalMode(maskString, mask))
+  {
+    return TRUE;
+  }
+  else if (ParseMode(maskString, actions))
+  {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+//----------------------------------------------------------------------------
+// Function: FreeActions
+//
+// Description:
+//  Free a linked list of mode change actions given the head node.
+//
+// Returns:
+//  TRUE: on success
+//  FALSE: otherwise
+//
+// Notes:
+//  none
+//
+static BOOL FreeActions(PMODE_CHANGE_ACTION actions)
+{
+  PMODE_CHANGE_ACTION curr = NULL;
+  PMODE_CHANGE_ACTION next = NULL;
+  
+  // Nothing to free if NULL is passed in
+  //
+  if (actions == NULL)
+  {
+    return TRUE;
+  }
+
+  curr = actions;
+  while (curr != NULL)
+  {
+    next = curr->next_action;
+    LocalFree(curr);
+    curr = next;
+  }
+  actions = NULL;
+
+  return TRUE;
+}
+
+//----------------------------------------------------------------------------
+// Function: ComputeNewMode
+//
+// Description:
+//  Compute a new mode based on the old mode and a mode change action.
+//
+// Returns:
+//  The newly computed mode
+//
+// Notes:
+//  Apply 'rwx' permission mask or reference permission mode according to the
+//  '+', '-', or '=' operator.
+//
+static INT ComputeNewMode(__in INT oldMode,
+  __in USHORT who, __in USHORT op,
+  __in USHORT perm, __in USHORT ref)
+{
+  static const INT readMask  = 0444;
+  static const INT writeMask = 0222;
+  static const INT exeMask   = 0111;
+
+  INT mask = 0;
+  INT mode = 0;
+
+  // Operations are exclusive, and cannot be invalid
+  //
+  assert(op == CHMOD_OP_EQUAL || op == CHMOD_OP_PLUS || op == CHMOD_OP_MINUS);
+
+  // Nothing needs to be changed if there is not permission or reference
+  //
+  if(perm == CHMOD_PERM_NA && ref == CHMOD_WHO_NONE)
+  {
+    return oldMode;
+  }
+
+  // We should have only permissions or a reference target, not both.
+  //
+  assert((perm != CHMOD_PERM_NA && ref == CHMOD_WHO_NONE) ||
+    (perm == CHMOD_PERM_NA && ref != CHMOD_WHO_NONE));
+
+  if (perm != CHMOD_PERM_NA)
+  {
+    if ((perm & CHMOD_PERM_R) == CHMOD_PERM_R)
+      mask |= readMask;
+    if ((perm & CHMOD_PERM_W) == CHMOD_PERM_W)
+      mask |= writeMask;
+    if ((perm & CHMOD_PERM_X) == CHMOD_PERM_X)
+      mask |= exeMask;
+    if (((perm & CHMOD_PERM_LX) == CHMOD_PERM_LX))
+    {
+      // It applies execute permissions to directories regardless of their
+      // current permissions and applies execute permissions to a file which
+      // already has at least 1 execute permission bit already set (either user,
+      // group or other). It is only really useful when used with '+' and
+      // usually in combination with the -R option for giving group or other
+      // access to a big directory tree without setting execute permission on
+      // normal files (such as text files), which would normally happen if you
+      // just used "chmod -R a+rx .", whereas with 'X' you can do
+      // "chmod -R a+rX ." instead (Source: Wikipedia)
+      //
+      if ((oldMode & UX_DIRECTORY) == UX_DIRECTORY || (oldMode & exeMask))
+        mask |= exeMask;
+    }
+  }
+  else if (ref != CHMOD_WHO_NONE)
+  {
+    mask |= oldMode & ref;
+    switch(ref)
+    {
+    case CHMOD_WHO_GROUP:
+      mask |= mask >> 3;
+      mask |= mask << 3;
+      break;
+    case CHMOD_WHO_OTHER:
+      mask |= mask << 3;
+      mask |= mask << 6;
+      break;
+    case CHMOD_WHO_USER:
+      mask |= mask >> 3;
+      mask |= mask >> 6;
+      break;
+    default:
+      // Reference modes can only be U/G/O and are exclusive
+      assert(FALSE);
+    }
+  }
+
+  mask &= who;
+
+  if (op == CHMOD_OP_EQUAL)
+  {
+    mode = (oldMode & (~who)) | mask;
+  }
+  else if (op == CHMOD_OP_MINUS)
+  {
+    mode = oldMode & (~mask);
+  }
+  else if (op == CHMOD_OP_PLUS)
+  {
+    mode = oldMode | mask;
+  }
+
+  return mode;
+}
+
+//----------------------------------------------------------------------------
+// Function: ConvertActionsToMask
+//
+// Description:
+//  Convert a linked list of mode change actions to the Unix permission mask
+//  given the head node.
+//
+// Returns:
+//  TRUE: on success
+//  FALSE: otherwise
+//
+// Notes:
+//  none
+//
+static BOOL ConvertActionsToMask(__in LPCWSTR path,
+  __in PMODE_CHANGE_ACTION actions, __out PINT puMask)
+{
+  PMODE_CHANGE_ACTION curr = NULL;
+
+  BY_HANDLE_FILE_INFORMATION fileInformation;
+  DWORD dwErrorCode = ERROR_SUCCESS;
+
+  INT mode = 0;
+
+  dwErrorCode = GetFileInformationByName(path, FALSE, &fileInformation);
+  if (dwErrorCode != ERROR_SUCCESS)
+  {
+    ReportErrorCode(L"GetFileInformationByName", dwErrorCode);
+    return FALSE;
+  }
+  if (IsDirFileInfo(&fileInformation))
+  {
+    mode |= UX_DIRECTORY;
+  }
+  dwErrorCode = FindFileOwnerAndPermission(path, NULL, NULL, &mode);
+  if (dwErrorCode != ERROR_SUCCESS)
+  {
+    ReportErrorCode(L"FindFileOwnerAndPermission", dwErrorCode);
+    return FALSE;
+  }
+  *puMask = mode;
+
+  // Nothing to change if NULL is passed in
+  //
+  if (actions == NULL)
+  {
+    return TRUE;
+  }
+
+  for (curr = actions; curr != NULL; curr = curr->next_action)
+  {
+    mode = ComputeNewMode(mode, curr->who, curr->op, curr->perm, curr->ref);
+  }
+
+  *puMask = mode;
+  return TRUE;
+}
+
+//----------------------------------------------------------------------------
+// Function: ChangeFileModeByActions
+//
+// Description:
+//  Change a file mode through a list of actions.
+//
+// Returns:
+//  TRUE: on success
+//  FALSE: otherwise
+//
+// Notes:
+//  none
+//
+static BOOL ChangeFileModeByActions(__in LPCWSTR path,
+  PMODE_CHANGE_ACTION actions)
+{
+  INT mask = 0;
+
+  if (ConvertActionsToMask(path, actions, &mask))
+  {
+    DWORD dwRtnCode = ChangeFileModeByMask(path, mask);
+    if (dwRtnCode != ERROR_SUCCESS)
+    {
+      ReportErrorCode(L"ChangeFileModeByMask", dwRtnCode);
+      return FALSE;
+    }
+    return TRUE;
+  }
+  else
+    return FALSE;
+}
+
+//----------------------------------------------------------------------------
+// Function: ParseMode
+//
+// Description:
+//  Convert a mode string into a linked list of actions
+//
+// Returns:
+//  TRUE: on success
+//  FALSE: otherwise
+//
+// Notes:
+//  Take a state machine approach to parse the mode. Each mode change action
+//  will be a node in the output linked list. The state machine has five state,
+//  and each will only transit to the next; the end state can transit back to
+//  the first state, and thus form a circle. In each state, if we see a
+//  a character not belongs to the state, we will move to next state. WHO, PERM,
+//  and REF states are optional; OP and END states are required; and errors
+//  will only be reported at the latter two states.
+//
+static BOOL ParseMode(LPCWSTR modeString, PMODE_CHANGE_ACTION *pActions)
+{
+  enum __PARSE_MODE_ACTION_STATE
+  {
+    PARSE_MODE_ACTION_WHO_STATE,
+    PARSE_MODE_ACTION_OP_STATE,
+    PARSE_MODE_ACTION_PERM_STATE,
+    PARSE_MODE_ACTION_REF_STATE,
+    PARSE_MODE_ACTION_END_STATE
+  } state = PARSE_MODE_ACTION_WHO_STATE;
+
+  MODE_CHANGE_ACTION action = INIT_MODE_CHANGE_ACTION;
+  PMODE_CHANGE_ACTION actionsEnd = NULL;
+  PMODE_CHANGE_ACTION actionsLast = NULL;
+  USHORT lastWho;
+  WCHAR c = 0;
+  size_t len = 0;
+  size_t i = 0;
+
+  assert(modeString != NULL && pActions != NULL);
+
+  if (FAILED(StringCchLengthW(modeString, STRSAFE_MAX_CCH, &len)))
+  {
+    return FALSE;
+  }
+
+  actionsEnd = *pActions;
+  while(i <= len)
+  {
+    c = modeString[i];
+    if (state == PARSE_MODE_ACTION_WHO_STATE)
+    {
+      switch (c)
+      {
+      case L'a':
+        action.who |= CHMOD_WHO_ALL;
+        i++;
+        break;
+      case L'u':
+        action.who |= CHMOD_WHO_USER;
+        i++;
+        break;
+      case L'g':
+        action.who |= CHMOD_WHO_GROUP;
+        i++;
+        break;
+      case L'o':
+        action.who |= CHMOD_WHO_OTHER;
+        i++;
+        break;
+      default:
+        state = PARSE_MODE_ACTION_OP_STATE;
+      } // WHO switch
+    }
+    else if (state == PARSE_MODE_ACTION_OP_STATE)
+    {
+      switch (c)
+      {
+      case L'+':
+        action.op = CHMOD_OP_PLUS;
+        break;
+      case L'-':
+        action.op = CHMOD_OP_MINUS;
+        break;
+      case L'=':
+        action.op = CHMOD_OP_EQUAL;
+        break;
+      default:
+        fwprintf(stderr, L"Invalid mode: '%s'\n", modeString);
+        FreeActions(*pActions);
+        return FALSE;
+      } // OP switch
+      i++;
+      state = PARSE_MODE_ACTION_PERM_STATE;
+    }
+    else if (state == PARSE_MODE_ACTION_PERM_STATE)
+    {
+      switch (c)
+      {
+      case L'r':
+        action.perm |= CHMOD_PERM_R;
+        i++;
+        break;
+      case L'w':
+        action.perm |= CHMOD_PERM_W;
+        i++;
+        break;
+      case L'x':
+        action.perm |= CHMOD_PERM_X;
+        i++;
+        break;
+      case L'X':
+        action.perm |= CHMOD_PERM_LX;
+        i++;
+        break;
+      default:
+        state = PARSE_MODE_ACTION_REF_STATE;
+      } // PERM switch
+    }
+    else if (state == PARSE_MODE_ACTION_REF_STATE)
+    {
+      switch (c)
+      {
+      case L'u':
+        action.ref = CHMOD_WHO_USER;
+        i++;
+        break;
+      case L'g':
+        action.ref = CHMOD_WHO_GROUP;
+        i++;
+        break;
+      case L'o':
+        action.ref = CHMOD_WHO_OTHER;
+        i++;
+        break;
+      default:
+        state = PARSE_MODE_ACTION_END_STATE;
+      } // REF switch
+    }
+    else if (state == PARSE_MODE_ACTION_END_STATE)
+    {
+      switch (c)
+      {
+      case NULL:
+      case L',':
+        i++;
+      case L'+':
+      case L'-':
+      case L'=':
+        state = PARSE_MODE_ACTION_WHO_STATE;
+
+        // Append the current action to the end of the linked list
+        //
+        assert(actionsEnd == NULL);
+        // Allocate memory
+        actionsEnd = (PMODE_CHANGE_ACTION) LocalAlloc(LPTR,
+          sizeof(MODE_CHANGE_ACTION));
+        if (actionsEnd == NULL)
+        {
+          ReportErrorCode(L"LocalAlloc", GetLastError());
+          FreeActions(*pActions);
+          return FALSE;
+        }
+        if (action.who == CHMOD_WHO_NONE) action.who = CHMOD_WHO_ALL;
+        // Copy the action to the new node
+        *actionsEnd = action;
+        // Append to the last node in the linked list
+        if (actionsLast != NULL) actionsLast->next_action = actionsEnd;
+        // pActions should point to the head of the linked list
+        if (*pActions == NULL) *pActions = actionsEnd;
+        // Update the two pointers to point to the last node and the tail
+        actionsLast = actionsEnd;
+        actionsEnd = actionsLast->next_action;
+
+        // Reset action
+        //
+        lastWho = action.who;
+        action = INIT_MODE_CHANGE_ACTION;
+        if (c != L',')
+        {
+          action.who = lastWho;
+        }
+
+        break;
+      default:
+        fwprintf(stderr, L"Invalid mode: '%s'\n", modeString);
+        FreeActions(*pActions);
+        return FALSE;
+      } // END switch
+    }
+  } // while
+  return TRUE;
+}
+
+//----------------------------------------------------------------------------
+// Function: ParseOctalMode
+//
+// Description:
+//  Convert the 3 or 4 digits Unix mask string into the binary representation
+//  of the Unix access mask, i.e. 9 bits each an indicator of the permission
+//  of 'rwxrwxrwx', i.e. user's, group's, and owner's read, write, and
+//  execute/search permissions.
+//
+// Returns:
+//  TRUE: on success
+//  FALSE: otherwise
+//
+// Notes:
+//	none
+//
+static BOOL ParseOctalMode(LPCWSTR tsMask, INT *uMask)
+{
+  size_t tsMaskLen = 0;
+  DWORD i;
+  LONG l;
+  WCHAR *end;
+
+  if (uMask == NULL)
+    return FALSE;
+
+  if (FAILED(StringCchLengthW(tsMask, STRSAFE_MAX_CCH, &tsMaskLen)))
+    return FALSE;
+
+  if (tsMaskLen == 0 || tsMaskLen > 4)
+  {
+    return FALSE;
+  }
+
+  for (i = 0; i < tsMaskLen; i++)
+  {
+    if (!(tsMask[tsMaskLen - i - 1] >= L'0' &&
+      tsMask[tsMaskLen - i - 1] <= L'7'))
+      return FALSE;
+  }
+
+  errno = 0;
+  if (tsMaskLen == 4)
+    // Windows does not have any equivalent of setuid/setgid and sticky bit.
+    // So the first bit is omitted for the 4 digit octal mode case.
+    //
+    l = wcstol(tsMask + 1, &end, 8);
+  else
+    l = wcstol(tsMask, &end, 8);
+
+  if (errno || l > 0x0777 || l < 0 || *end != 0)
+  {
+    return FALSE;
+  }
+
+  *uMask = (INT) l;
+
+  return TRUE;
+}
+
+void ChmodUsage(LPCWSTR program)
+{
+  fwprintf(stdout, L"\
+Usage: %s [OPTION] OCTAL-MODE [FILE]\n\
+   or: %s [OPTION] MODE [FILE]\n\
+Change the mode of the FILE to MODE.\n\
+\n\
+   -R: change files and directories recursively\n\
+\n\
+Each MODE is of the form '[ugoa]*([-+=]([rwxX]*|[ugo]))+'.\n",
+program, program);
+}

Added: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/chown.c
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/chown.c?rev=1453486&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/chown.c (added)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/chown.c Wed Mar  6 19:15:18 2013
@@ -0,0 +1,270 @@
+/**
+ * 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"
+
+//----------------------------------------------------------------------------
+// Function: ChangeFileOwnerBySid
+//
+// Description:
+//  Change a file or directory ownership by giving new owner and group SIDs
+//
+// Returns:
+//  ERROR_SUCCESS: on success
+//  Error code: otherwise
+//
+// Notes:
+//  This function is long path safe, i.e. the path will be converted to long
+//  path format if not already converted. So the caller does not need to do
+//  the converstion before calling the method.
+//
+static DWORD ChangeFileOwnerBySid(__in LPCWSTR path,
+  __in_opt PSID pNewOwnerSid, __in_opt PSID pNewGroupSid)
+{
+  LPWSTR longPathName = NULL;
+  INT oldMode = 0;
+
+  SECURITY_INFORMATION securityInformation = 0;
+
+  DWORD dwRtnCode = ERROR_SUCCESS;
+
+  // Convert the path the the long path
+  //
+  dwRtnCode = ConvertToLongPath(path, &longPathName);
+  if (dwRtnCode != ERROR_SUCCESS)
+  {
+    goto ChangeFileOwnerByNameEnd;
+  }
+
+  // Get a pointer to the existing owner information and DACL
+  //
+  dwRtnCode = FindFileOwnerAndPermission(longPathName, NULL, NULL, &oldMode);
+  if (dwRtnCode != ERROR_SUCCESS)
+  {
+    goto ChangeFileOwnerByNameEnd;
+  }
+
+  // We need SeTakeOwnershipPrivilege to set the owner if the caller does not
+  // have WRITE_OWNER access to the object; we need SeRestorePrivilege if the
+  // SID is not contained in the caller's token, and have the SE_GROUP_OWNER
+  // permission enabled.
+  //
+  if (!EnablePrivilege(L"SeTakeOwnershipPrivilege"))
+  {
+    fwprintf(stdout, L"INFO: The user does not have SeTakeOwnershipPrivilege.\n");
+  }
+  if (!EnablePrivilege(L"SeRestorePrivilege"))
+  {
+    fwprintf(stdout, L"INFO: The user does not have SeRestorePrivilege.\n");
+  }
+
+  assert(pNewOwnerSid != NULL || pNewGroupSid != NULL);
+
+  // Set the owners of the file.
+  //
+  if (pNewOwnerSid != NULL) securityInformation |= OWNER_SECURITY_INFORMATION;
+  if (pNewGroupSid != NULL) securityInformation |= GROUP_SECURITY_INFORMATION;
+  dwRtnCode = SetNamedSecurityInfoW(
+    longPathName,
+    SE_FILE_OBJECT,
+    securityInformation,
+    pNewOwnerSid,
+    pNewGroupSid,
+    NULL,
+    NULL);
+  if (dwRtnCode != ERROR_SUCCESS)
+  {
+    goto ChangeFileOwnerByNameEnd;
+  }
+
+  // Set the permission on the file for the new owner.
+  //
+  dwRtnCode = ChangeFileModeByMask(longPathName, oldMode);
+  if (dwRtnCode != ERROR_SUCCESS)
+  {
+    goto ChangeFileOwnerByNameEnd;
+  }
+
+ChangeFileOwnerByNameEnd:
+  LocalFree(longPathName);
+  return dwRtnCode;
+}
+
+//----------------------------------------------------------------------------
+// Function: Chown
+//
+// Description:
+//	The main method for chown command
+//
+// Returns:
+//	0: on success
+//
+// Notes:
+//
+//
+int Chown(int argc, wchar_t *argv[])
+{
+  LPWSTR pathName = NULL;
+
+  LPWSTR ownerInfo = NULL;
+
+  LPWSTR colonPos = NULL;
+
+  LPWSTR userName = NULL;
+  size_t userNameLen = 0;
+
+  LPWSTR groupName = NULL;
+  size_t groupNameLen = 0;
+
+  PSID pNewOwnerSid = NULL;
+  PSID pNewGroupSid = NULL;
+
+  DWORD dwRtnCode = 0;
+
+  int ret = EXIT_FAILURE;
+
+  if (argc >= 3)
+  {
+    ownerInfo = argv[1];
+    pathName = argv[2];
+  }
+  else
+  {
+    fwprintf(stderr, L"Incorrect command line arguments.\n\n");
+    ChownUsage(argv[0]);
+    return ret;
+  }
+
+  // Parsing the owner name
+  //
+  if ((colonPos = wcschr(ownerInfo, L':')) != NULL)
+  {
+    if (colonPos - ownerInfo != 0)
+    {
+      // Length includes NULL terminator
+      userNameLen = colonPos - ownerInfo + 1;
+      userName = (LPTSTR)LocalAlloc(LPTR, userNameLen * sizeof(WCHAR));
+      if (userName == NULL)
+      {
+        ReportErrorCode(L"LocalAlloc", GetLastError());
+        goto ChownEnd;
+      }
+      if (FAILED(StringCchCopyNW(userName, userNameLen,
+        ownerInfo, userNameLen - 1)))
+        goto ChownEnd;
+    }
+
+    if (*(colonPos + 1) != 0)
+    {
+      // Length includes NULL terminator
+      groupNameLen = wcslen(ownerInfo) - (colonPos - ownerInfo) + 1;
+      groupName = (LPTSTR)LocalAlloc(LPTR, groupNameLen * sizeof(WCHAR));
+      if (groupName == NULL)
+      {
+        ReportErrorCode(L"LocalAlloc", GetLastError());
+        goto ChownEnd;
+      }
+      if (FAILED(StringCchCopyNW(groupName, groupNameLen,
+        colonPos + 1, groupNameLen)))
+        goto ChownEnd;
+    }
+  }
+  else
+  {
+    // Length includes NULL terminator
+    userNameLen = wcslen(ownerInfo) + 1;
+    userName = (LPWSTR)LocalAlloc(LPTR, userNameLen * sizeof(WCHAR));
+    if (userName == NULL)
+    {
+      ReportErrorCode(L"LocalAlloc", GetLastError());
+      goto ChownEnd;
+    }
+    if (FAILED(StringCchCopyNW(userName, userNameLen, ownerInfo, userNameLen)))
+      goto ChownEnd;
+  }
+
+  // Not allow zero length user name or group name in the parsing results.
+  //
+  assert(userName == NULL || wcslen(userName) > 0);
+  assert(groupName == NULL || wcslen(groupName) > 0);
+
+  // Nothing to change if both names are empty
+  //
+  if ((userName == NULL) && (groupName == NULL))
+  {
+    ret = EXIT_SUCCESS;
+    goto ChownEnd;
+  }
+
+  if (userName != NULL)
+  {
+    dwRtnCode = GetSidFromAcctNameW(userName, &pNewOwnerSid);
+    if (dwRtnCode != ERROR_SUCCESS)
+    {
+      ReportErrorCode(L"GetSidFromAcctName", dwRtnCode);
+      fwprintf(stderr, L"Invalid user name: %s\n", userName);
+      goto ChownEnd;
+    }
+  }
+
+  if (groupName != NULL)
+  {
+    dwRtnCode = GetSidFromAcctNameW(groupName, &pNewGroupSid);
+    if (dwRtnCode != ERROR_SUCCESS)
+    {
+      ReportErrorCode(L"GetSidFromAcctName", dwRtnCode);
+      fwprintf(stderr, L"Invalid group name: %s\n", groupName);
+      goto ChownEnd;
+    }
+  }
+
+  if (wcslen(pathName) == 0 || wcsspn(pathName, L"/?|><:*\"") != 0)
+  {
+    fwprintf(stderr, L"Incorrect file name format: %s\n", pathName);
+    goto ChownEnd;
+  }
+
+  dwRtnCode = ChangeFileOwnerBySid(pathName, pNewOwnerSid, pNewGroupSid);
+  if (dwRtnCode != ERROR_SUCCESS)
+  {
+    ReportErrorCode(L"ChangeFileOwnerBySid", dwRtnCode);
+    goto ChownEnd;
+  }
+
+  ret = EXIT_SUCCESS;
+
+ChownEnd:
+  LocalFree(userName);
+  LocalFree(groupName);
+  LocalFree(pNewOwnerSid);
+  LocalFree(pNewGroupSid);
+
+  return ret;
+}
+
+void ChownUsage(LPCWSTR program)
+{
+  fwprintf(stdout, L"\
+Usage: %s [OWNER][:[GROUP]] [FILE]\n\
+Change the owner and/or group of the FILE to OWNER and/or GROUP.\n\
+\n\
+Note:\n\
+On Linux, if a colon but no group name follows the user name, the group of\n\
+the files is changed to that user\'s login group. Windows has no concept of\n\
+a user's login group. So we do not change the group owner in this case.\n",
+program);
+}

Added: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/groups.c
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/groups.c?rev=1453486&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/groups.c (added)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/groups.c Wed Mar  6 19:15:18 2013
@@ -0,0 +1,217 @@
+/**
+ * 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"
+
+//----------------------------------------------------------------------------
+// Function: PrintGroups
+//
+// Description:
+//	Print group names to the console standard output for the given user
+//
+// Returns:
+//	TRUE: on success
+//
+// Notes:
+//   This function could fail on first pass when we fail to find groups for
+//   domain account; so we do not report Windows API errors in this function.
+//   If formatOutput is true, pipe character is used as separator for groups
+//   otherwise, space.
+//
+static BOOL PrintGroups(
+  LPLOCALGROUP_USERS_INFO_0 groups,
+  DWORD entries,
+  BOOL formatOutput)
+{
+  BOOL ret = TRUE;
+  LPLOCALGROUP_USERS_INFO_0 pTmpBuf = groups;
+  DWORD i;
+
+  for (i = 0; i < entries; i++)
+  {
+    if (pTmpBuf == NULL)
+    {
+      ret = FALSE;
+      break;
+    }
+
+    if (i != 0)
+    {
+      if (formatOutput)
+      {
+        wprintf(L"|");
+      }
+      else
+      {
+        wprintf(L" ");
+      }
+    }
+    wprintf(L"%s", pTmpBuf->lgrui0_name);
+
+    pTmpBuf++;
+  }
+
+  if (ret)
+    wprintf(L"\n");
+
+  return ret;
+}
+
+//----------------------------------------------------------------------------
+// Function: ParseCommandLine
+//
+// Description:
+//   Parses the command line
+//
+// Returns:
+//   TRUE on the valid command line, FALSE otherwise
+//
+static BOOL ParseCommandLine(
+  int argc, wchar_t *argv[], wchar_t **user, BOOL *formatOutput)
+{
+  *formatOutput = FALSE;
+
+  assert(argv != NULL);
+  assert(user != NULL);
+
+  if (argc == 1)
+  {
+    // implicitly use the current user
+    *user = NULL;
+    return TRUE;
+  }
+  else if (argc == 2)
+  {
+    // check if the second argument is formating
+    if (wcscmp(argv[1], L"-F") == 0)
+    {
+      *user = NULL;
+      *formatOutput = TRUE;
+      return TRUE;
+    }
+    else
+    {
+      *user = argv[1];
+      return TRUE;
+    }
+  }
+  else if (argc == 3 && wcscmp(argv[1], L"-F") == 0)
+  {
+    // if 3 args, the second argument must be "-F"
+
+    *user = argv[2];
+    *formatOutput = TRUE;
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+//----------------------------------------------------------------------------
+// Function: Groups
+//
+// Description:
+//	The main method for groups command
+//
+// Returns:
+//	0: on success
+//
+// Notes:
+//
+//
+int Groups(int argc, wchar_t *argv[])
+{
+  LPWSTR input = NULL;
+
+  LPWSTR currentUser = NULL;
+  DWORD cchCurrentUser = 0;
+
+  LPLOCALGROUP_USERS_INFO_0 groups = NULL;
+  DWORD entries = 0;
+
+  DWORD dwRtnCode = ERROR_SUCCESS;
+
+  int ret = EXIT_SUCCESS;
+  BOOL formatOutput = FALSE;
+
+  if (!ParseCommandLine(argc, argv, &input, &formatOutput))
+  {
+    fwprintf(stderr, L"Incorrect command line arguments.\n\n");
+    GroupsUsage(argv[0]);
+    return EXIT_FAILURE;
+  }
+
+  // if username was not specified on the command line, fallback to the
+  // current user
+  if (input == NULL)
+  {
+    GetUserNameW(currentUser, &cchCurrentUser);
+    if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+    {
+      currentUser = (LPWSTR) LocalAlloc(LPTR,
+        (cchCurrentUser + 1) * sizeof(wchar_t));
+      if (!currentUser)
+      {
+        ReportErrorCode(L"LocalAlloc", GetLastError());
+        ret = EXIT_FAILURE;
+        goto GroupsEnd;
+      }
+      if (GetUserNameW(currentUser, &cchCurrentUser))
+        input = currentUser;
+      else
+      {
+        ReportErrorCode(L"GetUserName", GetLastError());
+        ret = EXIT_FAILURE;
+        goto GroupsEnd;
+      }
+    }
+    else
+    {
+      ReportErrorCode(L"GetUserName", GetLastError());
+      ret = EXIT_FAILURE;
+      goto GroupsEnd;
+    }
+  }
+
+  if ((dwRtnCode = GetLocalGroupsForUser(input, &groups, &entries))
+    != ERROR_SUCCESS)
+  {
+    ReportErrorCode(L"GetLocalGroupsForUser", dwRtnCode);
+    ret = EXIT_FAILURE;
+    goto GroupsEnd;
+  }
+
+  if (!PrintGroups(groups, entries, formatOutput))
+  {
+    ret = EXIT_FAILURE;
+  }
+
+GroupsEnd:
+  LocalFree(currentUser);
+  if (groups != NULL) NetApiBufferFree(groups);
+  return ret;
+}
+
+void GroupsUsage(LPCWSTR program)
+{
+  fwprintf(stdout, L"\
+Usage: %s [OPTIONS] [USERNAME]\n\
+Print group information of the specified USERNAME \
+(the current user by default).\n\
+\n\
+OPTIONS: -F format the output by separating tokens with a pipe\n",
+program);
+}

Added: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/hardlink.c
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/hardlink.c?rev=1453486&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/hardlink.c (added)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/hardlink.c Wed Mar  6 19:15:18 2013
@@ -0,0 +1,230 @@
+/**
+* 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"
+
+// List of different hardlink related command line options supported by
+// winutils.
+typedef enum HardLinkCommandOptionType
+{
+  HardLinkInvalid,
+  HardLinkCreate,
+  HardLinkStat
+} HardLinkCommandOption;
+
+//----------------------------------------------------------------------------
+// Function: ParseCommandLine
+//
+// Description:
+//  Parses the given command line. On success, out param 'command' contains
+//  the user specified command.
+//
+// Returns:
+// TRUE: If the command line is valid
+// FALSE: otherwise
+static BOOL ParseCommandLine(__in int argc,
+                             __in wchar_t *argv[],
+                             __out HardLinkCommandOption *command)
+{
+  *command = HardLinkInvalid;
+
+  if (argc != 3 && argc != 4) {
+    return FALSE;
+  }
+
+  if (argc == 3) {
+    if (wcscmp(argv[0], L"hardlink") != 0 || wcscmp(argv[1], L"stat") != 0)
+    {
+      return FALSE;
+    }
+
+    *command = HardLinkStat;
+  }
+
+  if (argc == 4) {
+    if (wcscmp(argv[0], L"hardlink") != 0 || wcscmp(argv[1], L"create") != 0)
+    {
+      return FALSE;
+    }
+
+    *command = HardLinkCreate;
+  }
+
+  assert(*command != HardLinkInvalid);
+
+  return TRUE;
+}
+
+//----------------------------------------------------------------------------
+// Function: HardlinkStat
+//
+// Description:
+//  Computes the number of hard links for a given file.
+//
+// Returns:
+// ERROR_SUCCESS: On success
+// error code: otherwise
+static DWORD HardlinkStat(__in LPCWSTR fileName, __out DWORD *puHardLinkCount)
+{
+  BY_HANDLE_FILE_INFORMATION fileInformation;
+  DWORD dwErrorCode = ERROR_SUCCESS;
+  PWSTR longFileName = NULL;
+
+  // First convert input paths to long paths
+  //
+  dwErrorCode = ConvertToLongPath(fileName, &longFileName);
+  if (dwErrorCode != ERROR_SUCCESS)
+  {
+    goto HardlinkStatExit;
+  }
+
+  // Get file information which contains the hard link count
+  //
+  dwErrorCode = GetFileInformationByName(longFileName, FALSE, &fileInformation);
+  if (dwErrorCode != ERROR_SUCCESS)
+  {
+    goto HardlinkStatExit;
+  }
+
+  *puHardLinkCount = fileInformation.nNumberOfLinks;
+
+HardlinkStatExit:
+  LocalFree(longFileName);
+
+  return dwErrorCode;
+}
+
+//----------------------------------------------------------------------------
+// Function: HardlinkCreate
+//
+// Description:
+//  Creates a hard link for a given file under the given name.
+//
+// Returns:
+// ERROR_SUCCESS: On success
+// error code: otherwise
+static DWORD HardlinkCreate(__in LPCWSTR linkName, __in LPCWSTR fileName)
+{
+  PWSTR longLinkName = NULL;
+  PWSTR longFileName = NULL;
+  DWORD dwErrorCode = ERROR_SUCCESS;
+
+  // First convert input paths to long paths
+  //
+  dwErrorCode = ConvertToLongPath(linkName, &longLinkName);
+  if (dwErrorCode != ERROR_SUCCESS)
+  {
+    goto HardlinkCreateExit;
+  }
+
+  dwErrorCode = ConvertToLongPath(fileName, &longFileName);
+  if (dwErrorCode != ERROR_SUCCESS)
+  {
+    goto HardlinkCreateExit;
+  }
+
+  // Create the hard link
+  //
+  if (!CreateHardLink(longLinkName, longFileName, NULL))
+  {
+    dwErrorCode = GetLastError();
+  }
+
+HardlinkCreateExit:
+  LocalFree(longLinkName);
+  LocalFree(longFileName);
+
+  return dwErrorCode;
+}
+
+//----------------------------------------------------------------------------
+// Function: Hardlink
+//
+// Description:
+//  Creates a hard link for a given file under the given name. Outputs the
+//  appropriate information to stdout on success, or stderr on failure.
+//
+// Returns:
+// EXIT_SUCCESS: On success
+// EXIT_FAILURE: otherwise
+int Hardlink(int argc, wchar_t *argv[])
+{
+  DWORD dwErrorCode = ERROR_SUCCESS;
+  int ret = EXIT_FAILURE;
+  HardLinkCommandOption command = HardLinkInvalid;
+
+  if (!ParseCommandLine(argc, argv, &command)) {
+    dwErrorCode = ERROR_INVALID_COMMAND_LINE;
+
+    fwprintf(stderr, L"Incorrect command line arguments.\n\n");
+    HardlinkUsage();
+    goto HardLinkExit;
+  }
+
+  if (command == HardLinkStat)
+  {
+    // Compute the number of hard links
+    //
+    DWORD uHardLinkCount = 0;
+    dwErrorCode = HardlinkStat(argv[2], &uHardLinkCount);
+    if (dwErrorCode != ERROR_SUCCESS)
+    {
+      ReportErrorCode(L"HardlinkStat", dwErrorCode);
+      goto HardLinkExit;
+    }
+
+    // Output the result
+    //
+    fwprintf(stdout, L"%d\n", uHardLinkCount);
+
+  } else if (command == HardLinkCreate)
+  {
+    // Create the hard link
+    //
+    dwErrorCode = HardlinkCreate(argv[2], argv[3]);
+    if (dwErrorCode != ERROR_SUCCESS)
+    {
+      ReportErrorCode(L"HardlinkCreate", dwErrorCode);
+      goto HardLinkExit;
+    }
+
+    // Output the success message
+    //
+    fwprintf(stdout, L"Hardlink created for %s <<===>> %s\n", argv[2], argv[3]);
+
+  } else
+  {
+    // Should not happen
+    //
+    assert(FALSE);
+  }
+
+  ret = EXIT_SUCCESS;
+
+HardLinkExit:
+
+  return ret;
+}
+
+void HardlinkUsage()
+{
+    fwprintf(stdout, L"\
+Usage: hardlink create [LINKNAME] [FILENAME] |\n\
+       hardlink stat [FILENAME]\n\
+Creates a new hardlink on the existing file or displays the number of links\n\
+for the given file\n");
+}
\ No newline at end of file

Added: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/include/winutils.h
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/include/winutils.h?rev=1453486&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/include/winutils.h (added)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/include/winutils.h Wed Mar  6 19:15:18 2013
@@ -0,0 +1,142 @@
+/**
+ * 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.
+ */
+
+#ifndef UNICODE
+#define UNICODE
+#endif
+
+#pragma once
+
+#include <stdio.h>
+#include <assert.h>
+#include <windows.h>
+#include <aclapi.h>
+#include <accctrl.h>
+#include <tchar.h>
+#include <strsafe.h>
+#include <lm.h>
+
+enum EXIT_CODE
+{
+  /* Common success exit code shared among all utilities */
+  SUCCESS = EXIT_SUCCESS,
+  /* Generic failure exit code share among all utilities */
+  FAILURE = EXIT_FAILURE,
+  /* Failure code indicates the user does not privilege to create symlinks */
+  SYMLINK_NO_PRIVILEGE = 2,
+};
+
+
+/*
+ * The array of 12 months' three-letter abbreviations 
+ */
+extern const LPCWSTR MONTHS[];
+
+/*
+ * The Unix masks
+ * The Windows version of <sys/stat.h> does not contain all the POSIX flag/mask
+ * definitions. The following masks are used in 'winutils' to represent POSIX
+ * permission mode.
+ * 
+ */
+enum UnixAclMask
+{
+  UX_O_EXECUTE = 00001, // S_IXOTH
+  UX_O_WRITE   = 00002, // S_IWOTH
+  UX_O_READ    = 00004, // S_IROTH
+  UX_G_EXECUTE = 00010, // S_IXGRP
+  UX_G_WRITE   = 00020, // S_IWGRP
+  UX_G_READ    = 00040, // S_IRGRP
+  UX_U_EXECUTE = 00100, // S_IXUSR
+  UX_U_WRITE   = 00200, // S_IWUSR
+  UX_U_READ    = 00400, // S_IRUSR
+  UX_DIRECTORY = 0040000, // S_IFDIR
+  UX_SYMLINK   = 0120000, // S_IFLNK
+};
+
+
+/*
+ * The WindowsAclMask and WinMasks contain the definitions used to establish
+ * the mapping between Unix and Windows.
+ */
+enum WindowsAclMask
+{
+  WIN_READ, // The permission(s) that enable Unix read permission
+  WIN_WRITE, // The permission(s) that enable Unix write permission
+  WIN_EXECUTE, // The permission(s) that enbale Unix execute permission
+  WIN_OWNER_SE, // The permissions that are always set for file owners 
+  WIN_ALL, // The permissions that all files on Windows should have
+  WIN_MASKS_TOTAL
+};
+extern const ACCESS_MASK WinMasks[];
+
+
+int Ls(int argc, wchar_t *argv[]);
+void LsUsage(LPCWSTR program);
+
+int Chmod(int argc, wchar_t *argv[]);
+void ChmodUsage(LPCWSTR program);
+
+int Chown(int argc, wchar_t *argv[]);
+void ChownUsage(LPCWSTR program);
+
+int Groups(int argc, wchar_t *argv[]);
+void GroupsUsage(LPCWSTR program);
+
+int Hardlink(int argc, wchar_t *argv[]);
+void HardlinkUsage();
+
+int Task(int argc, wchar_t *argv[]);
+void TaskUsage();
+
+int Symlink(int argc, wchar_t *argv[]);
+void SymlinkUsage();
+
+int SystemInfo();
+void SystemInfoUsage();
+
+DWORD GetFileInformationByName(__in LPCWSTR pathName,  __in BOOL followLink,
+  __out LPBY_HANDLE_FILE_INFORMATION lpFileInformation);
+
+DWORD ConvertToLongPath(__in PCWSTR path, __deref_out PWSTR *newPath);
+
+DWORD GetSidFromAcctNameW(LPCWSTR acctName, PSID* ppSid);
+
+DWORD GetAccntNameFromSid(PSID pSid, LPWSTR *ppAcctName);
+
+void ReportErrorCode(LPCWSTR func, DWORD err);
+
+BOOL IsDirFileInfo(const BY_HANDLE_FILE_INFORMATION *fileInformation);
+
+DWORD FindFileOwnerAndPermission(
+  __in LPCWSTR pathName,
+  __out_opt LPWSTR *pOwnerName,
+  __out_opt LPWSTR *pGroupName,
+  __out_opt PINT pMask);
+
+DWORD DirectoryCheck(__in LPCWSTR pathName, __out LPBOOL result);
+
+DWORD SymbolicLinkCheck(__in LPCWSTR pathName, __out LPBOOL result);
+
+DWORD JunctionPointCheck(__in LPCWSTR pathName, __out LPBOOL result);
+
+DWORD ChangeFileModeByMask(__in LPCWSTR path, INT mode);
+
+DWORD GetLocalGroupsForUser(__in LPCWSTR user,
+  __out LPLOCALGROUP_USERS_INFO_0 *groups, __out LPDWORD entries);
+
+BOOL EnablePrivilege(__in LPCWSTR privilegeName);
\ No newline at end of file