123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- /**
- * 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;
- 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);
- }
|