436 lines
11 KiB
C++
436 lines
11 KiB
C++
|
/* s_direct.cpp
|
||
|
*
|
||
|
* Copyright (c) 1994-1996, Marko Macek
|
||
|
*
|
||
|
* You may distribute under the terms of either the GNU General Public
|
||
|
* License or the Artistic License, as specified in the README file.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
// TODO: on OS/2 choose between UNIX and OS/2 style patterns (now OS/2 only)
|
||
|
// TODO: on OS/2 fetch multiple entries at once and cache them for speed
|
||
|
#include "fte.h"
|
||
|
|
||
|
#ifdef OS2
|
||
|
#define INCL_BASE
|
||
|
#include <os2.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef NT
|
||
|
#define WIN32_LEAN_AND_MEAN 1
|
||
|
#include <windows.h>
|
||
|
#endif
|
||
|
|
||
|
#if defined(DOSP32) || (defined(NT) && defined(USE_DIRENT)) // NT ?
|
||
|
# include "port.h"
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#ifdef DJGPP
|
||
|
#include <sys/stat.h>
|
||
|
static int my_stat(const char *name, struct stat *s)
|
||
|
{
|
||
|
unsigned short f = _djstat_flags;
|
||
|
// speed up directory access by turning off unused stat functionality
|
||
|
_djstat_flags |= _STAT_INODE;
|
||
|
_djstat_flags |= _STAT_EXEC_EXT;
|
||
|
_djstat_flags |= _STAT_EXEC_MAGIC;
|
||
|
_djstat_flags |= _STAT_DIRSIZE;
|
||
|
//_djstat_flags |= _STAT_ROOT_TIME;
|
||
|
_djstat_flags &= ~_STAT_ROOT_TIME;
|
||
|
_djstat_flags |= _STAT_WRITEBIT;
|
||
|
int r = stat(name,s);
|
||
|
_djstat_flags = f;
|
||
|
return r;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
FileInfo::FileInfo(char *Name, int Type, off_t Size, time_t MTime) {
|
||
|
name = new char[strlen (Name) + 1];
|
||
|
if (name)
|
||
|
strcpy(name, Name);
|
||
|
size = Size;
|
||
|
type = Type;
|
||
|
mtime = MTime;
|
||
|
}
|
||
|
|
||
|
FileInfo::~FileInfo() {
|
||
|
delete [] name;
|
||
|
}
|
||
|
|
||
|
FileFind::FileFind(const char *aDirectory, const char *aPattern, int aFlags) {
|
||
|
Directory = new char[strlen(aDirectory) + 1];
|
||
|
if (Directory) {
|
||
|
strcpy(Directory, aDirectory);
|
||
|
Slash(Directory, 0);
|
||
|
}
|
||
|
if (aPattern) {
|
||
|
Pattern = new char[strlen(aPattern) + 1];
|
||
|
if (Pattern)
|
||
|
strcpy(Pattern, aPattern);
|
||
|
} else {
|
||
|
Pattern = 0;
|
||
|
}
|
||
|
Flags = aFlags;
|
||
|
#if defined(USE_DIRENT)
|
||
|
//#if defined(UNIX) || defined(DOSP32) || defined(NT)
|
||
|
dir = 0;
|
||
|
#elif defined(OS2) && !defined(USE_DIRENT)
|
||
|
dir = 0;
|
||
|
#elif defined(NT) && !defined(USE_DIRENT)
|
||
|
dir = 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
FileFind::~FileFind() {
|
||
|
delete [] Directory;
|
||
|
if (Pattern)
|
||
|
delete [] Pattern;
|
||
|
//#if defined(UNIX) || defined(DOSP32) || defined(NT)
|
||
|
#if defined(USE_DIRENT)
|
||
|
if (dir)
|
||
|
closedir(dir);
|
||
|
#elif defined(OS2) && !defined(USE_DIRENT)
|
||
|
if (dir)
|
||
|
DosFindClose(dir);
|
||
|
#elif defined(NT) && !defined(USE_DIRENT)
|
||
|
if (dir)
|
||
|
FindClose((HANDLE)dir);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
int FileFind::FindFirst(FileInfo **fi) {
|
||
|
//#if defined(UNIX) || defined(NT) || defined(DOSP32)
|
||
|
#if defined(USE_DIRENT)
|
||
|
if (dir)
|
||
|
closedir(dir);
|
||
|
if ((dir = opendir(Directory)) == 0)
|
||
|
return -1;
|
||
|
return FindNext(fi);
|
||
|
#elif defined(OS2) && !defined(USE_DIRENT)
|
||
|
char fullpattern[MAXPATH];
|
||
|
HDIR hdir = HDIR_CREATE;
|
||
|
ULONG attr = FILE_ARCHIVED | FILE_READONLY;
|
||
|
ULONG count = 1;
|
||
|
FILEFINDBUF3 find; // need to improve to fetch multiple entries at once
|
||
|
char fullpath[MAXPATH];
|
||
|
char *name;
|
||
|
struct tm t;
|
||
|
int rc;
|
||
|
|
||
|
if (dir)
|
||
|
DosFindClose(dir);
|
||
|
|
||
|
if (Flags & ffDIRECTORY)
|
||
|
attr |= FILE_DIRECTORY;
|
||
|
|
||
|
if (Flags & ffHIDDEN)
|
||
|
attr |= FILE_HIDDEN | FILE_SYSTEM; // separate ?
|
||
|
|
||
|
if (Pattern)
|
||
|
JoinDirFile(fullpattern, Directory, Pattern);
|
||
|
else
|
||
|
JoinDirFile(fullpattern, Directory, "*");
|
||
|
|
||
|
if ((rc = DosFindFirst(fullpattern,
|
||
|
&hdir,
|
||
|
attr,
|
||
|
&find, sizeof(find),
|
||
|
&count,
|
||
|
FIL_STANDARD)) != 0)
|
||
|
{
|
||
|
//fprintf(stderr, "%s: %d\n\n", fullpattern, rc);
|
||
|
return -1;
|
||
|
}
|
||
|
dir = hdir;
|
||
|
if (count != 1)
|
||
|
return -1;
|
||
|
name = find.achName;
|
||
|
if (Flags & ffFULLPATH) {
|
||
|
JoinDirFile(fullpath, Directory, name);
|
||
|
name = fullpath;
|
||
|
}
|
||
|
memset((void *)&t, 0, sizeof(t));
|
||
|
t.tm_year = find.fdateLastWrite.year + 80; // ugh!
|
||
|
t.tm_mon = find.fdateLastWrite.month - 1;
|
||
|
t.tm_mday = find.fdateLastWrite.day;
|
||
|
t.tm_hour = find.ftimeLastWrite.hours;
|
||
|
t.tm_min = find.ftimeLastWrite.minutes;
|
||
|
t.tm_sec = find.ftimeLastWrite.twosecs * 2; // ugh!
|
||
|
t.tm_isdst = -1;
|
||
|
*fi = new FileInfo(name,
|
||
|
(find.attrFile & FILE_DIRECTORY) ? fiDIRECTORY : fiFILE,
|
||
|
find.cbFile,
|
||
|
mktime(&t));
|
||
|
return 0;
|
||
|
#elif defined(NT) && !defined(USE_DIRENT)
|
||
|
#if defined(USE_VCFIND)
|
||
|
char fullpattern[MAXPATH];
|
||
|
|
||
|
_finddata_t find; // need to improve to fetch multiple entries at once
|
||
|
char fullpath[MAXPATH];
|
||
|
char *name;
|
||
|
struct tm t;
|
||
|
int rc;
|
||
|
|
||
|
if (dir)
|
||
|
_findclose(dir);
|
||
|
|
||
|
/*if (Flags & ffDIRECTORY)
|
||
|
attr |= FILE_DIRECTORY;
|
||
|
|
||
|
if (Flags & ffHIDDEN)
|
||
|
attr |= FILE_HIDDEN | FILE_SYSTEM; // separate ?
|
||
|
*/
|
||
|
if (Pattern)
|
||
|
JoinDirFile(fullpattern, Directory, Pattern);
|
||
|
else
|
||
|
JoinDirFile(fullpattern, Directory, "*");
|
||
|
|
||
|
if ((rc = _findfirst(fullpattern, &find)) == -1)
|
||
|
{
|
||
|
// fprintf(stderr, "%s: %d\n\n", fullpattern, rc);
|
||
|
return -1;
|
||
|
}
|
||
|
dir = rc;
|
||
|
|
||
|
name = find.name;
|
||
|
if (Flags & ffFULLPATH) {
|
||
|
JoinDirFile(fullpath, Directory, name);
|
||
|
name = fullpath;
|
||
|
}
|
||
|
|
||
|
*fi = new FileInfo(name,
|
||
|
(find.attrib & _A_SUBDIR) ? fiDIRECTORY : fiFILE,
|
||
|
find.size,
|
||
|
find.time_create);
|
||
|
return 0;
|
||
|
#else
|
||
|
char fullpattern[MAXPATH];
|
||
|
|
||
|
WIN32_FIND_DATA find; // need to improve to fetch multiple entries at once
|
||
|
char fullpath[MAXPATH];
|
||
|
char *name;
|
||
|
struct tm t;
|
||
|
SYSTEMTIME st;
|
||
|
FILETIME localft; // needed for time conversion
|
||
|
int rc;
|
||
|
|
||
|
if (dir)
|
||
|
_findclose(dir);
|
||
|
|
||
|
/*if (Flags & ffDIRECTORY)
|
||
|
attr |= FILE_DIRECTORY;
|
||
|
|
||
|
if (Flags & ffHIDDEN)
|
||
|
attr |= FILE_HIDDEN | FILE_SYSTEM; // separate ?
|
||
|
*/
|
||
|
if (Pattern)
|
||
|
JoinDirFile(fullpattern, Directory, Pattern);
|
||
|
else
|
||
|
JoinDirFile(fullpattern, Directory, "*");
|
||
|
|
||
|
if ((rc = (int) FindFirstFile(fullpattern, &find)) < 0)
|
||
|
{
|
||
|
//fprintf(stderr, "%s: %d\n\n", fullpattern, rc);
|
||
|
return -1;
|
||
|
}
|
||
|
dir = rc;
|
||
|
|
||
|
name = find.cFileName;
|
||
|
if (Flags & ffFULLPATH) {
|
||
|
JoinDirFile(fullpath, Directory, name);
|
||
|
name = fullpath;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* since filetime is in UTC format we need to convert it first to
|
||
|
* localtime and when we have "correct" time we can use it.
|
||
|
*/
|
||
|
|
||
|
FileTimeToLocalFileTime(&find.ftLastWriteTime, &localft);
|
||
|
FileTimeToSystemTime(&localft, &st);
|
||
|
|
||
|
t.tm_year = st.wYear - 1900;
|
||
|
t.tm_mon = st.wMonth - 1; // in system time january is 1...
|
||
|
t.tm_mday = st.wDay;
|
||
|
t.tm_hour = st.wHour;
|
||
|
t.tm_min = st.wMinute;
|
||
|
t.tm_sec = st.wSecond;
|
||
|
t.tm_isdst = -1;
|
||
|
|
||
|
|
||
|
*fi = new FileInfo(name,
|
||
|
(find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? fiDIRECTORY : fiFILE,
|
||
|
find.nFileSizeLow, // !!!
|
||
|
mktime(&t));
|
||
|
return 0;
|
||
|
#endif
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
int FileFind::FindNext(FileInfo **fi) {
|
||
|
//#if defined(UNIX) || defined(NT) || defined(DOSP32)
|
||
|
#if defined(USE_DIRENT)
|
||
|
struct dirent *dent;
|
||
|
char fullpath[MAXPATH];
|
||
|
char *name;
|
||
|
|
||
|
*fi = 0;
|
||
|
again:
|
||
|
if ((dent = readdir(dir)) == NULL)
|
||
|
return -1;
|
||
|
name = dent->d_name;
|
||
|
|
||
|
if (name[0] == '.')
|
||
|
if (!(Flags & ffHIDDEN))
|
||
|
goto again;
|
||
|
|
||
|
if (Pattern && fnmatch(Pattern, dent->d_name, 0) != 0)
|
||
|
goto again;
|
||
|
|
||
|
if (Flags & ffFULLPATH) {
|
||
|
JoinDirFile(fullpath, Directory, dent->d_name);
|
||
|
name = fullpath;
|
||
|
}
|
||
|
|
||
|
if (Flags & ffFAST) {
|
||
|
*fi = new FileInfo(name, fiUNKNOWN, 0, 0);
|
||
|
} else {
|
||
|
struct stat st;
|
||
|
|
||
|
if (!(Flags & ffFULLPATH)) // need it now
|
||
|
JoinDirFile(fullpath, Directory, dent->d_name);
|
||
|
|
||
|
if (
|
||
|
#if defined(DJGPP)
|
||
|
my_stat
|
||
|
#elif defined(UNIX) // must use lstat if available
|
||
|
lstat
|
||
|
#else
|
||
|
stat
|
||
|
#endif
|
||
|
(fullpath, &st) != 0 && 0)
|
||
|
goto again;
|
||
|
|
||
|
if (!(Flags & ffDIRECTORY) && S_ISDIR(st.st_mode))
|
||
|
goto again;
|
||
|
|
||
|
*fi = new FileInfo(name,
|
||
|
S_ISDIR(st.st_mode) ? fiDIRECTORY : fiFILE,
|
||
|
st.st_size,
|
||
|
st.st_mtime);
|
||
|
}
|
||
|
//printf("ok\n");
|
||
|
return 0;
|
||
|
#elif defined(OS2) && !defined(USE_DIRENT)
|
||
|
ULONG count = 1;
|
||
|
FILEFINDBUF3 find; // need to improve to fetch multiple entries at once
|
||
|
char fullpath[MAXPATH];
|
||
|
char *name;
|
||
|
struct tm t;
|
||
|
int rc;
|
||
|
|
||
|
if ((rc = DosFindNext(dir,
|
||
|
&find, sizeof(find),
|
||
|
&count)) != 0)
|
||
|
{
|
||
|
//fprintf(stderr, "%d\n\n", rc);
|
||
|
return -1;
|
||
|
}
|
||
|
if (count != 1)
|
||
|
return -1;
|
||
|
name = find.achName;
|
||
|
if (Flags & ffFULLPATH) {
|
||
|
JoinDirFile(fullpath, Directory, name);
|
||
|
name = fullpath;
|
||
|
}
|
||
|
memset((void *)&t, 0, sizeof(t));
|
||
|
t.tm_year = find.fdateLastWrite.year + 80;
|
||
|
t.tm_mon = find.fdateLastWrite.month - 1;
|
||
|
t.tm_mday = find.fdateLastWrite.day;
|
||
|
t.tm_hour = find.ftimeLastWrite.hours;
|
||
|
t.tm_min = find.ftimeLastWrite.minutes;
|
||
|
t.tm_sec = find.ftimeLastWrite.twosecs * 2; // ugh!
|
||
|
t.tm_isdst = -1;
|
||
|
*fi = new FileInfo(name,
|
||
|
(find.attrFile & FILE_DIRECTORY) ? fiDIRECTORY : fiFILE,
|
||
|
find.cbFile,
|
||
|
mktime(&t));
|
||
|
|
||
|
return 0;
|
||
|
#elif defined(NT) && !defined(USE_DIRENT)
|
||
|
#if defined(USE_VCFIND)
|
||
|
_finddata_t find;
|
||
|
char fullpath[MAXPATH];
|
||
|
char *name;
|
||
|
struct tm t;
|
||
|
int rc;
|
||
|
|
||
|
if ((rc = _findnext(dir,
|
||
|
&find)) != 0)
|
||
|
{
|
||
|
// fprintf(stderr, "%d\n\n", rc);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
name = find.name;
|
||
|
if (Flags & ffFULLPATH) {
|
||
|
JoinDirFile(fullpath, Directory, name);
|
||
|
name = fullpath;
|
||
|
}
|
||
|
|
||
|
*fi = new FileInfo(name,
|
||
|
(find.attrib & _A_SUBDIR) ? fiDIRECTORY : fiFILE,
|
||
|
find.size,
|
||
|
find.time_create);
|
||
|
return 0;
|
||
|
#else
|
||
|
WIN32_FIND_DATA find;
|
||
|
char fullpath[MAXPATH];
|
||
|
char *name;
|
||
|
struct tm t;
|
||
|
SYSTEMTIME st;
|
||
|
FILETIME localft; // needed for time conversion
|
||
|
int rc;
|
||
|
|
||
|
if ((rc = FindNextFile((HANDLE)dir,
|
||
|
&find)) != TRUE)
|
||
|
{
|
||
|
//fprintf(stderr, "%d\n\n", rc);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
name = find.cFileName;
|
||
|
if (Flags & ffFULLPATH) {
|
||
|
JoinDirFile(fullpath, Directory, name);
|
||
|
name = fullpath;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* since filetime is in UTC format we need to convert it first to
|
||
|
* localtime and when we have "correct" time we can use it.
|
||
|
*/
|
||
|
|
||
|
FileTimeToLocalFileTime(&find.ftLastWriteTime, &localft);
|
||
|
FileTimeToSystemTime(&localft, &st);
|
||
|
|
||
|
t.tm_year = st.wYear - 1900;
|
||
|
t.tm_mon = st.wMonth - 1; // in system time january is 1...
|
||
|
t.tm_mday = st.wDay;
|
||
|
t.tm_hour = st.wHour;
|
||
|
t.tm_min = st.wMinute;
|
||
|
t.tm_sec = st.wSecond;
|
||
|
t.tm_isdst = -1;
|
||
|
|
||
|
*fi = new FileInfo(name,
|
||
|
(find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? fiDIRECTORY : fiFILE,
|
||
|
find.nFileSizeLow,
|
||
|
mktime(&t));
|
||
|
return 0;
|
||
|
#endif
|
||
|
// put code here
|
||
|
#endif
|
||
|
}
|