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 [5/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/libwinutils.c
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/libwinutils.c?rev=1453486&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/libwinutils.c (added)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/libwinutils.c Wed Mar 6 19:15:18 2013
@@ -0,0 +1,1515 @@
+/**
+ * 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.
+ */
+
+#pragma comment(lib, "authz.lib")
+#pragma comment(lib, "netapi32.lib")
+#include "winutils.h"
+#include <authz.h>
+#include <sddl.h>
+
+/*
+ * The array of 12 months' three-letter abbreviations
+ */
+const LPCWSTR MONTHS[] = { L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun",
+ L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec" };
+
+/*
+ * The WindowsAclMask and WinMasks contain the definitions used to establish
+ * the mapping between Unix and Windows.
+ * We set up the mapping with the following rules.
+ * 1. Everyone will have WIN_ALL permissions;
+ * 2. Owner will always have WIN_OWNER_SE permissions in addition;
+ * 2. When Unix read/write/excute permission is set on the file, the
+ * corresponding Windows allow ACE will be added to the file.
+ * More details and explaination can be found in the following white paper:
+ * http://technet.microsoft.com/en-us/library/bb463216.aspx
+ */
+const ACCESS_MASK WinMasks[WIN_MASKS_TOTAL] =
+{
+ /* WIN_READ */
+ FILE_READ_DATA,
+ /* WIN_WRITE */
+ FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_APPEND_DATA | FILE_WRITE_EA |
+ FILE_DELETE_CHILD,
+ /* WIN_EXECUTE */
+ FILE_EXECUTE,
+ /* WIN_OWNER_SE */
+ DELETE | WRITE_DAC | WRITE_OWNER | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES,
+ /* WIN_ALL */
+ READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
+};
+
+//----------------------------------------------------------------------------
+// Function: GetFileInformationByName
+//
+// Description:
+// To retrieve the by handle file information given the file name
+//
+// Returns:
+// ERROR_SUCCESS: on success
+// error code: otherwise
+//
+// Notes:
+// If followLink parameter is set to TRUE, we will follow the symbolic link
+// or junction point to get the target file information. Otherwise, the
+// information for the symbolic link or junction point is retrieved.
+//
+DWORD GetFileInformationByName(
+ __in LPCWSTR pathName,
+ __in BOOL followLink,
+ __out LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
+{
+ HANDLE fileHandle = INVALID_HANDLE_VALUE;
+ BOOL isSymlink = FALSE;
+ BOOL isJunction = FALSE;
+ DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS;
+ DWORD dwErrorCode = ERROR_SUCCESS;
+
+ assert(lpFileInformation != NULL);
+
+ if (!followLink)
+ {
+ if ((dwErrorCode = SymbolicLinkCheck(pathName, &isSymlink)) != ERROR_SUCCESS)
+ return dwErrorCode;
+ if ((dwErrorCode = JunctionPointCheck(pathName, &isJunction)) != ERROR_SUCCESS)
+ return dwErrorCode;
+ if (isSymlink || isJunction)
+ dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
+ }
+
+ fileHandle = CreateFileW(
+ pathName,
+ FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ dwFlagsAndAttributes,
+ NULL);
+ if (fileHandle == INVALID_HANDLE_VALUE)
+ {
+ dwErrorCode = GetLastError();
+ return dwErrorCode;
+ }
+
+ if (!GetFileInformationByHandle(fileHandle, lpFileInformation))
+ {
+ dwErrorCode = GetLastError();
+ CloseHandle(fileHandle);
+ return dwErrorCode;
+ }
+
+ CloseHandle(fileHandle);
+
+ return dwErrorCode;
+}
+
+//----------------------------------------------------------------------------
+// Function: IsLongWindowsPath
+//
+// Description:
+// Checks if the path is longer than MAX_PATH in which case it needs to be
+// prepended with \\?\ for Windows OS to understand it.
+//
+// Returns:
+// TRUE long path
+// FALSE otherwise
+static BOOL IsLongWindowsPath(__in PCWSTR path)
+{
+ return (wcslen(path) + 1) > MAX_PATH;
+}
+
+//----------------------------------------------------------------------------
+// Function: IsPrefixedAlready
+//
+// Description:
+// Checks if the given path is already prepended with \\?\.
+//
+// Returns:
+// TRUE if yes
+// FALSE otherwise
+static BOOL IsPrefixedAlready(__in PCWSTR path)
+{
+ static const PCWSTR LongPathPrefix = L"\\\\?\\";
+ size_t Prefixlen = wcslen(LongPathPrefix);
+ size_t i = 0;
+
+ if (path == NULL || wcslen(path) < Prefixlen)
+ {
+ return FALSE;
+ }
+
+ for (i = 0; i < Prefixlen; ++i)
+ {
+ if (path[i] != LongPathPrefix[i])
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+//----------------------------------------------------------------------------
+// Function: ConvertToLongPath
+//
+// Description:
+// Prepends the path with the \\?\ prefix if the path is longer than MAX_PATH.
+// On success, newPath should be freed with LocalFree(). Given that relative
+// paths cannot be longer than MAX_PATH, we will never prepend the prefix
+// to relative paths.
+//
+// Returns:
+// ERROR_SUCCESS on success
+// error code on failure
+DWORD ConvertToLongPath(__in PCWSTR path, __deref_out PWSTR *newPath)
+{
+ DWORD dwErrorCode = ERROR_SUCCESS;
+ static const PCWSTR LongPathPrefix = L"\\\\?\\";
+ BOOL bAppendPrefix = IsLongWindowsPath(path) && !IsPrefixedAlready(path);
+ HRESULT hr = S_OK;
+
+ size_t newPathLen = wcslen(path) + (bAppendPrefix ? wcslen(LongPathPrefix) : 0);
+
+ // Allocate the buffer for the output path (+1 for terminating NULL char)
+ //
+ PWSTR newPathValue = (PWSTR)LocalAlloc(LPTR, (newPathLen + 1) * sizeof(WCHAR));
+ if (newPathValue == NULL)
+ {
+ dwErrorCode = GetLastError();
+ goto ConvertToLongPathExit;
+ }
+
+ if (bAppendPrefix)
+ {
+ // Append the prefix to the path
+ //
+ hr = StringCchPrintfW(newPathValue, newPathLen + 1, L"%s%s",
+ LongPathPrefix, path);
+ if (FAILED(hr))
+ {
+ dwErrorCode = HRESULT_CODE(hr);
+ goto ConvertToLongPathExit;
+ }
+ }
+ else
+ {
+ // Just copy the original value into the output path. In this scenario
+ // we are doing extra buffer copy. We decided to trade code simplicity
+ // on the call site for small performance impact (extra allocation and
+ // buffer copy). As paths are short, the impact is generally small.
+ //
+ hr = StringCchPrintfW(newPathValue, newPathLen + 1, L"%s", path);
+ if (FAILED(hr))
+ {
+ dwErrorCode = HRESULT_CODE(hr);
+ goto ConvertToLongPathExit;
+ }
+ }
+
+ *newPath = newPathValue;
+
+ConvertToLongPathExit:
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ LocalFree(newPathValue);
+ *newPath = NULL;
+ }
+
+ return dwErrorCode;
+}
+
+//----------------------------------------------------------------------------
+// Function: IsDirFileInfo
+//
+// Description:
+// Test if the given file information is a directory
+//
+// Returns:
+// TRUE if it is a directory
+// FALSE otherwise
+//
+// Notes:
+//
+BOOL IsDirFileInfo(const BY_HANDLE_FILE_INFORMATION *fileInformation)
+{
+ if ((fileInformation->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ == FILE_ATTRIBUTE_DIRECTORY)
+ return TRUE;
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+// Function: CheckFileAttributes
+//
+// Description:
+// Check if the given file has all the given attribute(s)
+//
+// Returns:
+// ERROR_SUCCESS on success
+// error code otherwise
+//
+// Notes:
+//
+static DWORD FileAttributesCheck(
+ __in LPCWSTR path, __in DWORD attr, __out PBOOL res)
+{
+ DWORD attrs = INVALID_FILE_ATTRIBUTES;
+ *res = FALSE;
+ if ((attrs = GetFileAttributes(path)) != INVALID_FILE_ATTRIBUTES)
+ *res = ((attrs & attr) == attr);
+ else
+ return GetLastError();
+ return ERROR_SUCCESS;
+}
+
+//----------------------------------------------------------------------------
+// Function: IsDirectory
+//
+// Description:
+// Check if the given file is a directory
+//
+// Returns:
+// ERROR_SUCCESS on success
+// error code otherwise
+//
+// Notes:
+//
+DWORD DirectoryCheck(__in LPCWSTR pathName, __out PBOOL res)
+{
+ return FileAttributesCheck(pathName, FILE_ATTRIBUTE_DIRECTORY, res);
+}
+
+//----------------------------------------------------------------------------
+// Function: IsReparsePoint
+//
+// Description:
+// Check if the given file is a reparse point
+//
+// Returns:
+// ERROR_SUCCESS on success
+// error code otherwise
+//
+// Notes:
+//
+static DWORD ReparsePointCheck(__in LPCWSTR pathName, __out PBOOL res)
+{
+ return FileAttributesCheck(pathName, FILE_ATTRIBUTE_REPARSE_POINT, res);
+}
+
+//----------------------------------------------------------------------------
+// Function: CheckReparseTag
+//
+// Description:
+// Check if the given file is a reparse point of the given tag.
+//
+// Returns:
+// ERROR_SUCCESS on success
+// error code otherwise
+//
+// Notes:
+//
+static DWORD ReparseTagCheck(__in LPCWSTR path, __in DWORD tag, __out PBOOL res)
+{
+ BOOL isReparsePoint = FALSE;
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ WIN32_FIND_DATA findData;
+ DWORD dwRtnCode;
+
+ if ((dwRtnCode = ReparsePointCheck(path, &isReparsePoint)) != ERROR_SUCCESS)
+ return dwRtnCode;
+
+ if (!isReparsePoint)
+ {
+ *res = FALSE;
+ }
+ else
+ {
+ if ((hFind = FindFirstFile(path, &findData)) == INVALID_HANDLE_VALUE)
+ {
+ return GetLastError();
+ }
+ else
+ {
+ *res = (findData.dwReserved0 == tag);
+ FindClose(hFind);
+ }
+ }
+ return ERROR_SUCCESS;
+}
+
+//----------------------------------------------------------------------------
+// Function: IsSymbolicLink
+//
+// Description:
+// Check if the given file is a symbolic link.
+//
+// Returns:
+// ERROR_SUCCESS on success
+// error code otherwise
+//
+// Notes:
+//
+DWORD SymbolicLinkCheck(__in LPCWSTR pathName, __out PBOOL res)
+{
+ return ReparseTagCheck(pathName, IO_REPARSE_TAG_SYMLINK, res);
+}
+
+//----------------------------------------------------------------------------
+// Function: IsJunctionPoint
+//
+// Description:
+// Check if the given file is a junction point.
+//
+// Returns:
+// ERROR_SUCCESS on success
+// error code otherwise
+//
+// Notes:
+//
+DWORD JunctionPointCheck(__in LPCWSTR pathName, __out PBOOL res)
+{
+ return ReparseTagCheck(pathName, IO_REPARSE_TAG_MOUNT_POINT, res);
+}
+
+//----------------------------------------------------------------------------
+// Function: GetSidFromAcctNameW
+//
+// Description:
+// To retrieve the SID for a user account
+//
+// Returns:
+// ERROR_SUCCESS: on success
+// Other error code: otherwise
+//
+// Notes:
+// Caller needs to destroy the memory of Sid by calling LocalFree()
+//
+DWORD GetSidFromAcctNameW(LPCWSTR acctName, PSID *ppSid)
+{
+ DWORD dwSidSize = 0;
+ DWORD cchDomainName = 0;
+ DWORD dwDomainNameSize = 0;
+ LPWSTR domainName = NULL;
+ SID_NAME_USE eSidType;
+
+ DWORD dwErrorCode = ERROR_SUCCESS;
+
+ // Validate the input parameters.
+ //
+ assert (acctName != NULL && ppSid != NULL);
+
+ // Empty name is invalid. However, LookupAccountName() function will return a
+ // false Sid, i.e. Sid for 'BUILDIN', for an empty name instead failing. We
+ // report the error before calling LookupAccountName() function for this
+ // special case. The error code returned here is the same as the last error
+ // code set by LookupAccountName() function for an invalid name.
+ //
+ if (wcslen(acctName) == 0)
+ return ERROR_NONE_MAPPED;
+
+ // First pass to retrieve the buffer size.
+ //
+ LookupAccountName(
+ NULL, // Computer name. NULL for the local computer
+ acctName,
+ NULL, // pSid. NULL to retrieve buffer size
+ &dwSidSize,
+ NULL, // Domain Name. NULL to retrieve buffer size
+ &cchDomainName,
+ &eSidType);
+
+ if((dwErrorCode = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
+ {
+ return dwErrorCode;
+ }
+ else
+ {
+ // Reallocate memory for the buffers.
+ //
+ *ppSid = (PSID)LocalAlloc(LPTR, dwSidSize);
+ if (*ppSid == NULL)
+ {
+ return GetLastError();
+ }
+ dwDomainNameSize = (cchDomainName + 1) * sizeof(wchar_t);
+ domainName = (LPWSTR)LocalAlloc(LPTR, dwDomainNameSize);
+ if (domainName == NULL)
+ {
+ return GetLastError();
+ }
+
+ // Second pass to retrieve the SID and domain name.
+ //
+ if (!LookupAccountNameW(
+ NULL, // Computer name. NULL for the local computer
+ acctName,
+ *ppSid,
+ &dwSidSize,
+ domainName,
+ &cchDomainName,
+ &eSidType))
+ {
+ LocalFree(domainName);
+ return GetLastError();
+ }
+
+ assert(IsValidSid(*ppSid));
+ }
+
+ LocalFree(domainName);
+ return ERROR_SUCCESS;
+}
+
+//----------------------------------------------------------------------------
+// Function: GetUnixAccessMask
+//
+// Description:
+// Compute the 3 bit Unix mask for the owner, group, or, others
+//
+// Returns:
+// The 3 bit Unix mask in INT
+//
+// Notes:
+//
+static INT GetUnixAccessMask(ACCESS_MASK Mask)
+{
+ static const INT exe = 0x0001;
+ static const INT write = 0x0002;
+ static const INT read = 0x0004;
+ INT mask = 0;
+
+ if ((Mask & WinMasks[WIN_READ]) == WinMasks[WIN_READ])
+ mask |= read;
+ if ((Mask & WinMasks[WIN_WRITE]) == WinMasks[WIN_WRITE])
+ mask |= write;
+ if ((Mask & WinMasks[WIN_EXECUTE]) == WinMasks[WIN_EXECUTE])
+ mask |= exe;
+ return mask;
+}
+
+//----------------------------------------------------------------------------
+// Function: GetAccess
+//
+// Description:
+// Get Windows acces mask by AuthZ methods
+//
+// Returns:
+// ERROR_SUCCESS: on success
+//
+// Notes:
+//
+static DWORD GetAccess(AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClient,
+ PSECURITY_DESCRIPTOR psd, PACCESS_MASK pAccessRights)
+{
+ AUTHZ_ACCESS_REQUEST AccessRequest = {0};
+ AUTHZ_ACCESS_REPLY AccessReply = {0};
+ BYTE Buffer[1024];
+
+ assert (pAccessRights != NULL);
+
+ // Do AccessCheck
+ AccessRequest.DesiredAccess = MAXIMUM_ALLOWED;
+ AccessRequest.PrincipalSelfSid = NULL;
+ AccessRequest.ObjectTypeList = NULL;
+ AccessRequest.ObjectTypeListLength = 0;
+ AccessRequest.OptionalArguments = NULL;
+
+ RtlZeroMemory(Buffer, sizeof(Buffer));
+ AccessReply.ResultListLength = 1;
+ AccessReply.GrantedAccessMask = (PACCESS_MASK) (Buffer);
+ AccessReply.Error = (PDWORD) (Buffer + sizeof(ACCESS_MASK));
+
+ if (!AuthzAccessCheck(0,
+ hAuthzClient,
+ &AccessRequest,
+ NULL,
+ psd,
+ NULL,
+ 0,
+ &AccessReply,
+ NULL))
+ {
+ return GetLastError();
+ }
+ *pAccessRights = (*(PACCESS_MASK)(AccessReply.GrantedAccessMask));
+ return ERROR_SUCCESS;
+}
+
+//----------------------------------------------------------------------------
+// Function: GetEffectiveRightsForSid
+//
+// Description:
+// Get Windows acces mask by AuthZ methods
+//
+// Returns:
+// ERROR_SUCCESS: on success
+//
+// Notes:
+// We run into problems for local user accounts when using the method
+// GetEffectiveRightsFromAcl(). We resort to using AuthZ methods as
+// an alternative way suggested on MSDN:
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa446637.aspx
+//
+static DWORD GetEffectiveRightsForSid(PSECURITY_DESCRIPTOR psd,
+ PSID pSid,
+ PACCESS_MASK pAccessRights)
+{
+ AUTHZ_RESOURCE_MANAGER_HANDLE hManager;
+ LUID unusedId = { 0 };
+ AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClientContext = NULL;
+ DWORD dwRtnCode = ERROR_SUCCESS;
+ DWORD ret = ERROR_SUCCESS;
+
+ assert (pAccessRights != NULL);
+
+ if (!AuthzInitializeResourceManager(AUTHZ_RM_FLAG_NO_AUDIT,
+ NULL, NULL, NULL, NULL, &hManager))
+ {
+ return GetLastError();
+ }
+
+ if(!AuthzInitializeContextFromSid(AUTHZ_SKIP_TOKEN_GROUPS,
+ pSid, hManager, NULL, unusedId, NULL, &hAuthzClientContext))
+ {
+ ret = GetLastError();
+ goto GetEffectiveRightsForSidEnd;
+ }
+
+ if ((dwRtnCode = GetAccess(hAuthzClientContext, psd, pAccessRights))
+ != ERROR_SUCCESS)
+ {
+ ret = dwRtnCode;
+ goto GetEffectiveRightsForSidEnd;
+ }
+ if (!AuthzFreeContext(hAuthzClientContext))
+ {
+ ret = GetLastError();
+ goto GetEffectiveRightsForSidEnd;
+ }
+
+GetEffectiveRightsForSidEnd:
+ return ret;
+}
+
+//----------------------------------------------------------------------------
+// Function: FindFileOwnerAndPermission
+//
+// Description:
+// Find the owner, primary group and permissions of a file object
+//
+// Returns:
+// ERROR_SUCCESS: on success
+// Error code otherwise
+//
+// Notes:
+// - Caller needs to destroy the memeory of owner and group names by calling
+// LocalFree() function.
+//
+// - If the user or group name does not exist, the user or group SID will be
+// returned as the name.
+//
+DWORD FindFileOwnerAndPermission(
+ __in LPCWSTR pathName,
+ __out_opt LPWSTR *pOwnerName,
+ __out_opt LPWSTR *pGroupName,
+ __out_opt PINT pMask)
+{
+ DWORD dwRtnCode = 0;
+
+ PSECURITY_DESCRIPTOR pSd = NULL;
+
+ PSID psidOwner = NULL;
+ PSID psidGroup = NULL;
+ PSID psidEveryone = NULL;
+ DWORD cbSid = SECURITY_MAX_SID_SIZE;
+ PACL pDacl = NULL;
+
+ ACCESS_MASK ownerAccessRights = 0;
+ ACCESS_MASK groupAccessRights = 0;
+ ACCESS_MASK worldAccessRights = 0;
+
+ DWORD ret = ERROR_SUCCESS;
+
+ // Do nothing if the caller request nothing
+ //
+ if (pOwnerName == NULL && pGroupName == NULL && pMask == NULL)
+ {
+ return ret;
+ }
+
+ dwRtnCode = GetNamedSecurityInfo(pathName, SE_FILE_OBJECT,
+ OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION,
+ &psidOwner, &psidGroup, &pDacl, NULL, &pSd);
+ if (dwRtnCode != ERROR_SUCCESS)
+ {
+ ret = dwRtnCode;
+ goto FindFileOwnerAndPermissionEnd;
+ }
+
+ if (pOwnerName != NULL)
+ {
+ dwRtnCode = GetAccntNameFromSid(psidOwner, pOwnerName);
+ if (dwRtnCode == ERROR_NONE_MAPPED)
+ {
+ if (!ConvertSidToStringSid(psidOwner, pOwnerName))
+ {
+ ret = GetLastError();
+ goto FindFileOwnerAndPermissionEnd;
+ }
+ }
+ else if (dwRtnCode != ERROR_SUCCESS)
+ {
+ ret = dwRtnCode;
+ goto FindFileOwnerAndPermissionEnd;
+ }
+ }
+
+ if (pGroupName != NULL)
+ {
+ dwRtnCode = GetAccntNameFromSid(psidGroup, pGroupName);
+ if (dwRtnCode == ERROR_NONE_MAPPED)
+ {
+ if (!ConvertSidToStringSid(psidGroup, pGroupName))
+ {
+ ret = GetLastError();
+ goto FindFileOwnerAndPermissionEnd;
+ }
+ }
+ else if (dwRtnCode != ERROR_SUCCESS)
+ {
+ ret = dwRtnCode;
+ goto FindFileOwnerAndPermissionEnd;
+ }
+ }
+
+ if (pMask == NULL) goto FindFileOwnerAndPermissionEnd;
+
+ if ((dwRtnCode = GetEffectiveRightsForSid(pSd,
+ psidOwner, &ownerAccessRights)) != ERROR_SUCCESS)
+ {
+ ret = dwRtnCode;
+ goto FindFileOwnerAndPermissionEnd;
+ }
+
+ if ((dwRtnCode = GetEffectiveRightsForSid(pSd,
+ psidGroup, &groupAccessRights)) != ERROR_SUCCESS)
+ {
+ ret = dwRtnCode;
+ goto FindFileOwnerAndPermissionEnd;
+ }
+
+ if ((psidEveryone = LocalAlloc(LPTR, cbSid)) == NULL)
+ {
+ ret = GetLastError();
+ goto FindFileOwnerAndPermissionEnd;
+ }
+ if (!CreateWellKnownSid(WinWorldSid, NULL, psidEveryone, &cbSid))
+ {
+ ret = GetLastError();
+ goto FindFileOwnerAndPermissionEnd;
+ }
+ if ((dwRtnCode = GetEffectiveRightsForSid(pSd,
+ psidEveryone, &worldAccessRights)) != ERROR_SUCCESS)
+ {
+ ret = dwRtnCode;
+ goto FindFileOwnerAndPermissionEnd;
+ }
+
+ *pMask |= GetUnixAccessMask(ownerAccessRights) << 6;
+ *pMask |= GetUnixAccessMask(groupAccessRights) << 3;
+ *pMask |= GetUnixAccessMask(worldAccessRights);
+
+FindFileOwnerAndPermissionEnd:
+ LocalFree(psidEveryone);
+ LocalFree(pSd);
+
+ return ret;
+}
+
+//----------------------------------------------------------------------------
+// Function: GetWindowsAccessMask
+//
+// Description:
+// Get the Windows AccessMask for user, group and everyone based on the Unix
+// permission mask
+//
+// Returns:
+// none
+//
+// Notes:
+// none
+//
+static void GetWindowsAccessMask(INT unixMask,
+ ACCESS_MASK *userAllow,
+ ACCESS_MASK *userDeny,
+ ACCESS_MASK *groupAllow,
+ ACCESS_MASK *groupDeny,
+ ACCESS_MASK *otherAllow)
+{
+ assert (userAllow != NULL && userDeny != NULL &&
+ groupAllow != NULL && groupDeny != NULL &&
+ otherAllow != NULL);
+
+ *userAllow = WinMasks[WIN_ALL] | WinMasks[WIN_OWNER_SE];
+ if ((unixMask & UX_U_READ) == UX_U_READ)
+ *userAllow |= WinMasks[WIN_READ];
+
+ if ((unixMask & UX_U_WRITE) == UX_U_WRITE)
+ *userAllow |= WinMasks[WIN_WRITE];
+
+ if ((unixMask & UX_U_EXECUTE) == UX_U_EXECUTE)
+ *userAllow |= WinMasks[WIN_EXECUTE];
+
+ *userDeny = 0;
+ if ((unixMask & UX_U_READ) != UX_U_READ &&
+ ((unixMask & UX_G_READ) == UX_G_READ ||
+ (unixMask & UX_O_READ) == UX_O_READ))
+ *userDeny |= WinMasks[WIN_READ];
+
+ if ((unixMask & UX_U_WRITE) != UX_U_WRITE &&
+ ((unixMask & UX_G_WRITE) == UX_G_WRITE ||
+ (unixMask & UX_O_WRITE) == UX_O_WRITE))
+ *userDeny |= WinMasks[WIN_WRITE];
+
+ if ((unixMask & UX_U_EXECUTE) != UX_U_EXECUTE &&
+ ((unixMask & UX_G_EXECUTE) == UX_G_EXECUTE ||
+ (unixMask & UX_O_EXECUTE) == UX_O_EXECUTE))
+ *userDeny |= WinMasks[WIN_EXECUTE];
+
+ *groupAllow = WinMasks[WIN_ALL];
+ if ((unixMask & UX_G_READ) == UX_G_READ)
+ *groupAllow |= FILE_GENERIC_READ;
+
+ if ((unixMask & UX_G_WRITE) == UX_G_WRITE)
+ *groupAllow |= WinMasks[WIN_WRITE];
+
+ if ((unixMask & UX_G_EXECUTE) == UX_G_EXECUTE)
+ *groupAllow |= WinMasks[WIN_EXECUTE];
+
+ *groupDeny = 0;
+ if ((unixMask & UX_G_READ) != UX_G_READ &&
+ (unixMask & UX_O_READ) == UX_O_READ)
+ *groupDeny |= WinMasks[WIN_READ];
+
+ if ((unixMask & UX_G_WRITE) != UX_G_WRITE &&
+ (unixMask & UX_O_WRITE) == UX_O_WRITE)
+ *groupDeny |= WinMasks[WIN_WRITE];
+
+ if ((unixMask & UX_G_EXECUTE) != UX_G_EXECUTE &&
+ (unixMask & UX_O_EXECUTE) == UX_O_EXECUTE)
+ *groupDeny |= WinMasks[WIN_EXECUTE];
+
+ *otherAllow = WinMasks[WIN_ALL];
+ if ((unixMask & UX_O_READ) == UX_O_READ)
+ *otherAllow |= WinMasks[WIN_READ];
+
+ if ((unixMask & UX_O_WRITE) == UX_O_WRITE)
+ *otherAllow |= WinMasks[WIN_WRITE];
+
+ if ((unixMask & UX_O_EXECUTE) == UX_O_EXECUTE)
+ *otherAllow |= WinMasks[WIN_EXECUTE];
+}
+
+//----------------------------------------------------------------------------
+// Function: GetWindowsDACLs
+//
+// Description:
+// Get the Windows DACs based the Unix access mask
+//
+// Returns:
+// ERROR_SUCCESS: on success
+// Error code: otherwise
+//
+// Notes:
+// - Administrators and SYSTEM are always given full permission to the file,
+// unless Administrators or SYSTEM itself is the file owner and the user
+// explictly set the permission to something else. For example, file 'foo'
+// belongs to Administrators, 'chmod 000' on the file will not directly
+// assign Administrators full permission on the file.
+// - Only full permission for Administrators and SYSTEM are inheritable.
+// - CREATOR OWNER is always given full permission and the permission is
+// inheritable, more specifically OBJECT_INHERIT_ACE, CONTAINER_INHERIT_ACE
+// flags are set. The reason is to give the creator of child file full
+// permission, i.e., the child file will have permission mode 700 for
+// a user other than Administrator or SYSTEM.
+//
+static DWORD GetWindowsDACLs(__in INT unixMask,
+ __in PSID pOwnerSid, __in PSID pGroupSid, __out PACL *ppNewDACL)
+{
+ DWORD winUserAccessDenyMask;
+ DWORD winUserAccessAllowMask;
+ DWORD winGroupAccessDenyMask;
+ DWORD winGroupAccessAllowMask;
+ DWORD winOtherAccessAllowMask;
+
+ PSID pEveryoneSid = NULL;
+ DWORD cbEveryoneSidSize = SECURITY_MAX_SID_SIZE;
+
+ PSID pSystemSid = NULL;
+ DWORD cbSystemSidSize = SECURITY_MAX_SID_SIZE;
+ BOOL bAddSystemAcls = FALSE;
+
+ PSID pAdministratorsSid = NULL;
+ DWORD cbAdministratorsSidSize = SECURITY_MAX_SID_SIZE;
+ BOOL bAddAdministratorsAcls = FALSE;
+
+ PSID pCreatorOwnerSid = NULL;
+ DWORD cbCreatorOwnerSidSize = SECURITY_MAX_SID_SIZE;
+
+ PACL pNewDACL = NULL;
+ DWORD dwNewAclSize = 0;
+
+ DWORD ret = ERROR_SUCCESS;
+
+ GetWindowsAccessMask(unixMask,
+ &winUserAccessAllowMask, &winUserAccessDenyMask,
+ &winGroupAccessAllowMask, &winGroupAccessDenyMask,
+ &winOtherAccessAllowMask);
+
+ // Create a well-known SID for the Everyone group
+ //
+ if ((pEveryoneSid = LocalAlloc(LPTR, cbEveryoneSidSize)) == NULL)
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+ if (!CreateWellKnownSid(WinWorldSid, NULL, pEveryoneSid, &cbEveryoneSidSize))
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+
+ // Create a well-known SID for the Administrators group
+ //
+ if ((pAdministratorsSid = LocalAlloc(LPTR, cbAdministratorsSidSize)) == NULL)
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+ if (!CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL,
+ pAdministratorsSid, &cbAdministratorsSidSize))
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+ if (!EqualSid(pAdministratorsSid, pOwnerSid)
+ && !EqualSid(pAdministratorsSid, pGroupSid))
+ bAddAdministratorsAcls = TRUE;
+
+ // Create a well-known SID for the SYSTEM
+ //
+ if ((pSystemSid = LocalAlloc(LPTR, cbSystemSidSize)) == NULL)
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+ if (!CreateWellKnownSid(WinLocalSystemSid, NULL,
+ pSystemSid, &cbSystemSidSize))
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+ if (!EqualSid(pSystemSid, pOwnerSid)
+ && !EqualSid(pSystemSid, pGroupSid))
+ bAddSystemAcls = TRUE;
+
+ // Create a well-known SID for the Creator Owner
+ //
+ if ((pCreatorOwnerSid = LocalAlloc(LPTR, cbCreatorOwnerSidSize)) == NULL)
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+ if (!CreateWellKnownSid(WinCreatorOwnerSid, NULL,
+ pCreatorOwnerSid, &cbCreatorOwnerSidSize))
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+
+ // Create the new DACL
+ //
+ dwNewAclSize = sizeof(ACL);
+ dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
+ GetLengthSid(pOwnerSid) - sizeof(DWORD);
+ if (winUserAccessDenyMask)
+ dwNewAclSize += sizeof(ACCESS_DENIED_ACE) +
+ GetLengthSid(pOwnerSid) - sizeof(DWORD);
+ dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
+ GetLengthSid(pGroupSid) - sizeof(DWORD);
+ if (winGroupAccessDenyMask)
+ dwNewAclSize += sizeof(ACCESS_DENIED_ACE) +
+ GetLengthSid(pGroupSid) - sizeof(DWORD);
+ dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
+ GetLengthSid(pEveryoneSid) - sizeof(DWORD);
+
+ if (bAddSystemAcls)
+ {
+ dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
+ cbSystemSidSize - sizeof(DWORD);
+ }
+
+ if (bAddAdministratorsAcls)
+ {
+ dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
+ cbAdministratorsSidSize - sizeof(DWORD);
+ }
+
+ dwNewAclSize += sizeof(ACCESS_ALLOWED_ACE) +
+ cbCreatorOwnerSidSize - sizeof(DWORD);
+
+ pNewDACL = (PACL)LocalAlloc(LPTR, dwNewAclSize);
+ if (pNewDACL == NULL)
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+ if (!InitializeAcl(pNewDACL, dwNewAclSize, ACL_REVISION))
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+
+ if (!AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
+ CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
+ GENERIC_ALL, pCreatorOwnerSid))
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+
+ if (bAddSystemAcls &&
+ !AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
+ CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
+ GENERIC_ALL, pSystemSid))
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+
+ if (bAddAdministratorsAcls &&
+ !AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
+ CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
+ GENERIC_ALL, pAdministratorsSid))
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+
+ if (winUserAccessDenyMask &&
+ !AddAccessDeniedAceEx(pNewDACL, ACL_REVISION,
+ NO_PROPAGATE_INHERIT_ACE,
+ winUserAccessDenyMask, pOwnerSid))
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+ if (!AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
+ NO_PROPAGATE_INHERIT_ACE,
+ winUserAccessAllowMask, pOwnerSid))
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+ if (winGroupAccessDenyMask &&
+ !AddAccessDeniedAceEx(pNewDACL, ACL_REVISION,
+ NO_PROPAGATE_INHERIT_ACE,
+ winGroupAccessDenyMask, pGroupSid))
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+ if (!AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
+ NO_PROPAGATE_INHERIT_ACE,
+ winGroupAccessAllowMask, pGroupSid))
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+ if (!AddAccessAllowedAceEx(pNewDACL, ACL_REVISION,
+ NO_PROPAGATE_INHERIT_ACE,
+ winOtherAccessAllowMask, pEveryoneSid))
+ {
+ ret = GetLastError();
+ goto GetWindowsDACLsEnd;
+ }
+
+ *ppNewDACL = pNewDACL;
+
+GetWindowsDACLsEnd:
+ LocalFree(pEveryoneSid);
+ LocalFree(pAdministratorsSid);
+ LocalFree(pSystemSid);
+ LocalFree(pCreatorOwnerSid);
+ if (ret != ERROR_SUCCESS) LocalFree(pNewDACL);
+
+ return ret;
+}
+
+//----------------------------------------------------------------------------
+// Function: ChangeFileModeByMask
+//
+// Description:
+// Change a file or direcotry at the path to Unix mode
+//
+// 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.
+//
+DWORD ChangeFileModeByMask(__in LPCWSTR path, INT mode)
+{
+ LPWSTR longPathName = NULL;
+ PACL pNewDACL = NULL;
+ PSID pOwnerSid = NULL;
+ PSID pGroupSid = NULL;
+ PSECURITY_DESCRIPTOR pSD = NULL;
+
+ SECURITY_DESCRIPTOR_CONTROL control;
+ DWORD revision = 0;
+
+ PSECURITY_DESCRIPTOR pAbsSD = NULL;
+ PACL pAbsDacl = NULL;
+ PACL pAbsSacl = NULL;
+ PSID pAbsOwner = NULL;
+ PSID pAbsGroup = NULL;
+
+ DWORD dwRtnCode = 0;
+ DWORD dwErrorCode = 0;
+
+ DWORD ret = ERROR_SUCCESS;
+
+ dwRtnCode = ConvertToLongPath(path, &longPathName);
+ if (dwRtnCode != ERROR_SUCCESS)
+ {
+ ret = dwRtnCode;
+ goto ChangeFileModeByMaskEnd;
+ }
+
+ // Get owner and group Sids
+ //
+ dwRtnCode = GetNamedSecurityInfoW(
+ longPathName,
+ SE_FILE_OBJECT,
+ OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION,
+ &pOwnerSid,
+ &pGroupSid,
+ NULL,
+ NULL,
+ &pSD);
+ if (ERROR_SUCCESS != dwRtnCode)
+ {
+ ret = dwRtnCode;
+ goto ChangeFileModeByMaskEnd;
+ }
+
+ // SetSecurityDescriptorDacl function used below only accepts security
+ // descriptor in absolute format, meaning that its members must be pointers to
+ // other structures, rather than offsets to contiguous data.
+ // To determine whether a security descriptor is self-relative or absolute,
+ // call the GetSecurityDescriptorControl function and check the
+ // SE_SELF_RELATIVE flag of the SECURITY_DESCRIPTOR_CONTROL parameter.
+ //
+ if (!GetSecurityDescriptorControl(pSD, &control, &revision))
+ {
+ ret = GetLastError();
+ goto ChangeFileModeByMaskEnd;
+ }
+
+ // If the security descriptor is self-relative, we use MakeAbsoluteSD function
+ // to convert it to absolute format.
+ //
+ if ((control & SE_SELF_RELATIVE) == SE_SELF_RELATIVE)
+ {
+ DWORD absSDSize = 0;
+ DWORD daclSize = 0;
+ DWORD saclSize = 0;
+ DWORD ownerSize = 0;
+ DWORD primaryGroupSize = 0;
+ MakeAbsoluteSD(pSD, NULL, &absSDSize, NULL, &daclSize, NULL,
+ &saclSize, NULL, &ownerSize, NULL, &primaryGroupSize);
+ if ((dwErrorCode = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
+ {
+ ret = dwErrorCode;
+ goto ChangeFileModeByMaskEnd;
+ }
+
+ if ((pAbsSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, absSDSize)) == NULL)
+ {
+ ret = GetLastError();
+ goto ChangeFileModeByMaskEnd;
+ }
+ if ((pAbsDacl = (PACL) LocalAlloc(LPTR, daclSize)) == NULL)
+ {
+ ret = GetLastError();
+ goto ChangeFileModeByMaskEnd;
+ }
+ if ((pAbsSacl = (PACL) LocalAlloc(LPTR, saclSize)) == NULL)
+ {
+ ret = GetLastError();
+ goto ChangeFileModeByMaskEnd;
+ }
+ if ((pAbsOwner = (PSID) LocalAlloc(LPTR, ownerSize)) == NULL)
+ {
+ ret = GetLastError();
+ goto ChangeFileModeByMaskEnd;
+ }
+ if ((pAbsGroup = (PSID) LocalAlloc(LPTR, primaryGroupSize)) == NULL)
+ {
+ ret = GetLastError();
+ goto ChangeFileModeByMaskEnd;
+ }
+
+ if (!MakeAbsoluteSD(pSD, pAbsSD, &absSDSize, pAbsDacl, &daclSize, pAbsSacl,
+ &saclSize, pAbsOwner, &ownerSize, pAbsGroup, &primaryGroupSize))
+ {
+ ret = GetLastError();
+ goto ChangeFileModeByMaskEnd;
+ }
+ }
+
+ // Get Windows DACLs based on Unix access mask
+ //
+ if ((dwRtnCode = GetWindowsDACLs(mode, pOwnerSid, pGroupSid, &pNewDACL))
+ != ERROR_SUCCESS)
+ {
+ ret = dwRtnCode;
+ goto ChangeFileModeByMaskEnd;
+ }
+
+ // Set the DACL information in the security descriptor; if a DACL is already
+ // present in the security descriptor, the DACL is replaced. The security
+ // descriptor is then used to set the security of a file or directory.
+ //
+ if (!SetSecurityDescriptorDacl(pAbsSD, TRUE, pNewDACL, FALSE))
+ {
+ ret = GetLastError();
+ goto ChangeFileModeByMaskEnd;
+ }
+
+ // MSDN states "This function is obsolete. Use the SetNamedSecurityInfo
+ // function instead." However we have the following problem when using
+ // SetNamedSecurityInfo:
+ // - When PROTECTED_DACL_SECURITY_INFORMATION is not passed in as part of
+ // security information, the object will include inheritable permissions
+ // from its parent.
+ // - When PROTECTED_DACL_SECURITY_INFORMATION is passsed in to set
+ // permissions on a directory, the child object of the directory will lose
+ // inheritable permissions from their parent (the current directory).
+ // By using SetFileSecurity, we have the nice property that the new
+ // permissions of the object does not include the inheritable permissions from
+ // its parent, and the child objects will not lose their inherited permissions
+ // from the current object.
+ //
+ if (!SetFileSecurity(longPathName, DACL_SECURITY_INFORMATION, pAbsSD))
+ {
+ ret = GetLastError();
+ goto ChangeFileModeByMaskEnd;
+ }
+
+ChangeFileModeByMaskEnd:
+ LocalFree(longPathName);
+ LocalFree(pSD);
+ LocalFree(pNewDACL);
+ LocalFree(pAbsDacl);
+ LocalFree(pAbsSacl);
+ LocalFree(pAbsOwner);
+ LocalFree(pAbsGroup);
+ LocalFree(pAbsSD);
+
+ return ret;
+}
+
+//----------------------------------------------------------------------------
+// Function: GetAccntNameFromSid
+//
+// Description:
+// To retrieve an account name given the SID
+//
+// Returns:
+// ERROR_SUCCESS: on success
+// Other error code: otherwise
+//
+// Notes:
+// Caller needs to destroy the memory of account name by calling LocalFree()
+//
+DWORD GetAccntNameFromSid(PSID pSid, LPWSTR *ppAcctName)
+{
+ LPWSTR lpName = NULL;
+ DWORD cchName = 0;
+ LPWSTR lpDomainName = NULL;
+ DWORD cchDomainName = 0;
+ SID_NAME_USE eUse = SidTypeUnknown;
+ DWORD cchAcctName = 0;
+ DWORD dwErrorCode = ERROR_SUCCESS;
+ HRESULT hr = S_OK;
+
+ DWORD ret = ERROR_SUCCESS;
+
+ assert(ppAcctName != NULL);
+
+ // NOTE:
+ // MSDN says the length returned for the buffer size including the terminating
+ // null character. However we found it is not true during debuging.
+ //
+ LookupAccountSid(NULL, pSid, NULL, &cchName, NULL, &cchDomainName, &eUse);
+ if ((dwErrorCode = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
+ return dwErrorCode;
+ lpName = (LPWSTR) LocalAlloc(LPTR, (cchName + 1) * sizeof(WCHAR));
+ if (lpName == NULL)
+ {
+ ret = GetLastError();
+ goto GetAccntNameFromSidEnd;
+ }
+ lpDomainName = (LPWSTR) LocalAlloc(LPTR, (cchDomainName + 1) * sizeof(WCHAR));
+ if (lpDomainName == NULL)
+ {
+ ret = GetLastError();
+ goto GetAccntNameFromSidEnd;
+ }
+
+ if (!LookupAccountSid(NULL, pSid,
+ lpName, &cchName, lpDomainName, &cchDomainName, &eUse))
+ {
+ ret = GetLastError();
+ goto GetAccntNameFromSidEnd;
+ }
+
+ // Buffer size = name length + 1 for '\' + domain length + 1 for NULL
+ cchAcctName = cchName + cchDomainName + 2;
+ *ppAcctName = (LPWSTR) LocalAlloc(LPTR, cchAcctName * sizeof(WCHAR));
+ if (*ppAcctName == NULL)
+ {
+ ret = GetLastError();
+ goto GetAccntNameFromSidEnd;
+ }
+
+ hr = StringCchCopyW(*ppAcctName, cchAcctName, lpDomainName);
+ if (FAILED(hr))
+ {
+ ret = HRESULT_CODE(hr);
+ goto GetAccntNameFromSidEnd;
+ }
+
+ hr = StringCchCatW(*ppAcctName, cchAcctName, L"\\");
+ if (FAILED(hr))
+ {
+ ret = HRESULT_CODE(hr);
+ goto GetAccntNameFromSidEnd;
+ }
+
+ hr = StringCchCatW(*ppAcctName, cchAcctName, lpName);
+ if (FAILED(hr))
+ {
+ ret = HRESULT_CODE(hr);
+ goto GetAccntNameFromSidEnd;
+ }
+
+GetAccntNameFromSidEnd:
+ LocalFree(lpName);
+ LocalFree(lpDomainName);
+ if (ret != ERROR_SUCCESS)
+ {
+ LocalFree(*ppAcctName);
+ *ppAcctName = NULL;
+ }
+ return ret;
+}
+
+//----------------------------------------------------------------------------
+// Function: GetLocalGroupsForUser
+//
+// Description:
+// Get an array of groups for the given user.
+//
+// Returns:
+// ERROR_SUCCESS on success
+// Other error code on failure
+//
+// Notes:
+// - NetUserGetLocalGroups() function only accepts full user name in the format
+// [domain name]\[username]. The user input to this function can be only the
+// username. In this case, NetUserGetLocalGroups() will fail on the first try,
+// and we will try to find full user name using LookupAccountNameW() method,
+// and call NetUserGetLocalGroups() function again with full user name.
+// However, it is not always possible to find full user name given only user
+// name. For example, a computer named 'win1' joined domain 'redmond' can have
+// two different users, 'win1\alex' and 'redmond\alex'. Given only 'alex', we
+// cannot tell which one is correct.
+//
+// - Caller needs to destroy the memory of groups by using the
+// NetApiBufferFree() function
+//
+DWORD GetLocalGroupsForUser(
+ __in LPCWSTR user,
+ __out LPLOCALGROUP_USERS_INFO_0 *groups,
+ __out LPDWORD entries)
+{
+ DWORD dwEntriesRead = 0;
+ DWORD dwTotalEntries = 0;
+ NET_API_STATUS nStatus = NERR_Success;
+
+ PSID pUserSid = NULL;
+ LPWSTR fullName = NULL;
+
+ DWORD dwRtnCode = ERROR_SUCCESS;
+
+ DWORD ret = ERROR_SUCCESS;
+
+ *groups = NULL;
+ *entries = 0;
+
+ nStatus = NetUserGetLocalGroups(NULL,
+ user,
+ 0,
+ 0,
+ (LPBYTE *) groups,
+ MAX_PREFERRED_LENGTH,
+ &dwEntriesRead,
+ &dwTotalEntries);
+
+ if (nStatus == NERR_Success)
+ {
+ *entries = dwEntriesRead;
+ return ERROR_SUCCESS;
+ }
+ else if (nStatus != NERR_UserNotFound)
+ {
+ return nStatus;
+ }
+
+ if ((dwRtnCode = GetSidFromAcctNameW(user, &pUserSid)) != ERROR_SUCCESS)
+ {
+ ret = dwRtnCode;
+ goto GetLocalGroupsForUserEnd;
+ }
+
+ if ((dwRtnCode = GetAccntNameFromSid(pUserSid, &fullName)) != ERROR_SUCCESS)
+ {
+ ret = dwRtnCode;
+ goto GetLocalGroupsForUserEnd;
+ }
+
+ nStatus = NetUserGetLocalGroups(NULL,
+ fullName,
+ 0,
+ 0,
+ (LPBYTE *) groups,
+ MAX_PREFERRED_LENGTH,
+ &dwEntriesRead,
+ &dwTotalEntries);
+ if (nStatus != NERR_Success)
+ {
+ // NERR_DCNotFound (2453) and NERR_UserNotFound (2221) are not published
+ // Windows System Error Code. All other error codes returned by
+ // NetUserGetLocalGroups() are valid System Error Codes according to MSDN.
+ ret = nStatus;
+ goto GetLocalGroupsForUserEnd;
+ }
+
+ *entries = dwEntriesRead;
+
+GetLocalGroupsForUserEnd:
+ LocalFree(pUserSid);
+ LocalFree(fullName);
+ return ret;
+}
+
+//----------------------------------------------------------------------------
+// Function: EnablePrivilege
+//
+// Description:
+// Check if the process has the given privilege. If yes, enable the privilege
+// to the process's access token.
+//
+// Returns:
+// TRUE: on success
+//
+// Notes:
+//
+BOOL EnablePrivilege(__in LPCWSTR privilegeName)
+{
+ HANDLE hToken = INVALID_HANDLE_VALUE;
+ TOKEN_PRIVILEGES tp = { 0 };
+ DWORD dwErrCode = ERROR_SUCCESS;
+
+ if (!OpenProcessToken(GetCurrentProcess(),
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
+ {
+ ReportErrorCode(L"OpenProcessToken", GetLastError());
+ return FALSE;
+ }
+
+ tp.PrivilegeCount = 1;
+ if (!LookupPrivilegeValueW(NULL,
+ privilegeName, &(tp.Privileges[0].Luid)))
+ {
+ ReportErrorCode(L"LookupPrivilegeValue", GetLastError());
+ CloseHandle(hToken);
+ return FALSE;
+ }
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ // As stated on MSDN, we need to use GetLastError() to check if
+ // AdjustTokenPrivileges() adjusted all of the specified privileges.
+ //
+ AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
+ dwErrCode = GetLastError();
+ CloseHandle(hToken);
+
+ return dwErrCode == ERROR_SUCCESS;
+}
+
+//----------------------------------------------------------------------------
+// Function: ReportErrorCode
+//
+// Description:
+// Report an error. Use FormatMessage function to get the system error message.
+//
+// Returns:
+// None
+//
+// Notes:
+//
+//
+void ReportErrorCode(LPCWSTR func, DWORD err)
+{
+ DWORD len = 0;
+ LPWSTR msg = NULL;
+
+ assert(func != NULL);
+
+ len = FormatMessageW(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPWSTR)&msg, 0, NULL);
+ if (len > 0)
+ {
+ fwprintf(stderr, L"%s error (%d): %s\n", func, err, msg);
+ }
+ else
+ {
+ fwprintf(stderr, L"%s error code: %d.\n", func, err);
+ }
+ if (msg != NULL) LocalFree(msg);
+}
Added: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/libwinutils.vcxproj
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/libwinutils.vcxproj?rev=1453486&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/libwinutils.vcxproj (added)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/libwinutils.vcxproj Wed Mar 6 19:15:18 2013
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ 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.
+-->
+
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{12131AA7-902E-4a6d-9CE3-043261D22A12}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>winutils</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <IncludePath>include;$(IncludePath)</IncludePath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir />
+ <IntDir>..\..\..\target\winutils\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>..\..\..\target\bin\</OutDir>
+ <IntDir>..\..\..\target\winutils\$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="libwinutils.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="include/winutils.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
Added: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/ls.c
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/ls.c?rev=1453486&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/ls.c (added)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/ls.c Wed Mar 6 19:15:18 2013
@@ -0,0 +1,346 @@
+/**
+ * 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: GetMaskString
+//
+// Description:
+// Get the mask string that are used for output to the console.
+//
+// Returns:
+// TRUE: on success
+//
+// Notes:
+// The function only sets the existed permission in the mask string. If the
+// permission does not exist, the corresponding character in mask string is not
+// altered. The caller need to initilize the mask string to be all '-' to get
+// the correct mask string.
+//
+static BOOL GetMaskString(INT accessMask, LPWSTR maskString)
+{
+ if(wcslen(maskString) != 10)
+ return FALSE;
+
+ if ((accessMask & UX_DIRECTORY) == UX_DIRECTORY)
+ maskString[0] = L'd';
+ else if ((accessMask & UX_SYMLINK) == UX_SYMLINK)
+ maskString[0] = L'l';
+
+ if ((accessMask & UX_U_READ) == UX_U_READ)
+ maskString[1] = L'r';
+ if ((accessMask & UX_U_WRITE) == UX_U_WRITE)
+ maskString[2] = L'w';
+ if ((accessMask & UX_U_EXECUTE) == UX_U_EXECUTE)
+ maskString[3] = L'x';
+
+ if ((accessMask & UX_G_READ) == UX_G_READ)
+ maskString[4] = L'r';
+ if ((accessMask & UX_G_WRITE) == UX_G_WRITE)
+ maskString[5] = L'w';
+ if ((accessMask & UX_G_EXECUTE) == UX_G_EXECUTE)
+ maskString[6] = L'x';
+
+ if ((accessMask & UX_O_READ) == UX_O_READ)
+ maskString[7] = L'r';
+ if ((accessMask & UX_O_WRITE) == UX_O_WRITE)
+ maskString[8] = L'w';
+ if ((accessMask & UX_O_EXECUTE) == UX_O_EXECUTE)
+ maskString[9] = L'x';
+
+ return TRUE;
+}
+
+//----------------------------------------------------------------------------
+// Function: LsPrintLine
+//
+// Description:
+// Print one line of 'ls' command given all the information needed
+//
+// Returns:
+// None
+//
+// Notes:
+// if useSeparator is false, separates the output tokens with a space
+// character, otherwise, with a pipe character
+//
+static BOOL LsPrintLine(
+ const INT mask,
+ const DWORD hardlinkCount,
+ LPCWSTR ownerName,
+ LPCWSTR groupName,
+ const FILETIME *lpFileWritetime,
+ const LARGE_INTEGER fileSize,
+ LPCWSTR path,
+ BOOL useSeparator)
+{
+ // 'd' + 'rwx' for user, group, other
+ static const size_t ck_ullMaskLen = 1 + 3 * 3;
+
+ LPWSTR maskString = NULL;
+ SYSTEMTIME stFileWriteTime;
+ BOOL ret = FALSE;
+
+ maskString = (LPWSTR)LocalAlloc(LPTR, (ck_ullMaskLen+1)*sizeof(WCHAR));
+ if (maskString == NULL)
+ {
+ ReportErrorCode(L"LocalAlloc", GetLastError());
+ return FALSE;
+ }
+
+ // Build mask string from mask mode
+ if (FAILED(StringCchCopyW(maskString, (ck_ullMaskLen+1), L"----------")))
+ {
+ goto LsPrintLineEnd;
+ }
+
+ if (!GetMaskString(mask, maskString))
+ {
+ goto LsPrintLineEnd;
+ }
+
+ // Convert file time to system time
+ if (!FileTimeToSystemTime(lpFileWritetime, &stFileWriteTime))
+ {
+ goto LsPrintLineEnd;
+ }
+
+ if (useSeparator)
+ {
+ fwprintf(stdout, L"%10s|%d|%s|%s|%lld|%3s|%2d|%4d|%s\n",
+ maskString, hardlinkCount, ownerName, groupName, fileSize.QuadPart,
+ MONTHS[stFileWriteTime.wMonth-1], stFileWriteTime.wDay,
+ stFileWriteTime.wYear, path);
+ }
+ else
+ {
+ fwprintf(stdout, L"%10s %d %s %s %lld %3s %2d %4d %s\n",
+ maskString, hardlinkCount, ownerName, groupName, fileSize.QuadPart,
+ MONTHS[stFileWriteTime.wMonth-1], stFileWriteTime.wDay,
+ stFileWriteTime.wYear, path);
+ }
+
+ ret = TRUE;
+
+LsPrintLineEnd:
+ LocalFree(maskString);
+
+ return ret;
+}
+
+// List of command line options supported by "winutils ls"
+enum CmdLineOption
+{
+ CmdLineOptionFollowSymlink = 0x1, // "-L"
+ CmdLineOptionSeparator = 0x2 // "-F"
+ // options should be powers of 2 (aka next is 0x4)
+};
+
+static wchar_t* CurrentDir = L".";
+
+//----------------------------------------------------------------------------
+// Function: ParseCommandLine
+//
+// Description:
+// Parses the command line
+//
+// Returns:
+// TRUE on the valid command line, FALSE otherwise
+//
+BOOL ParseCommandLine(
+ int argc, wchar_t *argv[], wchar_t** path, int *optionsMask)
+{
+ int MaxOptions = 2; // Should be equal to the number of elems in CmdLineOption
+ int i = 0;
+
+ assert(optionsMask != NULL);
+ assert(argv != NULL);
+ assert(path != NULL);
+
+ *optionsMask = 0;
+
+ if (argc == 1)
+ {
+ // no path specified, assume "."
+ *path = CurrentDir;
+ return TRUE;
+ }
+
+ if (argc == 2)
+ {
+ // only path specified, no other options
+ *path = argv[1];
+ return TRUE;
+ }
+
+ if (argc > 2 + MaxOptions)
+ {
+ // too many parameters
+ return FALSE;
+ }
+
+ for (i = 1; i < argc - 1; ++i)
+ {
+ if (wcscmp(argv[i], L"-L") == 0)
+ {
+ // Check if this option was already specified
+ BOOL alreadySet = *optionsMask & CmdLineOptionFollowSymlink;
+ if (alreadySet)
+ return FALSE;
+
+ *optionsMask |= CmdLineOptionFollowSymlink;
+ }
+ else if (wcscmp(argv[i], L"-F") == 0)
+ {
+ // Check if this option was already specified
+ BOOL alreadySet = *optionsMask & CmdLineOptionSeparator;
+ if (alreadySet)
+ return FALSE;
+
+ *optionsMask |= CmdLineOptionSeparator;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+
+ *path = argv[argc - 1];
+
+ return TRUE;
+}
+
+//----------------------------------------------------------------------------
+// Function: Ls
+//
+// Description:
+// The main method for ls command
+//
+// Returns:
+// 0: on success
+//
+// Notes:
+//
+int Ls(int argc, wchar_t *argv[])
+{
+ LPWSTR pathName = NULL;
+ LPWSTR longPathName = NULL;
+
+ BY_HANDLE_FILE_INFORMATION fileInformation;
+
+ LPWSTR ownerName = NULL;
+ LPWSTR groupName = NULL;
+ INT unixAccessMode = 0;
+ DWORD dwErrorCode = ERROR_SUCCESS;
+
+ LARGE_INTEGER fileSize;
+
+ BOOL isSymlink = FALSE;
+
+ int ret = EXIT_FAILURE;
+ int optionsMask = 0;
+
+ if (!ParseCommandLine(argc, argv, &pathName, &optionsMask))
+ {
+ fwprintf(stderr, L"Incorrect command line arguments.\n\n");
+ LsUsage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ assert(pathName != NULL);
+
+ if (wcsspn(pathName, L"/?|><:*\"") != 0)
+ {
+ fwprintf(stderr, L"Incorrect file name format: %s\n", pathName);
+ return EXIT_FAILURE;
+ }
+
+ // Convert the path the the long path
+ //
+ dwErrorCode = ConvertToLongPath(pathName, &longPathName);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ReportErrorCode(L"ConvertToLongPath", dwErrorCode);
+ goto LsEnd;
+ }
+
+ dwErrorCode = GetFileInformationByName(
+ longPathName, optionsMask & CmdLineOptionFollowSymlink, &fileInformation);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ReportErrorCode(L"GetFileInformationByName", dwErrorCode);
+ goto LsEnd;
+ }
+
+ dwErrorCode = SymbolicLinkCheck(longPathName, &isSymlink);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ReportErrorCode(L"IsSymbolicLink", dwErrorCode);
+ goto LsEnd;
+ }
+
+ if (isSymlink)
+ unixAccessMode |= UX_SYMLINK;
+ else if (IsDirFileInfo(&fileInformation))
+ unixAccessMode |= UX_DIRECTORY;
+
+ dwErrorCode = FindFileOwnerAndPermission(longPathName,
+ &ownerName, &groupName, &unixAccessMode);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ReportErrorCode(L"FindFileOwnerAndPermission", dwErrorCode);
+ goto LsEnd;
+ }
+
+ fileSize.HighPart = fileInformation.nFileSizeHigh;
+ fileSize.LowPart = fileInformation.nFileSizeLow;
+
+ // Print output using the input path name (not the long one)
+ //
+ if (!LsPrintLine(unixAccessMode,
+ fileInformation.nNumberOfLinks,
+ ownerName, groupName,
+ &fileInformation.ftLastWriteTime,
+ fileSize,
+ pathName,
+ optionsMask & CmdLineOptionSeparator))
+ goto LsEnd;
+
+ ret = EXIT_SUCCESS;
+
+LsEnd:
+ LocalFree(ownerName);
+ LocalFree(groupName);
+ LocalFree(longPathName);
+
+ return ret;
+}
+
+void LsUsage(LPCWSTR program)
+{
+ fwprintf(stdout, L"\
+Usage: %s [OPTIONS] [FILE]\n\
+List information about the FILE (the current directory by default).\n\
+Using long listing format and list directory entries instead of contents,\n\
+and do not dereference symbolic links.\n\
+Provides equivalent or similar function as 'ls -ld' on GNU/Linux.\n\
+\n\
+OPTIONS: -L dereference symbolic links\n\
+ -F format the output by separating tokens with a pipe\n",
+program);
+}
Added: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/main.c
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/main.c?rev=1453486&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/main.c (added)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/main.c Wed Mar 6 19:15:18 2013
@@ -0,0 +1,115 @@
+/**
+ * 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"
+
+static void Usage(LPCWSTR program);
+
+int wmain(int argc, wchar_t* argv[])
+{
+ LPCWSTR cmd = NULL;
+
+ if (argc < 2)
+ {
+ Usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ cmd = argv[1];
+
+ if (wcscmp(L"ls", cmd) == 0)
+ {
+ return Ls(argc - 1, argv + 1);
+ }
+ else if (wcscmp(L"chmod", cmd) == 0)
+ {
+ return Chmod(argc - 1, argv + 1);
+ }
+ else if (wcscmp(L"chown", cmd) == 0)
+ {
+ return Chown(argc - 1, argv + 1);
+ }
+ else if (wcscmp(L"groups", cmd) == 0)
+ {
+ return Groups(argc - 1, argv + 1);
+ }
+ else if (wcscmp(L"hardlink", cmd) == 0)
+ {
+ return Hardlink(argc - 1, argv + 1);
+ }
+ else if (wcscmp(L"symlink", cmd) == 0)
+ {
+ return Symlink(argc - 1, argv + 1);
+ }
+ else if (wcscmp(L"task", cmd) == 0)
+ {
+ return Task(argc - 1, argv + 1);
+ }
+ else if (wcscmp(L"systeminfo", cmd) == 0)
+ {
+ return SystemInfo();
+ }
+ else if (wcscmp(L"help", cmd) == 0)
+ {
+ Usage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+ else
+ {
+ Usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+}
+
+static void Usage(LPCWSTR program)
+{
+ fwprintf(stdout, L"Usage: %s [command] ...\n\
+Provide basic command line utilities for Hadoop on Windows.\n\n\
+The available commands and their usages are:\n\n", program);
+
+ fwprintf(stdout, L"%-15s%s\n\n", L"chmod", L"Change file mode bits.");
+ ChmodUsage(L"chmod");
+ fwprintf(stdout, L"\n\n");
+
+ fwprintf(stdout, L"%-15s%s\n\n", L"chown", L"Change file owner.");
+ ChownUsage(L"chown");
+ fwprintf(stdout, L"\n\n");
+
+ fwprintf(stdout, L"%-15s%s\n\n", L"groups", L"List user groups.");
+ GroupsUsage(L"groups");
+ fwprintf(stdout, L"\n\n");
+
+ fwprintf(stdout, L"%-15s%s\n\n", L"hardlink", L"Hard link operations.");
+ HardlinkUsage();
+ fwprintf(stdout, L"\n\n");
+
+ fwprintf(stdout, L"%-15s%s\n\n", L"ls", L"List file information.");
+ LsUsage(L"ls");
+ fwprintf(stdout, L"\n\n");
+
+ fwprintf(stdout, L"%-10s%s\n\n", L"symlink", L"Create a symbolic link.");
+ SymlinkUsage();
+ fwprintf(stdout, L"\n\n");
+
+ fwprintf(stdout, L"%-15s%s\n\n", L"systeminfo", L"System information.");
+ SystemInfoUsage();
+ fwprintf(stdout, L"\n\n");
+
+ fwprintf(stdout, L"%-15s%s\n\n", L"task", L"Task operations.");
+ TaskUsage();
+ fwprintf(stdout, L"\n\n");
+}
Added: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/symlink.c
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/symlink.c?rev=1453486&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/symlink.c (added)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/symlink.c Wed Mar 6 19:15:18 2013
@@ -0,0 +1,115 @@
+/**
+ * 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: Symlink
+//
+// Description:
+// The main method for symlink command
+//
+// Returns:
+// 0: on success
+//
+// Notes:
+//
+int Symlink(int argc, wchar_t *argv[])
+{
+ PWSTR longLinkName = NULL;
+ PWSTR longFileName = NULL;
+ DWORD dwErrorCode = ERROR_SUCCESS;
+
+ BOOL isDir = FALSE;
+
+ DWORD dwRtnCode = ERROR_SUCCESS;
+ DWORD dwFlag = 0;
+
+ int ret = SUCCESS;
+
+ if (argc != 3)
+ {
+ SymlinkUsage();
+ return FAILURE;
+ }
+
+ dwErrorCode = ConvertToLongPath(argv[1], &longLinkName);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ret = FAILURE;
+ goto SymlinkEnd;
+ }
+ dwErrorCode = ConvertToLongPath(argv[2], &longFileName);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ret = FAILURE;
+ goto SymlinkEnd;
+ }
+
+ // Check if the the process's access token has the privilege to create
+ // symbolic links. Without this step, the call to CreateSymbolicLink() from
+ // users have the privilege to create symbolic links will still succeed.
+ // This is just an additional step to do the privilege check by not using
+ // error code from CreateSymbolicLink() method.
+ //
+ if (!EnablePrivilege(L"SeCreateSymbolicLinkPrivilege"))
+ {
+ fwprintf(stderr,
+ L"No privilege to create symbolic links.\n");
+ ret = SYMLINK_NO_PRIVILEGE;
+ goto SymlinkEnd;
+ }
+
+ if ((dwRtnCode = DirectoryCheck(longFileName, &isDir)) != ERROR_SUCCESS)
+ {
+ ReportErrorCode(L"DirectoryCheck", dwRtnCode);
+ ret = FAILURE;
+ goto SymlinkEnd;
+ }
+
+ if (isDir)
+ dwFlag = SYMBOLIC_LINK_FLAG_DIRECTORY;
+
+ if (!CreateSymbolicLinkW(longLinkName, longFileName, dwFlag))
+ {
+ ReportErrorCode(L"CreateSymbolicLink", GetLastError());
+ ret = FAILURE;
+ goto SymlinkEnd;
+ }
+
+SymlinkEnd:
+ LocalFree(longLinkName);
+ LocalFree(longFileName);
+ return ret;
+}
+
+void SymlinkUsage()
+{
+ fwprintf(stdout, L"\
+Usage: symlink [LINKNAME] [FILENAME]\n\
+Creates a symbolic link\n\
+\n\
+0 is returned on success.\n\
+2 is returned if the user does no have privilege to create symbolic links.\n\
+1 is returned for all other errors.\n\
+\n\
+The default security settings in Windows disallow non-elevated administrators\n\
+and all non-administrators from creating symbolic links. The security settings\n\
+for symbolic links can be changed in the Local Security Policy management\n\
+console.\n");
+}
+
Added: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/systeminfo.c
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/systeminfo.c?rev=1453486&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/systeminfo.c (added)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/systeminfo.c Wed Mar 6 19:15:18 2013
@@ -0,0 +1,120 @@
+/**
+* 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 <psapi.h>
+#include <PowrProf.h>
+
+#define PSAPI_VERSION 1
+#pragma comment(lib, "psapi.lib")
+#pragma comment(lib, "Powrprof.lib")
+
+typedef struct _PROCESSOR_POWER_INFORMATION {
+ ULONG Number;
+ ULONG MaxMhz;
+ ULONG CurrentMhz;
+ ULONG MhzLimit;
+ ULONG MaxIdleState;
+ ULONG CurrentIdleState;
+} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
+
+//----------------------------------------------------------------------------
+// Function: SystemInfo
+//
+// Description:
+// Returns the resource information about the machine
+//
+// Returns:
+// EXIT_SUCCESS: On success
+// EXIT_FAILURE: otherwise
+int SystemInfo()
+{
+ size_t vmemSize, vmemFree, memSize, memFree;
+ PERFORMANCE_INFORMATION memInfo;
+ SYSTEM_INFO sysInfo;
+ FILETIME idleTimeFt, kernelTimeFt, userTimeFt;
+ ULARGE_INTEGER idleTime, kernelTime, userTime;
+ ULONGLONG cpuTimeMs;
+ size_t size;
+ LPBYTE pBuffer;
+ PPROCESSOR_POWER_INFORMATION ppi;
+ long cpuFrequencyKhz;
+ NTSTATUS status;
+
+ ZeroMemory(&memInfo, sizeof(PERFORMANCE_INFORMATION));
+ memInfo.cb = sizeof(PERFORMANCE_INFORMATION);
+ if(!GetPerformanceInfo(&memInfo, sizeof(PERFORMANCE_INFORMATION)))
+ {
+ ReportErrorCode(L"GetPerformanceInfo", GetLastError());
+ return EXIT_FAILURE;
+ }
+ vmemSize = memInfo.CommitLimit*memInfo.PageSize;
+ vmemFree = vmemSize - memInfo.CommitTotal*memInfo.PageSize;
+ memSize = memInfo.PhysicalTotal*memInfo.PageSize;
+ memFree = memInfo.PhysicalAvailable*memInfo.PageSize;
+
+ GetSystemInfo(&sysInfo);
+
+ if(!GetSystemTimes(&idleTimeFt, &kernelTimeFt, &userTimeFt))
+ {
+ ReportErrorCode(L"GetSystemTimes", GetLastError());
+ return EXIT_FAILURE;
+ }
+ idleTime.HighPart = idleTimeFt.dwHighDateTime;
+ idleTime.LowPart = idleTimeFt.dwLowDateTime;
+ kernelTime.HighPart = kernelTimeFt.dwHighDateTime;
+ kernelTime.LowPart = kernelTimeFt.dwLowDateTime;
+ userTime.HighPart = userTimeFt.dwHighDateTime;
+ userTime.LowPart = userTimeFt.dwLowDateTime;
+
+ cpuTimeMs = (kernelTime.QuadPart - idleTime.QuadPart + userTime.QuadPart)/10000;
+
+ // allocate buffer to get info for each processor
+ size = sysInfo.dwNumberOfProcessors * sizeof(PROCESSOR_POWER_INFORMATION);
+ pBuffer = (BYTE*) LocalAlloc(LPTR, size);
+ if(!pBuffer)
+ {
+ ReportErrorCode(L"LocalAlloc", GetLastError());
+ return EXIT_FAILURE;
+ }
+ status = CallNtPowerInformation(ProcessorInformation, NULL, 0, pBuffer, (long)size);
+ if(0 != status)
+ {
+ fwprintf_s(stderr, L"Error in CallNtPowerInformation. Err:%d\n", status);
+ LocalFree(pBuffer);
+ return EXIT_FAILURE;
+ }
+ ppi = (PPROCESSOR_POWER_INFORMATION)pBuffer;
+ cpuFrequencyKhz = ppi->MaxMhz*1000;
+ LocalFree(pBuffer);
+
+ fwprintf_s(stdout, L"%Iu,%Iu,%Iu,%Iu,%Iu,%Iu,%Iu\n", vmemSize, memSize, vmemFree, memFree, sysInfo.dwNumberOfProcessors, cpuFrequencyKhz, cpuTimeMs);
+
+ return EXIT_SUCCESS;
+}
+
+void SystemInfoUsage()
+{
+ fwprintf(stdout, L"\
+ Usage: systeminfo\n\
+ Prints machine information on stdout\n\
+ Comma separated list of the following values.\n\
+ VirtualMemorySize(bytes),PhysicalMemorySize(bytes),\n\
+ FreeVirtualMemory(bytes),FreePhysicalMemory(bytes),\n\
+ NumberOfProcessors,CpuFrequency(Khz),\n\
+ CpuTime(MilliSec,Kernel+User)\n");
+}
\ No newline at end of file
Added: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/task.c
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/task.c?rev=1453486&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/task.c (added)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/winutils/task.c Wed Mar 6 19:15:18 2013
@@ -0,0 +1,461 @@
+/**
+* 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>
+#include <psapi.h>
+
+#define PSAPI_VERSION 1
+#pragma comment(lib, "psapi.lib")
+
+#define ERROR_TASK_NOT_ALIVE 1
+
+// List of different task related command line options supported by
+// winutils.
+typedef enum TaskCommandOptionType
+{
+ TaskInvalid,
+ TaskCreate,
+ TaskIsAlive,
+ TaskKill,
+ TaskProcessList
+} TaskCommandOption;
+
+//----------------------------------------------------------------------------
+// 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 TaskCommandOption *command)
+{
+ *command = TaskInvalid;
+
+ if (wcscmp(argv[0], L"task") != 0 )
+ {
+ return FALSE;
+ }
+
+ if (argc == 3) {
+ if (wcscmp(argv[1], L"isAlive") == 0)
+ {
+ *command = TaskIsAlive;
+ return TRUE;
+ }
+ if (wcscmp(argv[1], L"kill") == 0)
+ {
+ *command = TaskKill;
+ return TRUE;
+ }
+ if (wcscmp(argv[1], L"processList") == 0)
+ {
+ *command = TaskProcessList;
+ return TRUE;
+ }
+ }
+
+ if (argc == 4) {
+ if (wcscmp(argv[1], L"create") == 0)
+ {
+ *command = TaskCreate;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+// Function: createTask
+//
+// Description:
+// Creates a task via a jobobject. Outputs the
+// appropriate information to stdout on success, or stderr on failure.
+//
+// Returns:
+// ERROR_SUCCESS: On success
+// GetLastError: otherwise
+DWORD createTask(_TCHAR* jobObjName, _TCHAR* cmdLine)
+{
+ DWORD err = ERROR_SUCCESS;
+ DWORD exitCode = EXIT_FAILURE;
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ HANDLE jobObject = NULL;
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
+
+ // Create un-inheritable job object handle and set job object to terminate
+ // when last handle is closed. So winutils.exe invocation has the only open
+ // job object handle. Exit of winutils.exe ensures termination of job object.
+ // Either a clean exit of winutils or crash or external termination.
+ jobObject = CreateJobObject(NULL, jobObjName);
+ err = GetLastError();
+ if(jobObject == NULL || err == ERROR_ALREADY_EXISTS)
+ {
+ return err;
+ }
+ jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+ if(SetInformationJobObject(jobObject,
+ JobObjectExtendedLimitInformation,
+ &jeli,
+ sizeof(jeli)) == 0)
+ {
+ err = GetLastError();
+ CloseHandle(jobObject);
+ return err;
+ }
+
+ if(AssignProcessToJobObject(jobObject, GetCurrentProcess()) == 0)
+ {
+ err = GetLastError();
+ CloseHandle(jobObject);
+ return err;
+ }
+
+ // the child JVM uses this env var to send the task OS process identifier
+ // to the TaskTracker. We pass the job object name.
+ if(SetEnvironmentVariable(_T("JVM_PID"), jobObjName) == 0)
+ {
+ err = GetLastError();
+ CloseHandle(jobObject);
+ return err;
+ }
+
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory( &pi, sizeof(pi) );
+ if(CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi) == 0)
+ {
+ err = GetLastError();
+ CloseHandle(jobObject);
+ return err;
+ }
+ CloseHandle(pi.hThread);
+
+ // Wait until child process exits.
+ WaitForSingleObject( pi.hProcess, INFINITE );
+ if(GetExitCodeProcess(pi.hProcess, &exitCode) == 0)
+ {
+ err = GetLastError();
+ }
+ CloseHandle( pi.hProcess );
+
+ // Terminate job object so that all spawned processes are also killed.
+ // This is needed because once this process closes the handle to the job
+ // object and none of the spawned objects have the handle open (via
+ // inheritance on creation) then it will not be possible for any other external
+ // program (say winutils task kill) to terminate this job object via its name.
+ if(TerminateJobObject(jobObject, exitCode) == 0)
+ {
+ err = GetLastError();
+ }
+
+ // comes here only on failure or TerminateJobObject
+ CloseHandle(jobObject);
+
+ if(err != ERROR_SUCCESS)
+ {
+ return err;
+ }
+ return exitCode;
+}
+
+//----------------------------------------------------------------------------
+// Function: isTaskAlive
+//
+// Description:
+// Checks if a task is alive via a jobobject. Outputs the
+// appropriate information to stdout on success, or stderr on failure.
+//
+// Returns:
+// ERROR_SUCCESS: On success
+// GetLastError: otherwise
+DWORD isTaskAlive(const _TCHAR* jobObjName, int* isAlive, int* procsInJob)
+{
+ PJOBOBJECT_BASIC_PROCESS_ID_LIST procList;
+ HANDLE jobObject = NULL;
+ int numProcs = 100;
+
+ *isAlive = FALSE;
+
+ jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, jobObjName);
+
+ if(jobObject == NULL)
+ {
+ DWORD err = GetLastError();
+ if(err == ERROR_FILE_NOT_FOUND)
+ {
+ // job object does not exist. assume its not alive
+ return ERROR_SUCCESS;
+ }
+ return err;
+ }
+
+ procList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST) LocalAlloc(LPTR, sizeof (JOBOBJECT_BASIC_PROCESS_ID_LIST) + numProcs*32);
+ if (!procList)
+ {
+ DWORD err = GetLastError();
+ CloseHandle(jobObject);
+ return err;
+ }
+ if(QueryInformationJobObject(jobObject, JobObjectBasicProcessIdList, procList, sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST)+numProcs*32, NULL) == 0)
+ {
+ DWORD err = GetLastError();
+ if(err != ERROR_MORE_DATA)
+ {
+ CloseHandle(jobObject);
+ LocalFree(procList);
+ return err;
+ }
+ }
+
+ if(procList->NumberOfAssignedProcesses > 0)
+ {
+ *isAlive = TRUE;
+ *procsInJob = procList->NumberOfAssignedProcesses;
+ }
+
+ LocalFree(procList);
+
+ return ERROR_SUCCESS;
+}
+
+//----------------------------------------------------------------------------
+// Function: killTask
+//
+// Description:
+// Kills a task via a jobobject. Outputs the
+// appropriate information to stdout on success, or stderr on failure.
+//
+// Returns:
+// ERROR_SUCCESS: On success
+// GetLastError: otherwise
+DWORD killTask(_TCHAR* jobObjName)
+{
+ HANDLE jobObject = OpenJobObject(JOB_OBJECT_TERMINATE, FALSE, jobObjName);
+ if(jobObject == NULL)
+ {
+ DWORD err = GetLastError();
+ if(err == ERROR_FILE_NOT_FOUND)
+ {
+ // job object does not exist. assume its not alive
+ return ERROR_SUCCESS;
+ }
+ return err;
+ }
+
+ if(TerminateJobObject(jobObject, 1) == 0)
+ {
+ return GetLastError();
+ }
+ CloseHandle(jobObject);
+
+ return ERROR_SUCCESS;
+}
+
+//----------------------------------------------------------------------------
+// Function: printTaskProcessList
+//
+// Description:
+// Prints resource usage of all processes in the task jobobject
+//
+// Returns:
+// ERROR_SUCCESS: On success
+// GetLastError: otherwise
+DWORD printTaskProcessList(const _TCHAR* jobObjName)
+{
+ DWORD i;
+ PJOBOBJECT_BASIC_PROCESS_ID_LIST procList;
+ int numProcs = 100;
+ HANDLE jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, jobObjName);
+ if(jobObject == NULL)
+ {
+ DWORD err = GetLastError();
+ return err;
+ }
+
+ procList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST) LocalAlloc(LPTR, sizeof (JOBOBJECT_BASIC_PROCESS_ID_LIST) + numProcs*32);
+ if (!procList)
+ {
+ DWORD err = GetLastError();
+ CloseHandle(jobObject);
+ return err;
+ }
+ while(QueryInformationJobObject(jobObject, JobObjectBasicProcessIdList, procList, sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST)+numProcs*32, NULL) == 0)
+ {
+ DWORD err = GetLastError();
+ if(err != ERROR_MORE_DATA)
+ {
+ CloseHandle(jobObject);
+ LocalFree(procList);
+ return err;
+ }
+ numProcs = procList->NumberOfAssignedProcesses;
+ LocalFree(procList);
+ procList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST) LocalAlloc(LPTR, sizeof (JOBOBJECT_BASIC_PROCESS_ID_LIST) + numProcs*32);
+ if (!procList)
+ {
+ DWORD err = GetLastError();
+ CloseHandle(jobObject);
+ return err;
+ }
+ }
+
+ for(i=0; i<procList->NumberOfProcessIdsInList; ++i)
+ {
+ HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, (DWORD)procList->ProcessIdList[i] );
+ if( hProcess != NULL )
+ {
+ PROCESS_MEMORY_COUNTERS_EX pmc;
+ if ( GetProcessMemoryInfo( hProcess, (PPROCESS_MEMORY_COUNTERS)&pmc, sizeof(pmc)) )
+ {
+ FILETIME create, exit, kernel, user;
+ if( GetProcessTimes( hProcess, &create, &exit, &kernel, &user) )
+ {
+ ULARGE_INTEGER kernelTime, userTime;
+ ULONGLONG cpuTimeMs;
+ kernelTime.HighPart = kernel.dwHighDateTime;
+ kernelTime.LowPart = kernel.dwLowDateTime;
+ userTime.HighPart = user.dwHighDateTime;
+ userTime.LowPart = user.dwLowDateTime;
+ cpuTimeMs = (kernelTime.QuadPart+userTime.QuadPart)/10000;
+ _ftprintf_s(stdout, TEXT("%u,%Iu,%Iu,%Iu\n"), procList->ProcessIdList[i], pmc.PrivateUsage, pmc.WorkingSetSize, cpuTimeMs);
+ }
+ }
+ CloseHandle( hProcess );
+ }
+ }
+
+ LocalFree(procList);
+ CloseHandle(jobObject);
+
+ return ERROR_SUCCESS;
+}
+
+//----------------------------------------------------------------------------
+// Function: Task
+//
+// Description:
+// Manages a task via a jobobject (create/isAlive/kill). Outputs the
+// appropriate information to stdout on success, or stderr on failure.
+//
+// Returns:
+// ERROR_SUCCESS: On success
+// Error code otherwise: otherwise
+int Task(int argc, wchar_t *argv[])
+{
+ DWORD dwErrorCode = ERROR_SUCCESS;
+ TaskCommandOption command = TaskInvalid;
+
+ if (!ParseCommandLine(argc, argv, &command)) {
+ dwErrorCode = ERROR_INVALID_COMMAND_LINE;
+
+ fwprintf(stderr, L"Incorrect command line arguments.\n\n");
+ TaskUsage();
+ goto TaskExit;
+ }
+
+ if (command == TaskCreate)
+ {
+ // Create the task jobobject
+ //
+ dwErrorCode = createTask(argv[2], argv[3]);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ReportErrorCode(L"createTask", dwErrorCode);
+ goto TaskExit;
+ }
+ } else if (command == TaskIsAlive)
+ {
+ // Check if task jobobject
+ //
+ int isAlive;
+ int numProcs;
+ dwErrorCode = isTaskAlive(argv[2], &isAlive, &numProcs);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ReportErrorCode(L"isTaskAlive", dwErrorCode);
+ goto TaskExit;
+ }
+
+ // Output the result
+ if(isAlive == TRUE)
+ {
+ fwprintf(stdout, L"IsAlive,%d\n", numProcs);
+ }
+ else
+ {
+ dwErrorCode = ERROR_TASK_NOT_ALIVE;
+ ReportErrorCode(L"isTaskAlive returned false", dwErrorCode);
+ goto TaskExit;
+ }
+ } else if (command == TaskKill)
+ {
+ // Check if task jobobject
+ //
+ dwErrorCode = killTask(argv[2]);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ReportErrorCode(L"killTask", dwErrorCode);
+ goto TaskExit;
+ }
+ } else if (command == TaskProcessList)
+ {
+ // Check if task jobobject
+ //
+ dwErrorCode = printTaskProcessList(argv[2]);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ReportErrorCode(L"printTaskProcessList", dwErrorCode);
+ goto TaskExit;
+ }
+ } else
+ {
+ // Should not happen
+ //
+ assert(FALSE);
+ }
+
+TaskExit:
+ return dwErrorCode;
+}
+
+void TaskUsage()
+{
+ // Hadoop code checks for this string to determine if
+ // jobobject's are being used.
+ // ProcessTree.isSetsidSupported()
+ fwprintf(stdout, L"\
+ Usage: task create [TASKNAME] [COMMAND_LINE] |\n\
+ task isAlive [TASKNAME] |\n\
+ task kill [TASKNAME]\n\
+ task processList [TASKNAME]\n\
+ Creates a new task jobobject with taskname\n\
+ Checks if task jobobject is alive\n\
+ Kills task jobobject\n\
+ Prints to stdout a list of processes in the task\n\
+ along with their resource usage. One process per line\n\
+ and comma separated info per process\n\
+ ProcessId,VirtualMemoryCommitted(bytes),\n\
+ WorkingSetSize(bytes),CpuTime(Millisec,Kernel+User)\n");
+}