2e99da4853
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1494341 13f79535-47bb-0310-9956-ffa450edef68
337 lines
8.4 KiB
C
337 lines
8.4 KiB
C
/**
|
|
* 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(__in INT accessMask, __in_ecount(10) 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(
|
|
__in int argc,
|
|
__in_ecount(argc) wchar_t *argv[],
|
|
__deref_out PWSTR *path,
|
|
__out 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(__in int argc, __in_ecount(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;
|
|
|
|
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 = FindFileOwnerAndPermission(longPathName,
|
|
optionsMask & CmdLineOptionFollowSymlink,
|
|
&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);
|
|
}
|