scandir.c
来自「<Win2k系统编程>源码.次数为国人自编,内容丰富,还是不错的.」· C语言 代码 · 共 1,259 行 · 第 1/3 页
C
1,259 行
/****************************** Module Header *******************************
* Module Name: SCANDIR.C
*
* Scan a directory tree and build a sorted list of filenames within that
* tree.
*
* Functions:
*
* dir_buildlist()
* dir_delete()
* dir_isfile()
* dir_firstitem()
* dir_nextitem()
* dir_findnextfile()
* dir_getrelname()
* dir_getfullname()
* dir_getroot_list()
* dir_getroot_item()
* dir_freerelname()
* dir_freefullname()
* dir_freeroot_list()
* dir_freerootitem()
* dir_getopenname()
* dir_freeopenname()
* dir_openfile()
* dir_closefile()
* dir_filesize()
* dir_startcopy()
* dir_endcopy()
* dir_copy()
* dir_finalelem()
* dir_cleardirect()
* dir_adddirect()
* dir_addfile()
* dir_scan()
* dir_isvaliddir()
* dir_isvalidfile()
* dir_fileinit()
* dir_dirinit()
* dir_getpathsize()
* dir_findnextfile()
*
* Comments:
*
* The call dir_buildlist takes a pathname and returns a handle. Subsequent
* calls to dir_firstitem and dir_nextitem return handles to
* items within the list, from which you can get the name of the
* file (relative to the original pathname, or complete), and filesize.
*
* The list can be either built entirely during the build call, or
* built one directory at a time as required by dir_nextitem calls. This
* option affects only relative performance, and is taken as a
* recommendation only (ie some of the time we will ignore the flag).
*
* The list is ordered alphabetically (case-insensitive using lstrcmpi).
* within any one directory, we list filenames before going on
* to subdirectory contents.
*
* All memory is allocated from a gmem_* heap hHeap declared
* and initialised elsewhere.
*
* The caller gets handles to two things: a DIRLIST, representing the
* entire list of filenames, and a DIRITEM: one item within the list.
*
* From the DIRITEM he can get the filename (including or excluding the
* tree root passed to dir_build*) - and also he can get to the next
* DIRITEM.
*
* We permit lazy building of the tree (usually so the caller can keep
* the user-interface up-to-date as we go along). In this case,
* we need to store information about how far we have scanned and
* what is next to do. We need to scan an entire directory at a time and then
* sort it so we can return files in the correct order.
*
* We scan an entire directory and store it in a DIRECT struct. This contains
* a list of DIRITEMs for the files in the current directory, and a list of
* DIRECTs for the subdirectories (possible un-scanned).
*
* dir_nextitem will use the list functions to get the next DIRITEM on the list.
* When the end of the list is reached, it will use the backpointer back to the
* DIRECT struct to find the next directory to scan.
*
****************************************************************************/
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <direct.h>
#include "gutils.h"
#include "list.h"
#include "scandir.h"
#include "windiff.h"
#include "wdiffrc.h"
/*
* Hold name and information about a given file (one ITEM in a DIRectory)
* caller's DIRITEM handle is a pointer to one of these structures
*/
struct diritem {
LPSTR name; /* ptr to filename (final element only) */
long size; /* filesize */
struct direct FAR * direct; /* containing directory */
LPSTR localname; /* name of temp copy of file */
BOOL bLocalIsTemp; /* true if localname is tempfile.
*/
};
/* DIRECT: Hold state about directory and current position in list of filenames.
*/
typedef struct direct {
LPSTR relname; /* name of dir relative to DIRLIST root */
DIRLIST head; /* back ptr (to get fullname) */
struct direct FAR * parent; /* parent directory (NULL if above tree root)*/
BOOL bScanned; /* TRUE if scanned */
LIST diritems; /* list of DIRITEMs for files in cur. dir */
LIST directs; /* list of DIRECTs for child dirs */
int pos; /* where are we begin, files, dirs */
struct direct FAR * curdir; /* subdir being scanned (ptr to list element)*/
} FAR * DIRECT;
/* Values for direct.pos */
#define DL_FILES 1 /* reading files from the diritems */
#define DL_DIRS 2 /* in the dirs: List_Next on curdir */
/*
* The DIRLIST handle returned from a build function is in fact
* a pointer to one of these
*/
struct dirlist {
char rootname[256]; /* name of root of tree */
BOOL bFile; /* TRUE if root of tree is file, not dir */
DIRECT dot; /* dir for '.' - for tree root dir */
};
extern BOOL bAbort; /* from windiff.c (read only here). */
/* ------ memory allocation ---------------------------------------------*/
/* All memory is allocated from a heap created by the application */
extern HANDLE hHeap;
/*-- forward declaration of internal functions ---------------------------*/
LPSTR dir_finalelem(LPSTR path);
void dir_cleardirect(DIRECT dir);
void dir_adddirect(DIRECT dir, LPSTR path);
void dir_addfile(DIRECT dir, LPSTR path, DWORD size);
void dir_scan(DIRECT dir, BOOL bRecurse);
BOOL dir_isvaliddir(LPSTR path);
BOOL dir_isvalidfile(LPSTR path);
void dir_fileinit(DIRITEM pfile, DIRECT dir, LPSTR path, long size);
void dir_dirinit(DIRECT dir, DIRLIST head, DIRECT parent, LPSTR name);
long dir_getpathsize(LPSTR path);
DIRITEM dir_findnextfile(DIRLIST dl, DIRECT curdir);
/***************************************************************************
* Function: dir_buildlist
*
* Purpose:
*
* Build a list of filenames
*
* Optionally build the list on demand, in which case we scan the
* entire directory but don't recurse into subdirs until needed
*
*/
DIRLIST
dir_buildlist(LPSTR path, BOOL bOnDemand)
{
DIRLIST dl;
BOOL bFile;
/* first check if the path is valid */
if (dir_isvaliddir(path)) {
bFile = FALSE;
} else if (dir_isvalidfile(path)) {
bFile = TRUE;
} else {
/* not valid */
return(NULL);
}
/* alloc and init the DIRLIST head */
dl = (DIRLIST) gmem_get(hHeap, sizeof(struct dirlist));
memset(dl, 0, sizeof(struct dirlist));
/* convert the pathname to an absolute path */
_fullpath(dl->rootname, path, sizeof(dl->rootname));
dl->bFile = bFile;
/* make a '.' directory for the current directory -
* all files and subdirs will be listed from here
*/
dl->dot = (DIRECT) gmem_get(hHeap, sizeof(struct direct));
dir_dirinit(dl->dot, dl, NULL, ".");
/* were we given a file or a directory ? */
if (bFile) {
/* its a file. create a single file entry
* and set the state accordingly
*/
dl->dot->bScanned = TRUE;
dir_addfile(dl->dot, dir_finalelem(path),
dir_getpathsize(path));
return(dl);
}
/* scan the root directory and return. if we are asked
* to scan the whole thing, this will cause a recursive
* scan all the way down the tree
*/
dir_scan(dl->dot, (!bOnDemand) );
return(dl);
} /* dir_buildlist */
/***************************************************************************
* Function: dir_delete
*
* Purpose:
*
* Free up the DIRLIST and all associated memory
*/
void
dir_delete(DIRLIST dl)
{
if (dl == NULL) {
return;
}
dir_cleardirect(dl->dot);
gmem_free(hHeap, (LPSTR) dl->dot, sizeof(struct direct));
gmem_free(hHeap, (LPSTR) dl, sizeof(struct dirlist));
}
/***************************************************************************
* Function: dir_isfile
*
* Purpose:
*
* Was the original build request a file or a directory ?
*/
BOOL
dir_isfile(DIRLIST dl)
{
if (dl == NULL) {
return(FALSE);
}
return(dl->bFile);
}
/***************************************************************************
* Function: dir_firstitem
*
* Purpose:
*
* Return the first file in the list, or NULL if no files found.
* Returns a DIRITEM. This can be used to get filename, size and chcksum.
* If there are no files in the root, we recurse down until we find a file.
*/
DIRITEM
dir_firstitem(DIRLIST dl)
{
if (dl == NULL) {
return(NULL);
}
/*
* reset the state to indicate that no files have been read yet
*/
dl->dot->pos = DL_FILES;
dl->dot->curdir = NULL;
/* now get the next filename */
return(dir_findnextfile(dl, dl->dot));
} /* dir_firstitem */
/***************************************************************************
* Function:dir_nextitem
*
* Purpose:
*
* Get the next filename after the one given.
*
* The List_Next function can give us the next element on the list of files.
* If this is null, we need to go back to the DIRECT and find the
* next list of files to traverse (in the next subdir).
*
* After scanning all the subdirs, return to the parent to scan further
* dirs that are peers of this, if there are any. If we have reached the end of
* the tree (no more dirs in dl->dot to scan), return NULL.
*
* Don't recurse to lower levels unless fDeep is TRUE
*/
DIRITEM
dir_nextitem(DIRLIST dl, DIRITEM cur, BOOL fDeep)
{
DIRITEM next;
if ((dl == NULL) || (cur == NULL)) {
return(NULL);
}
if (bAbort) return NULL; /* user requested abort */
if ( (next = List_Next(cur)) != NULL) {
/* there was another file on this list */
return(next);
}
if (!fDeep) return NULL;
/* get the head of the next list of filenames from the directory */
cur->direct->pos = DL_DIRS;
cur->direct->curdir = NULL;
return(dir_findnextfile(dl, cur->direct));
} /* dir_nextitem */
/***************************************************************************
* Function: dir_findnextfile
*
* Purpose:
*
* Gets the next file in the directory
*/
DIRITEM
dir_findnextfile(DIRLIST dl, DIRECT curdir)
{
DIRITEM curfile;
if ((dl == NULL) || (curdir == NULL)) {
return(NULL);
}
/* scan the subdir if necessary */
if (!curdir->bScanned) {
dir_scan(curdir, FALSE);
}
/* have we already read the files in this directory ? */
if (curdir->pos == DL_FILES) {
/* no - return head of file list */
curfile = (DIRITEM) List_First(curdir->diritems);
if (curfile != NULL) {
return(curfile);
}
/* no more files - try the subdirs */
curdir->pos = DL_DIRS;
}
/* try the next subdir on the list, if any */
/* is this the first or the next */
if (curdir->curdir == NULL) {
curdir->curdir = (DIRECT) List_First(curdir->directs);
} else {
curdir->curdir = (DIRECT) List_Next(curdir->curdir);
}
/* did we find a subdir ? */
if (curdir->curdir == NULL) {
/* no more dirs - go back to parent if there is one */
if (curdir->parent == NULL) {
/* no parent - we have exhausted the tree */
return(NULL);
}
/* reset parent state to indicate this is the current
* directory - so that next gets the next after this.
* this ensures that multiple callers of dir_nextitem()
* to the same tree work.
*/
curdir->parent->pos = DL_DIRS;
curdir->parent->curdir = curdir;
return(dir_findnextfile(dl, curdir->parent));
}
/* there is a next directory - set it to the
* beginning and get the first file from it
*/
curdir->curdir->pos = DL_FILES;
curdir->curdir->curdir = NULL;
return(dir_findnextfile(dl, curdir->curdir));
} /* dir_findnextfile */
/*-- pathnames ----
*
* This module supports two types of pathnames, called relative and full.
* Relative names are relative to the root passed in the initial call
* to dir_build*, and full names include the tree root.
*
* Note that this is a different distinction to relative vs absolute
* pathnames, since the tree root may still be either relative or absolute.
*
* Examples:
*
* - if you called dir_buildlist("c:\")
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?