687 lines
17 KiB
C++
687 lines
17 KiB
C++
////////////////////////////////////////////////////////////////////
|
|
// File.h
|
|
//
|
|
// Copyright 2007 cDc@seacave
|
|
// Distributed under the Boost Software License, Version 1.0
|
|
// (See http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
#ifndef __SEACAVE_FILE_H__
|
|
#define __SEACAVE_FILE_H__
|
|
|
|
|
|
// I N C L U D E S /////////////////////////////////////////////////
|
|
|
|
#include "Streams.h"
|
|
|
|
// Under both Windows and Unix, the stat function is used for classification
|
|
|
|
// Under Gnu/Linux, the following classifications are defined
|
|
// source: Gnu/Linux man page for stat(2) http://linux.die.net/man/2/stat
|
|
// S_IFMT 0170000 bitmask for the file type bitfields
|
|
// S_IFSOCK 0140000 socket (Note this overlaps with S_IFDIR)
|
|
// S_IFLNK 0120000 symbolic link
|
|
// S_IFREG 0100000 regular file
|
|
// S_IFBLK 0060000 block device
|
|
// S_IFDIR 0040000 directory
|
|
// S_IFCHR 0020000 character device
|
|
// S_IFIFO 0010000 FIFO
|
|
// There are also some Posix-standard macros:
|
|
// S_ISREG(m) is it a regular file?
|
|
// S_ISDIR(m) directory?
|
|
// S_ISCHR(m) character device?
|
|
// S_ISBLK(m) block device?
|
|
// S_ISFIFO(m) FIFO (named pipe)?
|
|
// S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)
|
|
// S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
|
|
// Under Windows, the following are defined:
|
|
// source: Header file sys/stat.h distributed with Visual Studio 10
|
|
// _S_IFMT (S_IFMT) 0xF000 file type mask
|
|
// _S_IFREG (S_IFREG) 0x8000 regular
|
|
// _S_IFDIR (S_IFDIR) 0x4000 directory
|
|
// _S_IFCHR (S_IFCHR) 0x2000 character special
|
|
// _S_IFIFO 0x1000 pipe
|
|
|
|
#ifdef _MSC_VER
|
|
#include <io.h>
|
|
// file type tests are not defined for some reason on Windows despite them providing the stat() function!
|
|
#define F_OK 0
|
|
#define X_OK 1
|
|
#define W_OK 2
|
|
#define R_OK 4
|
|
// Posix-style macros for Windows
|
|
#ifndef S_ISREG
|
|
#define S_ISREG(mode) ((mode & _S_IFMT) == _S_IFREG)
|
|
#endif
|
|
#ifndef S_ISDIR
|
|
#define S_ISDIR(mode) ((mode & _S_IFMT) == _S_IFDIR)
|
|
#endif
|
|
#ifndef S_ISCHR
|
|
#define S_ISCHR(mode) ((mode & _S_IFMT) == _S_IFCHR)
|
|
#endif
|
|
#ifndef S_ISBLK
|
|
#define S_ISBLK(mode) (false)
|
|
#endif
|
|
#ifndef S_ISFIFO
|
|
#define S_ISFIFO(mode) ((mode & _S_IFMT) == _S_IFIFO)
|
|
#endif
|
|
#ifndef S_ISLNK
|
|
#define S_ISLNK(mode) (false)
|
|
#endif
|
|
#ifndef S_ISSOCK
|
|
#define S_ISSOCK(mode) (false)
|
|
#endif
|
|
#else
|
|
#include <unistd.h>
|
|
#include <dirent.h>
|
|
#define _taccess access
|
|
#endif
|
|
#ifdef __APPLE__
|
|
#define fdatasync fsync
|
|
#endif
|
|
|
|
|
|
// D E F I N E S ///////////////////////////////////////////////////
|
|
|
|
// size of the stored file size variable
|
|
#ifdef LARGEFILESIZE
|
|
#define FILESIZE size_f_t
|
|
#else
|
|
#define FILESIZE size_t
|
|
#endif
|
|
|
|
// invalid file handle
|
|
#ifdef _MSC_VER
|
|
#define FILE_INVALID_HANDLE INVALID_HANDLE_VALUE
|
|
#else
|
|
#define FILE_INVALID_HANDLE int(-1)
|
|
#endif
|
|
|
|
|
|
namespace SEACAVE {
|
|
|
|
// S T R U C T S ///////////////////////////////////////////////////
|
|
|
|
class GENERAL_API File : public IOStream {
|
|
public:
|
|
typedef struct FILEINFO_TYPE {
|
|
String path;
|
|
FILESIZE size;
|
|
DWORD attrib;
|
|
} FILEINFO;
|
|
typedef cList<FILEINFO> FileInfoArr;
|
|
|
|
typedef enum FMCREATE_TYPE {
|
|
OPEN = 0x01,
|
|
CREATE = 0x02,
|
|
TRUNCATE = 0x04
|
|
} FMCREATE;
|
|
|
|
typedef enum FMFLAGS_TYPE {
|
|
SYNC = 0x01,
|
|
NOBUFFER = 0x02,
|
|
RANDOM = 0x04,
|
|
SEQUENTIAL = 0x08
|
|
} FMFLAGS;
|
|
|
|
inline File() : h(FILE_INVALID_HANDLE) {
|
|
#ifndef _RELEASE
|
|
breakRead = -1;
|
|
breakWrite = -1;
|
|
#endif
|
|
}
|
|
inline File(LPCTSTR aFileName, int access, int mode, int flags=0) : h(FILE_INVALID_HANDLE) {
|
|
#ifndef _RELEASE
|
|
breakRead = -1;
|
|
breakWrite = -1;
|
|
#endif
|
|
File::open(aFileName, access, mode, flags);
|
|
}
|
|
|
|
virtual ~File() {
|
|
File::close();
|
|
}
|
|
|
|
#ifdef _SUPPORT_CPP11
|
|
inline File(File&& rhs) : h(rhs.h) {
|
|
#ifndef _RELEASE
|
|
breakRead = rhs.breakRead;
|
|
breakWrite = rhs.breakWrite;
|
|
#endif
|
|
rhs.h = FILE_INVALID_HANDLE;
|
|
}
|
|
|
|
inline File& operator=(File&& rhs) {
|
|
h = rhs.h;
|
|
#ifndef _RELEASE
|
|
breakRead = rhs.breakRead;
|
|
breakWrite = rhs.breakWrite;
|
|
#endif
|
|
rhs.h = FILE_INVALID_HANDLE;
|
|
return *this;
|
|
}
|
|
#endif
|
|
|
|
bool isOpen() const {
|
|
return h != FILE_INVALID_HANDLE;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
typedef enum FMACCESS_TYPE {
|
|
READ = GENERIC_READ,
|
|
WRITE = GENERIC_WRITE,
|
|
RW = READ | WRITE
|
|
} FMACCESS;
|
|
|
|
typedef enum FMCHECKACCESS_TYPE {
|
|
CA_EXIST = F_OK, // existence
|
|
CA_WRITE = W_OK, // write
|
|
CA_READ = R_OK, // read
|
|
CA_RW = R_OK | W_OK,
|
|
} FMCHECKACCESS;
|
|
|
|
/**
|
|
* Open the file specified.
|
|
* If there are errors, h is set to FILE_INVALID_HANDLE.
|
|
* Use isOpen() to check.
|
|
*/
|
|
virtual void open(LPCTSTR aFileName, int access, int mode, int flags=0) {
|
|
ASSERT(access == WRITE || access == READ || access == (READ | WRITE));
|
|
|
|
close();
|
|
|
|
DWORD m = 0;
|
|
if (mode & OPEN) {
|
|
if (mode & CREATE) {
|
|
m = (mode & TRUNCATE) ? CREATE_ALWAYS : OPEN_ALWAYS;
|
|
} else {
|
|
m = (mode & TRUNCATE) ? TRUNCATE_EXISTING : OPEN_EXISTING;
|
|
}
|
|
} else {
|
|
ASSERT(mode & CREATE);
|
|
m = (mode & TRUNCATE) ? CREATE_ALWAYS : CREATE_NEW;
|
|
}
|
|
|
|
DWORD f = 0;
|
|
if (flags & SYNC)
|
|
f |= FILE_FLAG_WRITE_THROUGH;
|
|
if (flags & NOBUFFER)
|
|
f |= FILE_FLAG_NO_BUFFERING;
|
|
if (flags & RANDOM)
|
|
f |= FILE_FLAG_RANDOM_ACCESS;
|
|
if (flags & SEQUENTIAL)
|
|
f |= FILE_FLAG_SEQUENTIAL_SCAN;
|
|
|
|
h = ::CreateFile(aFileName, access, FILE_SHARE_READ, NULL, m, f, NULL);
|
|
}
|
|
|
|
virtual void close() {
|
|
if (isOpen()) {
|
|
FlushFileBuffers(h);
|
|
CloseHandle(h);
|
|
h = FILE_INVALID_HANDLE;
|
|
}
|
|
}
|
|
|
|
uint32_t getLastModified() {
|
|
ASSERT(isOpen());
|
|
FILETIME f = {0};
|
|
::GetFileTime(h, NULL, NULL, &f);
|
|
return convertTime(&f);
|
|
}
|
|
|
|
static uint32_t convertTime(FILETIME* f) {
|
|
SYSTEMTIME s = { 1970, 1, 0, 1, 0, 0, 0, 0 };
|
|
FILETIME f2 = {0};
|
|
if (::SystemTimeToFileTime(&s, &f2)) {
|
|
uint64_t* a = (uint64_t*)f;
|
|
uint64_t* b = (uint64_t*)&f2;
|
|
*a -= *b;
|
|
*a /= (1000LL*1000LL*1000LL/100LL); // 100ns > s
|
|
return (uint32_t)*a;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
size_f_t getSize() const override {
|
|
ASSERT(isOpen());
|
|
DWORD x;
|
|
DWORD l = ::GetFileSize(h, &x);
|
|
if ((l == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
|
|
return SIZE_NA;
|
|
return (size_f_t)l | ((size_f_t)x)<<32;
|
|
}
|
|
|
|
virtual bool setSize(size_f_t newSize) {
|
|
const size_f_t pos = getPos();
|
|
if (pos == SIZE_NA)
|
|
return false;
|
|
if (!setPos(newSize))
|
|
return false;
|
|
if (!setEOF())
|
|
return false;
|
|
if (!setPos(pos))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
size_f_t getPos() const override {
|
|
ASSERT(isOpen());
|
|
LONG x = 0;
|
|
const DWORD l = ::SetFilePointer(h, 0, &x, FILE_CURRENT);
|
|
if (l == INVALID_SET_FILE_POINTER)
|
|
return SIZE_NA;
|
|
return (size_f_t)l | ((size_f_t)x)<<32;
|
|
}
|
|
|
|
bool setPos(size_f_t pos) override {
|
|
ASSERT(isOpen());
|
|
LONG x = (LONG) (pos>>32);
|
|
return (::SetFilePointer(h, (DWORD)(pos & 0xffffffff), &x, FILE_BEGIN) != INVALID_SET_FILE_POINTER);
|
|
}
|
|
|
|
virtual bool setEndPos(size_f_t pos) {
|
|
ASSERT(isOpen());
|
|
LONG x = (LONG) (pos>>32);
|
|
return (::SetFilePointer(h, (DWORD)(pos & 0xffffffff), &x, FILE_END) != INVALID_SET_FILE_POINTER);
|
|
}
|
|
|
|
virtual bool movePos(size_f_t pos) {
|
|
ASSERT(isOpen());
|
|
LONG x = (LONG) (pos>>32);
|
|
return (::SetFilePointer(h, (DWORD)(pos & 0xffffffff), &x, FILE_CURRENT) != INVALID_SET_FILE_POINTER);
|
|
}
|
|
|
|
size_t read(void* buf, size_t len) override {
|
|
ASSERT(isOpen());
|
|
#ifndef _RELEASE
|
|
if (breakRead != (size_t)(-1)) {
|
|
if (breakRead <= len) {
|
|
ASSERT("FILE::read() break" == NULL);
|
|
breakRead = -1;
|
|
} else {
|
|
breakRead -= len;
|
|
}
|
|
}
|
|
#endif
|
|
DWORD x;
|
|
if (!::ReadFile(h, buf, (DWORD)len, &x, NULL))
|
|
return STREAM_ERROR;
|
|
return x;
|
|
}
|
|
|
|
size_t write(const void* buf, size_t len) override {
|
|
ASSERT(isOpen());
|
|
#ifndef _RELEASE
|
|
if (breakWrite != (size_t)(-1)) {
|
|
if (breakWrite <= len) {
|
|
ASSERT("FILE::write() break" == NULL);
|
|
breakWrite = -1;
|
|
} else {
|
|
breakWrite -= len;
|
|
}
|
|
}
|
|
#endif
|
|
DWORD x;
|
|
if (!::WriteFile(h, buf, (DWORD)len, &x, NULL))
|
|
return STREAM_ERROR;
|
|
ASSERT(x == len);
|
|
return x;
|
|
}
|
|
virtual bool setEOF() {
|
|
ASSERT(isOpen());
|
|
return (SetEndOfFile(h) != FALSE);
|
|
}
|
|
|
|
size_t flush() override {
|
|
ASSERT(isOpen());
|
|
return (FlushFileBuffers(h) ? 0 : STREAM_ERROR);
|
|
}
|
|
|
|
virtual bool getInfo(BY_HANDLE_FILE_INFORMATION* fileInfo) {
|
|
ASSERT(isOpen());
|
|
return (GetFileInformationByHandle(h, fileInfo) != FALSE);
|
|
}
|
|
|
|
static uint32_t getAttrib(LPCTSTR aFileName) {
|
|
return GetFileAttributes(aFileName);
|
|
}
|
|
|
|
static bool setAttrib(LPCTSTR aFileName, uint32_t attribs) {
|
|
return (SetFileAttributes(aFileName, attribs) != FALSE);
|
|
}
|
|
|
|
static void deleteFile(LPCTSTR aFileName) { ::DeleteFile(aFileName); }
|
|
static bool renameFile(LPCTSTR source, LPCTSTR target) {
|
|
if (!::MoveFile(source, target)) {
|
|
// Can't move, try copy/delete...
|
|
if (!::CopyFile(source, target, FALSE))
|
|
return false;
|
|
deleteFile(source);
|
|
}
|
|
return true;
|
|
}
|
|
static bool copyFile(LPCTSTR source, LPCTSTR target) { return ::CopyFile(source, target, FALSE) == TRUE; }
|
|
|
|
static size_f_t getSize(LPCTSTR aFileName) {
|
|
const HANDLE fh = ::CreateFile(aFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL);
|
|
if (fh == FILE_INVALID_HANDLE)
|
|
return SIZE_NA;
|
|
DWORD x;
|
|
DWORD l = ::GetFileSize(fh, &x);
|
|
CloseHandle(fh);
|
|
if ((l == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
|
|
return SIZE_NA;
|
|
return (((size_f_t)l) | (((size_f_t)x)<<32));
|
|
}
|
|
|
|
|
|
static size_f_t findFiles(const String& _strPath, const String& strMask, bool bProcessSubdir, FileInfoArr& arrFiles) {
|
|
// List all the files.
|
|
WIN32_FIND_DATA fd;
|
|
HANDLE hFind;
|
|
size_f_t totalSize = 0;
|
|
String strPath(_strPath);
|
|
Util::ensureFolderSlash(strPath);
|
|
//Find all the files in this folder.
|
|
hFind = FindFirstFile((strPath + strMask).c_str(), &fd);
|
|
if (hFind != FILE_INVALID_HANDLE) {
|
|
do {
|
|
// this is a file that can be used
|
|
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
continue;
|
|
// Store the file name.
|
|
FILEINFO& fileInfo = arrFiles.AddEmpty();
|
|
fileInfo.path = strPath + fd.cFileName;
|
|
#ifdef LARGEFILESIZE
|
|
fileInfo.size = (((size_f_t)fd.nFileSizeLow) | (((size_f_t)fd.nFileSizeHigh)<<32));
|
|
#else
|
|
fileInfo.size = fd.nFileSizeLow;
|
|
#endif
|
|
fileInfo.attrib = fd.dwFileAttributes;
|
|
totalSize += fileInfo.size;
|
|
} while (FindNextFile(hFind, &fd));
|
|
FindClose(hFind);
|
|
}
|
|
//Process the subfolders also...
|
|
if (!bProcessSubdir)
|
|
return totalSize;
|
|
hFind = FindFirstFile((strPath + '*').c_str(), &fd);
|
|
if (hFind != FILE_INVALID_HANDLE) {
|
|
do {
|
|
// if SUBDIR then process that too
|
|
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
continue;
|
|
if (!_tcscmp(fd.cFileName, _T(".")))
|
|
continue;
|
|
if (!_tcscmp(fd.cFileName, _T("..")))
|
|
continue;
|
|
// Process all subfolders recursively
|
|
totalSize += findFiles(strPath + fd.cFileName + PATH_SEPARATOR, strMask, true, arrFiles);
|
|
} while (FindNextFile(hFind, &fd));
|
|
FindClose(hFind);
|
|
}
|
|
return totalSize;
|
|
}
|
|
|
|
#else // _MSC_VER
|
|
|
|
typedef enum FMACCESS_TYPE {
|
|
READ = 0x01,
|
|
WRITE = 0x02,
|
|
RW = READ | WRITE,
|
|
} FMACCESS;
|
|
|
|
typedef enum FMCHECKACCESS_TYPE {
|
|
CA_EXIST = F_OK, // existence
|
|
CA_WRITE = W_OK, // write
|
|
CA_READ = R_OK, // read
|
|
CA_RW = R_OK | W_OK,
|
|
CA_EXEC = X_OK, // execute
|
|
} FMCHECKACCESS;
|
|
|
|
/**
|
|
* Open the file specified.
|
|
* If there are errors, h is set to FILE_INVALID_HANDLE.
|
|
* Use isOpen() to check.
|
|
*/
|
|
virtual void open(LPCTSTR aFileName, int access, int mode, int flags=0) {
|
|
ASSERT(access == WRITE || access == READ || access == (READ | WRITE));
|
|
|
|
close();
|
|
|
|
int m = 0;
|
|
if (access == READ)
|
|
m |= O_RDONLY;
|
|
else if (access == WRITE)
|
|
m |= O_WRONLY;
|
|
else
|
|
m |= O_RDWR;
|
|
|
|
if (mode & CREATE)
|
|
m |= O_CREAT;
|
|
if (mode & TRUNCATE)
|
|
m |= O_TRUNC;
|
|
|
|
if (flags & SYNC)
|
|
m |= O_DSYNC;
|
|
#ifndef __APPLE__
|
|
if (flags & NOBUFFER)
|
|
m |= O_DIRECT;
|
|
#endif
|
|
h = ::open(aFileName, m, S_IRUSR | S_IWUSR);
|
|
}
|
|
|
|
virtual void close() {
|
|
if (h != FILE_INVALID_HANDLE) {
|
|
::close(h);
|
|
h = FILE_INVALID_HANDLE;
|
|
}
|
|
}
|
|
|
|
uint32_t getLastModified() {
|
|
ASSERT(isOpen());
|
|
struct stat s;
|
|
if (::fstat(h, &s) == -1)
|
|
return 0;
|
|
return (uint32_t)s.st_mtime;
|
|
}
|
|
|
|
size_f_t getSize() const override {
|
|
ASSERT(isOpen());
|
|
struct stat s;
|
|
if (::fstat(h, &s) == -1)
|
|
return SIZE_NA;
|
|
return (size_f_t)s.st_size;
|
|
}
|
|
|
|
size_f_t getPos() const override {
|
|
ASSERT(isOpen());
|
|
return (size_f_t)lseek(h, 0, SEEK_CUR);
|
|
}
|
|
|
|
bool setPos(size_f_t pos) override { ASSERT(isOpen()); return lseek(h, (off_t)pos, SEEK_SET) != (off_t)-1; }
|
|
virtual bool setEndPos(size_f_t pos) { ASSERT(isOpen()); return lseek(h, (off_t)pos, SEEK_END) != (off_t)-1; }
|
|
virtual bool movePos(size_f_t pos) { ASSERT(isOpen()); return lseek(h, (off_t)pos, SEEK_CUR) != (off_t)-1; }
|
|
|
|
size_t read(void* buf, size_t len) override {
|
|
ASSERT(isOpen());
|
|
#ifndef _RELEASE
|
|
if (breakRead != (size_t)(-1)) {
|
|
if (breakRead <= len) {
|
|
ASSERT("FILE::read() break" == NULL);
|
|
breakRead = -1;
|
|
} else {
|
|
breakRead -= len;
|
|
}
|
|
}
|
|
#endif
|
|
ssize_t x = ::read(h, buf, len);
|
|
if (x == -1)
|
|
return STREAM_ERROR;
|
|
return (size_t)x;
|
|
}
|
|
|
|
size_t write(const void* buf, size_t len) override {
|
|
ASSERT(isOpen());
|
|
#ifndef _RELEASE
|
|
if (breakWrite != (size_t)(-1)) {
|
|
if (breakWrite <= len) {
|
|
ASSERT("FILE::write() break" == NULL);
|
|
breakWrite = -1;
|
|
} else {
|
|
breakWrite -= len;
|
|
}
|
|
}
|
|
#endif
|
|
ssize_t x = ::write(h, buf, len);
|
|
if (x == -1)
|
|
return STREAM_ERROR;
|
|
if (x < (ssize_t)len)
|
|
return STREAM_ERROR;
|
|
return x;
|
|
}
|
|
|
|
virtual bool setEOF() {
|
|
ASSERT(isOpen());
|
|
return (ftruncate(h, (off_t)getPos()) != -1);
|
|
}
|
|
virtual bool setSize(size_f_t newSize) {
|
|
ASSERT(isOpen());
|
|
return (ftruncate(h, (off_t)newSize) != -1);
|
|
}
|
|
|
|
size_t flush() override {
|
|
ASSERT(isOpen());
|
|
return fdatasync(h);
|
|
}
|
|
|
|
static void deleteFile(LPCTSTR aFileName) { ::remove(aFileName); }
|
|
static bool renameFile(LPCTSTR source, LPCTSTR target) { return ::rename(source, target) == 0; }
|
|
static bool copyFile(LPCTSTR source, LPCTSTR target) {
|
|
std::ifstream src(source, std::ios::binary);
|
|
if (!src.is_open())
|
|
return false;
|
|
std::ofstream dst(target, std::ios::binary);
|
|
if (!dst.is_open())
|
|
return false;
|
|
dst << src.rdbuf();
|
|
return true;
|
|
}
|
|
|
|
static size_f_t getSize(LPCTSTR aFileName) {
|
|
struct stat buf;
|
|
if (stat(aFileName, &buf) != 0)
|
|
return SIZE_NA;
|
|
return buf.st_size;
|
|
}
|
|
|
|
#endif // _MSC_VER
|
|
|
|
// test for whether there's something (i.e. folder or file) with this name
|
|
// and what access mode is supported
|
|
static bool isPresent(LPCTSTR path) {
|
|
struct stat buf;
|
|
return stat(path, &buf) == 0;
|
|
}
|
|
static bool access(LPCTSTR path, int mode=CA_EXIST) {
|
|
return ::_taccess(path, mode) == 0;
|
|
}
|
|
// test for whether there's something present and its a folder
|
|
static bool isFolder(LPCTSTR path) {
|
|
struct stat buf;
|
|
if (!(stat(path, &buf) == 0))
|
|
return false;
|
|
// If the object is present, see if it is a directory
|
|
// this is the Posix-approved way of testing
|
|
return S_ISDIR(buf.st_mode);
|
|
}
|
|
// test for whether there's something present and its a file
|
|
// a file can be a regular file, a symbolic link, a FIFO or a socket, but not a device
|
|
static bool isFile(LPCTSTR path) {
|
|
struct stat buf;
|
|
if (!(stat(path, &buf) == 0))
|
|
return false;
|
|
// If the object is present, see if it is a file or file-like object
|
|
// Note that devices are neither folders nor files
|
|
// this is the Posix-approved way of testing
|
|
return S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode) || S_ISSOCK(buf.st_mode) || S_ISFIFO(buf.st_mode);
|
|
}
|
|
|
|
// time the file was originally created
|
|
static time_t getCreated(LPCTSTR path) {
|
|
struct stat buf;
|
|
if (stat(path, &buf) != 0) return 0;
|
|
return buf.st_ctime;
|
|
}
|
|
// time the file was last modified
|
|
static time_t getModified(LPCTSTR path) {
|
|
struct stat buf;
|
|
if (stat(path, &buf) != 0) return 0;
|
|
return buf.st_mtime;
|
|
}
|
|
// time the file was accessed
|
|
static time_t getAccessed(LPCTSTR path) {
|
|
struct stat buf;
|
|
if (stat(path, &buf) != 0) return 0;
|
|
return buf.st_atime;
|
|
}
|
|
|
|
// set the current folder
|
|
static bool setCurrentFolder(LPCTSTR path) {
|
|
if (!isFolder(path))
|
|
return false;
|
|
#ifdef _MSC_VER
|
|
// Windows implementation - this returns non-zero for success
|
|
return (SetCurrentDirectory(path) != 0);
|
|
#else
|
|
// Unix implementation - this returns zero for success
|
|
return (chdir(path) == 0);
|
|
#endif
|
|
}
|
|
|
|
template <class VECTOR>
|
|
inline size_t write(const VECTOR& arr) {
|
|
const typename VECTOR::IDX nSize(arr.GetSize());
|
|
size_t nBytes(write(&nSize, sizeof(typename VECTOR::IDX)));
|
|
nBytes += write(arr.GetData(), arr.GetDataSize());
|
|
return nBytes;
|
|
}
|
|
|
|
template <class VECTOR>
|
|
inline size_t read(VECTOR& arr) {
|
|
typename VECTOR::IDX nSize;
|
|
size_t nBytes(read(&nSize, sizeof(typename VECTOR::IDX)));
|
|
arr.Resize(nSize);
|
|
nBytes += read(arr.GetData(), arr.GetDataSize());
|
|
return nBytes;
|
|
}
|
|
|
|
enum { LAYER_ID_IN=3 };
|
|
InputStream* getInputStream(int typ=InputStream::LAYER_ID_IN) override { return (typ == LAYER_ID_IN ? static_cast<InputStream*>(this) : IOStream::getInputStream(typ)); }
|
|
enum { LAYER_ID_OUT=3 };
|
|
OutputStream* getOutputStream(int typ=OutputStream::LAYER_ID_OUT) override { return (typ == LAYER_ID_OUT ? static_cast<OutputStream*>(this) : IOStream::getOutputStream(typ)); }
|
|
|
|
protected:
|
|
#ifdef _MSC_VER
|
|
HANDLE h;
|
|
#else
|
|
int h;
|
|
#endif
|
|
|
|
public:
|
|
#ifndef _RELEASE
|
|
size_t breakRead;
|
|
size_t breakWrite;
|
|
#endif
|
|
|
|
private:
|
|
File(const File&);
|
|
File& operator=(const File&);
|
|
};
|
|
typedef File* LPFILE;
|
|
/*----------------------------------------------------------------*/
|
|
|
|
} // namespace SEACAVE
|
|
|
|
#endif // __SEACAVE_FILE_H__
|