Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 437 lines (371 sloc) 8.72 KB
#ifndef com_sleepless_io_file_cpp
#define com_sleepless_io_file_cpp
/* Copyright 2004 Sleepless Software Inc. All Rights Reserved */
#if defined(linux) || (defined(__APPLE__) && defined(__GNUC__))
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <time.h>
# include <utime.h>
# include <sys/stat.h>
#endif
#ifdef WIN32
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <time.h>
# include <sys/utime.h>
# include <sys/stat.h>
# ifndef __CYGWIN__
# define utimbuf _utimbuf
# define utime _utime
# define stat _stat
# define lstat _stat
# define S_IFREG _S_IFREG
# define S_IFDIR _S_IFDIR
# endif
#endif
#ifdef __palmos__
# include <string.h>
typedef long int time_t;
typedef long int dev_t;
typedef long int ino_t;
typedef long int mode_t;
typedef long int nlink_t;
typedef long int uid_t;
typedef long int gid_t;
typedef long int off_t;
typedef long int blksize_t;
typedef long int blkcnt_t;
struct stat {
dev_t st_dev; /* device */
ino_t st_ino; /* inode */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device type (if inode device) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last change */
};
int lstat(const char *file_name, struct stat *buf);
#endif
#include "str.cpp"
struct File
{
char *path;
unsigned char *bytes;
unsigned long size;
// Note that this constructor doesn't actually do anything to the
// file represented by '_path'.
// It doesn't open, read, write or examine it.
// You do that sort of thing with the other functions.
File(const char *_path)
{
path = Str::dup(_path);
size = 0;
bytes = 0;
}
~File()
{
if(path)
free(path);
if(bytes)
free(bytes);
}
bool exists()
{
struct stat buf;
return lstat(path, &buf) == 0;
}
static bool exists(const char *path)
{
File f(path);
return f.exists();
}
// Returns true if 'path' exists in persistant storage
// and is a regular file.
int isFile()
{
struct stat buf;
int r = lstat(path, &buf );
if(r == 0)
{
#ifdef WIN32
return (buf.st_mode & S_IFREG) ? 1 : 0;
#endif
#if defined(linux) || (defined(__APPLE__) && defined(__GNUC__))
return S_ISREG(buf.st_mode);
#endif
}
return 0;
}
// Returns true if 'path' exists in persistant storage
// and is a directory.
int isDir()
{
struct stat buf;
int r = lstat(path, &buf );
if(r == 0)
{
#ifdef WIN32
return (buf.st_mode & S_IFDIR) ? 1 : 0;
#endif
#if defined(linux) || (defined(__APPLE__) && defined(__GNUC__))
return S_ISDIR(buf.st_mode);
#endif
}
return 0;
};
// Returns true if 'path' exists in persistant storage
// and is a symbolic link.
int isLink()
{
#if defined(linux) || (defined(__APPLE__) && defined(__GNUC__))
struct stat buf;
int r = lstat(path, &buf );
if(r == 0)
return S_ISLNK(buf.st_mode); //(buf.st_mode & S_IFLNK) ? 1 : 0;
#endif
return 0;
};
unsigned long getATime()
{
struct stat buf;
if(lstat(path, &buf) == 0)
return (unsigned long)buf.st_atime;
return 0;
}
unsigned long getMTime()
{
struct stat buf;
if(lstat(path, &buf) == 0)
return (unsigned long)buf.st_mtime;
return 0;
}
int setATime(unsigned long t)
{
struct utimbuf utb;
utb.actime = t;
utb.modtime = getMTime();
return utime(path, &utb);
}
int setMTime(unsigned long t)
{
struct utimbuf utb;
utb.actime = getATime();
utb.modtime = t;
return utime(path, &utb);
}
// Returns the size in bytes of the file
// represented by this instance.
//
// xxx: should probably return -1 if the file doesn't exist,
//
unsigned long diskSize()
{
unsigned long s = 0;
if(isFile())
{
struct stat buf;
int r = lstat(path, &buf );
if(r == 0)
return buf.st_size;
return 0;
}
return s;
}
// Writes the bytes provided out to the path/file associated with this
// instance.
unsigned long flush(const unsigned char *buf, const unsigned long len)
{
unsigned long r = 0;
#if defined WIN32 || linux || (defined(__APPLE__) && defined(__GNUC__))
FILE *fp = fopen(path, "wb");
if(fp)
{
r = (unsigned long)fwrite(buf, 1, len, fp);
fclose(fp);
}
#endif
return r;
}
// Returns size of the file if it exists, is a regular file, and was
// read into memory ok.
// Returns 0 otherwise.
unsigned long getSize()
{
if(!bytes)
return diskSize();
return size;
}
// Loads the contents of the file from persistant storage (disk)
// to memory.
unsigned char *refresh()
{
// dispose of current snapshot if it exists
if(bytes)
{
free(bytes);
bytes = 0;
}
if(!isDir())
{
#if defined WIN32 || linux || (defined(__APPLE__) && defined(__GNUC__))
unsigned long dSize = diskSize();
unsigned char *dBytes = (unsigned char *)malloc(dSize + 1);
if(dBytes)
{
dBytes[dSize] = 0;
FILE *fp = fopen(path, "rb");
if(fp)
{
unsigned long r = (unsigned long)fread(dBytes, 1, dSize, fp);
fclose(fp);
if(r == dSize)
{
// successfully created a mem snapshot of disk image
bytes = dBytes;
size = dSize;
}
else
free(dBytes);
}
}
#endif
}
return bytes;
}
// Returns a pointer to the buffer containing the contents of the file
// specified by 'path' in the constructor.
// Returns NULL if, the contents of the file couldn't be delivered.
// Possible reasons for a NULL return:
// - The 'path' refers to an existing DIRECTORY on disk
// - Memory couldn't be allocated to hold the file contents
// - There was some sort of error reading the contents of the file
// The buffer returned from this functions is created with malloc()
// but the caller shouldn't free() it.
unsigned char *getBytes()
{
if(bytes)
return bytes;
return refresh();
}
const char *toStr()
{
return (const char *)getBytes();
}
// Write the currently held snapshot out to disk.
// Returns the # of bytes written.
unsigned long putBytes()
{
return flush(bytes, size);
}
// Writes the bytes provided out to the path/file associated with this
// instance and replaces the current memory image a copy of the
// contents of 'newBytes'.
unsigned long putBytes(const unsigned char *newBytes, const unsigned long newSize)
{
unsigned long r = flush(newBytes, newSize);
if(r == newSize)
{
// dispose of old image
if(bytes)
free(bytes);
bytes = 0;
size = 0;
bytes = (unsigned char *)malloc(newSize + 1);
if(bytes)
{
memcpy(bytes, newBytes, newSize);
bytes[newSize] = 0;
size = newSize;
}
}
else
{
getBytes();
}
return r;
}
// Same as putBytes(newBytes, newSize) except that it
// accepts a null terminated string as the buffer.
// The trailing null will not be a part of the new memory
// image or disk file.
unsigned long putBytes(const char *str)
{
return putBytes((const unsigned char *)str, (unsigned long)strlen(str));
}
// Append bytes to disk file.
unsigned long appendBytes(const unsigned char *newBytes, const unsigned long newSize)
{
unsigned long r = 0;
#if defined WIN32 || linux || (defined(__APPLE__) && defined(__GNUC__))
FILE *fp = fopen(path, "a+b");
if(fp)
{
r = (unsigned long)fwrite(newBytes, 1, newSize, fp);
fclose(fp);
}
// dispose of old image and leave the file contents unbuffered
// (hope this works)
if(bytes)
free(bytes);
bytes = 0;
size = 0;
#endif
return r;
}
unsigned long appendBytes(const char *s)
{
return appendBytes((const unsigned char *)s, (unsigned long)strlen(s));
}
// Return the path associated with this instance.
const char *getPath()
{
return path;
}
bool permOwnerWrite()
{
struct stat buf;
int r = lstat(path, &buf );
if(r == 0)
{
#ifdef WIN32
return (buf.st_mode & _S_IWRITE) ? 1 : 0;
#endif
#if defined(linux) || (defined(__APPLE__) && defined(__GNUC__))
return (buf.st_mode & S_IWUSR) ? 1 : 0;
#endif
}
return 0;
}
#if defined WIN32 || linux || (defined(__APPLE__) && defined(__GNUC__))
time_t timeStamp()
{
struct stat buf;
int r = lstat(path, &buf );
if(r == 0)
return buf.st_mtime;
return 0;
}
char *timeStampStr(char *buf, int buflen)
{
time_t t = timeStamp();
char *s = ctime(&t);
strncpy(buf, s, buflen);
buf[buflen - 1] = 0;
return buf;
}
#endif
static int put(const char *path, const char *buf)
{
File f(path);
return f.putBytes(buf);
}
};
#endif // com_sleepless_io_file_cpp