Example: Listing File Attributes
It is now time to illustrate the file and directory management functions. Program 3-2 shows a limited version of the UNIX ls directory listing command, which can show file modification times and the file size, although this version gives only the low order of the file size.The program scans the directory for files that satisfy the search pattern. For each file located, the program shows the file name and, if the -l option is specified, the file attributes. This program illustrates many, but not all, Windows directory management functions.The bulk of Program 3-2 is concerned with directory traversal. Notice that each directory is traversed twiceonce to process files and again to process subdirectoriesin order to support the -R recursive option.Program 3-2, as listed here, will properly carry out a command with a relative pathname such as:
lsW -R include\*.h
It will not work properly, however, with an absolute pathname such as:
lsW -R C:\Projects\ls\Debug\*.obj
because the program, as listed, depends on setting the directory relative to the current directory. The complete solution (on the Web site) analyzes pathnames and will also carry out the second command.
Program 3-2. lsW: File Listing and Directory Traversal
/* Chapter 3. lsW file list command */
/* lsW [options] [files] */
#include "EvryThng.h"
BOOL TraverseDirectory (LPCTSTR, DWORD, LPBOOL);
DWORD FileType (LPWIN32_FIND_DATA);
BOOL ProcessItem (LPWIN32_FIND_DATA, DWORD, LPBOOL);
int _tmain (int argc, LPTSTR argv [])
{
BOOL Flags [MAX_OPTIONS], ok = TRUE;
TCHAR PathName [MAX_PATH + 1], CurrPath [MAX_PATH + 1];
LPTSTR pSlash, pFileName;
int i, FileIndex;
FileIndex = Options (
argc, argv, _T ("Rl"), &Flags [0], &Flags [1], NULL);
/* "Parse" the search pattern into "parent" and file name. */
GetCurrentDirectory (MAX_PATH, CurrPath); /* Save current path. */
if (argc < FileIndex + 1) /* No path specified. Current dir. */
ok = TraverseDirectory (_T ("*"), MAX_OPTIONS, Flags);
else for (i = FileIndex; i < argc; i++) {
/* Process all paths on the command line. */
ok = TraverseDirectory (pFileName, MAX_OPTIONS, Flags) && ok;
SetCurrentDirectory (CurrPath); /* Restore directory. */
}
return ok ? 0 : 1;
}
static BOOL TraverseDirectory (LPCTSTR PathName, DWORD NumFlags,
LPBOOL Flags)
/* Traverse a directory; perform ProcessItem for every match. */
/* PathName: Relative or absolute pathname to traverse. */
{
HANDLE SearchHandle;
WIN32_FIND_DATA FindData;
BOOL Recursive = Flags [0];
DWORD FType, iPass;
TCHAR CurrPath [MAX_PATH + 1];
GetCurrentDirectory (MAX_PATH, CurrPath);
for (iPass = 1; iPass <= 2; iPass++) {
/* Pass 1: List files. */
/* Pass 2: Traverse directories (if -R specified). */
SearchHandle = FindFirstFile (PathName, &FindData);
do {
FType = FileType (&FindData); /* File or directory? */
if (iPass == 1) /* List name and attributes. */
ProcessItem (&FindData, MAX_OPTIONS, Flags);
if (FType == TYPE_DIR && iPass == 2 && Recursive) {
/* Process a subdirectory. */
_tprintf (_T ("\n%s\\%s:"), CurrPath,
FindData.cFileName);
/* Prepare to traverse a directory. */
SetCurrentDirectory (FindData.cFileName);
TraverseDirectory (_T ("*"), NumFlags, Flags);
/* Recursive call. */
SetCurrentDirectory (_T (".."));
}
} while (FindNextFile (SearchHandle, &FindData));
FindClose (SearchHandle);
}
return TRUE;
}
static BOOL ProcessItem (LPWIN32_FIND_DATA pFileData,
DWORD NumFlags, LPBOOL Flags)
/* List file or directory attributes. */
{
const TCHAR FileTypeChar [] = {' ', 'd'};
DWORD FType = FileType (pFileData);
BOOL Long = Flags [1];
SYSTEMTIME LastWrite;
if (FType != TYPE_FILE && FType != TYPE_DIR) return FALSE;
_tprintf (_T ("\n"));
if (Long) { /* Was "-1" option used on the command line? */
_tprintf (_T ("%c"), FileTypeChar [FType - 1]);
_tprintf (_T ("%10d"), pFileData->nFileSizeLow);
FileTimeToSystemTime (&(pFileData->ftLastWriteTime),
&LastWrite);
_tprintf (_T (" %02d/%02d/%04d %02d:%02d:%02d"),
LastWrite.wMonth, LastWrite.wDay,
LastWrite.wYear, LastWrite.wHour,
LastWrite.wMinute, LastWrite.wSecond);
}
_tprintf (_T (" %s"), pFileData->cFileName);
return TRUE;
}
static DWORD FileType (LPWIN32_FIND_DATA pFileData)
/* Types supported - TYPE_FILE: file; TYPE_DIR: directory;
TYPE_DOT: . or .. directory */
{
BOOL IsDir;
DWORD FType;
FType = TYPE_FILE;
IsDir = (pFileData->dwFileAttributes &
FILE_ATTRIBUTE_DIRECTORY) != 0;
if (IsDir)
if (lstrcmp (pFileData->cFileName, _T (".")) == 0
|| lstrcmp (pFileData->cFileName, _T ("..")) == 0)
FType = TYPE_DOT;
else FType = TYPE_DIR;
return FType;
}