2007-03-27 17:47:10 +00:00
|
|
|
/*
|
|
|
|
* CiderPress
|
|
|
|
* Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved.
|
|
|
|
* See the file LICENSE for distribution terms.
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* Generic file descriptor class.
|
|
|
|
*/
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "DiskImgPriv.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ===========================================================================
|
2014-11-04 00:26:53 +00:00
|
|
|
* GenericFD utility functions
|
2007-03-27 17:47:10 +00:00
|
|
|
* ===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy "length" bytes from "pSrc" to "pDst". Both GenericFDs should be
|
|
|
|
* seeked to their initial positions.
|
|
|
|
*
|
2014-11-18 05:13:13 +00:00
|
|
|
* If "pCRC" is non-NULL, this computes a CRC32 as it goes, using the zlib
|
2007-03-27 17:47:10 +00:00
|
|
|
* library function.
|
|
|
|
*/
|
|
|
|
/*static*/ DIError
|
|
|
|
GenericFD::CopyFile(GenericFD* pDst, GenericFD* pSrc, di_off_t length,
|
2014-11-04 00:26:53 +00:00
|
|
|
unsigned long* pCRC)
|
2007-03-27 17:47:10 +00:00
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
DIError dierr = kDIErrNone;
|
|
|
|
const int kCopyBufSize = 32768;
|
2014-11-18 05:13:13 +00:00
|
|
|
unsigned char* copyBuf = NULL;
|
2014-11-04 00:26:53 +00:00
|
|
|
int copySize;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI("+++ CopyFile: %ld bytes", (long) length);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-18 05:13:13 +00:00
|
|
|
if (pDst == NULL || pSrc == NULL || length < 0)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrInvalidArg;
|
|
|
|
if (length == 0)
|
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
copyBuf = new unsigned char[kCopyBufSize];
|
2014-11-18 05:13:13 +00:00
|
|
|
if (copyBuf == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrMalloc;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-18 05:13:13 +00:00
|
|
|
if (pCRC != NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
*pCRC = crc32(0L, Z_NULL, 0);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
while (length != 0) {
|
|
|
|
copySize = kCopyBufSize;
|
|
|
|
if (copySize > length)
|
|
|
|
copySize = (int) length;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
dierr = pSrc->Read(copyBuf, copySize);
|
|
|
|
if (dierr != kDIErrNone)
|
|
|
|
goto bail;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-18 05:13:13 +00:00
|
|
|
if (pCRC != NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
*pCRC = crc32(*pCRC, copyBuf, copySize);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
dierr = pDst->Write(copyBuf, copySize);
|
|
|
|
if (dierr != kDIErrNone)
|
|
|
|
goto bail;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
length -= copySize;
|
|
|
|
}
|
2007-03-27 17:47:10 +00:00
|
|
|
|
|
|
|
bail:
|
2014-11-04 00:26:53 +00:00
|
|
|
delete[] copyBuf;
|
|
|
|
return dierr;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ===========================================================================
|
2014-11-04 00:26:53 +00:00
|
|
|
* GFDFile
|
2007-03-27 17:47:10 +00:00
|
|
|
* ===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The stdio functions (fopen/fread/fwrite/fseek/ftell) are buffered and,
|
|
|
|
* therefore, faster for small operations. Unfortunately we need 64-bit
|
|
|
|
* file offsets, and it doesn't look like the Windows stdio stuff will
|
|
|
|
* support it cleanly (e.g. even the _FPOSOFF macro returns a "long").
|
|
|
|
*
|
|
|
|
* Recent versions of Linux have "fseeko", which is like fseek but takes
|
|
|
|
* an off_t, so we can continue to use the FILE* functions there. Under
|
|
|
|
* Windows "lseek" takes a long, so we have to use their specific 64-bit
|
|
|
|
* variant.
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_FSEEKO
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDFile::Open(const char* filename, bool readOnly)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
DIError dierr = kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-18 05:13:13 +00:00
|
|
|
if (fFp != NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrAlreadyOpen;
|
2014-11-18 05:13:13 +00:00
|
|
|
if (filename == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrInvalidArg;
|
2007-03-27 17:47:10 +00:00
|
|
|
if (filename[0] == '\0')
|
|
|
|
return kDIErrInvalidArg;
|
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
delete[] fPathName;
|
|
|
|
fPathName = new char[strlen(filename) +1];
|
|
|
|
strcpy(fPathName, filename);
|
|
|
|
|
|
|
|
fFp = fopen(filename, readOnly ? "rb" : "r+b");
|
2014-11-18 05:13:13 +00:00
|
|
|
if (fFp == NULL) {
|
2014-11-04 00:26:53 +00:00
|
|
|
if (errno == EACCES)
|
|
|
|
dierr = kDIErrAccessDenied;
|
|
|
|
else
|
|
|
|
dierr = ErrnoOrGeneric();
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GDFile Open failed opening '%s', ro=%d (err=%d)",
|
2014-11-04 00:26:53 +00:00
|
|
|
filename, readOnly, dierr);
|
|
|
|
return dierr;
|
|
|
|
}
|
2007-03-27 17:47:10 +00:00
|
|
|
fReadOnly = readOnly;
|
2014-11-04 00:26:53 +00:00
|
|
|
return dierr;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDFile::Read(void* buf, size_t length, size_t* pActual)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
DIError dierr = kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
size_t actual;
|
|
|
|
|
2014-11-18 05:13:13 +00:00
|
|
|
if (fFp == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNotReady;
|
|
|
|
actual = ::fread(buf, 1, length, fFp);
|
2007-03-27 17:47:10 +00:00
|
|
|
if (actual == 0) {
|
|
|
|
if (feof(fFp))
|
|
|
|
return kDIErrEOF;
|
|
|
|
if (ferror(fFp)) {
|
|
|
|
dierr = ErrnoOrGeneric();
|
|
|
|
return dierr;
|
|
|
|
}
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI("MYSTERY FREAD RESULT");
|
2007-03-27 17:47:10 +00:00
|
|
|
return kDIErrInternal;
|
|
|
|
}
|
|
|
|
|
2014-11-18 05:13:13 +00:00
|
|
|
if (pActual == NULL) {
|
2007-03-27 17:47:10 +00:00
|
|
|
if (actual != length) {
|
|
|
|
dierr = ErrnoOrGeneric();
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GDFile Read failed on %d bytes (actual=%d, err=%d)",
|
2007-03-27 17:47:10 +00:00
|
|
|
length, actual, dierr);
|
|
|
|
return dierr;
|
|
|
|
}
|
2014-11-04 00:26:53 +00:00
|
|
|
} else {
|
2007-03-27 17:47:10 +00:00
|
|
|
*pActual = actual;
|
|
|
|
}
|
2014-11-04 00:26:53 +00:00
|
|
|
return dierr;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDFile::Write(const void* buf, size_t length, size_t* pActual)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
DIError dierr = kDIErrNone;
|
|
|
|
|
2014-11-18 05:13:13 +00:00
|
|
|
if (fFp == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNotReady;
|
|
|
|
if (fReadOnly)
|
|
|
|
return kDIErrAccessDenied;
|
2014-11-18 05:13:13 +00:00
|
|
|
assert(pActual == NULL); // not handling this yet
|
2014-11-04 00:26:53 +00:00
|
|
|
if (::fwrite(buf, length, 1, fFp) != 1) {
|
|
|
|
dierr = ErrnoOrGeneric();
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GDFile Write failed on %d bytes (err=%d)", length, dierr);
|
2014-11-04 00:26:53 +00:00
|
|
|
return dierr;
|
|
|
|
}
|
|
|
|
return dierr;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDFile::Seek(di_off_t offset, DIWhence whence)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
DIError dierr = kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
//static const long kOneGB = 1024*1024*1024;
|
|
|
|
//static const long kAlmostTwoGB = kOneGB + (kOneGB -1);
|
|
|
|
|
2014-11-18 05:13:13 +00:00
|
|
|
if (fFp == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNotReady;
|
|
|
|
//assert(offset <= kAlmostTwoGB);
|
|
|
|
//if (::fseek(fFp, (long) offset, whence) != 0) {
|
|
|
|
if (::fseeko(fFp, offset, whence) != 0) {
|
|
|
|
dierr = ErrnoOrGeneric();
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GDFile Seek failed (err=%d)", dierr);
|
2014-11-04 00:26:53 +00:00
|
|
|
return dierr;
|
|
|
|
}
|
|
|
|
return dierr;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
di_off_t
|
|
|
|
GFDFile::Tell(void)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
DIError dierr = kDIErrNone;
|
|
|
|
di_off_t result;
|
|
|
|
|
2014-11-18 05:13:13 +00:00
|
|
|
if (fFp == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNotReady;
|
|
|
|
//result = ::ftell(fFp);
|
|
|
|
result = ::ftello(fFp);
|
|
|
|
if (result == -1) {
|
|
|
|
dierr = ErrnoOrGeneric();
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GDFile Tell failed (err=%d)", dierr);
|
2014-11-04 00:26:53 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
return result;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDFile::Truncate(void)
|
|
|
|
{
|
|
|
|
#if defined(HAVE_FTRUNCATE)
|
2014-11-04 00:26:53 +00:00
|
|
|
int cc;
|
|
|
|
cc = ::ftruncate(fileno(fFp), (long) Tell());
|
|
|
|
if (cc != 0)
|
|
|
|
return kDIErrWriteFailed;
|
2007-03-27 17:47:10 +00:00
|
|
|
#elif defined(HAVE_CHSIZE)
|
2014-11-04 00:26:53 +00:00
|
|
|
assert(false); // not tested
|
|
|
|
int cc;
|
|
|
|
cc = ::chsize(fFd, (long) Tell());
|
|
|
|
if (cc != 0)
|
|
|
|
return kDIErrWriteFailed;
|
2007-03-27 17:47:10 +00:00
|
|
|
#else
|
|
|
|
# error "missing truncate"
|
|
|
|
#endif
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDFile::Close(void)
|
|
|
|
{
|
2014-11-18 05:13:13 +00:00
|
|
|
if (fFp == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNotReady;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GFDFile closing '%s'", fPathName);
|
2014-11-04 00:26:53 +00:00
|
|
|
fclose(fFp);
|
2014-11-18 05:13:13 +00:00
|
|
|
fFp = NULL;
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#else /*HAVE_FSEEKO*/
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDFile::Open(const char* filename, bool readOnly)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
DIError dierr = kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
if (fFd >= 0)
|
|
|
|
return kDIErrAlreadyOpen;
|
2014-11-18 05:13:13 +00:00
|
|
|
if (filename == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrInvalidArg;
|
2007-03-27 17:47:10 +00:00
|
|
|
if (filename[0] == '\0')
|
|
|
|
return kDIErrInvalidArg;
|
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
delete[] fPathName;
|
|
|
|
fPathName = new char[strlen(filename) +1];
|
|
|
|
strcpy(fPathName, filename);
|
|
|
|
|
|
|
|
fFd = open(filename, readOnly ? O_RDONLY|O_BINARY : O_RDWR|O_BINARY, 0);
|
|
|
|
if (fFd < 0) {
|
|
|
|
if (errno == EACCES)
|
|
|
|
dierr = kDIErrAccessDenied;
|
|
|
|
else
|
|
|
|
dierr = ErrnoOrGeneric();
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GDFile Open failed opening '%s', ro=%d (err=%d)",
|
2014-11-04 00:26:53 +00:00
|
|
|
filename, readOnly, dierr);
|
|
|
|
return dierr;
|
|
|
|
}
|
2007-03-27 17:47:10 +00:00
|
|
|
fReadOnly = readOnly;
|
2014-11-04 00:26:53 +00:00
|
|
|
return dierr;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDFile::Read(void* buf, size_t length, size_t* pActual)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
DIError dierr;
|
2007-03-27 17:47:10 +00:00
|
|
|
ssize_t actual;
|
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
if (fFd < 0)
|
|
|
|
return kDIErrNotReady;
|
|
|
|
actual = ::read(fFd, buf, length);
|
2007-03-27 17:47:10 +00:00
|
|
|
if (actual == 0)
|
|
|
|
return kDIErrEOF;
|
2014-11-04 00:26:53 +00:00
|
|
|
if (actual < 0) {
|
2007-03-27 17:47:10 +00:00
|
|
|
dierr = ErrnoOrGeneric();
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GDFile Read failed on %d bytes (actual=%d, err=%d)",
|
2007-03-27 17:47:10 +00:00
|
|
|
length, actual, dierr);
|
|
|
|
return dierr;
|
2014-11-04 00:26:53 +00:00
|
|
|
}
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-18 05:13:13 +00:00
|
|
|
if (pActual == NULL) {
|
2007-03-27 17:47:10 +00:00
|
|
|
if (actual != (ssize_t) length) {
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GDFile Read partial (wanted=%d actual=%d)",
|
2007-03-27 17:47:10 +00:00
|
|
|
length, actual);
|
|
|
|
return kDIErrReadFailed;
|
|
|
|
}
|
2014-11-04 00:26:53 +00:00
|
|
|
} else {
|
2007-03-27 17:47:10 +00:00
|
|
|
*pActual = actual;
|
|
|
|
}
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDFile::Write(const void* buf, size_t length, size_t* pActual)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
DIError dierr;
|
|
|
|
ssize_t actual;
|
|
|
|
|
|
|
|
if (fFd < 0)
|
|
|
|
return kDIErrNotReady;
|
|
|
|
if (fReadOnly)
|
|
|
|
return kDIErrAccessDenied;
|
2014-11-18 05:13:13 +00:00
|
|
|
assert(pActual == NULL); // not handling partial writes yet
|
2014-11-04 00:26:53 +00:00
|
|
|
actual = ::write(fFd, buf, length);
|
|
|
|
if (actual != (ssize_t) length) {
|
|
|
|
dierr = ErrnoOrGeneric();
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GDFile Write failed on %d bytes (actual=%d err=%d)",
|
2014-11-04 00:26:53 +00:00
|
|
|
length, actual, dierr);
|
|
|
|
return dierr;
|
|
|
|
}
|
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDFile::Seek(di_off_t offset, DIWhence whence)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
DIError dierr = kDIErrNone;
|
|
|
|
if (fFd < 0)
|
|
|
|
return kDIErrNotReady;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
|
|
|
#ifdef WIN32
|
2014-11-04 00:26:53 +00:00
|
|
|
__int64 newPosn;
|
|
|
|
const __int64 kFailure = (__int64) -1;
|
|
|
|
newPosn = ::_lseeki64(fFd, (__int64) offset, whence);
|
2007-03-27 17:47:10 +00:00
|
|
|
#else
|
2014-11-04 00:26:53 +00:00
|
|
|
di_off_t newPosn;
|
|
|
|
const di_off_t kFailure = (di_off_t) -1;
|
|
|
|
newPosn = lseek(fFd, offset, whence);
|
2007-03-27 17:47:10 +00:00
|
|
|
#endif
|
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
if (newPosn == kFailure) {
|
|
|
|
assert((unsigned long) offset != 0xccccccccUL); // uninitialized data!
|
|
|
|
dierr = ErrnoOrGeneric();
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GDFile Seek %ld-%lu failed (err=%d)",
|
2014-11-04 00:26:53 +00:00
|
|
|
(long) (offset >> 32), (unsigned long) offset, dierr);
|
|
|
|
}
|
|
|
|
return dierr;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
di_off_t
|
|
|
|
GFDFile::Tell(void)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
DIError dierr = kDIErrNone;
|
|
|
|
di_off_t result;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
if (fFd < 0)
|
|
|
|
return kDIErrNotReady;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
|
|
|
#ifdef WIN32
|
2014-11-04 00:26:53 +00:00
|
|
|
result = ::_lseeki64(fFd, 0, SEEK_CUR);
|
2007-03-27 17:47:10 +00:00
|
|
|
#else
|
2014-11-04 00:26:53 +00:00
|
|
|
result = lseek(fFd, 0, SEEK_CUR);
|
2007-03-27 17:47:10 +00:00
|
|
|
#endif
|
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
if (result == -1) {
|
|
|
|
dierr = ErrnoOrGeneric();
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GDFile Tell failed (err=%d)", dierr);
|
2014-11-04 00:26:53 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
return result;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDFile::Truncate(void)
|
|
|
|
{
|
|
|
|
#if defined(HAVE_FTRUNCATE)
|
2014-11-04 00:26:53 +00:00
|
|
|
int cc;
|
|
|
|
cc = ::ftruncate(fFd, (long) Tell());
|
|
|
|
if (cc != 0)
|
|
|
|
return kDIErrWriteFailed;
|
2007-03-27 17:47:10 +00:00
|
|
|
#elif defined(HAVE_CHSIZE)
|
2014-11-04 00:26:53 +00:00
|
|
|
int cc;
|
|
|
|
cc = ::chsize(fFd, (long) Tell());
|
|
|
|
if (cc != 0)
|
|
|
|
return kDIErrWriteFailed;
|
2007-03-27 17:47:10 +00:00
|
|
|
#else
|
|
|
|
# error "missing truncate"
|
|
|
|
#endif
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDFile::Close(void)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
if (fFd < 0)
|
|
|
|
return kDIErrNotReady;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GFDFile closing '%s'", fPathName);
|
2014-11-04 00:26:53 +00:00
|
|
|
::close(fFd);
|
|
|
|
fFd = -1;
|
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
#endif /*HAVE_FSEEKO else*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ===========================================================================
|
2014-11-04 00:26:53 +00:00
|
|
|
* GFDBuffer
|
2007-03-27 17:47:10 +00:00
|
|
|
* ===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDBuffer::Open(void* buffer, di_off_t length, bool doDelete, bool doExpand,
|
|
|
|
bool readOnly)
|
|
|
|
{
|
2014-11-18 05:13:13 +00:00
|
|
|
if (fBuffer != NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrAlreadyOpen;
|
|
|
|
if (length <= 0)
|
|
|
|
return kDIErrInvalidArg;
|
|
|
|
if (length > kMaxReasonableSize) {
|
|
|
|
// be reasonable
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GFDBuffer refusing to allocate buffer size(long)=%ld bytes",
|
2014-11-04 00:26:53 +00:00
|
|
|
(long) length);
|
|
|
|
return kDIErrInvalidArg;
|
|
|
|
}
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-18 05:13:13 +00:00
|
|
|
/* if buffer is NULL, allocate it ourselves */
|
|
|
|
if (buffer == NULL) {
|
2007-03-27 17:47:10 +00:00
|
|
|
fBuffer = (void*) new char[(int) length];
|
2014-11-18 05:13:13 +00:00
|
|
|
if (fBuffer == NULL)
|
2007-03-27 17:47:10 +00:00
|
|
|
return kDIErrMalloc;
|
|
|
|
} else
|
|
|
|
fBuffer = buffer;
|
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
fLength = (long) length;
|
2007-03-27 17:47:10 +00:00
|
|
|
fAllocLength = (long) length;
|
2014-11-04 00:26:53 +00:00
|
|
|
fDoDelete = doDelete;
|
2007-03-27 17:47:10 +00:00
|
|
|
fDoExpand = doExpand;
|
2014-11-04 00:26:53 +00:00
|
|
|
fReadOnly = readOnly;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
fCurrentOffset = 0;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDBuffer::Read(void* buf, size_t length, size_t* pActual)
|
|
|
|
{
|
2014-11-18 05:13:13 +00:00
|
|
|
if (fBuffer == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNotReady;
|
2007-03-27 17:47:10 +00:00
|
|
|
if (length == 0)
|
|
|
|
return kDIErrInvalidArg;
|
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
if (fCurrentOffset + (long)length > fLength) {
|
2014-11-18 05:13:13 +00:00
|
|
|
if (pActual == NULL) {
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GFDBuffer underrrun off=%ld len=%d flen=%ld",
|
2007-03-27 17:47:10 +00:00
|
|
|
(long) fCurrentOffset, length, (long) fLength);
|
|
|
|
return kDIErrDataUnderrun;
|
|
|
|
} else {
|
|
|
|
/* set *pActual and adjust "length" */
|
|
|
|
assert(fLength >= fCurrentOffset);
|
|
|
|
length = (size_t) (fLength - fCurrentOffset);
|
|
|
|
*pActual = length;
|
|
|
|
|
|
|
|
if (length == 0)
|
|
|
|
return kDIErrEOF;
|
|
|
|
}
|
2014-11-04 00:26:53 +00:00
|
|
|
}
|
2014-11-18 05:13:13 +00:00
|
|
|
if (pActual != NULL)
|
2007-03-27 17:47:10 +00:00
|
|
|
*pActual = length;
|
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
memcpy(buf, (const char*)fBuffer + fCurrentOffset, length);
|
|
|
|
fCurrentOffset += length;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDBuffer::Write(const void* buf, size_t length, size_t* pActual)
|
|
|
|
{
|
2014-11-18 05:13:13 +00:00
|
|
|
if (fBuffer == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNotReady;
|
2014-11-18 05:13:13 +00:00
|
|
|
assert(pActual == NULL); // not handling this yet
|
2014-11-04 00:26:53 +00:00
|
|
|
if (fCurrentOffset + (long)length > fLength) {
|
2007-03-27 17:47:10 +00:00
|
|
|
if (!fDoExpand) {
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GFDBuffer overrun off=%ld len=%d flen=%ld",
|
2007-03-27 17:47:10 +00:00
|
|
|
(long) fCurrentOffset, length, (long) fLength);
|
|
|
|
return kDIErrDataOverrun;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Expand the buffer as needed.
|
|
|
|
*
|
|
|
|
* We delete the old buffer unless "doDelete" is not set, in
|
|
|
|
* which case we just drop the pointer. Anything we allocate
|
|
|
|
* here can and will be deleted; "doDelete" only applies to the
|
|
|
|
* pointer initially passed in.
|
|
|
|
*/
|
|
|
|
if (fCurrentOffset + (long)length <= fAllocLength) {
|
|
|
|
/* fits inside allocated space, so just extend length */
|
|
|
|
fLength = (long) fCurrentOffset + (long)length;
|
|
|
|
} else {
|
|
|
|
/* does not fit, realloc buffer */
|
|
|
|
fAllocLength = (long) fCurrentOffset + (long)length + 8*1024;
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI("Reallocating buffer (new size = %ld)", fAllocLength);
|
2014-11-04 00:26:53 +00:00
|
|
|
assert(fAllocLength < kMaxReasonableSize);
|
2007-03-27 17:47:10 +00:00
|
|
|
char* newBuf = new char[(int) fAllocLength];
|
2014-11-18 05:13:13 +00:00
|
|
|
if (newBuf == NULL)
|
2007-03-27 17:47:10 +00:00
|
|
|
return kDIErrMalloc;
|
|
|
|
|
|
|
|
memcpy(newBuf, fBuffer, fLength);
|
|
|
|
|
|
|
|
if (fDoDelete)
|
|
|
|
delete[] (char*)fBuffer;
|
|
|
|
else
|
|
|
|
fDoDelete = true; // future deletions are okay
|
|
|
|
|
|
|
|
fBuffer = newBuf;
|
|
|
|
fLength = (long) fCurrentOffset + (long)length;
|
|
|
|
}
|
2014-11-04 00:26:53 +00:00
|
|
|
}
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
memcpy((char*)fBuffer + fCurrentOffset, buf, length);
|
|
|
|
fCurrentOffset += length;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDBuffer::Seek(di_off_t offset, DIWhence whence)
|
|
|
|
{
|
2014-11-18 05:13:13 +00:00
|
|
|
if (fBuffer == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNotReady;
|
|
|
|
|
|
|
|
switch (whence) {
|
|
|
|
case kSeekSet:
|
|
|
|
if (offset < 0 || offset >= fLength)
|
|
|
|
return kDIErrInvalidArg;
|
|
|
|
fCurrentOffset = offset;
|
|
|
|
break;
|
|
|
|
case kSeekEnd:
|
|
|
|
if (offset > 0 || offset < -fLength)
|
|
|
|
return kDIErrInvalidArg;
|
|
|
|
fCurrentOffset = fLength + offset;
|
|
|
|
break;
|
|
|
|
case kSeekCur:
|
|
|
|
if (offset < -fCurrentOffset ||
|
|
|
|
offset >= (fLength - fCurrentOffset))
|
|
|
|
{
|
|
|
|
return kDIErrInvalidArg;
|
|
|
|
}
|
|
|
|
fCurrentOffset += offset;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
return kDIErrInvalidArg;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(fCurrentOffset >= 0 && fCurrentOffset <= fLength);
|
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
di_off_t
|
|
|
|
GFDBuffer::Tell(void)
|
|
|
|
{
|
2014-11-18 05:13:13 +00:00
|
|
|
if (fBuffer == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return (di_off_t) -1;
|
|
|
|
return fCurrentOffset;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDBuffer::Close(void)
|
|
|
|
{
|
2014-11-18 05:13:13 +00:00
|
|
|
if (fBuffer == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrNone;
|
|
|
|
|
|
|
|
if (fDoDelete) {
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GFDBuffer closing and deleting");
|
2014-11-04 00:26:53 +00:00
|
|
|
delete[] (char*) fBuffer;
|
|
|
|
} else {
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GFDBuffer closing");
|
2014-11-04 00:26:53 +00:00
|
|
|
}
|
2014-11-18 05:13:13 +00:00
|
|
|
fBuffer = NULL;
|
2014-11-04 00:26:53 +00:00
|
|
|
|
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
/*
|
|
|
|
* ===========================================================================
|
2014-11-04 00:26:53 +00:00
|
|
|
* GFDWinVolume
|
2007-03-27 17:47:10 +00:00
|
|
|
* ===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This class is intended for use with logical volumes under Win32. Such
|
|
|
|
* devices must be accessed on 512-byte boundaries, which means no arbitrary
|
|
|
|
* seeks or reads. The device driver doesn't seem too adept at figuring
|
|
|
|
* out how large the device is, either, so we need to work that out for
|
|
|
|
* ourselves. (The standard approach appears to involve examining the
|
|
|
|
* partition map for the logical or physical volume, but we don't have a
|
|
|
|
* partition map to look at.)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Prepare a logical volume device for reading or writing. "deviceName"
|
|
|
|
* must have the form "N:\" for a logical volume or "80:\" for a physical
|
|
|
|
* volume.
|
|
|
|
*/
|
|
|
|
DIError
|
|
|
|
GFDWinVolume::Open(const char* deviceName, bool readOnly)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
DIError dierr = kDIErrNone;
|
2014-11-18 05:13:13 +00:00
|
|
|
HANDLE handle = NULL;
|
2014-11-04 00:26:53 +00:00
|
|
|
//unsigned long kTwoGBBlocks;
|
|
|
|
|
|
|
|
if (fVolAccess.Ready())
|
|
|
|
return kDIErrAlreadyOpen;
|
2014-11-18 05:13:13 +00:00
|
|
|
if (deviceName == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrInvalidArg;
|
2007-03-27 17:47:10 +00:00
|
|
|
if (deviceName[0] == '\0')
|
|
|
|
return kDIErrInvalidArg;
|
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
delete[] fPathName;
|
|
|
|
fPathName = new char[strlen(deviceName) +1];
|
|
|
|
strcpy(fPathName, deviceName);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
Large set of changes to restore CiderPress build.
CiderPress and MDC now compile, and execute far enough to open
their respective "about" boxes, but I doubt they'll do much
more than that.
* Switch from MBCS to UNICODE APIs
Microsoft switched to UTF-16 (by way of UCS-2) a long time ago,
and the support for MBCS seems to be getting phased out. So it's
time to switch to wide strings.
This is a bit awkward for CiderPress because it works with disk
and file archives with 8-bit filenames, and I want NufxLib and
DiskImgLib to continue to work on Linux (which has largely taken
the UTF-8 approach to Unicode). The libraries will continue to
work with 8-bit filenames, with CiderPress/MDC doing the
conversion at the appropriate point.
There were a couple of places where strings from a structure
handed back by one of the libraries were used directly in the UI,
or vice-versa, which is a problem because we have nowhere to
store the result of the conversion. These currently have fixed
place-holder "xyzzy" strings.
All UI strings are now wide.
Various format strings now use "%ls" and "%hs" to explicitly
specify wide and narrow. This doesn't play well with gcc, so
only the Windows-specific parts use those.
* Various updates to vcxproj files
The project-file conversion had some cruft that is now largely
gone. The build now has a common output directory for the EXEs
and libraries, avoiding the old post-build copy steps.
* Added zlib 1.2.8 and nufxlib 2.2.2 source snapshots
The old "prebuilts" directory is now gone. The libraries are now
built as part of building the apps.
I added a minimal set of files for zlib, and a full set for nufxlib.
The Linux-specific nufxlib goodies are included for the benefit of
the Linux utilities, which are currently broken (don't build).
* Replace symbols used for include guards
Symbols with a leading "__" are reserved.
2014-11-10 23:32:55 +00:00
|
|
|
// Create a UNICODE representation of the device name. We may want
|
|
|
|
// to make the argument UNICODE instead, but most of diskimg is 8-bit
|
|
|
|
// character oriented.
|
|
|
|
size_t srcLen = strlen(deviceName) + 1;
|
|
|
|
WCHAR* wdeviceName = new WCHAR[srcLen];
|
|
|
|
size_t convertedChars;
|
|
|
|
mbstowcs_s(&convertedChars, wdeviceName, srcLen, deviceName, _TRUNCATE);
|
|
|
|
dierr = fVolAccess.Open(wdeviceName, readOnly);
|
|
|
|
delete[] wdeviceName;
|
2014-11-04 00:26:53 +00:00
|
|
|
if (dierr != kDIErrNone)
|
|
|
|
goto bail;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
fBlockSize = fVolAccess.GetBlockSize(); // must be power of 2
|
|
|
|
assert(fBlockSize > 0);
|
|
|
|
//kTwoGBBlocks = kTwoGB / fBlockSize;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
unsigned long totalBlocks;
|
|
|
|
totalBlocks = fVolAccess.GetTotalBlocks();
|
|
|
|
fVolumeEOF = (di_off_t)totalBlocks * fBlockSize;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
assert(fVolumeEOF > 0);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
|
|
|
fReadOnly = readOnly;
|
|
|
|
|
|
|
|
bail:
|
2014-11-04 00:26:53 +00:00
|
|
|
return dierr;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDWinVolume::Read(void* buf, size_t length, size_t* pActual)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
DIError dierr = kDIErrNone;
|
2014-11-18 05:13:13 +00:00
|
|
|
unsigned char* blkBuf = NULL;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-18 21:05:15 +00:00
|
|
|
//LOGI(" GFDWinVolume: reading %ld bytes from offset %ld", length,
|
2014-11-04 00:26:53 +00:00
|
|
|
// fCurrentOffset);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
if (!fVolAccess.Ready())
|
|
|
|
return kDIErrNotReady;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
// don't allow reading past the end of file
|
|
|
|
if (fCurrentOffset + (long) length > fVolumeEOF) {
|
2014-11-18 05:13:13 +00:00
|
|
|
if (pActual == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrDataUnderrun;
|
|
|
|
length = (size_t) (fVolumeEOF - fCurrentOffset);
|
|
|
|
}
|
2014-11-18 05:13:13 +00:00
|
|
|
if (pActual != NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
*pActual = length;
|
|
|
|
if (length == 0)
|
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
long advanceLen = length;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
blkBuf = new unsigned char[fBlockSize]; // get this off the heap??
|
|
|
|
long blockIndex = (long) (fCurrentOffset / fBlockSize);
|
|
|
|
int bufOffset = (int) (fCurrentOffset % fBlockSize); // req power of 2
|
|
|
|
assert(blockIndex >= 0);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
/*
|
|
|
|
* When possible, do multi-block reads directly into "buf". The first
|
|
|
|
* and last block may require special handling.
|
|
|
|
*/
|
|
|
|
while (length) {
|
|
|
|
assert(length > 0);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
if (bufOffset != 0 || length < (size_t) fBlockSize) {
|
|
|
|
assert(bufOffset >= 0 && bufOffset < fBlockSize);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
size_t thisCount;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
dierr = fVolAccess.ReadBlocks(blockIndex, 1, blkBuf);
|
|
|
|
if (dierr != kDIErrNone)
|
|
|
|
goto bail;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
thisCount = fBlockSize - bufOffset;
|
|
|
|
if (thisCount > length)
|
|
|
|
thisCount = length;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-18 21:05:15 +00:00
|
|
|
//LOGI(" Copying %d bytes from block %d",
|
2014-11-04 00:26:53 +00:00
|
|
|
// thisCount, blockIndex);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
memcpy(buf, blkBuf + bufOffset, thisCount);
|
|
|
|
length -= thisCount;
|
|
|
|
buf = (char*) buf + thisCount;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
bufOffset = 0;
|
|
|
|
blockIndex++;
|
|
|
|
} else {
|
|
|
|
assert(bufOffset == 0);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
long blockCount = length / fBlockSize;
|
|
|
|
assert(blockCount < 32768);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
dierr = fVolAccess.ReadBlocks(blockIndex, (short) blockCount, buf);
|
|
|
|
if (dierr != kDIErrNone)
|
|
|
|
goto bail;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
length -= blockCount * fBlockSize;
|
|
|
|
buf = (char*) buf + blockCount * fBlockSize;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
blockIndex += blockCount;
|
|
|
|
}
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
}
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
fCurrentOffset += advanceLen;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
|
|
|
bail:
|
2014-11-04 00:26:53 +00:00
|
|
|
delete[] blkBuf;
|
|
|
|
return dierr;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDWinVolume::Write(const void* buf, size_t length, size_t* pActual)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
DIError dierr = kDIErrNone;
|
2014-11-18 05:13:13 +00:00
|
|
|
unsigned char* blkBuf = NULL;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-18 21:05:15 +00:00
|
|
|
//LOGI(" GFDWinVolume: writing %ld bytes at offset %ld", length,
|
2014-11-04 00:26:53 +00:00
|
|
|
// fCurrentOffset);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
if (!fVolAccess.Ready())
|
|
|
|
return kDIErrNotReady;
|
|
|
|
if (fReadOnly)
|
|
|
|
return kDIErrAccessDenied;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
// don't allow writing past the end of the volume
|
|
|
|
if (fCurrentOffset + (long) length > fVolumeEOF) {
|
2014-11-18 05:13:13 +00:00
|
|
|
if (pActual == NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
return kDIErrDataOverrun;
|
|
|
|
length = (size_t) (fVolumeEOF - fCurrentOffset);
|
|
|
|
}
|
2014-11-18 05:13:13 +00:00
|
|
|
if (pActual != NULL)
|
2014-11-04 00:26:53 +00:00
|
|
|
*pActual = length;
|
|
|
|
if (length == 0)
|
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
long advanceLen = length;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
blkBuf = new unsigned char[fBlockSize]; // get this out of the heap??
|
|
|
|
long blockIndex = (long) (fCurrentOffset / fBlockSize);
|
|
|
|
int bufOffset = (int) (fCurrentOffset % fBlockSize); // req power of 2
|
|
|
|
assert(blockIndex >= 0);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
/*
|
|
|
|
* When possible, do multi-block writes directly from "buf". The first
|
|
|
|
* and last block may require special handling.
|
|
|
|
*/
|
|
|
|
while (length) {
|
|
|
|
assert(length > 0);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
if (bufOffset != 0 || length < (size_t) fBlockSize) {
|
|
|
|
assert(bufOffset >= 0 && bufOffset < fBlockSize);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
size_t thisCount;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
dierr = fVolAccess.ReadBlocks(blockIndex, 1, blkBuf);
|
|
|
|
if (dierr != kDIErrNone)
|
|
|
|
goto bail;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
thisCount = fBlockSize - bufOffset;
|
|
|
|
if (thisCount > length)
|
|
|
|
thisCount = length;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-18 21:05:15 +00:00
|
|
|
//LOGI(" Copying %d bytes into block %d (off=%d)",
|
2014-11-04 00:26:53 +00:00
|
|
|
// thisCount, blockIndex, bufOffset);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
memcpy(blkBuf + bufOffset, buf, thisCount);
|
|
|
|
length -= thisCount;
|
|
|
|
buf = (char*) buf + thisCount;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
dierr = fVolAccess.WriteBlocks(blockIndex, 1, blkBuf);
|
|
|
|
if (dierr != kDIErrNone)
|
|
|
|
goto bail;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
bufOffset = 0;
|
|
|
|
blockIndex++;
|
|
|
|
} else {
|
|
|
|
assert(bufOffset == 0);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
long blockCount = length / fBlockSize;
|
|
|
|
assert(blockCount < 32768);
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
dierr = fVolAccess.WriteBlocks(blockIndex, (short) blockCount, buf);
|
|
|
|
if (dierr != kDIErrNone)
|
|
|
|
goto bail;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
length -= blockCount * fBlockSize;
|
|
|
|
buf = (char*) buf + blockCount * fBlockSize;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
blockIndex += blockCount;
|
|
|
|
}
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
}
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-04 00:26:53 +00:00
|
|
|
fCurrentOffset += advanceLen;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
|
|
|
bail:
|
2014-11-04 00:26:53 +00:00
|
|
|
delete[] blkBuf;
|
|
|
|
return dierr;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDWinVolume::Seek(di_off_t offset, DIWhence whence)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
if (!fVolAccess.Ready())
|
|
|
|
return kDIErrNotReady;
|
|
|
|
|
|
|
|
switch (whence) {
|
|
|
|
case kSeekSet:
|
|
|
|
if (offset < 0 || offset >= fVolumeEOF)
|
|
|
|
return kDIErrInvalidArg;
|
|
|
|
fCurrentOffset = offset;
|
|
|
|
break;
|
|
|
|
case kSeekEnd:
|
|
|
|
if (offset > 0 || offset < -fVolumeEOF)
|
|
|
|
return kDIErrInvalidArg;
|
|
|
|
fCurrentOffset = fVolumeEOF + offset;
|
|
|
|
break;
|
|
|
|
case kSeekCur:
|
|
|
|
if (offset < -fCurrentOffset ||
|
|
|
|
offset >= (fVolumeEOF - fCurrentOffset))
|
|
|
|
{
|
|
|
|
return kDIErrInvalidArg;
|
|
|
|
}
|
|
|
|
fCurrentOffset += offset;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
return kDIErrInvalidArg;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(fCurrentOffset >= 0 && fCurrentOffset <= fVolumeEOF);
|
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
di_off_t
|
|
|
|
GFDWinVolume::Tell(void)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
if (!fVolAccess.Ready())
|
|
|
|
return (di_off_t) -1;
|
|
|
|
return fCurrentOffset;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DIError
|
|
|
|
GFDWinVolume::Close(void)
|
|
|
|
{
|
2014-11-04 00:26:53 +00:00
|
|
|
if (!fVolAccess.Ready())
|
|
|
|
return kDIErrNotReady;
|
2007-03-27 17:47:10 +00:00
|
|
|
|
2014-11-18 21:05:15 +00:00
|
|
|
LOGI(" GFDWinVolume closing");
|
2014-11-04 00:26:53 +00:00
|
|
|
fVolAccess.Close();
|
|
|
|
return kDIErrNone;
|
2007-03-27 17:47:10 +00:00
|
|
|
}
|
|
|
|
#endif /*_WIN32*/
|