From 57f76bd3cf04c177c61e1a4bea33d0b4719d45f5 Mon Sep 17 00:00:00 2001 From: Jason Edmeades Date: Thu, 5 Apr 2007 22:47:55 +0100 Subject: [PATCH] cmd.exe: Fix dir filename /s and resolve many output differences. --- programs/cmd/directory.c | 388 ++++++++++++++++++++++----------------- 1 file changed, 219 insertions(+), 169 deletions(-) diff --git a/programs/cmd/directory.c b/programs/cmd/directory.c index 79d755a7e32..557cbc9dc3c 100644 --- a/programs/cmd/directory.c +++ b/programs/cmd/directory.c @@ -57,6 +57,12 @@ typedef enum _DISPLAYORDER Date } DISPLAYORDER; +struct directory_stack +{ + struct directory_stack *next; + char *name; +}; + static int file_total, dir_total, recurse, wide, bare, max_width, lower; static int shortname, usernames; static ULONGLONG byte_total; @@ -286,7 +292,7 @@ void WCMD_directory (void) { if (errorlevel==0 && !bare) { if (recurse) { - WCMD_output ("\n\n Total files listed:\n%8d files%25s bytes\n", + WCMD_output ("\n Total files listed:\n%8d files%25s bytes\n", file_total, WCMD_filesize64 (byte_total)); WCMD_output ("%8d directories %18s bytes free\n\n", dir_total, WCMD_filesize64 (free.QuadPart)); @@ -333,10 +339,12 @@ void WCMD_list_directory (char *search_path, int level) { /* * 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. + * directory not the directory file itself. However, only do this on first + * entry and not subsequent recursion */ - if ((strchr(search_path, '*') == NULL) && (strchr(search_path, '%') == NULL)) { + if ((level == 0) && + (strchr(search_path, '*') == NULL) && (strchr(search_path, '%') == NULL)) { status = GetFileAttributes (search_path); if ((status != INVALID_FILE_ATTRIBUTES) && (status & FILE_ATTRIBUTE_DIRECTORY)) { if (search_path[strlen(search_path)-1] == '\\') { @@ -355,196 +363,238 @@ void WCMD_list_directory (char *search_path, int level) { /* Load all files into an in memory structure */ fd = HeapAlloc(GetProcessHeap(),0,sizeof(WIN32_FIND_DATA)); + WINE_TRACE("Looking for matches to '%s'\n", search_path); hff = FindFirstFile (search_path, fd); if (hff == INVALID_HANDLE_VALUE) { - SetLastError (ERROR_FILE_NOT_FOUND); - WCMD_print_error (); - HeapFree(GetProcessHeap(),0,fd); - errorlevel = 1; - return; + entry_count = 0; + } else { + 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 = strlen((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_DATA)); + if (fd == NULL) { + FindClose (hff); + WCMD_output ("Memory Allocation Error"); + errorlevel = 1; + return; + } + } while (FindNextFile(hff, (fd+entry_count)) != 0); + FindClose (hff); } - 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 = strlen((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_DATA)); - if (fd == NULL) { - FindClose (hff); - WCMD_output ("Memory Allocation Error"); - errorlevel = 1; - return; - } - } while (FindNextFile(hff, (fd+entry_count)) != 0); - FindClose (hff); - - /* Handle case where everything is filtered out */ - if (entry_count == 0) { - SetLastError (ERROR_FILE_NOT_FOUND); - WCMD_print_error (); - HeapFree(GetProcessHeap(),0,fd); - errorlevel = 1; - return; - } - - /* Sort the list of files */ - qsort (fd, entry_count, sizeof(WIN32_FIND_DATA), WCMD_dir_sort); /* Output the results */ if (!bare) { - if (level != 0) WCMD_output ("\n\n"); - WCMD_output ("Directory of %s\n\n", real_path); + if (level != 0 && (entry_count > 0)) WCMD_output ("\n"); + if ((entry_count > 0) || (!recurse && level == 0)) WCMD_output ("Directory of %s\n\n", real_path); } - /* 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, (int)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); + /* Handle case where everything is filtered out */ + if (entry_count > 0) { - for (rows=0; rows= entry_count) continue; + /* 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, (int)max_width / widest); + numRows = entry_count / numCols; + if (entry_count % numCols) numRows++; } else { - i = (rows * numCols) + cols; - if (i >= entry_count) continue; + numCols = 1; + numRows = entry_count; } + WINE_TRACE("cols=%d, rows=%d\n", numCols, numRows); - /* /L convers all names to lower case */ - if (lower) { - char *p = (fd+i)->cFileName; - while ( (*p = tolower(*p)) ) ++p; - } + for (rows=0; rowscFileName); - WCMD_getfileowner(string, username, sizeof(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); - GetDateFormat (0, DATE_SHORTDATE, &st, NULL, datestring, - sizeof(datestring)); - GetTimeFormat (0, TIME_NOSECONDS, &st, - NULL, timestring, sizeof(timestring)); - - if (wide) { - - tmp_width = cur_width; - if ((fd+i)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - WCMD_output ("[%s]", (fd+i)->cFileName); - dir_count++; - tmp_width = tmp_width + strlen((fd+i)->cFileName) + 2; + /* Work out the index of the entry being pointed to */ + if (orderByCol) { + i = (cols * numRows) + rows; + if (i >= entry_count) continue; } else { - WCMD_output ("%s", (fd+i)->cFileName); - tmp_width = tmp_width + strlen((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 ("%*.s", (tmp_width - cur_width) ,""); + i = (rows * numCols) + cols; + if (i >= entry_count) continue; } - } else if ((fd+i)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - dir_count++; - - if (!bare) { - WCMD_output ("%10s %8s ", datestring, timestring); - if (shortname) WCMD_output ("%-13s", (fd+i)->cAlternateFileName); - if (usernames) WCMD_output ("%-23s", username); - WCMD_output("%s",(fd+i)->cFileName); - } else { - if (!((strcmp((fd+i)->cFileName, ".") == 0) || - (strcmp((fd+i)->cFileName, "..") == 0))) { - WCMD_output ("%s%s", recurse?real_path:"", (fd+i)->cFileName); - } + /* /L convers all names to lower case */ + if (lower) { + char *p = (fd+i)->cFileName; + while ( (*p = tolower(*p)) ) ++p; } - } - 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 ("%10s %8s %10s ", datestring, timestring, - WCMD_filesize64(file_size.QuadPart)); - if (shortname) WCMD_output ("%-13s", (fd+i)->cAlternateFileName); - if (usernames) WCMD_output ("%-23s", username); - WCMD_output("%s",(fd+i)->cFileName); - } else { - WCMD_output ("%s%s", recurse?real_path:"", (fd+i)->cFileName); - } - } - } - WCMD_output ("\n"); - cur_width = 0; - } - if (!bare) { - if (file_count == 1) { - WCMD_output (" 1 file %25s bytes\n", WCMD_filesize64 (byte_count.QuadPart)); + /* /Q gets file ownership information */ + if (usernames) { + p = strrchr (search_path, '\\'); + lstrcpyn (string, search_path, (p-search_path+2)); + lstrcat (string, (fd+i)->cFileName); + WCMD_getfileowner(string, username, sizeof(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); + GetDateFormat (0, DATE_SHORTDATE, &st, NULL, datestring, + sizeof(datestring)); + GetTimeFormat (0, TIME_NOSECONDS, &st, + NULL, timestring, sizeof(timestring)); + + if (wide) { + + tmp_width = cur_width; + if ((fd+i)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + WCMD_output ("[%s]", (fd+i)->cFileName); + dir_count++; + tmp_width = tmp_width + strlen((fd+i)->cFileName) + 2; + } else { + WCMD_output ("%s", (fd+i)->cFileName); + tmp_width = tmp_width + strlen((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 ("%*.s", (tmp_width - cur_width) ,""); + } + + } else if ((fd+i)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + dir_count++; + + if (!bare) { + WCMD_output ("%10s %8s ", datestring, timestring); + if (shortname) WCMD_output ("%-13s", (fd+i)->cAlternateFileName); + if (usernames) WCMD_output ("%-23s", username); + WCMD_output("%s",(fd+i)->cFileName); + } else { + if (!((strcmp((fd+i)->cFileName, ".") == 0) || + (strcmp((fd+i)->cFileName, "..") == 0))) { + WCMD_output ("%s%s", recurse?real_path:"", (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 ("%10s %8s %10s ", datestring, timestring, + WCMD_filesize64(file_size.QuadPart)); + if (shortname) WCMD_output ("%-13s", (fd+i)->cAlternateFileName); + if (usernames) WCMD_output ("%-23s", username); + WCMD_output("%s",(fd+i)->cFileName); + } else { + WCMD_output ("%s%s", recurse?real_path:"", (fd+i)->cFileName); + } + } } - else { - WCMD_output ("%8d files %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 (addNewLine) WCMD_output ("\n"); + cur_width = 0; + } - if (!bare) { - if (dir_count == 1) WCMD_output ("1 directory "); - else WCMD_output ("%8d directories", dir_count); - } - for (i=0; icFileName[0] != '.') && - ((fd+i)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { -#if 0 - GetFullPathName ((fd+i)->cFileName, sizeof(string), string, NULL); -#endif - p = strrchr (search_path, '\\'); - lstrcpyn (string, search_path, (p-search_path+2)); - lstrcat (string, (fd+i)->cFileName); - lstrcat (string, p); - WCMD_list_directory (string, 1); + if (!bare) { + if (file_count == 1) { + WCMD_output (" 1 file %25s bytes\n", WCMD_filesize64 (byte_count.QuadPart)); + } + else { + WCMD_output ("%8d files %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 ("%8d directory ", 1); + else WCMD_output ("%8d directories", dir_count); } } HeapFree(GetProcessHeap(),0,fd); + + /* When recursing, look in all subdirectories for matches */ + if (recurse) { + struct directory_stack *dirStack = NULL; + struct directory_stack *lastEntry = NULL; + WIN32_FIND_DATA finddata; + + /* Build path to search */ + strcpy(string, search_path); + p = strrchr (string, '\\'); + strcpy(p+1, "*"); + + WINE_TRACE("Recursive, looking for '%s'\n", string); + hff = FindFirstFile (string, &finddata); + if (hff != INVALID_HANDLE_VALUE) { + do { + if ((finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && + (strcmp(finddata.cFileName, "..") != 0) && + (strcmp(finddata.cFileName, ".") != 0)) { + + struct directory_stack *thisDir; + + /* Work out search parameter in sub dir */ + p = strrchr (search_path, '\\'); + lstrcpyn (string, search_path, (p-search_path+2)); + string[(p-search_path+2)] = 0x00; + lstrcat (string, finddata.cFileName); + lstrcat (string, p); + WINE_TRACE("Recursive, Adding to search list '%s'\n", string); + + /* Allocate memory, add to list */ + thisDir = (struct directory_stack *) HeapAlloc(GetProcessHeap(),0,sizeof(struct directory_stack)); + if (dirStack == NULL) dirStack = thisDir; + if (lastEntry != NULL) lastEntry->next = thisDir; + lastEntry = thisDir; + thisDir->next = NULL; + thisDir->name = HeapAlloc(GetProcessHeap(),0,(strlen(string)+1)); + strcpy(thisDir->name, string); + } + } while (FindNextFile(hff, &finddata) != 0); + FindClose (hff); + + while (dirStack != NULL) { + struct directory_stack *thisDir = dirStack; + dirStack = thisDir->next; + + WCMD_list_directory (thisDir->name, 1); + HeapFree(GetProcessHeap(),0,thisDir->name); + HeapFree(GetProcessHeap(),0,thisDir); + } + } + } + + /* 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; }