123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900 |
- /*
- * CMD - Wine-compatible command line interface - Directory functions.
- *
- * Copyright (C) 1999 D A Pickles
- * Copyright (C) 2007 J Edmeades
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
- #define WIN32_LEAN_AND_MEAN
- #include "wcmd.h"
- #include "wine/debug.h"
- WINE_DEFAULT_DEBUG_CHANNEL(cmd);
- typedef enum _DISPLAYTIME
- {
- Creation = 0,
- Access,
- Written
- } DISPLAYTIME;
- typedef enum _DISPLAYORDER
- {
- Name = 0,
- Extension,
- Size,
- Date
- } DISPLAYORDER;
- static int file_total, dir_total, max_width;
- static ULONGLONG byte_total;
- static DISPLAYTIME dirTime;
- static DISPLAYORDER dirOrder;
- static BOOL orderReverse, orderGroupDirs, orderGroupDirsReverse, orderByCol;
- static BOOL paged_mode, recurse, wide, bare, lower, shortname, usernames, separator;
- static ULONG showattrs, attrsbits;
- /*****************************************************************************
- * WCMD_strrev
- *
- * Reverse a WCHARacter string in-place (strrev() is not available under unixen :-( ).
- */
- static WCHAR * WCMD_strrev (WCHAR *buff) {
- int r, i;
- WCHAR b;
- r = lstrlenW (buff);
- for (i=0; i<r/2; i++) {
- b = buff[i];
- buff[i] = buff[r-i-1];
- buff[r-i-1] = b;
- }
- return (buff);
- }
- /*****************************************************************************
- * WCMD_filesize64
- *
- * Convert a 64-bit number into a WCHARacter string, with commas every three digits.
- * Result is returned in a static string overwritten with each call.
- * FIXME: There must be a better algorithm!
- */
- static WCHAR * WCMD_filesize64 (ULONGLONG n) {
- ULONGLONG q;
- unsigned int r, i;
- WCHAR *p;
- static WCHAR buff[32];
- p = buff;
- i = -3;
- do {
- if (separator && ((++i)%3 == 1)) *p++ = ',';
- q = n / 10;
- r = n - (q * 10);
- *p++ = r + '0';
- *p = '\0';
- n = q;
- } while (n != 0);
- WCMD_strrev (buff);
- return buff;
- }
- /*****************************************************************************
- * WCMD_dir_sort
- *
- * Sort based on the /O options supplied on the command line
- */
- static int __cdecl WCMD_dir_sort (const void *a, const void *b)
- {
- const WIN32_FIND_DATAW *filea = (const WIN32_FIND_DATAW *)a;
- const WIN32_FIND_DATAW *fileb = (const WIN32_FIND_DATAW *)b;
- int result = 0;
- /* If /OG or /O-G supplied, dirs go at the top or bottom, ignoring the
- requested sort order for the directory components */
- if (orderGroupDirs &&
- ((filea->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
- (fileb->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)))
- {
- BOOL aDir = filea->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
- if (aDir) result = -1;
- else result = 1;
- if (orderGroupDirsReverse) result = -result;
- return result;
- /* Order by Name: */
- } else if (dirOrder == Name) {
- result = lstrcmpiW(filea->cFileName, fileb->cFileName);
- /* Order by Size: */
- } else if (dirOrder == Size) {
- ULONG64 sizea = (((ULONG64)filea->nFileSizeHigh) << 32) + filea->nFileSizeLow;
- ULONG64 sizeb = (((ULONG64)fileb->nFileSizeHigh) << 32) + fileb->nFileSizeLow;
- if( sizea < sizeb ) result = -1;
- else if( sizea == sizeb ) result = 0;
- else result = 1;
- /* Order by Date: (Takes into account which date (/T option) */
- } else if (dirOrder == Date) {
- const FILETIME *ft;
- ULONG64 timea, timeb;
- if (dirTime == Written) {
- ft = &filea->ftLastWriteTime;
- timea = (((ULONG64)ft->dwHighDateTime) << 32) + ft->dwLowDateTime;
- ft = &fileb->ftLastWriteTime;
- timeb = (((ULONG64)ft->dwHighDateTime) << 32) + ft->dwLowDateTime;
- } else if (dirTime == Access) {
- ft = &filea->ftLastAccessTime;
- timea = (((ULONG64)ft->dwHighDateTime) << 32) + ft->dwLowDateTime;
- ft = &fileb->ftLastAccessTime;
- timeb = (((ULONG64)ft->dwHighDateTime) << 32) + ft->dwLowDateTime;
- } else {
- ft = &filea->ftCreationTime;
- timea = (((ULONG64)ft->dwHighDateTime) << 32) + ft->dwLowDateTime;
- ft = &fileb->ftCreationTime;
- timeb = (((ULONG64)ft->dwHighDateTime) << 32) + ft->dwLowDateTime;
- }
- if( timea < timeb ) result = -1;
- else if( timea == timeb ) result = 0;
- else result = 1;
- /* Order by Extension: (Takes into account which date (/T option) */
- } else if (dirOrder == Extension) {
- WCHAR drive[10];
- WCHAR dir[MAX_PATH];
- WCHAR fname[MAX_PATH];
- WCHAR extA[MAX_PATH];
- WCHAR extB[MAX_PATH];
- /* Split into components */
- _wsplitpath(filea->cFileName, drive, dir, fname, extA);
- _wsplitpath(fileb->cFileName, drive, dir, fname, extB);
- result = lstrcmpiW(extA, extB);
- }
- if (orderReverse) result = -result;
- return result;
- }
- /*****************************************************************************
- * WCMD_getfileowner
- *
- * Reverse a WCHARacter string in-place (strrev() is not available under unixen :-( ).
- */
- static void WCMD_getfileowner(WCHAR *filename, WCHAR *owner, int ownerlen) {
- ULONG sizeNeeded = 0;
- DWORD rc;
- WCHAR name[MAXSTRING];
- WCHAR domain[MAXSTRING];
- /* In case of error, return empty string */
- *owner = 0x00;
- /* Find out how much space we need for the owner security descriptor */
- GetFileSecurityW(filename, OWNER_SECURITY_INFORMATION, 0, 0, &sizeNeeded);
- rc = GetLastError();
- if(rc == ERROR_INSUFFICIENT_BUFFER && sizeNeeded > 0) {
- LPBYTE secBuffer;
- PSID pSID = NULL;
- BOOL defaulted = FALSE;
- ULONG nameLen = MAXSTRING;
- ULONG domainLen = MAXSTRING;
- SID_NAME_USE nameuse;
- secBuffer = heap_xalloc(sizeNeeded * sizeof(BYTE));
- /* Get the owners security descriptor */
- if(!GetFileSecurityW(filename, OWNER_SECURITY_INFORMATION, secBuffer,
- sizeNeeded, &sizeNeeded)) {
- heap_free(secBuffer);
- return;
- }
- /* Get the SID from the SD */
- if(!GetSecurityDescriptorOwner(secBuffer, &pSID, &defaulted)) {
- heap_free(secBuffer);
- return;
- }
- /* Convert to a username */
- if (LookupAccountSidW(NULL, pSID, name, &nameLen, domain, &domainLen, &nameuse)) {
- swprintf(owner, ownerlen, L"%s%c%s", domain, '\\', name);
- }
- heap_free(secBuffer);
- }
- return;
- }
- /*****************************************************************************
- * WCMD_list_directory
- *
- * List a single file directory. This function (and those below it) can be called
- * recursively when the /S switch is used.
- *
- * FIXME: Assumes 24-line display for the /P qualifier.
- */
- static DIRECTORY_STACK *WCMD_list_directory (DIRECTORY_STACK *inputparms, int level) {
- WCHAR string[1024], datestring[32], timestring[32];
- WCHAR real_path[MAX_PATH];
- WIN32_FIND_DATAW *fd;
- FILETIME ft;
- SYSTEMTIME st;
- HANDLE hff;
- int dir_count, file_count, entry_count, i, widest, cur_width, tmp_width;
- int numCols, numRows;
- int rows, cols;
- ULARGE_INTEGER byte_count, file_size;
- DIRECTORY_STACK *parms;
- int concurrentDirs = 0;
- BOOL done_header = FALSE;
- dir_count = 0;
- file_count = 0;
- entry_count = 0;
- byte_count.QuadPart = 0;
- widest = 0;
- cur_width = 0;
- /* Loop merging all the files from consecutive parms which relate to the
- same directory. Note issuing a directory header with no contents
- mirrors what windows does */
- parms = inputparms;
- fd = heap_xalloc(sizeof(WIN32_FIND_DATAW));
- while (parms && lstrcmpW(inputparms->dirName, parms->dirName) == 0) {
- concurrentDirs++;
- /* Work out the full path + filename */
- lstrcpyW(real_path, parms->dirName);
- lstrcatW(real_path, parms->fileName);
- /* Load all files into an in memory structure */
- WINE_TRACE("Looking for matches to '%s'\n", wine_dbgstr_w(real_path));
- hff = FindFirstFileW(real_path, &fd[entry_count]);
- if (hff != INVALID_HANDLE_VALUE) {
- do {
- /* Skip any which are filtered out by attribute */
- if ((fd[entry_count].dwFileAttributes & attrsbits) != showattrs) continue;
- entry_count++;
- /* Keep running track of longest filename for wide output */
- if (wide || orderByCol) {
- int tmpLen = lstrlenW(fd[entry_count-1].cFileName) + 3;
- if (fd[entry_count-1].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) tmpLen = tmpLen + 2;
- if (tmpLen > widest) widest = tmpLen;
- }
- fd = HeapReAlloc(GetProcessHeap(),0,fd,(entry_count+1)*sizeof(WIN32_FIND_DATAW));
- if (fd == NULL) {
- FindClose (hff);
- WINE_ERR("Out of memory\n");
- errorlevel = 1;
- return parms->next;
- }
- } while (FindNextFileW(hff, &fd[entry_count]) != 0);
- FindClose (hff);
- }
- /* Work out the actual current directory name without a trailing \ */
- lstrcpyW(real_path, parms->dirName);
- real_path[lstrlenW(parms->dirName)-1] = 0x00;
- /* Output the results */
- if (!bare) {
- if (level != 0 && (entry_count > 0)) WCMD_output_asis(L"\r\n");
- if (!recurse || ((entry_count > 0) && done_header==FALSE)) {
- WCMD_output (L"Directory of %1\n\n", real_path);
- done_header = TRUE;
- }
- }
- /* Move to next parm */
- parms = parms->next;
- }
- /* Handle case where everything is filtered out */
- if (entry_count > 0) {
- /* Sort the list of files */
- qsort (fd, entry_count, sizeof(WIN32_FIND_DATAW), WCMD_dir_sort);
- /* Work out the number of columns */
- WINE_TRACE("%d entries, maxwidth=%d, widest=%d\n", entry_count, max_width, widest);
- if (wide || orderByCol) {
- numCols = max(1, max_width / widest);
- numRows = entry_count / numCols;
- if (entry_count % numCols) numRows++;
- } else {
- numCols = 1;
- numRows = entry_count;
- }
- WINE_TRACE("cols=%d, rows=%d\n", numCols, numRows);
- for (rows=0; rows<numRows; rows++) {
- BOOL addNewLine = TRUE;
- for (cols=0; cols<numCols; cols++) {
- WCHAR username[24];
- /* Work out the index of the entry being pointed to */
- if (orderByCol) {
- i = (cols * numRows) + rows;
- if (i >= entry_count) continue;
- } else {
- i = (rows * numCols) + cols;
- if (i >= entry_count) continue;
- }
- /* /L convers all names to lower case */
- if (lower) {
- WCHAR *p = fd[i].cFileName;
- while ( (*p = tolower(*p)) ) ++p;
- }
- /* /Q gets file ownership information */
- if (usernames) {
- lstrcpyW (string, inputparms->dirName);
- lstrcatW (string, fd[i].cFileName);
- WCMD_getfileowner(string, username, ARRAY_SIZE(username));
- }
- if (dirTime == Written) {
- FileTimeToLocalFileTime (&fd[i].ftLastWriteTime, &ft);
- } else if (dirTime == Access) {
- FileTimeToLocalFileTime (&fd[i].ftLastAccessTime, &ft);
- } else {
- FileTimeToLocalFileTime (&fd[i].ftCreationTime, &ft);
- }
- FileTimeToSystemTime (&ft, &st);
- GetDateFormatW(0, DATE_SHORTDATE, &st, NULL, datestring, ARRAY_SIZE(datestring));
- GetTimeFormatW(0, TIME_NOSECONDS, &st, NULL, timestring, ARRAY_SIZE(timestring));
- if (wide) {
- tmp_width = cur_width;
- if (fd[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- WCMD_output (L"[%1]", fd[i].cFileName);
- dir_count++;
- tmp_width = tmp_width + lstrlenW(fd[i].cFileName) + 2;
- } else {
- WCMD_output (L"%1", fd[i].cFileName);
- tmp_width = tmp_width + lstrlenW(fd[i].cFileName) ;
- file_count++;
- file_size.u.LowPart = fd[i].nFileSizeLow;
- file_size.u.HighPart = fd[i].nFileSizeHigh;
- byte_count.QuadPart += file_size.QuadPart;
- }
- cur_width = cur_width + widest;
- if ((cur_width + widest) > max_width) {
- cur_width = 0;
- } else {
- WCMD_output(L"%1!*s!", cur_width - tmp_width, L"");
- }
- } else if (fd[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- dir_count++;
- if (!bare) {
- WCMD_output (L"%1!10s! %2!8s! <DIR> ", datestring, timestring);
- if (shortname) WCMD_output(L"%1!-13s!", fd[i].cAlternateFileName);
- if (usernames) WCMD_output(L"%1!-23s!", username);
- WCMD_output(L"%1",fd[i].cFileName);
- } else {
- if (!((lstrcmpW(fd[i].cFileName, L".") == 0) ||
- (lstrcmpW(fd[i].cFileName, L"..") == 0))) {
- WCMD_output(L"%1%2", recurse ? inputparms->dirName : L"", fd[i].cFileName);
- } else {
- addNewLine = FALSE;
- }
- }
- }
- else {
- file_count++;
- file_size.u.LowPart = fd[i].nFileSizeLow;
- file_size.u.HighPart = fd[i].nFileSizeHigh;
- byte_count.QuadPart += file_size.QuadPart;
- if (!bare) {
- WCMD_output (L"%1!10s! %2!8s! %3!10s! ", datestring, timestring,
- WCMD_filesize64(file_size.QuadPart));
- if (shortname) WCMD_output(L"%1!-13s!", fd[i].cAlternateFileName);
- if (usernames) WCMD_output(L"%1!-23s!", username);
- WCMD_output(L"%1",fd[i].cFileName);
- } else {
- WCMD_output(L"%1%2", recurse ? inputparms->dirName : L"", fd[i].cFileName);
- }
- }
- }
- if (addNewLine) WCMD_output_asis(L"\r\n");
- cur_width = 0;
- }
- if (!bare) {
- if (file_count == 1) {
- WCMD_output (L" 1 file %1!25s! bytes\n", WCMD_filesize64 (byte_count.QuadPart));
- }
- else {
- WCMD_output (L"%1!8d! files %2!24s! bytes\n", file_count, WCMD_filesize64 (byte_count.QuadPart));
- }
- }
- byte_total = byte_total + byte_count.QuadPart;
- file_total = file_total + file_count;
- dir_total = dir_total + dir_count;
- if (!bare && !recurse) {
- if (dir_count == 1) {
- WCMD_output (L"%1!8d! directory ", 1);
- } else {
- WCMD_output (L"%1!8d! directories", dir_count);
- }
- }
- }
- heap_free(fd);
- /* When recursing, look in all subdirectories for matches */
- if (recurse) {
- DIRECTORY_STACK *dirStack = NULL;
- DIRECTORY_STACK *lastEntry = NULL;
- WIN32_FIND_DATAW finddata;
- /* Build path to search */
- lstrcpyW(string, inputparms->dirName);
- lstrcatW(string, L"*");
- WINE_TRACE("Recursive, looking for '%s'\n", wine_dbgstr_w(string));
- hff = FindFirstFileW(string, &finddata);
- if (hff != INVALID_HANDLE_VALUE) {
- do {
- if ((finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
- (lstrcmpW(finddata.cFileName, L"..") != 0) &&
- (lstrcmpW(finddata.cFileName, L".") != 0)) {
- DIRECTORY_STACK *thisDir;
- int dirsToCopy = concurrentDirs;
- /* Loop creating list of subdirs for all concurrent entries */
- parms = inputparms;
- while (dirsToCopy > 0) {
- dirsToCopy--;
- /* Work out search parameter in sub dir */
- lstrcpyW (string, inputparms->dirName);
- lstrcatW (string, finddata.cFileName);
- lstrcatW(string, L"\\");
- WINE_TRACE("Recursive, Adding to search list '%s'\n", wine_dbgstr_w(string));
- /* Allocate memory, add to list */
- thisDir = heap_xalloc(sizeof(DIRECTORY_STACK));
- if (dirStack == NULL) dirStack = thisDir;
- if (lastEntry != NULL) lastEntry->next = thisDir;
- lastEntry = thisDir;
- thisDir->next = NULL;
- thisDir->dirName = heap_strdupW(string);
- thisDir->fileName = heap_strdupW(parms->fileName);
- parms = parms->next;
- }
- }
- } while (FindNextFileW(hff, &finddata) != 0);
- FindClose (hff);
- while (dirStack != NULL) {
- DIRECTORY_STACK *thisDir = dirStack;
- dirStack = WCMD_list_directory (thisDir, 1);
- while (thisDir != dirStack) {
- DIRECTORY_STACK *tempDir = thisDir->next;
- heap_free(thisDir->dirName);
- heap_free(thisDir->fileName);
- heap_free(thisDir);
- thisDir = tempDir;
- }
- }
- }
- }
- /* Handle case where everything is filtered out */
- if ((file_total + dir_total == 0) && (level == 0)) {
- SetLastError (ERROR_FILE_NOT_FOUND);
- WCMD_print_error ();
- errorlevel = 1;
- }
- return parms;
- }
- /*****************************************************************************
- * WCMD_dir_trailer
- *
- * Print out the trailer for the supplied drive letter
- */
- static void WCMD_dir_trailer(WCHAR drive) {
- ULARGE_INTEGER avail, total, freebytes;
- DWORD status;
- WCHAR driveName[] = L"c:\\";
- driveName[0] = drive;
- status = GetDiskFreeSpaceExW(driveName, &avail, &total, &freebytes);
- WINE_TRACE("Writing trailer for '%s' gave %d(%d)\n", wine_dbgstr_w(driveName),
- status, GetLastError());
- if (errorlevel==0 && !bare) {
- if (recurse) {
- WCMD_output (L"\n Total files listed:\n%1!8d! files%2!25s! bytes\n", file_total, WCMD_filesize64 (byte_total));
- WCMD_output (L"%1!8d! directories %2!18s! bytes free\n\n", dir_total, WCMD_filesize64 (freebytes.QuadPart));
- } else {
- WCMD_output (L" %1!18s! bytes free\n\n", WCMD_filesize64 (freebytes.QuadPart));
- }
- }
- }
- /*****************************************************************************
- * WCMD_directory
- *
- * List a file directory.
- *
- */
- void WCMD_directory (WCHAR *args)
- {
- WCHAR path[MAX_PATH], cwd[MAX_PATH];
- DWORD status;
- CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
- WCHAR *p;
- WCHAR string[MAXSTRING];
- int argno = 0;
- WCHAR *argN = args;
- WCHAR lastDrive;
- BOOL trailerReqd = FALSE;
- DIRECTORY_STACK *fullParms = NULL;
- DIRECTORY_STACK *prevEntry = NULL;
- DIRECTORY_STACK *thisEntry = NULL;
- WCHAR drive[10];
- WCHAR dir[MAX_PATH];
- WCHAR fname[MAX_PATH];
- WCHAR ext[MAX_PATH];
- errorlevel = 0;
- /* Prefill quals with (uppercased) DIRCMD env var */
- if (GetEnvironmentVariableW(L"DIRCMD", string, ARRAY_SIZE(string))) {
- p = string;
- while ( (*p = toupper(*p)) ) ++p;
- lstrcatW(string,quals);
- lstrcpyW(quals, string);
- }
- byte_total = 0;
- file_total = dir_total = 0;
- /* Initialize all flags to their defaults as if no DIRCMD or quals */
- paged_mode = FALSE;
- recurse = FALSE;
- wide = FALSE;
- bare = FALSE;
- lower = FALSE;
- shortname = FALSE;
- usernames = FALSE;
- orderByCol = FALSE;
- separator = TRUE;
- dirTime = Written;
- dirOrder = Name;
- orderReverse = FALSE;
- orderGroupDirs = FALSE;
- orderGroupDirsReverse = FALSE;
- showattrs = 0;
- attrsbits = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
- /* Handle args - Loop through so right most is the effective one */
- /* Note: /- appears to be a negate rather than an off, eg. dir
- /-W is wide, or dir /w /-w /-w is also wide */
- p = quals;
- while (*p && (*p=='/' || *p==' ')) {
- BOOL negate = FALSE;
- if (*p++==' ') continue; /* Skip / and blanks introduced through DIRCMD */
- if (*p=='-') {
- negate = TRUE;
- p++;
- }
- WINE_TRACE("Processing arg '%c' (in %s)\n", *p, wine_dbgstr_w(quals));
- switch (*p) {
- case 'P': if (negate) paged_mode = !paged_mode;
- else paged_mode = TRUE;
- break;
- case 'S': if (negate) recurse = !recurse;
- else recurse = TRUE;
- break;
- case 'W': if (negate) wide = !wide;
- else wide = TRUE;
- break;
- case 'B': if (negate) bare = !bare;
- else bare = TRUE;
- break;
- case 'L': if (negate) lower = !lower;
- else lower = TRUE;
- break;
- case 'X': if (negate) shortname = !shortname;
- else shortname = TRUE;
- break;
- case 'Q': if (negate) usernames = !usernames;
- else usernames = TRUE;
- break;
- case 'D': if (negate) orderByCol = !orderByCol;
- else orderByCol = TRUE;
- break;
- case 'C': if (negate) separator = !separator;
- else separator = TRUE;
- break;
- case 'T': p = p + 1;
- if (*p==':') p++; /* Skip optional : */
- if (*p == 'A') dirTime = Access;
- else if (*p == 'C') dirTime = Creation;
- else if (*p == 'W') dirTime = Written;
- /* Support /T and /T: with no parms, default to written */
- else if (*p == 0x00 || *p == '/') {
- dirTime = Written;
- p = p - 1; /* So when step on, move to '/' */
- } else {
- SetLastError(ERROR_INVALID_PARAMETER);
- WCMD_print_error();
- errorlevel = 1;
- return;
- }
- break;
- case 'O': p = p + 1;
- if (*p==':') p++; /* Skip optional : */
- while (*p && *p != '/') {
- WINE_TRACE("Processing subparm '%c' (in %s)\n", *p, wine_dbgstr_w(quals));
- switch (*p) {
- case 'N': dirOrder = Name; break;
- case 'E': dirOrder = Extension; break;
- case 'S': dirOrder = Size; break;
- case 'D': dirOrder = Date; break;
- case '-': if (*(p+1)=='G') orderGroupDirsReverse=TRUE;
- else orderReverse = TRUE;
- break;
- case 'G': orderGroupDirs = TRUE; break;
- default:
- SetLastError(ERROR_INVALID_PARAMETER);
- WCMD_print_error();
- errorlevel = 1;
- return;
- }
- p++;
- }
- p = p - 1; /* So when step on, move to '/' */
- break;
- case 'A': p = p + 1;
- showattrs = 0;
- attrsbits = 0;
- if (*p==':') p++; /* Skip optional : */
- while (*p && *p != '/') {
- BOOL anegate = FALSE;
- ULONG mask;
- /* Note /A: - options are 'offs' not toggles */
- if (*p=='-') {
- anegate = TRUE;
- p++;
- }
- WINE_TRACE("Processing subparm '%c' (in %s)\n", *p, wine_dbgstr_w(quals));
- switch (*p) {
- case 'D': mask = FILE_ATTRIBUTE_DIRECTORY; break;
- case 'H': mask = FILE_ATTRIBUTE_HIDDEN; break;
- case 'S': mask = FILE_ATTRIBUTE_SYSTEM; break;
- case 'R': mask = FILE_ATTRIBUTE_READONLY; break;
- case 'A': mask = FILE_ATTRIBUTE_ARCHIVE; break;
- default:
- SetLastError(ERROR_INVALID_PARAMETER);
- WCMD_print_error();
- errorlevel = 1;
- return;
- }
- /* Keep running list of bits we care about */
- attrsbits |= mask;
- /* Mask shows what MUST be in the bits we care about */
- if (anegate) showattrs = showattrs & ~mask;
- else showattrs |= mask;
- p++;
- }
- p = p - 1; /* So when step on, move to '/' */
- WINE_TRACE("Result: showattrs %x, bits %x\n", showattrs, attrsbits);
- break;
- default:
- SetLastError(ERROR_INVALID_PARAMETER);
- WCMD_print_error();
- errorlevel = 1;
- return;
- }
- p = p + 1;
- }
- /* Handle conflicting args and initialization */
- if (bare || shortname) wide = FALSE;
- if (bare) shortname = FALSE;
- if (wide) usernames = FALSE;
- if (orderByCol) wide = TRUE;
- if (wide) {
- if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo))
- max_width = consoleInfo.dwSize.X;
- else
- max_width = 80;
- }
- if (paged_mode) {
- WCMD_enter_paged_mode(NULL);
- }
- argno = 0;
- argN = args;
- GetCurrentDirectoryW(MAX_PATH, cwd);
- lstrcatW(cwd, L"\\");
- /* Loop through all args, calculating full effective directory */
- fullParms = NULL;
- prevEntry = NULL;
- while (argN) {
- WCHAR fullname[MAXSTRING];
- WCHAR *thisArg = WCMD_parameter(args, argno++, &argN, FALSE, FALSE);
- if (argN && argN[0] != '/') {
- WINE_TRACE("Found parm '%s'\n", wine_dbgstr_w(thisArg));
- if (thisArg[1] == ':' && thisArg[2] == '\\') {
- lstrcpyW(fullname, thisArg);
- } else if (thisArg[1] == ':' && thisArg[2] != '\\') {
- WCHAR envvar[4];
- wsprintfW(envvar, L"=%c:", thisArg[0]);
- if (!GetEnvironmentVariableW(envvar, fullname, MAX_PATH)) {
- wsprintfW(fullname, L"%c:", thisArg[0]);
- }
- lstrcatW(fullname, L"\\");
- lstrcatW(fullname, &thisArg[2]);
- } else if (thisArg[0] == '\\') {
- memcpy(fullname, cwd, 2 * sizeof(WCHAR));
- lstrcpyW(fullname+2, thisArg);
- } else {
- lstrcpyW(fullname, cwd);
- lstrcatW(fullname, thisArg);
- }
- WINE_TRACE("Using location '%s'\n", wine_dbgstr_w(fullname));
- status = GetFullPathNameW(fullname, ARRAY_SIZE(path), path, NULL);
- /*
- * If the path supplied does not include a wildcard, and the endpoint of the
- * path references a directory, we need to list the *contents* of that
- * directory not the directory file itself.
- */
- if ((wcschr(path, '*') == NULL) && (wcschr(path, '%') == NULL)) {
- status = GetFileAttributesW(path);
- if ((status != INVALID_FILE_ATTRIBUTES) && (status & FILE_ATTRIBUTE_DIRECTORY)) {
- if (!ends_with_backslash(path)) lstrcatW(path, L"\\");
- lstrcatW(path, L"*");
- }
- } else {
- /* Special case wildcard search with no extension (ie parameters ending in '.') as
- GetFullPathName strips off the additional '.' */
- if (fullname[lstrlenW(fullname)-1] == '.') lstrcatW(path, L".");
- }
- WINE_TRACE("Using path '%s'\n", wine_dbgstr_w(path));
- thisEntry = heap_xalloc(sizeof(DIRECTORY_STACK));
- if (fullParms == NULL) fullParms = thisEntry;
- if (prevEntry != NULL) prevEntry->next = thisEntry;
- prevEntry = thisEntry;
- thisEntry->next = NULL;
- /* Split into components */
- _wsplitpath(path, drive, dir, fname, ext);
- WINE_TRACE("Path Parts: drive: '%s' dir: '%s' name: '%s' ext:'%s'\n",
- wine_dbgstr_w(drive), wine_dbgstr_w(dir),
- wine_dbgstr_w(fname), wine_dbgstr_w(ext));
- thisEntry->dirName = heap_xalloc(sizeof(WCHAR) * (lstrlenW(drive)+lstrlenW(dir)+1));
- lstrcpyW(thisEntry->dirName, drive);
- lstrcatW(thisEntry->dirName, dir);
- thisEntry->fileName = heap_xalloc(sizeof(WCHAR) * (lstrlenW(fname)+lstrlenW(ext)+1));
- lstrcpyW(thisEntry->fileName, fname);
- lstrcatW(thisEntry->fileName, ext);
- }
- }
- /* If just 'dir' entered, a '*' parameter is assumed */
- if (fullParms == NULL) {
- WINE_TRACE("Inserting default '*'\n");
- fullParms = heap_xalloc(sizeof(DIRECTORY_STACK));
- fullParms->next = NULL;
- fullParms->dirName = heap_strdupW(cwd);
- fullParms->fileName = heap_strdupW(L"*");
- }
- lastDrive = '?';
- prevEntry = NULL;
- thisEntry = fullParms;
- trailerReqd = FALSE;
- while (thisEntry != NULL) {
- /* Output disk free (trailer) and volume information (header) if the drive
- letter changes */
- if (lastDrive != toupper(thisEntry->dirName[0])) {
- /* Trailer Information */
- if (lastDrive != '?') {
- trailerReqd = FALSE;
- WCMD_dir_trailer(prevEntry->dirName[0]);
- }
- lastDrive = toupper(thisEntry->dirName[0]);
- if (!bare) {
- WCHAR drive[3];
- WINE_TRACE("Writing volume for '%c:'\n", thisEntry->dirName[0]);
- memcpy(drive, thisEntry->dirName, 2 * sizeof(WCHAR));
- drive[2] = 0x00;
- status = WCMD_volume (0, drive);
- trailerReqd = TRUE;
- if (!status) {
- errorlevel = 1;
- goto exit;
- }
- }
- } else {
- if (!bare) WCMD_output_asis (L"\n\n");
- }
- /* Clear any errors from previous invocations, and process it */
- errorlevel = 0;
- prevEntry = thisEntry;
- thisEntry = WCMD_list_directory (thisEntry, 0);
- }
- /* Trailer Information */
- if (trailerReqd) {
- WCMD_dir_trailer(prevEntry->dirName[0]);
- }
- exit:
- if (paged_mode) WCMD_leave_paged_mode();
- /* Free storage allocated for parms */
- while (fullParms != NULL) {
- prevEntry = fullParms;
- fullParms = prevEntry->next;
- heap_free(prevEntry->dirName);
- heap_free(prevEntry->fileName);
- heap_free(prevEntry);
- }
- }
|