Return-Path: X-Original-To: apmail-hadoop-common-commits-archive@www.apache.org Delivered-To: apmail-hadoop-common-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 31F48D3E0 for ; Fri, 19 Oct 2012 20:13:55 +0000 (UTC) Received: (qmail 39108 invoked by uid 500); 19 Oct 2012 20:13:54 -0000 Delivered-To: apmail-hadoop-common-commits-archive@hadoop.apache.org Received: (qmail 39065 invoked by uid 500); 19 Oct 2012 20:13:54 -0000 Mailing-List: contact common-commits-help@hadoop.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: common-dev@hadoop.apache.org Delivered-To: mailing list common-commits@hadoop.apache.org Received: (qmail 39056 invoked by uid 99); 19 Oct 2012 20:13:54 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 19 Oct 2012 20:13:54 +0000 X-ASF-Spam-Status: No, hits=-1998.0 required=5.0 tests=ALL_TRUSTED,FB_GET_MEDS X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 19 Oct 2012 20:13:51 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id E320823888E3; Fri, 19 Oct 2012 20:13:07 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1400262 [1/3] - in /hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils: ./ include/ tests/ Date: Fri, 19 Oct 2012 20:13:06 -0000 To: common-commits@hadoop.apache.org From: suresh@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20121019201307.E320823888E3@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: suresh Date: Fri Oct 19 20:13:06 2012 New Revision: 1400262 URL: http://svn.apache.org/viewvc?rev=1400262&view=rev Log: HADOOP-8945. Merge winutils from branch-1-win to branch-trunk-win. Contributed by Bikas Saha, Chuan Liu, Giridharan Kesavan, Ivan Mitic, and Steve Maine. Ported by Chris Nauroth. Added: hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/ hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/chmod.c hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/chown.c hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/groups.c hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/hardlink.c hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/include/ hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/include/winutils.h hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/libwinutils.c hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/libwinutils.vcxproj hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/ls.c hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/main.c hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/symlink.c hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/systeminfo.c hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/task.c hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/tests/ hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/tests/test-all.bat hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/tests/test-winutils-basics.bat hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/tests/test-winutils-chmod.bat hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/tests/test-winutils-chown.bat hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/winutils.sln hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/winutils.vcxproj Added: hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/chmod.c URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/chmod.c?rev=1400262&view=auto ============================================================================== --- hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/chmod.c (added) +++ hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/chmod.c Fri Oct 19 20:13:06 2012 @@ -0,0 +1,880 @@ +/** +* 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 + +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; + 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; + } + + if(!ChangeFileModeRecursively(filename, mode, actions)) + { + LocalFree(filename); + goto ChangeFileModeRecursivelyEnd; + } + + LocalFree(filename); + + } 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); +} \ No newline at end of file Added: hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/chown.c URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/chown.c?rev=1400262&view=auto ============================================================================== --- hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/chown.c (added) +++ hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/chown.c Fri Oct 19 20:13:06 2012 @@ -0,0 +1,498 @@ +/** + * 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: GetNewAclSize +// +// Description: +// Compute the extra size of the new ACL if we replace the old owner Sid with +// the new owner Sid. +// +// Returns: +// The extra size needed for the new ACL compared with the ACL passed in. If +// the value is negative, it means the size of the new ACL could be reduced. +// +// Notes: +// +static BOOL GetNewAclSizeDelta(__in PACL pDACL, + __in PSID pOldOwnerSid, __in PSID pNewOwnerSid, __out PLONG pDelta) +{ + PVOID pAce = NULL; + DWORD i; + PSID aceSid = NULL; + ACE_HEADER *aceHeader = NULL; + PACCESS_ALLOWED_ACE accessAllowedAce = NULL; + PACCESS_DENIED_ACE accessDenieddAce = NULL; + + assert(pDACL != NULL && pNewOwnerSid != NULL && + pOldOwnerSid != NULL && pDelta != NULL); + + *pDelta = 0; + for (i = 0; i < pDACL->AceCount; i++) + { + if (!GetAce(pDACL, i, &pAce)) + { + ReportErrorCode(L"GetAce", GetLastError()); + return FALSE; + } + + aceHeader = (ACE_HEADER *) pAce; + if (aceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE) + { + accessAllowedAce = (PACCESS_ALLOWED_ACE) pAce; + aceSid = (PSID) &accessAllowedAce->SidStart; + } + else if (aceHeader->AceType == ACCESS_DENIED_ACE_TYPE) + { + accessDenieddAce = (PACCESS_DENIED_ACE) pAce; + aceSid = (PSID) &accessDenieddAce->SidStart; + } + else + { + continue; + } + + if (EqualSid(pOldOwnerSid, aceSid)) + { + *pDelta += GetLengthSid(pNewOwnerSid) - GetLengthSid(pOldOwnerSid); + } + } + + return TRUE; +} + +//---------------------------------------------------------------------------- +// Function: AddNewAce +// +// Description: +// Add an Ace of new owner to the new ACL +// +// Returns: +// TRUE: on success +// +// Notes: +// The Ace type should be either ACCESS_ALLOWED_ACE or ACCESS_DENIED_ACE +// +static BOOL AddNewAce(PACL pNewDACL, PVOID pOldAce, + PSID pOwnerSid, PSID pUserSid) +{ + PVOID pNewAce = NULL; + DWORD newAceSize = 0; + + assert(pNewDACL != NULL && pOldAce != NULL && + pOwnerSid != NULL && pUserSid != NULL); + assert(((PACE_HEADER)pOldAce)->AceType == ACCESS_ALLOWED_ACE_TYPE || + ((PACE_HEADER)pOldAce)->AceType == ACCESS_DENIED_ACE_TYPE); + + newAceSize = ((PACE_HEADER)pOldAce)->AceSize + + GetLengthSid(pUserSid) - GetLengthSid(pOwnerSid); + pNewAce = LocalAlloc(LPTR, newAceSize); + if (pNewAce == NULL) + { + ReportErrorCode(L"LocalAlloc", GetLastError()); + return FALSE; + } + + ((PACE_HEADER)pNewAce)->AceType = ((PACE_HEADER) pOldAce)->AceType; + ((PACE_HEADER)pNewAce)->AceFlags = ((PACE_HEADER) pOldAce)->AceFlags; + ((PACE_HEADER)pNewAce)->AceSize = (WORD) newAceSize; + + if (((PACE_HEADER)pOldAce)->AceType == ACCESS_ALLOWED_ACE_TYPE) + { + ((PACCESS_ALLOWED_ACE)pNewAce)->Mask = ((PACCESS_ALLOWED_ACE)pOldAce)->Mask; + if (!CopySid(GetLengthSid(pUserSid), + &((PACCESS_ALLOWED_ACE) pNewAce)->SidStart, pUserSid)) + { + ReportErrorCode(L"CopySid", GetLastError()); + LocalFree(pNewAce); + return FALSE; + } + } + else + { + ((PACCESS_DENIED_ACE)pNewAce)->Mask = ((PACCESS_DENIED_ACE)pOldAce)->Mask; + if (!CopySid(GetLengthSid(pUserSid), + &((PACCESS_DENIED_ACE) pNewAce)->SidStart, pUserSid)) + { + ReportErrorCode(L"CopySid", GetLastError()); + LocalFree(pNewAce); + return FALSE; + } + } + + if (!AddAce(pNewDACL, ACL_REVISION, MAXDWORD, + pNewAce, ((PACE_HEADER)pNewAce)->AceSize)) + { + ReportErrorCode(L"AddAce", GetLastError()); + LocalFree(pNewAce); + return FALSE; + } + + LocalFree(pNewAce); + return TRUE; +} + +//---------------------------------------------------------------------------- +// Function: CreateDaclForNewOwner +// +// Description: +// Create a new DACL for the new owner +// +// Returns: +// TRUE: on success +// +// Notes: +// Caller needs to destroy the memory of the new DACL by calling LocalFree() +// +static BOOL CreateDaclForNewOwner( + __in PACL pDACL, + __in_opt PSID pOldOwnerSid, + __in_opt PSID pNewOwnerSid, + __in_opt PSID pOldGroupSid, + __in_opt PSID pNewGroupSid, + __out PACL *ppNewDACL) +{ + PSID aceSid = NULL; + PACE_HEADER aceHeader = NULL; + PACCESS_ALLOWED_ACE accessAllowedAce = NULL; + PACCESS_DENIED_ACE accessDenieddAce = NULL; + PVOID pAce = NULL; + ACL_SIZE_INFORMATION aclSizeInfo; + LONG delta = 0; + DWORD dwNewAclSize = 0; + DWORD dwRtnCode = 0; + DWORD i; + + assert(pDACL != NULL && ppNewDACL != NULL); + assert(pOldOwnerSid != NULL && pOldGroupSid != NULL); + assert(pNewOwnerSid != NULL || pNewGroupSid != NULL); + + if (!GetAclInformation(pDACL, (LPVOID)&aclSizeInfo, + sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) + { + ReportErrorCode(L"GetAclInformation", GetLastError()); + return FALSE; + } + + dwNewAclSize = aclSizeInfo.AclBytesInUse + aclSizeInfo.AclBytesFree; + + delta = 0; + if (pNewOwnerSid != NULL && + !GetNewAclSizeDelta(pDACL, pOldOwnerSid, pNewOwnerSid, &delta)) + { + return FALSE; + } + dwNewAclSize += delta; + + delta = 0; + if (pNewGroupSid != NULL && + !GetNewAclSizeDelta(pDACL, pOldGroupSid, pNewGroupSid, &delta)) + { + return FALSE; + } + dwNewAclSize += delta; + + *ppNewDACL = (PACL)LocalAlloc(LPTR, dwNewAclSize); + if (*ppNewDACL == NULL) + { + ReportErrorCode(L"LocalAlloc", GetLastError()); + return FALSE; + } + + if (!InitializeAcl(*ppNewDACL, dwNewAclSize, ACL_REVISION)) + { + ReportErrorCode(L"InitializeAcl", GetLastError()); + return FALSE; + } + + // Go through the DACL to change permissions + // + for (i = 0; i < pDACL->AceCount; i++) + { + if (!GetAce(pDACL, i, &pAce)) + { + ReportErrorCode(L"GetAce", GetLastError()); + return FALSE; + } + + aceHeader = (PACE_HEADER) pAce; + aceSid = NULL; + if (aceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE) + { + accessAllowedAce = (PACCESS_ALLOWED_ACE) pAce; + aceSid = (PSID) &accessAllowedAce->SidStart; + } + else if (aceHeader->AceType == ACCESS_DENIED_ACE_TYPE) + { + accessDenieddAce = (PACCESS_DENIED_ACE) pAce; + aceSid = (PSID) &accessDenieddAce->SidStart; + } + + if (aceSid != NULL) + { + if (pNewOwnerSid != NULL && EqualSid(pOldOwnerSid, aceSid)) + { + if (!AddNewAce(*ppNewDACL, pAce, pOldOwnerSid, pNewOwnerSid)) + return FALSE; + else + continue; + } + else if (pNewGroupSid != NULL && EqualSid(pOldGroupSid, aceSid)) + { + if (!AddNewAce(*ppNewDACL, pAce, pOldGroupSid, pNewGroupSid)) + return FALSE; + else + continue; + } + } + + // At this point, either: + // 1. The Ace is not of type ACCESS_ALLOWED_ACE or ACCESS_DENIED_ACE; + // 2. The Ace does not belong to the owner + // For both cases, we just add the oringal Ace to the new ACL. + // + if (!AddAce(*ppNewDACL, ACL_REVISION, MAXDWORD, pAce, aceHeader->AceSize)) + { + ReportErrorCode(L"AddAce", dwRtnCode); + return FALSE; + } + } + + return TRUE; +} + + +//---------------------------------------------------------------------------- +// 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 longPathName = 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; + + PACL pDACL = NULL; + PACL pNewDACL = NULL; + + PSID pOldOwnerSid = NULL; + PSID pOldGroupSid = NULL; + + PSECURITY_DESCRIPTOR pSD = NULL; + + SECURITY_INFORMATION securityInformation; + + 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 != NULL) + { + // 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; + } + + if ((userName == NULL || wcslen(userName) == 0) && + (groupName == NULL || wcslen(groupName) == 0)) + { + fwprintf(stderr, L"User name and group name cannot both be empty."); + 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; + } + + // Convert the path the the long path + // + dwRtnCode = ConvertToLongPath(pathName, &longPathName); + if (dwRtnCode != ERROR_SUCCESS) + { + ReportErrorCode(L"ConvertToLongPath", dwRtnCode); + goto ChownEnd; + } + + // Get a pointer to the existing owner information and DACL + // + dwRtnCode = GetNamedSecurityInfoW( + longPathName, + SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION, + &pOldOwnerSid, + &pOldGroupSid, + &pDACL, + NULL, + &pSD); + if (dwRtnCode != ERROR_SUCCESS) + { + ReportErrorCode(L"GetNamedSecurityInfo", dwRtnCode); + goto ChownEnd; + } + + // Create the new DACL + // + if (!CreateDaclForNewOwner(pDACL, + pOldOwnerSid, pNewOwnerSid, + pOldGroupSid, pNewGroupSid, + &pNewDACL)) + { + goto ChownEnd; + } + + // Set the owner and DACLs in the object's security descriptor. Use + // PROTECTED_DACL_SECURITY_INFORMATION flag to remove permission inheritance + // + securityInformation = + DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION; + if (pNewOwnerSid != NULL) securityInformation |= OWNER_SECURITY_INFORMATION; + if (pNewGroupSid != NULL) securityInformation |= GROUP_SECURITY_INFORMATION; + dwRtnCode = SetNamedSecurityInfoW( + longPathName, + SE_FILE_OBJECT, + securityInformation, + pNewOwnerSid, + pNewGroupSid, + pNewDACL, + NULL); + if (dwRtnCode != ERROR_SUCCESS) + { + ReportErrorCode(L"SetNamedSecurityInfo", dwRtnCode); + goto ChownEnd; + } + + ret = EXIT_SUCCESS; + +ChownEnd: + LocalFree(userName); + LocalFree(groupName); + LocalFree(pNewOwnerSid); + LocalFree(pNewGroupSid); + LocalFree(pNewDACL); + LocalFree(pSD); + LocalFree(longPathName); + + 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", +program); +} Added: hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/groups.c URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/groups.c?rev=1400262&view=auto ============================================================================== --- hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/groups.c (added) +++ hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/groups.c Fri Oct 19 20:13:06 2012 @@ -0,0 +1,154 @@ +/** + * 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. +// +static BOOL PrintGroups(LPLOCALGROUP_USERS_INFO_0 groups, DWORD entries) +{ + 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) + { + wprintf(L" "); + } + wprintf(L"%s", pTmpBuf->lgrui0_name); + + pTmpBuf++; + } + + if (ret) + wprintf(L"\n"); + + return ret; +} + +//---------------------------------------------------------------------------- +// 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; + + if (argc != 2 && argc != 1) + { + fwprintf(stderr, L"Incorrect command line arguments.\n\n"); + GroupsUsage(argv[0]); + return EXIT_FAILURE; + } + + if (argc == 1) + { + 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; + } + } + else + { + input = argv[1]; + } + + if ((dwRtnCode = GetLocalGroupsForUser(input, &groups, &entries)) + != ERROR_SUCCESS) + { + ReportErrorCode(L"GetLocalGroupsForUser", dwRtnCode); + ret = EXIT_FAILURE; + goto GroupsEnd; + } + + if (!PrintGroups(groups, entries)) + { + ret = EXIT_FAILURE; + } + +GroupsEnd: + LocalFree(currentUser); + if (groups != NULL) NetApiBufferFree(groups); + return ret; +} + +void GroupsUsage(LPCWSTR program) +{ + fwprintf(stdout, L"\ +Usage: %s [USERNAME]\n\ +Print group information of the specified USERNAME\ +(the current user by default).\n", +program); +} Added: hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/hardlink.c URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/hardlink.c?rev=1400262&view=auto ============================================================================== --- hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/hardlink.c (added) +++ hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/hardlink.c Fri Oct 19 20:13:06 2012 @@ -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/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/include/winutils.h URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/include/winutils.h?rev=1400262&view=auto ============================================================================== --- hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/include/winutils.h (added) +++ hadoop/common/branches/branch-trunk-win/hadoop-common-project/hadoop-common/src/main/winutils/include/winutils.h Fri Oct 19 20:13:06 2012 @@ -0,0 +1,140 @@ +/** + * 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 +#include +#include +#include +#include +#include +#include +#include + +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 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); \ No newline at end of file