in source/code/scxcorelib/pal/scxfile.cpp [518:778]
int SCXFile::ReadAvailableBytesAsUnsigned(const SCXFilePath& , unsigned char* , size_t , size_t /*= 0*/) {
throw SCXNotSupportedException(L"Reads not supported on windows", SCXSRCLOCATION);
#else
int SCXFile::ReadAvailableBytesAsUnsigned(const SCXFilePath& path, unsigned char* buf, size_t size, size_t offset /*= 0*/) {
int fd = open(SCXFileSystem::EncodePath(path).c_str(),O_RDONLY);
if (-1 == fd) {
return errno;
}
size_t remainder;
void *pDevice = NULL;
#ifdef _SC_PAGESIZE //!< Size of a page in bytes
remainder = offset% sysconf(_SC_PAGESIZE);
#else
remainder = offset% getpagesize();
#endif
//
//For API mmap, the sixth parameter mmapoffset must be a multiple of pagesize.
//
size_t mmapoffset = offset - remainder;
pDevice = mmap(NULL, remainder + size, PROT_READ, MAP_SHARED, fd, mmapoffset);
if (MAP_FAILED == pDevice) {
int ret = errno;
close(fd);
return ret;
}
memcpy(buf, reinterpret_cast<unsigned char*>(pDevice) + remainder, size);
munmap(reinterpret_cast<char*>(pDevice), remainder + size);
close(fd);
return 0;
#endif
}
/*--------------------------------------------------------------*/
/**
Seek get position to absolute position
\param[in] source stream
\param[in] pos Absolute position to seek to.
*/
void SCXFile::SeekG(std::wfstream& source, std::wstreampos pos) {
#if defined(linux) && defined(PF_DISTRO_SUSE) && (PF_MAJOR==9)
// seekg does not seem to work on suse9
// It moves the position pos*4 instead of just pos.
std::wstreampos current = source.tellg();
if (current > pos) {
source.seekg(0);
source.ignore(pos);
} else if (current < pos) {
source.ignore(pos-current);
}
#else
source.seekg(pos);
#endif
}
#if !defined(DISABLE_WIN_UNSUPPORTED)
pthread_mutex_t SCXFile::scxTempFileCountLock=PTHREAD_MUTEX_INITIALIZER;
int SCXFile::scxTempFileCount=0;
/*--------------------------------------------------------------*/
/**
Creates a temp file and writes to it
\param[in] fileContent Content to write to file.
\returns Complete path of newly created file.
*/
SCXFilePath SCXFile::CreateTempFile(const std::wstring& fileContent, const std::wstring& tmpDir /* = "/tmp/" */) {
/**
* The code below behaves as it does because of limitations in the
* various temp file functions.
*
* \li Use the tempnam function to retrieve an "appropriate" directory
* to store files in.
* \li Only use the directory part of what is returned and append a
* pattern to use for creating temporary file.
* \li Use the pattern as argument to mkstemp which is the recommended
* function since it avoids race conditions.
*
*/
SCXFilePath pattern;
#if defined(WIN32)
char* fp = tempnam(0, 0);
if (fp == 0) {
throw SCXInternalErrorException(
UnexpectedErrno(L"Failed to find an appropriate temporary file directory", errno),
SCXSRCLOCATION);
}
try
{
pattern = SCXFileSystem::DecodePath(fp);
}
catch ( SCXCoreLib::SCXException& e )
{
free(fp);
fp = 0;
SCXRETHROW(e, L"Unable to decode file path." );
}
free(fp);
fp = 0;
#else
pattern = SCXFileSystem::DecodePath(StrToUTF8(tmpDir));
if(!SCXCoreLib::SCXDirectory::Exists(pattern))
{
throw SCXCoreLib::SCXFilePathNotFoundException(pattern.GetDirectory(), SCXSRCLOCATION);
}
#endif
std::stringstream ss;
pthread_mutex_lock(&scxTempFileCountLock);
ss<<scxTempFileCount;
scxTempFileCount=(scxTempFileCount+1)%SCXTEMPPREFIXCOUNT;
pthread_mutex_unlock(&scxTempFileCountLock);
std::string tempfileNamePrefix;
ss>>tempfileNamePrefix;
tempfileNamePrefix="scx"+tempfileNamePrefix+"XXXXXX";
pattern.SetFilename(StrFromUTF8(tempfileNamePrefix));
std::string patternString = SCXFileSystem::EncodePath(pattern);
std::vector<char> buf;
buf.resize( patternString.length()+1, 0 );
strcpy(&buf[0], patternString.c_str());
mode_t oldUmask = umask(077);
int fileDescriptor = mkstemp(&buf[0]);
umask(oldUmask);
if (fileDescriptor == -1) {
std::wstring problem(L"Failed to create temporary file from pattern " + pattern.Get());
throw SCXInternalErrorException(UnexpectedErrno(problem, errno), SCXSRCLOCATION);
}
SCXFilePath filepath = SCXFileSystem::DecodePath(&buf[0]);
if ( access(SCRIPTCONTROLLOGFILE, W_OK) != -1 ) {
FILE *fptr = fopen(SCRIPTCONTROLLOGFILE,"a");
if( fptr != NULL ) {
std::string tempFileName = StrToUTF8(filepath.Get());
fprintf(fptr, "%s temporary file created.\n",tempFileName.c_str());
fclose(fptr);
}
}
std::ostringstream fileContentStream;
SCXStream::WriteAsUTF8(fileContentStream, fileContent);
std::string fileContentUTF8 = fileContentStream.str();
ssize_t written = write(fileDescriptor, fileContentUTF8.c_str(), fileContentUTF8.length());
if (written == -1) {
std::wstring problem(L"Failed to write to temporary file " + filepath.Get());
close(fileDescriptor);
throw SCXInternalErrorException(UnexpectedErrno(problem, errno), SCXSRCLOCATION);
}
close(fileDescriptor);
return filepath;
}
#endif
/*--------------------------------------------------------------*/
/**
* Retrieves preferred kind of new line of a particular path. May
* take into account the kind of file system the path refers to
* as well as new lines currently used if the path refers to an
* already existing file.
* \returns Preferred kind of new line
* \note Right now the implementation is simplified, it just returns
* SCXFileSystem::GetDefaultNewLine()
*/
SCXStream::NLF SCXFile::GetPreferredNewLine(const SCXFilePath&) {
return SCXFileSystem::GetDefaultNewLine();
}
/*--------------------------------------------------------------*/
/**
* Writes all lines to a file using preferred kind of new line
* \param[in] target Stream to be written to
* \param[in] lines Lines to be written
* \param[in] mode How to open the file
* No new line is appended after all lines.
* If mode is "append" an extra new line is prepended before the lines.
*/
void SCXFile::WriteAllLines(const SCXFilePath& target, const std::vector<std::wstring>& lines, std::ios_base::openmode mode) {
WriteAllLines(target, lines, mode, GetPreferredNewLine(target));
}
/*--------------------------------------------------------------*/
/**
* Writes all lines to a file using specified kind of new line
* \param[in] target Stream to be written to
* \param[in] lines Lines to be written
* \param[in] mode How to open the file
* \param[in] nlf Kind of new line to write
* No new line is appended after all lines.
* If mode is "append" an extra new line is prepended before the lines.
*/
void SCXFile::WriteAllLines(const SCXFilePath& target, const std::vector<std::wstring>& lines, std::ios_base::openmode mode,
SCXStream::NLF nlf) {
SCXHandle<std::wfstream> stream(OpenWFstream(target, mode));
if (lines.size() > 0) {
if (mode & std::ios_base::app) {
SCXStream::WriteNewLine(*stream, nlf);
}
SCXStream::Write(*stream, lines.at(0));
for (std::wstring::size_type lineNr = 1; lineNr < lines.size(); lineNr++) {
SCXStream::WriteNewLine(*stream, nlf);
SCXStream::Write(*stream, lines.at(lineNr));
}
}
}
/*--------------------------------------------------------------*/
/**
* Writes all lines to a UTF8 encoded file using preferred kind of new line
* \param[in] target Stream to be written to
* \param[in] lines Lines to be written
* \param[in] mode How to open the file
* No new line is appended after all lines.
* If mode is "append" an extra new line is prepended before the lines.
*/
void SCXFile::WriteAllLinesAsUTF8(const SCXFilePath& target,
const std::vector<std::wstring>& lines, std::ios_base::openmode mode) {
WriteAllLinesAsUTF8(target, lines, mode, GetPreferredNewLine(target));
}
/*--------------------------------------------------------------*/
/**
* Writes all lines to a UTF8 encoded file using specified kind of newline
* \param[in] target Stream to be written to
* \param[in] lines Lines to be written
* \param[in] mode How to open the file
* \param[in] nlf Kind of newline to write
* No newline is appended after all lines.
* If mode is "append" an extra newline is prepended before the lines.
*/
void SCXFile::WriteAllLinesAsUTF8(const SCXFilePath& target, const std::vector<std::wstring>& lines, std::ios_base::openmode mode,
SCXStream::NLF nlf) {
SCXHandle<std::fstream> stream(OpenFstream(target, mode));
if (lines.size() > 0) {
if (mode & std::ios_base::app) {
SCXStream::WriteNewLineAsUTF8(*stream, nlf);
}
SCXStream::WriteAsUTF8(*stream, lines.at(0));
for (std::wstring::size_type lineNr = 1; lineNr < lines.size(); lineNr++) {
SCXStream::WriteNewLineAsUTF8(*stream, nlf);
SCXStream::WriteAsUTF8(*stream, lines.at(lineNr));
}
}
}
}