cmd: Reorder some functions to avoid forward declarations.
Francois Gouget
fgouget at free.fr
Tue Dec 30 17:56:21 CST 2008
---
This patch is independent from the next.
The next step is to make a bunch of these functions static...
programs/cmd/directory.c | 1009 +++++++++++++++++++++++-----------------------
1 files changed, 500 insertions(+), 509 deletions(-)
diff --git a/programs/cmd/directory.c b/programs/cmd/directory.c
index c70fca5..cd17d31 100644
--- a/programs/cmd/directory.c
+++ b/programs/cmd/directory.c
@@ -33,11 +33,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(cmd);
-int WCMD_dir_sort (const void *a, const void *b);
-WCHAR * WCMD_filesize64 (ULONGLONG free);
-WCHAR * WCMD_strrev (WCHAR *buff);
-static void WCMD_getfileowner(WCHAR *filename, WCHAR *owner, int ownerlen);
-static void WCMD_dir_trailer(WCHAR drive);
extern int echo_mode;
extern WCHAR quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
@@ -58,7 +53,6 @@ typedef enum _DISPLAYORDER
Date
} DISPLAYORDER;
-static DIRECTORY_STACK *WCMD_list_directory (DIRECTORY_STACK *parms, int level);
static int file_total, dir_total, recurse, wide, bare, max_width, lower;
static int shortname, usernames;
static ULONGLONG byte_total;
@@ -76,368 +70,183 @@ static const WCHAR emptyW[] = {'\0'};
static const WCHAR spaceW[] = {' ','\0'};
/*****************************************************************************
- * WCMD_directory
- *
- * List a file directory.
+ * WCMD_strrev
*
+ * Reverse a WCHARacter string in-place (strrev() is not available under unixen :-( ).
*/
+WCHAR * WCMD_strrev (WCHAR *buff) {
-void WCMD_directory (WCHAR *cmd) {
-
- WCHAR path[MAX_PATH], cwd[MAX_PATH];
- int status, paged_mode;
- CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
- WCHAR *p;
- WCHAR string[MAXSTRING];
- int argno = 0;
- int argsProcessed = 0;
- WCHAR *argN = cmd;
- 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];
- static const WCHAR dircmdW[] = {'D','I','R','C','M','D','\0'};
-
- errorlevel = 0;
+ int r, i;
+ WCHAR b;
- /* Prefill quals with (uppercased) DIRCMD env var */
- if (GetEnvironmentVariable (dircmdW, string, sizeof(string)/sizeof(WCHAR))) {
- p = string;
- while ( (*p = toupper(*p)) ) ++p;
- strcatW(string,quals);
- strcpyW(quals, string);
+ r = strlenW (buff);
+ for (i=0; i<r/2; i++) {
+ b = buff[i];
+ buff[i] = buff[r-i-1];
+ buff[r-i-1] = b;
}
+ return (buff);
+}
- 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 = 0;
-
- /* 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 */
+/*****************************************************************************
+ * 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!
+ */
+WCHAR * WCMD_filesize64 (ULONGLONG n) {
- if (*p=='-') {
- negate = TRUE;
- p++;
- }
+ ULONGLONG q;
+ unsigned int r, i;
+ WCHAR *p;
+ static WCHAR buff[32];
- 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 : */
+ 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;
+}
- if (*p == 'A') dirTime = Access;
- else if (*p == 'C') dirTime = Creation;
- else if (*p == 'W') dirTime = Written;
+/*****************************************************************************
+ * WCMD_dir_sort
+ *
+ * Sort based on the /O options supplied on the command line
+ */
+int WCMD_dir_sort (const void *a, const void *b)
+{
+ WIN32_FIND_DATA *filea = (WIN32_FIND_DATA *)a;
+ WIN32_FIND_DATA *fileb = (WIN32_FIND_DATA *)b;
+ int result = 0;
- /* 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;
+ /* 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;
- /* Note /A: - options are 'offs' not toggles */
- if (*p=='-') {
- anegate = TRUE;
- p++;
- }
+ /* Order by Name: */
+ } else if (dirOrder == Name) {
+ result = lstrcmpiW(filea->cFileName, fileb->cFileName);
- 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;
- }
+ /* 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;
- /* Keep running list of bits we care about */
- attrsbits |= mask;
+ /* Order by Date: (Takes into account which date (/T option) */
+ } else if (dirOrder == Date) {
- /* Mask shows what MUST be in the bits we care about */
- if (anegate) showattrs = showattrs & ~mask;
- else showattrs |= mask;
+ FILETIME *ft;
+ ULONG64 timea, timeb;
- 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;
+ 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;
}
- 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;
- argsProcessed = 0;
- argN = cmd;
- GetCurrentDirectory (MAX_PATH, cwd);
- strcatW(cwd, slashW);
-
- /* Loop through all args, calculating full effective directory */
- fullParms = NULL;
- prevEntry = NULL;
- while (argN) {
- WCHAR fullname[MAXSTRING];
- WCHAR *thisArg = WCMD_parameter (cmd, argno++, &argN);
- if (argN && argN[0] != '/') {
-
- WINE_TRACE("Found parm '%s'\n", wine_dbgstr_w(thisArg));
- if (thisArg[1] == ':' && thisArg[2] == '\\') {
- strcpyW(fullname, thisArg);
- } else if (thisArg[1] == ':' && thisArg[2] != '\\') {
- WCHAR envvar[4];
- static const WCHAR envFmt[] = {'=','%','c',':','\0'};
- wsprintf(envvar, envFmt, thisArg[0]);
- if (!GetEnvironmentVariable(envvar, fullname, MAX_PATH)) {
- static const WCHAR noEnvFmt[] = {'%','c',':','\0'};
- wsprintf(fullname, noEnvFmt, thisArg[0]);
- }
- strcatW(fullname, slashW);
- strcatW(fullname, &thisArg[2]);
- } else if (thisArg[0] == '\\') {
- memcpy(fullname, cwd, 2 * sizeof(WCHAR));
- strcpyW(fullname+2, thisArg);
- } else {
- strcpyW(fullname, cwd);
- strcatW(fullname, thisArg);
- }
- WINE_TRACE("Using location '%s'\n", wine_dbgstr_w(fullname));
-
- status = GetFullPathName (fullname, sizeof(path)/sizeof(WCHAR), 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 ((strchrW(path, '*') == NULL) && (strchrW(path, '%') == NULL)) {
- status = GetFileAttributes (path);
- if ((status != INVALID_FILE_ATTRIBUTES) && (status & FILE_ATTRIBUTE_DIRECTORY)) {
- if (path[strlenW(path)-1] == '\\') {
- strcatW (path, starW);
- }
- else {
- const WCHAR slashStarW[] = {'\\','*','\0'};
- strcatW (path, slashStarW);
- }
- }
- } else {
- /* Special case wildcard search with no extension (ie parameters ending in '.') as
- GetFullPathName strips off the additional '.' */
- if (fullname[strlenW(fullname)-1] == '.') strcatW(path, dotW);
- }
+ if( timea < timeb ) result = -1;
+ else if( timea == timeb ) result = 0;
+ else result = 1;
- WINE_TRACE("Using path '%s'\n", wine_dbgstr_w(path));
- thisEntry = HeapAlloc(GetProcessHeap(),0,sizeof(DIRECTORY_STACK));
- if (fullParms == NULL) fullParms = thisEntry;
- if (prevEntry != NULL) prevEntry->next = thisEntry;
- prevEntry = thisEntry;
- thisEntry->next = NULL;
+ /* 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 */
- WCMD_splitpath(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 = HeapAlloc(GetProcessHeap(),0,
- sizeof(WCHAR) * (strlenW(drive)+strlenW(dir)+1));
- strcpyW(thisEntry->dirName, drive);
- strcatW(thisEntry->dirName, dir);
-
- thisEntry->fileName = HeapAlloc(GetProcessHeap(),0,
- sizeof(WCHAR) * (strlenW(fname)+strlenW(ext)+1));
- strcpyW(thisEntry->fileName, fname);
- strcatW(thisEntry->fileName, ext);
-
- }
- }
-
- /* If just 'dir' entered, a '*' parameter is assumed */
- if (fullParms == NULL) {
- WINE_TRACE("Inserting default '*'\n");
- fullParms = HeapAlloc(GetProcessHeap(),0, sizeof(DIRECTORY_STACK));
- fullParms->next = NULL;
- fullParms->dirName = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (strlenW(cwd)+1));
- strcpyW(fullParms->dirName, cwd);
- fullParms->fileName = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * 2);
- strcpyW(fullParms->fileName, starW);
+ WCMD_splitpath(filea->cFileName, drive, dir, fname, extA);
+ WCMD_splitpath(fileb->cFileName, drive, dir, fname, extB);
+ result = lstrcmpiW(extA, extB);
}
- lastDrive = '?';
- prevEntry = NULL;
- thisEntry = fullParms;
- trailerReqd = FALSE;
+ if (orderReverse) result = -result;
+ return result;
+}
- while (thisEntry != NULL) {
+/*****************************************************************************
+ * WCMD_getfileowner
+ *
+ * Reverse a WCHARacter string in-place (strrev() is not available under unixen :-( ).
+ */
+void WCMD_getfileowner(WCHAR *filename, WCHAR *owner, int ownerlen) {
- /* Output disk free (trailer) and volume information (header) if the drive
- letter changes */
- if (lastDrive != toupper(thisEntry->dirName[0])) {
+ ULONG sizeNeeded = 0;
+ DWORD rc;
+ WCHAR name[MAXSTRING];
+ WCHAR domain[MAXSTRING];
- /* Trailer Information */
- if (lastDrive != '?') {
- trailerReqd = FALSE;
- WCMD_dir_trailer(prevEntry->dirName[0]);
- }
+ /* In case of error, return empty string */
+ *owner = 0x00;
- lastDrive = toupper(thisEntry->dirName[0]);
+ /* Find out how much space we need for the owner security descriptor */
+ GetFileSecurity(filename, OWNER_SECURITY_INFORMATION, 0, 0, &sizeNeeded);
+ rc = GetLastError();
- if (!bare) {
- WCHAR drive[3];
+ if(rc == ERROR_INSUFFICIENT_BUFFER && sizeNeeded > 0) {
- 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 {
- static const WCHAR newLine2[] = {'\n','\n','\0'};
- if (!bare) WCMD_output (newLine2);
- }
+ LPBYTE secBuffer;
+ PSID pSID = NULL;
+ BOOL defaulted = FALSE;
+ ULONG nameLen = MAXSTRING;
+ ULONG domainLen = MAXSTRING;
+ SID_NAME_USE nameuse;
- /* Clear any errors from previous invocations, and process it */
- errorlevel = 0;
- prevEntry = thisEntry;
- thisEntry = WCMD_list_directory (thisEntry, 0);
- }
+ secBuffer = HeapAlloc(GetProcessHeap(),0,sizeNeeded * sizeof(BYTE));
+ if(!secBuffer) return;
- /* Trailer Information */
- if (trailerReqd) {
- WCMD_dir_trailer(prevEntry->dirName[0]);
- }
+ /* Get the owners security descriptor */
+ if(!GetFileSecurity(filename, OWNER_SECURITY_INFORMATION, secBuffer,
+ sizeNeeded, &sizeNeeded)) {
+ HeapFree(GetProcessHeap(),0,secBuffer);
+ return;
+ }
-exit:
- if (paged_mode) WCMD_leave_paged_mode();
+ /* Get the SID from the SD */
+ if(!GetSecurityDescriptorOwner(secBuffer, &pSID, &defaulted)) {
+ HeapFree(GetProcessHeap(),0,secBuffer);
+ return;
+ }
- /* Free storage allocated for parms */
- while (fullParms != NULL) {
- prevEntry = fullParms;
- fullParms = prevEntry->next;
- HeapFree(GetProcessHeap(),0,prevEntry->dirName);
- HeapFree(GetProcessHeap(),0,prevEntry->fileName);
- HeapFree(GetProcessHeap(),0,prevEntry);
- }
+ /* Convert to a username */
+ if (LookupAccountSid(NULL, pSID, name, &nameLen, domain, &domainLen, &nameuse)) {
+ static const WCHAR fmt[] = {'%','s','%','c','%','s','\0'};
+ snprintfW(owner, ownerlen, fmt, domain, '\\', name);
+ }
+ HeapFree(GetProcessHeap(),0,secBuffer);
+ }
+ return;
}
/*****************************************************************************
@@ -782,217 +591,399 @@ static DIRECTORY_STACK *WCMD_list_directory (DIRECTORY_STACK *inputparms, int le
}
/*****************************************************************************
- * WCMD_filesize64
+ * WCMD_dir_trailer
*
- * 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!
+ * 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[4] = {'c',':','\\','\0'};
-WCHAR * WCMD_filesize64 (ULONGLONG n) {
-
- ULONGLONG q;
- unsigned int r, i;
- WCHAR *p;
- static WCHAR buff[32];
+ driveName[0] = drive;
+ status = GetDiskFreeSpaceEx (driveName, &avail, &total, &freebytes);
+ WINE_TRACE("Writing trailer for '%s' gave %d(%d)\n", wine_dbgstr_w(driveName),
+ status, GetLastError());
- 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;
+ if (errorlevel==0 && !bare) {
+ if (recurse) {
+ static const WCHAR fmt1[] = {'\n',' ',' ',' ',' ',' ','T','o','t','a','l',' ','f','i','l','e','s',
+ ' ','l','i','s','t','e','d',':','\n','%','8','d',' ','f','i','l','e',
+ 's','%','2','5','s',' ','b','y','t','e','s','\n','\0'};
+ static const WCHAR fmt2[] = {'%','8','d',' ','d','i','r','e','c','t','o','r','i','e','s',' ','%',
+ '1','8','s',' ','b','y','t','e','s',' ','f','r','e','e','\n','\n',
+ '\0'};
+ WCMD_output (fmt1, file_total, WCMD_filesize64 (byte_total));
+ WCMD_output (fmt2, dir_total, WCMD_filesize64 (freebytes.QuadPart));
+ } else {
+ static const WCHAR fmt[] = {' ','%','1','8','s',' ','b','y','t','e','s',' ','f','r','e','e',
+ '\n','\n','\0'};
+ WCMD_output (fmt, WCMD_filesize64 (freebytes.QuadPart));
+ }
+ }
}
/*****************************************************************************
- * WCMD_strrev
+ * WCMD_directory
+ *
+ * List a file directory.
*
- * Reverse a WCHARacter string in-place (strrev() is not available under unixen :-( ).
*/
-WCHAR * WCMD_strrev (WCHAR *buff) {
+void WCMD_directory (WCHAR *cmd) {
- int r, i;
- WCHAR b;
+ WCHAR path[MAX_PATH], cwd[MAX_PATH];
+ int status, paged_mode;
+ CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
+ WCHAR *p;
+ WCHAR string[MAXSTRING];
+ int argno = 0;
+ int argsProcessed = 0;
+ WCHAR *argN = cmd;
+ 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];
+ static const WCHAR dircmdW[] = {'D','I','R','C','M','D','\0'};
- r = strlenW (buff);
- for (i=0; i<r/2; i++) {
- b = buff[i];
- buff[i] = buff[r-i-1];
- buff[r-i-1] = b;
+ errorlevel = 0;
+
+ /* Prefill quals with (uppercased) DIRCMD env var */
+ if (GetEnvironmentVariable (dircmdW, string, sizeof(string)/sizeof(WCHAR))) {
+ p = string;
+ while ( (*p = toupper(*p)) ) ++p;
+ strcatW(string,quals);
+ strcpyW(quals, string);
}
- return (buff);
-}
+ byte_total = 0;
+ file_total = dir_total = 0;
-/*****************************************************************************
- * WCMD_dir_sort
- *
- * Sort based on the /O options supplied on the command line
- */
-int WCMD_dir_sort (const void *a, const void *b)
-{
- WIN32_FIND_DATA *filea = (WIN32_FIND_DATA *)a;
- WIN32_FIND_DATA *fileb = (WIN32_FIND_DATA *)b;
- int result = 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 = 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;
+ /* 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 */
- /* Order by Name: */
- } else if (dirOrder == Name) {
- result = lstrcmpiW(filea->cFileName, fileb->cFileName);
+ if (*p=='-') {
+ negate = TRUE;
+ p++;
+ }
- /* 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;
+ 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 : */
- /* Order by Date: (Takes into account which date (/T option) */
- } else if (dirOrder == Date) {
+ if (*p == 'A') dirTime = Access;
+ else if (*p == 'C') dirTime = Creation;
+ else if (*p == 'W') dirTime = Written;
- FILETIME *ft;
- ULONG64 timea, timeb;
+ /* 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;
- 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;
+ /* Note /A: - options are 'offs' not toggles */
+ if (*p=='-') {
+ anegate = TRUE;
+ p++;
+ }
- /* 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];
+ 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;
+ }
- /* Split into components */
- WCMD_splitpath(filea->cFileName, drive, dir, fname, extA);
- WCMD_splitpath(fileb->cFileName, drive, dir, fname, extB);
- result = lstrcmpiW(extA, extB);
- }
+ /* Keep running list of bits we care about */
+ attrsbits |= mask;
- if (orderReverse) result = -result;
- return result;
-}
+ /* Mask shows what MUST be in the bits we care about */
+ if (anegate) showattrs = showattrs & ~mask;
+ else showattrs |= mask;
-/*****************************************************************************
- * WCMD_getfileowner
- *
- * Reverse a WCHARacter string in-place (strrev() is not available under unixen :-( ).
- */
-void WCMD_getfileowner(WCHAR *filename, WCHAR *owner, int ownerlen) {
+ 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;
+ }
- ULONG sizeNeeded = 0;
- DWORD rc;
- WCHAR name[MAXSTRING];
- WCHAR domain[MAXSTRING];
+ /* Handle conflicting args and initialization */
+ if (bare || shortname) wide = FALSE;
+ if (bare) shortname = FALSE;
+ if (wide) usernames = FALSE;
+ if (orderByCol) wide = TRUE;
- /* In case of error, return empty string */
- *owner = 0x00;
+ 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);
+ }
- /* Find out how much space we need for the owner security descriptor */
- GetFileSecurity(filename, OWNER_SECURITY_INFORMATION, 0, 0, &sizeNeeded);
- rc = GetLastError();
+ argno = 0;
+ argsProcessed = 0;
+ argN = cmd;
+ GetCurrentDirectory (MAX_PATH, cwd);
+ strcatW(cwd, slashW);
- if(rc == ERROR_INSUFFICIENT_BUFFER && sizeNeeded > 0) {
+ /* Loop through all args, calculating full effective directory */
+ fullParms = NULL;
+ prevEntry = NULL;
+ while (argN) {
+ WCHAR fullname[MAXSTRING];
+ WCHAR *thisArg = WCMD_parameter (cmd, argno++, &argN);
+ if (argN && argN[0] != '/') {
- LPBYTE secBuffer;
- PSID pSID = NULL;
- BOOL defaulted = FALSE;
- ULONG nameLen = MAXSTRING;
- ULONG domainLen = MAXSTRING;
- SID_NAME_USE nameuse;
+ WINE_TRACE("Found parm '%s'\n", wine_dbgstr_w(thisArg));
+ if (thisArg[1] == ':' && thisArg[2] == '\\') {
+ strcpyW(fullname, thisArg);
+ } else if (thisArg[1] == ':' && thisArg[2] != '\\') {
+ WCHAR envvar[4];
+ static const WCHAR envFmt[] = {'=','%','c',':','\0'};
+ wsprintf(envvar, envFmt, thisArg[0]);
+ if (!GetEnvironmentVariable(envvar, fullname, MAX_PATH)) {
+ static const WCHAR noEnvFmt[] = {'%','c',':','\0'};
+ wsprintf(fullname, noEnvFmt, thisArg[0]);
+ }
+ strcatW(fullname, slashW);
+ strcatW(fullname, &thisArg[2]);
+ } else if (thisArg[0] == '\\') {
+ memcpy(fullname, cwd, 2 * sizeof(WCHAR));
+ strcpyW(fullname+2, thisArg);
+ } else {
+ strcpyW(fullname, cwd);
+ strcatW(fullname, thisArg);
+ }
+ WINE_TRACE("Using location '%s'\n", wine_dbgstr_w(fullname));
- secBuffer = HeapAlloc(GetProcessHeap(),0,sizeNeeded * sizeof(BYTE));
- if(!secBuffer) return;
+ status = GetFullPathName (fullname, sizeof(path)/sizeof(WCHAR), path, NULL);
- /* Get the owners security descriptor */
- if(!GetFileSecurity(filename, OWNER_SECURITY_INFORMATION, secBuffer,
- sizeNeeded, &sizeNeeded)) {
- HeapFree(GetProcessHeap(),0,secBuffer);
- return;
+ /*
+ * 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 ((strchrW(path, '*') == NULL) && (strchrW(path, '%') == NULL)) {
+ status = GetFileAttributes (path);
+ if ((status != INVALID_FILE_ATTRIBUTES) && (status & FILE_ATTRIBUTE_DIRECTORY)) {
+ if (path[strlenW(path)-1] == '\\') {
+ strcatW (path, starW);
+ }
+ else {
+ const WCHAR slashStarW[] = {'\\','*','\0'};
+ strcatW (path, slashStarW);
+ }
}
+ } else {
+ /* Special case wildcard search with no extension (ie parameters ending in '.') as
+ GetFullPathName strips off the additional '.' */
+ if (fullname[strlenW(fullname)-1] == '.') strcatW(path, dotW);
+ }
- /* Get the SID from the SD */
- if(!GetSecurityDescriptorOwner(secBuffer, &pSID, &defaulted)) {
- HeapFree(GetProcessHeap(),0,secBuffer);
- return;
- }
+ WINE_TRACE("Using path '%s'\n", wine_dbgstr_w(path));
+ thisEntry = HeapAlloc(GetProcessHeap(),0,sizeof(DIRECTORY_STACK));
+ if (fullParms == NULL) fullParms = thisEntry;
+ if (prevEntry != NULL) prevEntry->next = thisEntry;
+ prevEntry = thisEntry;
+ thisEntry->next = NULL;
+
+ /* Split into components */
+ WCMD_splitpath(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 = HeapAlloc(GetProcessHeap(),0,
+ sizeof(WCHAR) * (strlenW(drive)+strlenW(dir)+1));
+ strcpyW(thisEntry->dirName, drive);
+ strcatW(thisEntry->dirName, dir);
+
+ thisEntry->fileName = HeapAlloc(GetProcessHeap(),0,
+ sizeof(WCHAR) * (strlenW(fname)+strlenW(ext)+1));
+ strcpyW(thisEntry->fileName, fname);
+ strcatW(thisEntry->fileName, ext);
- /* Convert to a username */
- if (LookupAccountSid(NULL, pSID, name, &nameLen, domain, &domainLen, &nameuse)) {
- static const WCHAR fmt[] = {'%','s','%','c','%','s','\0'};
- snprintfW(owner, ownerlen, fmt, domain, '\\', name);
- }
- HeapFree(GetProcessHeap(),0,secBuffer);
}
- return;
-}
+ }
-/*****************************************************************************
- * 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[4] = {'c',':','\\','\0'};
+ /* If just 'dir' entered, a '*' parameter is assumed */
+ if (fullParms == NULL) {
+ WINE_TRACE("Inserting default '*'\n");
+ fullParms = HeapAlloc(GetProcessHeap(),0, sizeof(DIRECTORY_STACK));
+ fullParms->next = NULL;
+ fullParms->dirName = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (strlenW(cwd)+1));
+ strcpyW(fullParms->dirName, cwd);
+ fullParms->fileName = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * 2);
+ strcpyW(fullParms->fileName, starW);
+ }
- driveName[0] = drive;
- status = GetDiskFreeSpaceEx (driveName, &avail, &total, &freebytes);
- WINE_TRACE("Writing trailer for '%s' gave %d(%d)\n", wine_dbgstr_w(driveName),
- status, GetLastError());
+ lastDrive = '?';
+ prevEntry = NULL;
+ thisEntry = fullParms;
+ trailerReqd = FALSE;
- if (errorlevel==0 && !bare) {
- if (recurse) {
- static const WCHAR fmt1[] = {'\n',' ',' ',' ',' ',' ','T','o','t','a','l',' ','f','i','l','e','s',
- ' ','l','i','s','t','e','d',':','\n','%','8','d',' ','f','i','l','e',
- 's','%','2','5','s',' ','b','y','t','e','s','\n','\0'};
- static const WCHAR fmt2[] = {'%','8','d',' ','d','i','r','e','c','t','o','r','i','e','s',' ','%',
- '1','8','s',' ','b','y','t','e','s',' ','f','r','e','e','\n','\n',
- '\0'};
- WCMD_output (fmt1, file_total, WCMD_filesize64 (byte_total));
- WCMD_output (fmt2, dir_total, WCMD_filesize64 (freebytes.QuadPart));
- } else {
- static const WCHAR fmt[] = {' ','%','1','8','s',' ','b','y','t','e','s',' ','f','r','e','e',
- '\n','\n','\0'};
- WCMD_output (fmt, WCMD_filesize64 (freebytes.QuadPart));
+ 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 {
+ static const WCHAR newLine2[] = {'\n','\n','\0'};
+ if (!bare) WCMD_output (newLine2);
}
+
+ /* 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;
+ HeapFree(GetProcessHeap(),0,prevEntry->dirName);
+ HeapFree(GetProcessHeap(),0,prevEntry->fileName);
+ HeapFree(GetProcessHeap(),0,prevEntry);
+ }
}
--
1.5.6.5
More information about the wine-patches
mailing list