commit x64 compilation from lulu cause the other branch dont seems to compile properly at home

This commit is contained in:
2026-07-17 16:08:20 +02:00
parent c0f3eeb00d
commit 0efa4ee6f7
625 changed files with 117283 additions and 4426 deletions
+160
View File
@@ -0,0 +1,160 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "filesystem/data_store.h"
#include "rand/rand.h"
#include "memory/nauto_ptr.h"
using namespace GS;
using namespace GS::IO;
//------------------------------------------------------------------------------
DataStore::Entry *DataStore::GetEntry(const String &id) const
{
ListForeachPtr(Entry *, e, entries)
if (e->id == id)
return e;
return NULL;
}
String DataStore::GetNewId()
{
for ( ; ; ++id_seed)
{
String id = String::Format("store_%012d", id_seed);
if (GetEntry(id) == NULL)
return id;
}
return String();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
size_t DataStore::GetEntrySize(const String &id) const
{
if (Entry *e = GetEntry(id))
return e->size;
return 0;
}
size_t DataStore::GetStoreSize() const
{
size_t size = 0;
ListForeachPtr(Entry *, e, entries)
size += e->size;
return size;
}
size_t DataStore::GetFreeStore() const
{ return limit - GetStoreSize(); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
String DataStore::Reserve(size_t size)
{
Threading::MutexLock lock(&mutex);
if (limit > 0) // enforce size limit
{
size_t store_size = GetStoreSize();
if (size > (limit - store_size))
return String(); // store is full
}
// Reserve a new entry.
Entry *entry = new Entry;
entry->id = GetNewId();
entry->size = size;
entries.Add(entry);
return entry->id;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool DataStore::Store(const String &id, const void *data, size_t size, const char *user)
{
Threading::MutexLock lock(&mutex);
Entry *entry = GetEntry(id);
if ((entry == NULL) || (entry->size != size))
return false; // invalid id/store size
lock.Unlock();
entry->user = user;
AutoPtr <Handle> h(io->Open(id, ModeWrite));
return h.IsValid() && (h->Write(data, size) == size);
}
bool DataStore::Free(const String &id)
{
Threading::MutexLock lock(&mutex);
Entry *entry = GetEntry(id);
if (entry == NULL)
return false; // invalid id
if (!io->Delete(id))
return false;
return entries.Remove(entry);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Store format
//
// 18 bytes - id
// 4 bytes - size in bytes
// -----------------------------
bool DataStore::Load(const char *path)
{
AutoPtr <Handle> h(io->Open(path));
if (h.IsNull())
return true; // nothing to restore
entries.Clear();
char id[18];
while (!h->IsEOF())
{
if (h->Read((void *)id, 18) != 18)
return false;
Entry *e = new Entry;
e->id.Set(id, id + 18);
e->size = h->Read <size_t> ();
uint user_data_size = h->Read <uint> ();
if (!e->user.Allocate(user_data_size))
return false;
h->Read((void *)e->user.c_str(), user_data_size);
entries.Add(e);
}
return true;
}
bool DataStore::Save(const char *path)
{
AutoPtr <Handle> h(io->Open(path, ModeWrite));
if (h.IsNull())
return false;
ListForeachPtr(Entry *, e, entries)
{
h->Write(e->id.c_str(), 18);
h->Write(&e->size, 4);
uint user_data_size = e->user.Len();
h->Write(user_data_size);
if (user_data_size > 0)
h->Write(e->user.c_str(), user_data_size);
}
return true;
}
//------------------------------------------------------------------------------
+218
View File
@@ -0,0 +1,218 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "filesystem/filesystem.h"
#include "filesystem/io_handle.h"
#include "log/log.h"
#if __PLATFORM_POSIX__
#include <unistd.h>
#include <sys/stat.h>
#elif __PLATFORM_WINDOWS__
#include <direct.h>
#endif
#include "filesystem/io_cfile.h"
#include "memory/nauto_ptr.h"
using GS::String;
using namespace GS::IO;
//------------------------------------------------------------------------------
bool Filesystem::Exists(const char *uri) const
{
AutoPtr <Handle> h(Open(uri));
return h.IsValid();
}
size_t Filesystem::FileSize(const char *uri) const
{
AutoPtr <Handle> h(Open(uri));
return h.IsNull() ? 0 : h->GetSize();
}
bool Filesystem::FileLoad(const char *uri, GS::Array <char> &buffer, bool verbose) const
{
AutoPtr <Handle> h(Open(uri));
if (h.IsNull())
{
if (verbose)
__LOG_W__ << "Failed to open '" << uri << "'.\n";
return false;
}
// Warning: Do not load through IO::Base::FileLoad. That would create another handle!
size_t size = h->GetSize();
if (!buffer.Allocate(size))
__ERR__(__LOG_W__ << "Failed to allocate memory to load '" << uri << "'.\n", false)
return asbool(h->Read(buffer.c_ptr(), size) == size);
}
bool Filesystem::FileSave(const char *uri, const GS::Array <char> &buffer) const
{
AutoPtr <Handle> h(Open(uri, ModeWrite));
if (h.IsNull())
__ERR__(__LOG_W__ << "Failed to open '" << uri << "'.\n", false)
return asbool(h->Write(buffer.c_ptr(), buffer.GetSize()) == buffer.GetSize());
}
bool Filesystem::FileCopy(const char *src, const char *dst) const
{
Array <char> buffer;
return FileLoad(src, buffer) && FileSave(dst, buffer);
}
bool Filesystem::FileMove(const char *src, const char *dst) const
{
Array <char> buffer;
return FileLoad(src, buffer) && FileSave(dst, buffer) && Delete(src);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
String Filesystem::MapToAbsolute(const char *uri) const
{
String _uri(uri);
ListForeachPtr(MountPoint *, m, mount_list)
if (_uri.StartsWith(m->mount_point))
return m->io_sys->MapToAbsolute(_uri.Mid(m->mount_point.Len())).CleanFilePath();
ListForeachPtr(Base *, i, root_mount)
{
AutoPtr <Handle> h(i->Open(_uri));
if (h.IsValid())
return i->MapToAbsolute(_uri).CleanFilePath();
}
return _uri;
}
String Filesystem::StripRootPath(const char *path) const
{
String _path(path);
_path.FileCleanName();
ListForeachPtr(Base *, i, root_mount)
{
String rpath = i->MapToRelative(_path);
if (!rpath.IsEmpty())
if (rpath != _path)
return rpath[0] == '/' ? rpath.Mid(1) : rpath; // Ensure no leading '/' remains.
}
return _path;
}
bool Filesystem::Mount(Base *io_sys, const char *mount_point)
{
if (mount_point)
{
ListForeachPtr(MountPoint *, m, mount_list)
if (m->mount_point == mount_point)
{
delete io_sys;
return false;
}
return asbool(mount_list.Prepend(new MountPoint(mount_point, io_sys)));
}
else
{
ListForeachPtr(Base *, i, root_mount)
if (i == io_sys)
__ERR__(__LOG_E__ << "Cannot mount IO system twice as root.\n", false)
return asbool(root_mount.Prepend(io_sys));
}
}
void Filesystem::Unmount(const char *mount_point)
{ Unmount(GetIOSystem(mount_point)); }
void Filesystem::Unmount(Base *io_sys)
{
ListForeachPtr(MountPoint *, m, mount_list)
if (m->io_sys.c_ptr() == io_sys)
mount_list.Remove(m);
ListForeachPtr(Base *, i, root_mount)
if (i == io_sys)
root_mount.Remove(i);
}
void Filesystem::UnmountAll()
{
ListForeachPtr(MountPoint *, m, mount_list)
mount_list.Remove(m);
while (List <Base *> ::Item *m = root_mount.GetRoot())
root_mount.Remove(m);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Base *Filesystem::GetIOSystem(const char *mount_point) const
{
ListForeachPtr(MountPoint *, m, mount_list)
if (m->mount_point == mount_point)
return m->io_sys;
return NULL;
}
const char *Filesystem::GetMountPoint(const Base *io_sys) const
{
ListForeachPtr(MountPoint *, m, mount_list)
if (m->io_sys == io_sys)
return m->mount_point;
return NULL;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Handle *Filesystem::Open(const char *uri, Mode mode) const
{
String _uri(uri);
if (_uri.IsEmpty())
return NULL;
ListForeachPtr(MountPoint *, m, mount_list)
if (_uri.StartsWith(m->mount_point))
return m->io_sys->Open(_uri.Mid(m->mount_point.Len()), mode);
ListForeachPtr(Base *, i, root_mount)
if (Handle *h = i->Open(uri, mode))
return h;
return NULL;
}
void Filesystem::Close(Handle *h) const
{
ListForeachPtr(MountPoint *, m, mount_list)
if (m->io_sys.c_ptr() == h->GetIOSystem())
m->io_sys->Close(h);
ListForeachPtr(Base *, i, root_mount)
if (i == h->GetIOSystem())
i->Close(h);
}
bool Filesystem::Delete(const char *uri) const
{
AutoPtr <Handle> h(Open(uri));
if (h.IsValid())
{
Base *io_sys = h->GetIOSystem();
h = NULL;
return io_sys->Delete(uri);
}
else
return asbool(unlink(uri) == 0);
return false;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Filesystem::MkDir(const char *path) const
{
String _path(path);
if (_path.IsEmpty())
return false;
ListForeachPtr(MountPoint *, m, mount_list)
if (_path.StartsWith(m->mount_point))
return m->io_sys->MkDir(_path.Mid(m->mount_point.Len()));
// [EJ] No creation on a root filesystem here!
return false;
}
//------------------------------------------------------------------------------
+984
View File
@@ -0,0 +1,984 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "filesystem/ftp_lib.h"
#include "nstring/nstring.h"
#include "platform_config.h"
#include "alloc/ialloc.h"
#include "log/log.h"
using namespace GS;
#define ConnectionBufferSize 1024
#if __PLATFORM_WINDOWS__
#define SETSOCKOPT_OPTVAL_TYPE (const char *)
#define net_read(x,y,z) recv(x,(char*)y,z,0)
#define net_write(x,y,z) send(x,(char*)y,z,0)
#define net_close closesocket
typedef int socklen_t;
#elif (__PLATFORM_LINUX__ || __PLATFORM_OSX__)
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#define SETSOCKOPT_OPTVAL_TYPE (void *)
#define net_read read
#define net_write write
#define net_close close
#define SOCKET int
#endif
//------------------------------------------------------------------------------
#if (__PLATFORM_WINDOWS__ || __PLATFORM_LINUX__ || __PLATFORM_OSX__)
#define FTP_PROPAGATE_ERROR__(__C__) { State s = __C__; if (s != FtpOk) return s; }
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
//----------------------------
FtpConnection::FtpConnection()
//----------------------------
{
handle = -1;
ready = false;
buffer = 0;
buffer_usage = 0;
}
//---------------------------------------------
void FtpConnection::FreeBuffer()
//---------------------------------------------
{ _safe_delete_array(buffer); }
//-------------------------------------------------
bool FtpConnection::AllocateBuffer()
//-------------------------------------------------
{
FreeBuffer();
return (buffer = new char[ConnectionBufferSize]) != NULL ? true : false;
}
//-------------------------------------------------------------------
FtpLibrary::State FtpLibrary::WaitSocket(FtpConnection *connection)
//-------------------------------------------------------------------
{
fd_set fd, *rfd = NULL, *wfd = NULL;
FD_ZERO(&fd);
if (connection->direction == FtpConnection::Upload)
wfd = &fd;
else
rfd = &fd;
forever
{
FD_SET(connection->handle, &fd);
// 5 seconds timeout.
timeval tv;
tv.tv_sec = 4;
tv.tv_usec = 100000;
SOCKET rv = select((int)(connection->handle + 1), rfd, wfd, NULL, &tv);
if (rv == -1)
return FtpError;
else if (!rv)
return FtpSocketTimeout;
else
break;
/*
if (!IdleCallback())
FtpSocketTimeout;
*/
}
return FtpOk;
}
//---------------------------------------------------
bool FtpLibrary::CheckResponse(char c)
//---------------------------------------------------
{
char match[5];
int length;
if (ReadASCII(response, 256, &master_connection, length) != FtpOk)
return false;
if (response[3] == '-')
{
strncpy(match, response, 3);
match[3] = ' ';
match[4] = '\0';
do
{
if (ReadASCII(response, 256, &master_connection, length) != FtpOk)
return false;
} while (strncmp(response, match, 4));
}
return (response[0] == c) ? true : false;
}
//-------------------------------------------------------
bool FtpLibrary::Connect(const char *host)
//-------------------------------------------------------
{
sockaddr_in sin;
memset(&sin,0,sizeof(sin));
sin.sin_family = AF_INET;
char *lhost = strdup(host), *pnum = strchr(lhost,':');
servent *pse;
if (!pnum)
{
if ((pse = getservbyname("ftp", "tcp")) == NULL)
__ERR__(__LOG__ << "[!] (FTP) Failed to get service port.\n", false)
sin.sin_port = pse->s_port;
}
else
{
*pnum++ = 0;
if (isdigit(*pnum))
sin.sin_port = htons((u_short)atoi(pnum));
else
{
pse = getservbyname(pnum, "tcp");
sin.sin_port = pse->s_port;
}
}
#if __PLATFORM_WINDOWS__
if ((sin.sin_addr.s_addr = inet_addr(lhost)) == -1)
#else
if (!inet_aton(lhost, &sin.sin_addr))
#endif
{
hostent *phe;
if ((phe = gethostbyname(lhost)) == NULL)
__ERR__(__LOG__ << "[!] (FTP) Failed to resolve host.\n", false)
memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length);
}
free(lhost);
//-------------------------------------------------------------------------------------------------------
#define __ConnectError__(_S_)\
{ __LOG__ << _S_; net_close(master_connection.handle); master_connection.handle = 0; return false; }
//-------------------------------------------------------------------------------------------------------
master_connection.handle = (int)socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (master_connection.handle == -1)
__ConnectError__("[!] (FTP) Failed to create socket.\n")
int on = 1;
if (setsockopt(master_connection.handle, SOL_SOCKET, SO_REUSEADDR, SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1)
__ConnectError__("[!] (FTP) Set socket option failed.\n")
if (connect(master_connection.handle, (struct sockaddr *)&sin, sizeof(sin)) == -1)
__ConnectError__("[!] (FTP) Socket failed to connect.\n")
if (!CheckResponse('2'))
__ConnectError__("")
return true;
}
//-----------------------------------------------------------------
bool FtpLibrary::CheckPASVResponse(unsigned char *v)
//-----------------------------------------------------------------
{
sockaddr sa;
socklen_t l = sizeof(sa);
if (getpeername(master_connection.handle, &sa, &l) == -1)
{
net_close(master_connection.handle);
return false;
}
for (int i = 2; i < 6; ++i)
v[i] = sa.sa_data[i];
return true;
}
//---------------------------------------------------------------------------
bool FtpLibrary::FtpSendCmd(const char *command, char expresp)
//---------------------------------------------------------------------------
{
if (!master_connection.handle)
return 0;
char ftp_command[256];
_snprintf(ftp_command, 255, "%s\r\n", command);
if (net_write(master_connection.handle, ftp_command, (int)strlen(ftp_command)) <= 0)
return false;
SendCommandCallback(ftp_command);
return CheckResponse(expresp);
}
//---------------------------------------------------------------------------
bool FtpLibrary::Login(const char *user, const char *password)
//---------------------------------------------------------------------------
{
char ftp_command[64];
// Send user.
_snprintf(ftp_command, 63, "USER %s", user);
if (!FtpSendCmd(ftp_command, '3'))
{
if (*GetLastResponse() == '2')
return true;
return false;
}
// Send password.
_snprintf(ftp_command, 63, "PASS %s", password);
return FtpSendCmd(ftp_command, '2');
}
//------------------------------------------------------------------------------------------------------------------------------
FtpConnection *FtpLibrary::CreatePORTConnection(TransferMode mode, FtpConnection::Direction dir, char *connection_command)
//------------------------------------------------------------------------------------------------------------------------------
{
union
{
sockaddr sa;
sockaddr_in in;
} sin;
// Create the new connection.
FtpConnection *connection = new FtpConnection;
if (!connection)
__ERR__(__LOG__ << "[!] (FTP) Failed to allocate new connection object.\n", NULL)
// Get socket from the master connection.
socklen_t l = sizeof(sin);
if (getsockname(master_connection.handle, &sin.sa, &l) < 0)
return connection;
// Create socket.
connection->handle = (int)socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (connection->handle == -1)
return connection;
// Set socket options.
int on = 1;
if (setsockopt(connection->handle, SOL_SOCKET, SO_REUSEADDR, SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1)
return connection;
linger lng = { 0, 0 };
if (setsockopt(connection->handle, SOL_SOCKET, SO_LINGER, SETSOCKOPT_OPTVAL_TYPE &lng, sizeof(lng)) == -1)
return connection;
// Bind socket.
sin.in.sin_port = 0;
if (
(bind(connection->handle, &sin.sa, sizeof(sin)) == -1) ||
(listen(connection->handle, 1) < 0) ||
(getsockname(connection->handle, &sin.sa, &l) < 0)
)
return connection;
// Open PORT connection.
char ftp_command[256];
_snprintf(ftp_command, 255, "PORT %hhu,%hhu,%hhu,%hhu,%hhu,%hhu",
(unsigned char)sin.sa.sa_data[2],
(unsigned char)sin.sa.sa_data[3],
(unsigned char)sin.sa.sa_data[4],
(unsigned char)sin.sa.sa_data[5],
(unsigned char)sin.sa.sa_data[0],
(unsigned char)sin.sa.sa_data[1] );
if (!FtpSendCmd(ftp_command, '2'))
return connection;
// Handle resuming.
if (offset)
{
_snprintf(ftp_command, 255, "REST %lld", offset);
if (!FtpSendCmd(ftp_command, '3'))
return connection; // TODO allow for a full restart here?
}
// Allocate buffer for binary transaction.
if ((mode == TransferASCII) && !connection->AllocateBuffer())
return connection;
// Finally send the connection command.
if (!FtpSendCmd(connection_command, '1'))
return connection;
// Connection is ready.
connection->direction = dir;
connection->ready = true;
return connection;
}
//------------------------------------------------------------------------------------------------------------------------------
FtpConnection *FtpLibrary::CreatePASVConnection(TransferMode mode, FtpConnection::Direction dir, char *connection_command)
//------------------------------------------------------------------------------------------------------------------------------
{
// Set PASV mode.
if (!FtpSendCmd("PASV", '2'))
return NULL;
// Check server answer.
char *cp = strchr(response,'(');
if (!cp)
return NULL;
unsigned char v[6];
sscanf(++cp, "%hhu,%hhu,%hhu,%hhu,%hhu,%hhu", &v[2], &v[3], &v[4], &v[5], &v[0], &v[1]);
if (correctpasv && !CheckPASVResponse(v))
__ERR__(__LOG__ << "[!] (FTP) Incorrect PASV response.\n", NULL)
struct sockaddr sa;
sa.sa_family = AF_INET;
sa.sa_data[2] = v[2];
sa.sa_data[3] = v[3];
sa.sa_data[4] = v[4];
sa.sa_data[5] = v[5];
sa.sa_data[0] = v[0];
sa.sa_data[1] = v[1];
// Handle resume.
char ftp_command[256];
if (offset)
{
_snprintf(ftp_command, 255, "REST %lld", offset);
if (!FtpSendCmd(ftp_command, '3'))
return NULL;
}
// Create the new connection.
FtpConnection *connection = new FtpConnection;
if (!connection)
__ERR__(__LOG__ << "[!] (FTP) Failed to allocate new connection object.\n", NULL)
// Create socket.
int on = 1;
linger lng = { 0, 0 };
connection->handle = (int)socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
if (
(connection->handle == -1) ||
(setsockopt(connection->handle, SOL_SOCKET, SO_REUSEADDR, SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1) ||
(setsockopt(connection->handle, SOL_SOCKET, SO_LINGER, SETSOCKOPT_OPTVAL_TYPE &lng, sizeof(lng)) == -1)
)
return connection;
// Setup connection.
_snprintf(ftp_command, 255, "%s\r\n", connection_command);
if (net_write(master_connection.handle, ftp_command, (int)strlen(ftp_command)) <= 0)
return connection;
// Connect socket.
if ((connect(connection->handle, &sa, sizeof(sa)) == -1) || !CheckResponse('1'))
return connection;
// Allocate buffer for binary transaction.
if ((mode == TransferASCII) && !connection->AllocateBuffer())
return connection;
// Connection is ready.
connection->direction = dir;
connection->ready = true;
return connection;
}
//----------------------------------------------------------------------------
bool FtpLibrary::FtpAcceptConnection(FtpConnection *connection)
//----------------------------------------------------------------------------
{
// Reset all connections.
fd_set mask;
FD_ZERO(&mask);
FD_SET(master_connection.handle, &mask);
FD_SET(connection->handle, &mask);
// Setup timeout.
timeval tv;
tv.tv_usec = 0;
tv.tv_sec = 30;
// Select handle.
int i = (int)master_connection.handle;
if (i < connection->handle)
i = connection->handle;
i = select((int)(i + 1), &mask, NULL, NULL, &tv);
switch (i)
{
case -1: // Error.
strncpy(response, strerror(errno), sizeof(response));
break;
case 0: // Time out.
strcpy(response, "Time out waiting for connection.");
break;
default:
if (FD_ISSET(connection->handle, &mask))
{
sockaddr addr;
socklen_t l = sizeof(addr);
int handle = (int)accept(connection->handle, &addr, &l);
i = errno;
net_close(connection->handle);
if (handle > 0)
{
connection->handle = handle;
return true;
}
strncpy(response, strerror((int)i), sizeof(response));
connection->handle = 0;
return false;
}
else
if (FD_ISSET(connection->handle, &mask))
CheckResponse('2');
break;
}
net_close(connection->handle);
connection->handle = 0;
return false;
}
//------------------------------------------------------------------------------
FtpConnection *FtpLibrary::CreateConnection(const char *path, AccessType type, TransferMode mode)
{
if (!path && ((type == AccessFileWrite) || (type == AccessFileRead) || (type == AccessFileReadAppend) || (type == AccessFileWriteAppend)))
__ERR__(__LOG__ << "[!] (FTP) Missing path argument.\n", NULL)
// Setup transfer mode.
char ftp_command[256];
_snprintf(ftp_command, 255, "TYPE %c", mode);
if (!FtpSendCmd(ftp_command, '2'))
__ERR__(__LOG__ << "[!] (FTP) Failed to set tranfer mode.\n", NULL)
// Select sub command.
const char *sub_command;
FtpConnection::Direction direction = FtpConnection::Download;
switch (type)
{
case AccessDir:
sub_command = "NLST";
break;
case AccessDirVerbose:
sub_command = "LIST -aL";
break;
case AccessFileReadAppend:
case AccessFileRead:
sub_command = "RETR";
break;
case AccessFileWriteAppend:
case AccessFileWrite:
sub_command = "STOR";
direction = FtpConnection::Upload;
break;
default:
__ERR__(__LOG__ << "[!] (FTP) Invalid access type.\n", NULL)
}
// Append path.
if (path)
_snprintf(ftp_command, 255, "%s %s", sub_command, path);
// Open connection.
FtpConnection *connection = NULL;
switch (connection_mode)
{
case ConnectionPASV:
connection = CreatePASVConnection(mode, direction, ftp_command);
break;
case ConnectionPORT:
connection = CreatePORTConnection(mode, direction, ftp_command);
if (!connection || !connection->ready)
break;
if (!FtpAcceptConnection(connection))
{
CloseConnection(connection);
return NULL;
}
break;
}
return connection;
}
bool FtpLibrary::CloseConnection(FtpConnection *connection)
{
// Sanity check.
if (connection == &master_connection)
return false;
// Purge writing cache.
int length;
if (connection->direction == FtpConnection::Upload)
if (connection->buffer)
WriteASCII(NULL, 0, connection, length);
shutdown(connection->handle, 2);
net_close(connection->handle);
_safe_delete(connection);
return CheckResponse('2');
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
FtpLibrary::State FtpLibrary::ReadASCII(char *buf, int max, FtpConnection *connection, int &total_read_count)
{
/// TODO
// Early exit case.
if (max == 0)
return FtpOk;
if ((connection != &master_connection) && (connection->direction != FtpConnection::Download))
return FtpError;
// Read.
total_read_count = 0;
char *p_buffer = buf;
forever
{
// Check available data on cache.
if (connection->buffer_usage > 0)
{
// Determine read size.
char *eol = (char *)memchr(connection->buffer, '\n', connection->buffer_usage);
int read_size = (int)(eol ? eol - connection->buffer + 1 : connection->buffer_usage);
if (read_size > (max - 1))
read_size = max - 1;
// Perform reading.
memcpy(p_buffer, connection->buffer, read_size);
max -= read_size;
total_read_count += read_size;
p_buffer += read_size;
// Update cache.
if (read_size < connection->buffer_usage)
memcpy(connection->buffer, &connection->buffer[read_size], connection->buffer_usage - read_size);
connection->buffer_usage -= read_size;
// Catch end of buffer.
if ((max == 1) || eol)
{
p_buffer[0] = 0;
break;
}
}
// Wait socket.
FTP_PROPAGATE_ERROR__(WaitSocket(connection))
// Fill cache.
int buffer_left = (ConnectionBufferSize - connection->buffer_usage) - 1,
read_count = net_read(connection->handle, &connection->buffer[connection->buffer_usage], buffer_left);
connection->buffer_usage += read_count;
if (read_count == -1)
__ERR__(__LOG__ << "[!] (FTP) Read error.\n", FtpError)
else if (!read_count)
break; // EOF
}
return FtpOk;
}
FtpLibrary::State FtpLibrary::WriteASCII(char *output, int length, FtpConnection *connection, int &x)
{
/// TODO
if (connection->direction != FtpConnection::Upload)
return FtpError;
FTP_PROPAGATE_ERROR__(WaitSocket(connection))
if ((x = net_write(connection->handle, output, length)) != length)
return FtpError;
return FtpOk;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
FtpLibrary::State FtpLibrary::ReadBinary(void *buf, int max, FtpConnection *connection, int &length)
{
if (connection->direction != FtpConnection::Download)
return FtpError;
FTP_PROPAGATE_ERROR__(WaitSocket(connection))
length = net_read(connection->handle, buf, max);
if (length == -1)
return FtpError;
DataReadCallback(connection);
return FtpOk;
}
FtpLibrary::State FtpLibrary::WriteBinary(void *buf, int len, FtpConnection *connection)
{
if (connection->direction != FtpConnection::Upload)
return FtpError;
FTP_PROPAGATE_ERROR__(WaitSocket(connection))
if (net_write(connection->handle, buf, len) != len)
return FtpError;
DataWriteCallback(connection);
return FtpOk;
}
//------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
FtpLibrary::State FtpLibrary::DataTransfer(const char *localfile, const char *path, AccessType type, TransferMode mode)
//-----------------------------------------------------------------------------------------------------------------------
{
// Open local file or I/O stream.
FILE *file;
if (localfile)
{
const char *access;
switch (type)
{
default:
case AccessDir:
case AccessDirVerbose:
case AccessFileRead:
access = (mode == TransferBinary) ? "wb" : "w";
break;
case AccessFileReadAppend:
access = (mode == TransferBinary) ? "ab" : "a";
break;
case AccessFileWriteAppend:
case AccessFileWrite:
access = (mode == TransferBinary) ? "rb" : "r";
break;
}
file = fopen(localfile, access);
if (!file)
__ERR__(__LOG_E__ << "Failed to open FTP output file.\n", FtpError)
if (type == AccessFileWriteAppend)
if (fseek(file, offset, SEEK_SET))
{
fclose(file);
__ERR__(__LOG_E__ << "Failed to seek in FTP file for transfer.\n", FtpError)
}
}
else
file = (type == AccessFileWrite || type == AccessFileWriteAppend) ? stdin : stdout;
// Create a new connection.
FtpConnection *connection = CreateConnection(path, type, mode);
if (!connection)
{
if (localfile)
fclose(file);
return FtpError;
}
// Perform transfer.
State retv = FtpOk;
GS::Array <char> temp_buffer(ConnectionBufferSize);
int length;
if ((type == AccessFileWrite) || (type == AccessFileWriteAppend))
{
while ((length = (int)fread(temp_buffer, 1, ConnectionBufferSize, file)) > 0)
if (WriteBinary(temp_buffer, length, connection) != FtpOk)
{
retv = FtpError; // FTP write failed.
break;
}
}
else
{
while ((retv = ReadBinary(temp_buffer, ConnectionBufferSize, connection, length)) == FtpOk)
if (!length || (fwrite(temp_buffer, 1, length, file) <= 0))
break; // Done.
}
// Flush file.
fflush(file);
if (localfile)
fclose(file);
CloseConnection(connection);
return retv;
}
//------------------------------------------------------------------------------
FtpLibrary::State FtpLibrary::Download(const char *file, const char *path, TransferMode mode, int _offset)
{
offset = _offset;
if (!offset)
return DataTransfer(file, path, AccessFileRead, mode);
else return DataTransfer(file, path, AccessFileReadAppend, mode);
}
FtpLibrary::State FtpLibrary::Upload(const char *file, const char *path, TransferMode mode, int _offset)
{
offset = _offset;
if (!offset)
return DataTransfer(file, path, AccessFileWrite, mode);
else return DataTransfer(file, path, AccessFileWriteAppend, mode);
}
//------------------------------------------------------------------------------
//------------------------------------
bool FtpLibrary::Quit()
//------------------------------------
{
if (!master_connection.handle)
return true;
bool r = FtpSendCmd("QUIT", '2');
net_close(master_connection.handle);
master_connection.handle = 0;
return r;
}
//------------------------------------------------------------------------------
bool FtpLibrary::DeleteFile(const char *path)
{ return FtpSendCmd(String::Format("DELE %s", path).c_str(), '2'); }
bool FtpLibrary::ChangeDirectory(const char *path)
{ return FtpSendCmd(String::Format("CWD %s", path).c_str(), '2'); }
bool FtpLibrary::UpDirectory()
{ return FtpSendCmd("CDUP", '2'); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
int FtpLibrary::GetFileSize(const char *path, TransferMode mode)
//------------------------------------------------------------------------------
{
int rs, sz = -1;
if ( FtpSendCmd(String::Format("TYPE %c", mode).c_str(), '2') &&
FtpSendCmd(String::Format("SIZE %s", path).c_str(), '2') &&
(sscanf(response, "%d %d", &rs, &sz) == 2) )
return sz;
return -1;
}
//----------------------------------------------------------------------------
bool FtpLibrary::Nlst(const char *outputfile, const char *path)
//----------------------------------------------------------------------------
{
offset = 0;
return DataTransfer(outputfile, path, FtpLibrary::AccessDir, FtpLibrary::TransferASCII) == FtpOk ? true : false;
}
//------------------------------------------------------------------------------
FtpLibrary::FtpLibrary()
{
#if __PLATFORM_WINDOWS__
WSADATA wsa;
if (WSAStartup(MAKEWORD(1, 1), &wsa))
__LOG__ << "[!] (FTP) WINSOCK startup error.\n";
#endif
connection_mode = ConnectionPORT;
master_connection.AllocateBuffer();
//
offset = 0;
correctpasv = false;
}
FtpLibrary::~FtpLibrary()
{ Quit(); }
//------------------------------------------------------------------------------
#endif
/*
int FtpLibrary::Site(const char *cmd)
{
char buf[256];
if ((strlen(cmd) + 7) > sizeof(buf)) return 0;
sprintf(buf,"SITE %s",cmd);
if (!FtpSendCmd(buf,'2',mp_ftphandle)) return 0;
return 1;
}
int FtpLibrary::Raw(const char *cmd)
{
char buf[256];
strncpy(buf, cmd, 256);
if (!FtpSendCmd(buf,'2',mp_ftphandle)) return 0;
return 1;
}
int FtpLibrary::SysType(char *buf, int max)
{
int l = max;
char *b = buf;
char *s;
if (!FtpSendCmd("SYST",'2',mp_ftphandle)) return 0;
s = &mp_ftphandle->response[4];
while ((--l) && (*s != ' ')) *b++ = *s++;
*b++ = '\0';
return 1;
}
int FtpLibrary::Mkdir(const char *path)
{
char buf[256];
if ((strlen(path) + 6) > sizeof(buf)) return 0;
sprintf(buf,"MKD %s",path);
if (!FtpSendCmd(buf,'2', mp_ftphandle)) return 0;
return 1;
}
int FtpLibrary::Rmdir(const char *path)
{
char buf[256];
if ((strlen(path) + 6) > sizeof(buf)) return 0;
sprintf(buf,"RMD %s",path);
if (!FtpSendCmd(buf,'2',mp_ftphandle)) return 0;
return 1;
}
int FtpLibrary::Pwd(char *path, int max)
{
int l = max;
char *b = path;
char *s;
if (!FtpSendCmd("PWD",'2',mp_ftphandle)) return 0;
s = strchr(mp_ftphandle->response, '"');
if (s == NULL) return 0;
s++;
while ((--l) && (*s) && (*s != '"')) *b++ = *s++;
*b++ = '\0';
return 1;
}
int FtpLibrary::Dir(const char *outputfile, const char *path)
{
mp_ftphandle->offset = 0;
return FtpXfer(outputfile, path, mp_ftphandle, FtpLibrary::dirverbose, FtpLibrary::ascii);
}
int FtpLibrary::ModDate(const char *path, char *dt, int max)
{
char buf[256];
int rv = 1;
if ((strlen(path) + 7) > sizeof(buf)) return 0;
sprintf(buf,"MDTM %s",path);
if (!FtpSendCmd(buf,'2',mp_ftphandle)) rv = 0;
else strncpy(dt, &mp_ftphandle->response[4], max);
return rv;
}
int FtpLibrary::Rename(const char *src, const char *dst)
{
char cmd[256];
if (((strlen(src) + 7) > sizeof(cmd)) || ((strlen(dst) + 7) > sizeof(cmd))) return 0;
sprintf(cmd,"RNFR %s",src);
if (!FtpSendCmd(cmd,'3',mp_ftphandle)) return 0;
sprintf(cmd,"RNTO %s",dst);
if (!FtpSendCmd(cmd,'2',mp_ftphandle)) return 0;
return 1;
}
void FtpLibrary::SetConnmode(connmode mode)
{
mp_ftphandle->cmode = mode;
}
ftphandle* FtpLibrary::RawOpen(const char *path, accesstype type, transfermode mode)
{
int ret;
ftphandle* datahandle;
ret = CreateConnection(path, type, mode, mp_ftphandle, &datahandle);
if (ret) return datahandle;
else return NULL;
}
int FtpLibrary::RawClose(ftphandle* handle)
{
return FtpClose(handle);
}
int FtpLibrary::RawWrite(void* buf, int len, ftphandle* handle)
{
return FtpWrite(buf, len, handle);
}
int FtpLibrary::RawRead(void* buf, int max, ftphandle* handle)
{
return FtpRead(buf, max, handle);
}
*/
+59
View File
@@ -0,0 +1,59 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "filesystem/io_base.h"
#include "filesystem/io_handle.h"
#include "memory/nauto_ptr.h"
#include "nstring/nstring.h"
#include "hash/nsha1.h"
#include "log/log.h"
using GS::String;
using namespace GS::IO;
//------------------------------------------------------------------------------
bool Base::FileLoad(const char *uri, GS::Array <char> &buffer)
{
AutoPtr <Handle> h(Open(uri));
if (h.IsNull())
return false;
size_t size = h->GetSize();
if (!buffer.Allocate(size))
return false;
return asbool(h->Read(buffer.c_ptr(), size) == size);
}
bool Base::FileSave(const char *uri, const GS::Array <char> &buffer)
{
AutoPtr <Handle> h(Open(uri, ModeWrite));
if (h.IsNull())
return false;
return asbool(h->Write(buffer.c_ptr(), buffer.GetSize()) == buffer.GetSize());
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Base::Exists(const char *uri)
{
AutoPtr <Handle> h(Open(uri, ModeRead));
return h.IsValid();
}
String Base::Hash(const char *uri)
{
Array <char> data;
return FileLoad(uri, data) ? SHA1::ComputeHexa(data) : String();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
String Base::MapToAbsolute(const char *uri) const
{ return String(uri); }
String Base::MapToRelative(const char *path) const
{ return String(path); }
//------------------------------------------------------------------------------
+130
View File
@@ -0,0 +1,130 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "filesystem/io_buffer.h"
#include "log/log.h"
#include "ntypes.h"
using namespace GS::IO;
//------------------------------------------------------------------------------
uint Buffer::GetCaps() const { return io->GetCaps(); }
Handle *Buffer::Open(const char *path, Mode mode)
{
AutoPtr <Handle> io_h(io->Open(path, mode));
if (io_h.IsNull())
return NULL;
AutoPtr <BufferHandle> b_h(new BufferHandle(this, io_h));
if (b_h.IsNull())
return NULL;
if (!b_h->read_buffer.buffer.Allocate(read_buffer_size))
return NULL;
b_h->size = io_h->GetSize();
io_h.Detach();
return b_h.Detach();
}
void Buffer::Close(Handle *h)
{
if (BufferHandle *b_h = (BufferHandle *)h)
b_h->handle = NULL;
}
bool Buffer::Delete(const char *path) { return io->Delete(path); }
size_t Buffer::Tell(Handle *h) { return ((BufferHandle *)h)->pos; }
size_t Buffer::Seek(Handle *h, ptrdiff_t offset, SeekRef seek)
{
if (BufferHandle *c_h = (BufferHandle *)h)
{
switch (seek)
{
case SeekStart:
c_h->pos = Types::Clamp <ptrdiff_t> (offset, 0, c_h->size);
break;
case SeekCurrent:
c_h->pos = Types::Clamp <ptrdiff_t> (c_h->pos + offset, 0, c_h->size);
break;
case SeekEnd:
c_h->pos = Types::Clamp <ptrdiff_t> (c_h->size + offset, 0, c_h->size);
break;
}
return 0;
}
return size_t(-1);
}
size_t Buffer::Read(Handle *h, void *data, size_t size)
{
// __LOG_V__ << "Buffer::Read: size = " << size << ".\n";
size_t read_size = 0;
if (BufferHandle *b_h = (BufferHandle *)h)
{
while (read_size < size)
{
ptrdiff_t buffer_pos = (b_h->pos + read_size) - b_h->read_buffer.start_pos;
if ((buffer_pos >= 0) && (buffer_pos < ptrdiff_t(b_h->read_buffer.usage)))
{
ptrdiff_t copy_size = Types::Min <ptrdiff_t> (b_h->read_buffer.usage - buffer_pos, size - read_size);
Memory::Copy((char *)data + read_size, b_h->read_buffer.buffer.c_ptr() + buffer_pos, copy_size);
// __LOG_V__ << "Buffer read: pos = " << buffer_pos << ", size = " << copy_size << ".\n";
read_size += copy_size;
}
else // refill cache
{
b_h->read_buffer.start_pos = b_h->pos + read_size;
if (b_h->read_buffer.start_pos >= b_h->size)
{
b_h->read_buffer.usage = 0;
break; // EJ 01/05: Improves EOF performance for the OGG streaming interface which makes many out of bound calls.
}
io->Seek(b_h->handle, b_h->read_buffer.start_pos, SeekStart);
b_h->read_buffer.usage = io->Read(b_h->handle, b_h->read_buffer.buffer.c_ptr(), b_h->read_buffer.buffer.GetSize());
// __LOG_V__ << "Buffer fill: pos = " << b_h->read_buffer.start_pos << ", size = " << b_h->read_buffer.usage << ".\n";
if (b_h->read_buffer.usage == 0)
break; // EOF
}
}
b_h->pos += read_size;
}
return read_size;
}
size_t Buffer::Write(Handle *h, const void *data, size_t size)
{
if (BufferHandle *b_h = (BufferHandle *)h)
{
size_t write_size = io->Write(b_h->handle, data, size);
b_h->pos += write_size;
return write_size;
}
return 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
GS::String Buffer::Hash(const char *path)
{ return io->Hash(path); } // [EJ] Do not perform a FileLoad here, IO::Buffer is typically sitting in front of a slow IO backend which potentially optimizes hash transfer.
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Buffer::MkDir(const char *path)
{ return io->MkDir(path); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Buffer::Buffer(Base *base, size_t read_size, size_t write_size) : io(base)
{
read_buffer_size = Types::Clamp <size_t> (read_size, 0, Units::MB(16));
write_buffer_size = Types::Clamp <size_t> (write_size, 0, Units::MB(16));
}
//------------------------------------------------------------------------------
+280
View File
@@ -0,0 +1,280 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "filesystem/io_cache.h"
#include "hash/nsha1.h"
#include "platform.h"
#include "log/log.h"
#include "ntypes.h"
using namespace GS::IO;
//------------------------------------------------------------------------------
struct FreeEntry // should be in ReserveOnStore but local type on template is prohibited until C++0x
{
Cache::Entry *entry;
int score;
FreeEntry(Cache::Entry *e, int s) : entry(e), score(s) {}
static int ComputeScore(const Cache::Entry *e, size_t request_size, const GS::Time &ctime)
{
int time_bonus = (int)(ctime - e->last_use).toSec();
int size_bonus = e->size - request_size;
return time_bonus + size_bonus / 8;
}
static int CompareScore(FreeEntry *a, FreeEntry *b)
{ return b->score - a->score; }
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
GS::String Cache::ReserveOnStore(size_t size)
{
String id = store.Reserve(size);
if (!id.IsEmpty())
return id;
// Build a list of reference free entries.
Time ctime = Platform::Get().GetTime();
// No need to drop anything if the request can't fit anyway...
size_t total_freeable_store = 0;
ListForeachPtr(Entry *, e, entries)
if (e->refc == 0)
total_freeable_store += e->size;
if (size > (store.GetFreeStore() + total_freeable_store))
return "";
// Drop entries until the request fits in the store.
List <FreeEntry *> free_entries;
ListForeachPtr(Entry *, e, entries)
if (e->refc == 0)
free_entries.Add(new FreeEntry(e, FreeEntry::ComputeScore(e, size, ctime)));
free_entries.MergeSort(FreeEntry::CompareScore);
ListForeachPtr(FreeEntry *, e, free_entries)
{
__LOG_V__ << "IO::Cache: Disposing of cache entry '" << e->entry->path << "' (score: " << e->score << ").\n";
DeleteCacheEntry(e->entry);
id = store.Reserve(size);
if (!id.IsEmpty())
break;
}
ListDeleteAllPtr(FreeEntry *, free_entries)
store.Save();
return id;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Cache::Entry *Cache::GetCacheEntry(const char *path) const
{
ListForeachPtr(Entry *, entry, entries)
if (entry->path == path)
return entry;
return NULL;
}
Cache::Entry *Cache::CreateCacheEntry(const char *path)
{
__LOG_V__ << "Create cache entry for '" << path << "'.\n";
Array <char> data;
if (!io->FileLoad(path, data))
return NULL;
AutoPtr <Entry> entry(new Entry);
if (entry.IsNull())
return NULL;
entry->path = path;
entry->id = ReserveOnStore(data.GetSize());
if (entry->id.IsEmpty())
return NULL; // store full
Entry *e = entry.Detach();
entries.Add(e);
return UpdateCacheEntry(e, &data) ? e : NULL;
}
bool Cache::UpdateCacheEntry(Entry *entry, GS::Array <char> *preloaded_data)
{
__LOG_V__ << "Update cache entry for '" << entry->path << "'.\n";
Array <char> data;
if (preloaded_data)
data.Transfer(*preloaded_data);
else
if (!io->FileLoad(entry->path, data))
return false;
// Check current store entry size.
if (store.GetEntrySize(entry->id) != data.GetSize())
{
store.Free(entry->id);
entry->id = ReserveOnStore(data.GetSize());
if (entry->id.IsEmpty())
return false; // store is full
}
// Update store data.
if (!store.Store(entry->id, data.c_ptr(), data.GetSize(), entry->path))
return false;
store.Save();
entry->hash = SHA1::ComputeHexa(data);
entry->size = data.GetSize();
return true;
}
bool Cache::DeleteCacheEntry(Entry *entry)
{
if (entry->refc > 0)
return false;
store.Free(entry->id);
store.Save();
return entries.Remove(entry);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint Cache::GetCaps() const { return io->GetCaps(); }
Handle *Cache::Open(const char *path, Mode mode)
{
if (mode == ModeRead)
{
Threading::MutexLock lock(&mutex);
// Update cache.
Entry *entry = GetCacheEntry(path);
if (entry)
{
__LOG_V__ << "Entry match for '" << path << "'.\n";
if (entry->hash != io->Hash(path))
{
__LOG_V__ << "Hash mismatch for '" << path << "'.\n";
if (entry->refc > 0)
__LOG_W__ << "IO::Cache: Support file '" << entry->path << "' has changed but its cached version is in use and cannot be updated.\n";
else
{
if (!UpdateCacheEntry(entry)) // contention risk here due to the mutex lock and a potentially long update (eg. networked fs)
DeleteCacheEntry(entry);
// Check for a match in updated cache.
entry = GetCacheEntry(path);
}
}
}
else
entry = CreateCacheEntry(path);
// Return handler to store fs.
if (entry)
{
__LOG_V__ << "Opening '" << path << "' from cache.\n";
entry->last_use = Platform::Get().GetTime();
entry->refc++;
return new CacheHandle(this, path, store.GetIO()->Open(entry->id, mode));
}
}
// Direct access to the underlying fs.
return io->Open(path, mode);
}
void Cache::Close(Handle *h)
{
if (CacheHandle *c_h = (CacheHandle *)h)
{
Threading::MutexLock lock(&mutex);
if (Entry *entry = GetCacheEntry(c_h->path))
entry->refc--;
c_h->handle = NULL;
}
}
bool Cache::Delete(const char *path)
{
/*
[EJ] Minor synchronization issue warning.
If a cached handle is already in use and the support fs file is deleted
the cached handle will remain valid. Further open requests will then
unexpectedly succeed as long as a single cached handler remains open.
The correct fix would be to prevent deleting a support file as long as
a cached entry with a non-zero reference count exists for it.
*/
return io->Delete(path);
}
size_t Cache::Tell(Handle *h)
{ return ((CacheHandle *)h)->handle->Tell(); }
size_t Cache::Seek(Handle *h, ptrdiff_t offset, SeekRef seek)
{ return ((CacheHandle *)h)->handle->Seek(offset, seek); }
size_t Cache::Read(Handle *h, void *data, size_t size)
{ return ((CacheHandle *)h)->handle->Read(data, size); }
size_t Cache::Write(Handle *h, const void *data, size_t size)
{ return ((CacheHandle *)h)->handle->Write(data, size); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Cache::SynchronizeWithStore(const char *store_path)
{
if (!store.Load(store_path))
return false;
entries.Clear();
__LOG_H__ << "IO::Cache: Synchronizing with store.\n";
ListForeachPtr(DataStore::Entry *, e, store.GetEntries())
{
Entry *entry = new Entry;
entry->id = e->id;
entry->size = e->size;
entry->path = e->user;
entry->hash = store.GetIO()->Hash(entry->id);
entries.Add(entry);
}
__LOG__ << "Done, " << entries.GetCount() << " entries synchronized.\n";
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Cache::MkDir(const char *path)
{ return io->MkDir(path); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Cache::Cache(Base *base, Base *store_io, size_t store_size) : io(base), store(store_io, store_size) {}
//------------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CacheHandle::~CacheHandle()
{ GetIOSystem()->Close(this); }
//-----------------------------------------------------------------------------
+137
View File
@@ -0,0 +1,137 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#if __PLATFORM_POSIX__
#include <unistd.h>
#include <sys/stat.h>
#elif __PLATFORM_WINDOWS__
#include <direct.h>
#endif
#include "filesystem/io_cfile.h"
#include "memory/nauto_ptr.h"
using GS::String;
using namespace GS::IO;
//------------------------------------------------------------------------------
void CFile::SetRootPath(const char *_root)
{ root = _root; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint CFile::GetCaps() const
{
uint flags = CanRead | CanWrite | CanSeek | CanMkDir;
#ifndef __PLATFORM_WINDOWS__
flags |= IsCaseSensitive;
#endif
return flags;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
String CFile::MapToAbsolute(const char *uri) const
{
if (!root.IsEmpty())
return root + "/" + uri;
return String(uri);
}
String CFile::MapToRelative(const char *path) const
{
String _path(path);
if (!root.IsEmpty() && _path.StartsWith(root, GetCaps() & IsCaseSensitive ? String::CaseSensitive : String::CaseInsensitive))
return _path.Mid(root.Len());
return _path;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Handle *CFile::Open(const char *path, Mode mode)
{
String _path(root.IsEmpty() ? path : (root + "/" + path).c_str()),
_access(mode == ModeRead ? "rb" : "wb");
AutoPtr <CFileHandle> h(new CFileHandle(this));
#if __PLATFORM_WINDOWS__
if (h->file = _wfopen((const wchar_t *)_path.toUcs2().c_ptr(), (const wchar_t *)_access.toUcs2().c_ptr()))
return h.Detach();
#else
if ((h->file = fopen(_path, _access)) != NULL)
return h.Detach();
#endif
return NULL;
}
void CFile::Close(Handle *h)
{
if (CFileHandle *ch = (CFileHandle *)h)
if (ch->file)
fclose(ch->file);
}
bool CFile::Delete(const char *uri)
{ return asbool(unlink(root + "/" + uri) == 0); }
size_t CFile::Seek(Handle *h, ptrdiff_t offset, SeekRef ref)
{
if (CFileHandle *ch = (CFileHandle *)h)
if (ch->file)
{
int c_seek[] = { SEEK_SET, SEEK_CUR, SEEK_END };
return fseek(ch->file, offset, c_seek[ref]);
}
return (size_t)-1;
}
size_t CFile::Tell(Handle *h)
{
if (CFileHandle *ch = (CFileHandle *)h)
if (ch->file)
return ftell(ch->file);
return (size_t)-1;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
size_t CFile::Read(Handle *h, void *b, size_t size)
{
if (CFileHandle *ch = (CFileHandle *)h)
if (ch->file)
return fread(b, 1, size, ch->file);
return 0;
}
size_t CFile::Write(Handle *h, const void *b, size_t size)
{
if (CFileHandle *ch = (CFileHandle *)h)
if (ch->file)
return fwrite(b, size, 1, ch->file) * size;
return 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool CFile::MkDir(const char *path)
{
String _path(root.IsEmpty() ? path : (root + "/" + path).c_str());
bool r = false;
#if __PLATFORM_WINDOWS__
r = _wmkdir((const wchar_t *)_path.toUcs2().c_ptr()) == 0;
#else
r = mkdir(path, 01777) == 0;
#endif
return r;
}
//------------------------------------------------------------------------------
CFile::CFile(const char *root_path)
{ SetRootPath(root_path); }
//------------------------------------------------------------------------------
CFileHandle::CFileHandle(Base *io) : Handle(io)
{ file = NULL; }
CFileHandle::~CFileHandle()
{ GetIOSystem()->Close(this); }
//------------------------------------------------------------------------------
+173
View File
@@ -0,0 +1,173 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "filesystem/io_crypto.h"
using namespace GS::IO;
//------------------------------------------------------------------------------
uint Crypto::GetCaps() const
{ return wrapped_io->GetCaps(); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Crypto::Encrypt(GS::Array <char> &data)
{
size_t len = key.Len();
for (size_t n = 0; n < data.GetSize(); ++n)
data[(int)n] = data[(int)n] ^ key[(int)(n % len)];
}
void Crypto::Decrypt(GS::Array <char> &data)
{
size_t len = key.Len();
for (size_t n = 0; n < data.GetSize(); ++n)
data[(int)n] = data[(int)n] ^ key[(int)(n % len)];
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Handle *Crypto::Open(const char *path, Mode mode)
{
/*
When opening a file in read mode, the wrapped io file is decrypted and
stored in the cached io file system for further access.
When opening a file in write mode, the file is first created in clear
on the cached io then encrypted and committed to the wrapped io.
*/
Handle *h = NULL;
switch (mode)
{
case ModeRead:
{
// Load wrapped IO file.
AutoPtr <Handle> _h(wrapped_io->Open(path, mode));
if (_h.IsNull())
break;
size_t size = _h->GetSize();
Array <char> data(size);
if (data.IsNull())
break;
if (_h->Read(data.c_ptr(), size) != size)
break;
// Decrypt buffer.
Decrypt(data);
// Write decrypted content to cache IO.
if ((h = cache_io->Open(path, ModeWrite)) != NULL)
h->Write(data.c_ptr(), size);
_safe_delete(h);
h = cache_io->Open(path, mode);
}
break;
case ModeWrite:
h = cache_io->Open(path, mode);
break;
default: break;
}
return h ? new CryptoHandle(this, h, path, mode) : NULL;
}
void Crypto::Close(Handle *_h)
{
if (CryptoHandle *h = (CryptoHandle *)_h)
{
h->cached_h = NULL;
switch (h->io_mode)
{
case ModeRead:
cache_io->Delete(h->path);
break;
case ModeWrite:
{
// Retrieve the whole cached file content and drop it from the cache IO.
h->cached_h = cache_io->Open(h->path);
size_t size = h->cached_h->GetSize();
Array <char> data(size);
if (data.IsValid())
h->cached_h->Read(data.c_ptr(), size);
h->cached_h = NULL;
cache_io->Delete(h->path);
// Encrypt buffer.
Encrypt(data);
// Commit file to the wrapped IO.
AutoPtr <Handle> _h(wrapped_io->Open(h->path, ModeWrite));
if (_h.IsValid())
_h->Write(data.c_ptr(), size);
}
break;
default: break;
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Crypto::Delete(const char *path)
{ return wrapped_io->Delete(path); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
size_t Crypto::Tell(Handle *_h)
{
if (CryptoHandle *h = (CryptoHandle *)_h)
return h->cached_h->Tell();
return (size_t)-1;
}
size_t Crypto::Seek(Handle *_h, ptrdiff_t offset, SeekRef seek)
{
if (CryptoHandle *h = (CryptoHandle *)_h)
return h->cached_h->Seek(offset, seek);
return (size_t)-1;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
size_t Crypto::Read(Handle *_h, void *p, size_t s)
{
if (CryptoHandle *h = (CryptoHandle *)_h)
return h->cached_h->Read(p, s);
return 0;
}
size_t Crypto::Write(Handle *_h, const void *p, size_t s)
{
if (CryptoHandle *h = (CryptoHandle *)_h)
return h->cached_h->Write(p, s);
return 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Crypto::MkDir(const char *path)
{ return wrapped_io->MkDir(path); }
//------------------------------------------------------------------------------
Crypto::Crypto(Base *_io, const char *_key) : wrapped_io(_io)
{
cache_io = new Memory;
key = _key;
}
//------------------------------------------------------------------------------
CryptoHandle::CryptoHandle(Base *io, Handle *h, const char *_path, Mode mode) : Handle(io), cached_h(h), path(_path), io_mode(mode)
{}
CryptoHandle::~CryptoHandle()
{ GetIOSystem()->Close(this); }
//------------------------------------------------------------------------------
@@ -0,0 +1,141 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#if __PLATFORM_POSIX__
#include <unistd.h>
#endif
#include "filesystem/io_dispatcher.h"
#include "memory/nauto_ptr.h"
using namespace GS;
using namespace GS::IO;
//------------------------------------------------------------------------------
bool Dispatcher::AddDispatch(Base *fs, const char *prefix)
{
if (prefix)
{
DispatchFS *d = new DispatchFS;
if (!d)
return false;
d->fs = fs;
d->prefix = prefix;
mounts.Add(d);
}
else
roots.Add(fs);
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint Dispatcher::GetCaps() const
{
uint flags = CanRead | CanWrite | CanSeek;
#ifndef __PLATFORM_WINDOWS__
flags |= IsCaseSensitive;
#endif
return flags;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Base *Dispatcher::Dispatch(String &uri, Mode mode)
{
ListForeachPtr(DispatchFS *, d, mounts)
if (uri.StartsWith(d->prefix))
{
uri = uri.Mid(d->prefix.Len());
return d->fs;
}
// Root FS make no sense for write operations.
if (mode == ModeRead)
ListForeachPtr(Base *, d, roots)
if (d->Exists(uri))
return d;
return NULL;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Handle *Dispatcher::Open(const char *uri, Mode mode)
{
String _uri(uri);
Base *base = Dispatch(_uri, mode);
if (!base)
return NULL;
Handle *h = base->Open(_uri, mode);
return h ? new DispatcherHandle(this, h) : NULL;
}
void Dispatcher::Close(Handle *h)
{
if (DispatcherHandle *dh = (DispatcherHandle *)h)
dh->handle->GetIOSystem()->Close(dh->handle);
}
bool Dispatcher::Delete(const char *uri)
{ return false; }
size_t Dispatcher::Seek(Handle *h, ptrdiff_t offset, SeekRef ref)
{
if (DispatcherHandle *dh = (DispatcherHandle *)h)
return dh->handle->GetIOSystem()->Seek(dh->handle, offset, ref);
return (size_t)-1;
}
size_t Dispatcher::Tell(Handle *h)
{
if (DispatcherHandle *dh = (DispatcherHandle *)h)
return dh->handle->GetIOSystem()->Tell(dh->handle);
return (size_t)-1;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
size_t Dispatcher::Read(Handle *h, void *b, size_t size)
{
if (DispatcherHandle *dh = (DispatcherHandle *)h)
return dh->handle->GetIOSystem()->Read(dh->handle, b, size);
return 0;
}
size_t Dispatcher::Write(Handle *h, const void *b, size_t size)
{
if (DispatcherHandle *dh = (DispatcherHandle *)h)
return dh->handle->GetIOSystem()->Write(dh->handle, b, size);
return 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Dispatcher::MkDir(const char *path)
{
String _path(path);
if (Base *base = Dispatch(_path, ModeWrite))
return base->MkDir(_path);
return false;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
String Dispatcher::Hash(const char *uri)
{
String _uri(uri);
if (Base *base = Dispatch(_uri, ModeRead))
return base->Hash(_uri);
return String();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
DispatcherHandle::DispatcherHandle(Base *io, Handle *h) : Handle(io), handle(h)
{}
DispatcherHandle::~DispatcherHandle()
{ GetIOSystem()->Close(this); }
//------------------------------------------------------------------------------
+58
View File
@@ -0,0 +1,58 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include <string.h>
#include "filesystem/io_handle.h"
#include "filesystem/io_base.h"
using namespace GS::IO;
//------------------------------------------------------------------------------
size_t Handle::GetSize()
{
size_t p = Tell();
Seek(0, Base::SeekEnd);
size_t s = Tell();
Seek(p, Base::SeekStart);
return s;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Handle::IsEOF()
{ return Tell() >= GetSize(); }
size_t Handle::Rewind()
{ return Seek(0, Base::SeekStart); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
size_t Handle::Tell()
{ return io_sys.IsValid() ? io_sys->Tell(this) : 0; }
size_t Handle::Seek(ptrdiff_t offset, Base::SeekRef seek_ref)
{ return io_sys.IsValid() ? io_sys->Seek(this, offset, seek_ref) : 0; }
size_t Handle::Read(void *p, size_t size)
{ return io_sys.IsValid() ? io_sys->Read(this, p, size) : 0; }
size_t Handle::Write(const void *p, size_t size)
{ return io_sys.IsValid() ? io_sys->Write(this, p, size) : 0; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Handle &Handle::operator << (const char *s)
{
if (s)
Write(s, strlen(s));
return *this;
}
Handle &Handle::operator << (char *s)
{ return *this << ((const char *)s); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Handle::Handle(Base *io) : io_sys(io) {}
Handle::~Handle() {}
//------------------------------------------------------------------------------
@@ -0,0 +1,80 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "filesystem/io_handle_segment.h"
using namespace GS::IO;
//------------------------------------------------------------------------------
size_t HandleSegment::GetSize()
{ return size; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
size_t HandleSegment::Tell()
{ return cursor; }
size_t HandleSegment::Seek(ptrdiff_t offset, Base::SeekRef ref)
{
switch (ref)
{
case Base::SeekStart:
cursor = offset;
break;
case Base::SeekCurrent:
cursor += offset;
break;
case Base::SeekEnd:
cursor = size - offset;
break;
}
if (cursor > size)
{
cursor = 0;
return (size_t)-1;
}
return 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/*
IO segment must always restore the original handle position and act as
transparently as possible.
*/
size_t HandleSegment::Read(void *b, size_t s)
{
size_t o = 0;
size_t t = handle->Tell();
if (!handle->Seek(offset + cursor, Base::SeekStart))
{
if (s > (size - cursor))
s = size - cursor;
o = handle->Read(b, s);
cursor += o;
}
handle->Seek(t, Base::SeekStart);
return o;
}
size_t HandleSegment::Write(const void *b, size_t s)
{
size_t o = 0;
size_t t = handle->Tell();
if (!handle->Seek(offset + cursor, Base::SeekStart))
{
o = handle->Write(b, s);
cursor += o;
}
handle->Seek(t, Base::SeekStart);
return o;
}
//------------------------------------------------------------------------------
+132
View File
@@ -0,0 +1,132 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "filesystem/io_memory.h"
using namespace GS::IO;
//------------------------------------------------------------------------------
uint Memory::GetCaps() const
{ return CanRead | CanWrite | CanSeek| IsCaseSensitive; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Handle *Memory::Open(const char *uri, Mode mode)
{
switch (mode)
{
case ModeRead:
ListForeachPtr(MemoryFile *, f, fat)
if (f->uri == uri)
return new MemoryHandle(this, f, mode);
break;
case ModeWrite:
{
MemoryFile *f_entry = NULL;
ListForeachPtr(MemoryFile *, f, fat)
if (f->uri == uri)
{
f_entry = f;
break;
}
if (!f_entry)
fat.Add(f_entry = new MemoryFile(uri));
return f_entry ? new MemoryHandle(this, f_entry, mode) : NULL;
}
break;
default: break;
}
return NULL;
}
void Memory::Close(Handle *h)
{ /* Nothing to be done. */ }
bool Memory::Delete(const char *uri)
{
ListForeachPtr(MemoryFile *, f, fat)
if (f->uri == uri)
return fat.Remove(f);
return false;
}
size_t Memory::Tell(Handle *h)
{
if (MemoryHandle *_h = (MemoryHandle *)h)
if (_h->file)
return _h->cursor;
return (size_t)-1;
}
size_t Memory::Seek(Handle *h, ptrdiff_t offset, SeekRef seek_ref)
{
if (MemoryHandle *_h = (MemoryHandle *)h)
if (_h->file)
{
switch (seek_ref)
{
case SeekStart:
_h->cursor = Types::Clamp <ptrdiff_t> (offset, 0, _h->file->size);
break;
case SeekCurrent:
_h->cursor = Types::Clamp <ptrdiff_t> (_h->cursor + offset, 0, _h->file->size);
break;
case SeekEnd:
_h->cursor = Types::Clamp <ptrdiff_t> (_h->file->size - offset, 0, _h->file->size);
break;
}
return 0;
}
return (size_t)-1;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
size_t Memory::Read(Handle *h, void *ptr, size_t size)
{
size_t read_size = 0;
if (MemoryHandle *_h = (MemoryHandle *)h)
if (_h->file && (_h->mode == ModeRead))
{
read_size = Types::Min <ptrdiff_t> (size, _h->file->size - _h->cursor);
GS::Memory::Copy(ptr, &_h->file->data[(int)_h->cursor], read_size);
_h->cursor += read_size;
}
return read_size;
}
size_t Memory::Write(Handle *h, const void *ptr, size_t size)
{
size_t write_size = 0;
if (MemoryHandle *_h = (MemoryHandle *)h)
if (_h->file && (_h->mode == ModeWrite))
{
size_t req_size = _h->cursor + size;
if (req_size > _h->file->data.GetSize())
if (!_h->file->data.Reallocate(req_size + 16384)) // required size + 16 kilobytes
return 0;
GS::Memory::Copy(&_h->file->data[(int)_h->cursor], ptr, size);
write_size = size;
_h->cursor += size;
_h->file->size = Types::Max(_h->file->size, req_size);
}
return write_size;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
MemoryHandle::MemoryHandle(Base *io, MemoryFile *_file, Mode _mode) : Handle(io), file(_file), cursor(0), mode(_mode)
{}
MemoryHandle::~MemoryHandle()
{ GetIOSystem()->Close(this); }
//------------------------------------------------------------------------------