--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/fileutils/src/nativefileiohandler.cpp Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,395 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Handler File IO Operations
+ *
+*/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <unistd.h>
+#include <string>
+
+#include "javacommonutils.h"
+#include "jniarrayutils.h"
+#include "logger.h"
+
+#include "nativefileiohandler.h"
+
+using namespace std;
+using namespace java::util;
+using namespace java::fileutils;
+
+NativeFileIOHandler::NativeFileIOHandler(const std::wstring aName)
+{
+ // Set the current locale to suit unicode for entire process
+ setlocale(LC_ALL, "");
+ mFileName = aName;
+ mFileDescriptor = 0;
+ mClosedTemporarily = false;
+
+ // Setting to -1 implies reading is not being done.
+ // On call to openForReading, set this to 0 and increment on subsequent reads
+ mReadPosition = -1;
+
+ // Setting to -1 implies writing is not being done.
+ // On call to openForWriting, set this to 0 and increment on subsequent writes
+ mWritePosition = -1;
+}
+
+NativeFileIOHandler::~NativeFileIOHandler()
+{
+ // Set the current locale to suit unicode for entire process
+ if (mFileDescriptor)
+ {
+ close(mFileDescriptor);
+ }
+}
+
+long NativeFileIOHandler::skip(const long aOffset)
+{
+ JELOG2(EJavaFile);
+
+ handleReopenCase();
+
+ // lseek can set the offset beyond end of file.
+ // but there will be no scenario where read position goes beyond end of file.
+
+ // First set file offset to read position.
+ int newOffset = lseek(mFileDescriptor, mReadPosition, SEEK_SET);
+
+ if (newOffset < 0)
+ {
+ WLOG1(EJavaFile, "NativeFileIOHandler::skip: Seek failure. %d", errno);
+ return 0;
+ }
+ else
+ {
+ // Now set the file offset in relation to the current read position.
+ newOffset = lseek(mFileDescriptor, aOffset, SEEK_CUR);
+ if (newOffset < 0)
+ {
+ WLOG1(EJavaFile, "NativeFileIOHandler::skip: Seek failure. %d",
+ errno);
+ return 0;
+ }
+ }
+
+ long retVal = newOffset - mReadPosition;
+ mReadPosition = newOffset;
+ return retVal;
+}
+
+int NativeFileIOHandler::readBytes(char* aBuffer, int aLength)
+{
+ JELOG2(EJavaFile);
+
+ // Throws exception in case of errors.
+ handleReopenCase();
+
+ // lseek can set the offset beyond end of file.
+ // but there will be no scenario where read position goes beyond end of file.
+ int error = lseek(mFileDescriptor, mReadPosition, SEEK_SET);
+
+ if (error < 0)
+ {
+ WLOG2(
+ EJavaFile,
+ "NativeFileIOHandler::readBytes:Seek failure. Read aborted:%d : Seek to: %d",
+ errno, mReadPosition);
+ // Errno cannot be thrown in S60. Causes random crashes.
+ // So copy and throw.
+ int err = errno;
+ throw err;
+ }
+
+ int bytesRead = read(mFileDescriptor, aBuffer, aLength);
+ if (bytesRead < 0)
+ {
+ LOG1(EJavaFile, EInfo,
+ "NativeFileIOHandler::readBytes: Read failure: %d", errno);
+ int err = errno;
+ throw err;
+ }
+
+ // Adding 0 does no harm ;-)
+ mReadPosition += bytesRead;
+ return bytesRead;
+}
+
+int NativeFileIOHandler::writeBytes(char* aBuffer, int aLength)
+{
+ JELOG2(EJavaFile);
+
+ // Throws exception in case of error
+ handleReopenCase();
+
+ // lseek can set the offset beyond end of file.
+ // but there will be no scenario where read position goes beyond end of file.
+ int error = lseek(mFileDescriptor, mWritePosition, SEEK_SET);
+ if (error < 0)
+ {
+ WLOG1(
+ EJavaFile,
+ "NativeFileIOHandler::writeBytes: Seek failure. Write aborted: %d",
+ errno);
+ // Errno cannot be thrown in S60. Causes random crashes.
+ // So copy and throw.
+ int err = errno;
+ throw err;
+ }
+
+ int bytesWritten = write(mFileDescriptor, aBuffer, aLength);
+ if (bytesWritten <= 0)
+ {
+ LOG1(EJavaFile, EInfo,
+ "NativeFileIOHandler::writeBytes: Write failure: %d", errno);
+ int err = errno;
+ throw err;
+ }
+
+ mWritePosition += bytesWritten;
+ return bytesWritten;
+}
+
+void NativeFileIOHandler::stopReading()
+{
+ JELOG2(EJavaFile);
+ mReadPosition = -1;
+ closeStream();
+}
+
+void NativeFileIOHandler::stopWriting()
+{
+ JELOG2(EJavaFile);
+ mWritePosition = -1;
+ closeStream();
+}
+
+void NativeFileIOHandler::closeStream()
+{
+ JELOG2(EJavaFile);
+ if ((-1 == mReadPosition) && (-1 == mWritePosition))
+ {
+ close(mFileDescriptor);
+ mFileDescriptor = 0;
+ }
+}
+
+void NativeFileIOHandler::openForReading()
+{
+ JELOG2(EJavaFile);
+
+ if (!mFileDescriptor)
+ {
+ // it will never come here if it is not a file.
+ // so, if there is a trailing slash, remove it.
+ char ch = mFileName.at(mFileName.length() - 1);
+ if (ch == '\\' || ch == '/')
+ {
+ mFileName = mFileName.substr(0, mFileName.length() - 1);
+ }
+
+ char* utf8Name = JavaCommonUtils::wstringToUtf8(mFileName);
+ if (access(utf8Name, R_OK) < 0)
+ {
+ // We do not have write access
+ delete[] utf8Name;
+ ELOG(EJavaFile,
+ "NativeFileUtils::OpenForReading: Exiting in between. no read permission");
+ int error = errno;
+ throw error;
+ }
+ mFileDescriptor = open(utf8Name, O_RDWR);
+
+ // If open fails with Read Write mode, try read mode atleast.
+ if (mFileDescriptor < 0)
+ {
+ mFileDescriptor = open(utf8Name, O_RDONLY);
+ }
+
+ delete[] utf8Name;
+ if (mFileDescriptor < 0)
+ {
+ // There is some problem opening the file. Throw the cause for error.
+ mFileDescriptor = 0;
+ ELOG(
+ EJavaFile,
+ "NativeFileUtils::OpenForReading: Exiting in between unable to open in read only");
+ int error = errno;
+ throw error;
+ }
+ }
+
+ mReadPosition = 0;
+}
+
+void NativeFileIOHandler::openForWriting(const long aOffset)
+{
+ JELOG2(EJavaFile);
+ char* utf8Name = JavaCommonUtils::wstringToUtf8(mFileName);
+
+ if (access(utf8Name, W_OK) < 0)
+ {
+ WLOG(EJavaFile,
+ "NativeFileIOHandler::openForWriting: Access not allowed");
+ // We do not have write access
+ delete[] utf8Name;
+ int error = errno;
+ throw error;
+ }
+
+ if (!mFileDescriptor)
+ {
+ // it will never come here if it is not a file.
+ // so, if there is a trailing slash, remove it.
+ char ch = mFileName.at(mFileName.length() - 1);
+ if (ch == '\\' || ch == '/')
+ {
+ mFileName = mFileName.substr(0, mFileName.length() - 1);
+ }
+
+ mFileDescriptor = open(utf8Name, O_RDWR);
+
+ if (mFileDescriptor < 0)
+ {
+ delete[] utf8Name;
+ mFileDescriptor = 0;
+ int error = errno;
+ throw error;
+ }
+ }
+
+ mWritePosition = 0;
+ if (aOffset > 0)
+ {
+ // We will need to stat the file and find out its size just to make sure
+ // lseek does not set the offset to beyond end of file.
+ struct stat fileStat;
+ int error = lstat(utf8Name, &fileStat);
+
+ if (error < 0)
+ {
+ int error = errno;
+ throw error;
+ }
+ long fileSize = fileStat.st_size;
+
+ if (aOffset >= fileSize)
+ {
+ // Move to end of file
+ if (lseek(mFileDescriptor, 0, SEEK_END) < 0)
+ {
+ delete[] utf8Name;
+ int error = errno;
+ throw error;
+ }
+ mWritePosition = fileSize;
+ }
+ else
+ {
+ // Move to given offset
+ if (lseek(mFileDescriptor, aOffset, SEEK_SET) < 0)
+ {
+ delete[] utf8Name;
+ int error = errno;
+ throw error;
+ }
+ mWritePosition = aOffset;
+ }
+ }
+ delete[] utf8Name;
+}
+
+void NativeFileIOHandler::closeFileToReopen()
+{
+ JELOG2(EJavaFile);
+
+ // We dont try to synchronize here. It must be done from java.
+ // In case of multithreaded apps, set hidden should not be done while read
+ // is in progress.
+ if (mFileDescriptor)
+ {
+ LOG(EJavaFile, EInfo,
+ "NativeFileUtils::closeFileToReopen: Closing already open Files");
+ LOG1(EJavaFile, EInfo, " Current Read Offset: %ld",
+ mReadPosition);
+ LOG1(EJavaFile, EInfo, " Current Write Offset: %ld",
+ mWritePosition);
+ mClosedTemporarily = true;
+ close(mFileDescriptor);
+ mFileDescriptor = 0;
+ }
+}
+
+void NativeFileIOHandler::handleReopenCase()
+{
+ JELOG2(EJavaFile);
+ if (!mClosedTemporarily)
+ {
+ return;
+ }
+
+ if ((-1 == mWritePosition) && (-1 == mReadPosition))
+ {
+ return;
+ }
+
+ if (mWritePosition > -1)
+ {
+ LOG(EJavaFile, EInfo,
+ "NativeFileUtils::handleReopenCase: Reopening for write");
+ long curWritePos = mWritePosition;
+ openForWriting(curWritePos);
+ }
+ else if (mReadPosition > -1)
+ {
+ LOG(EJavaFile, EInfo,
+ "NativeFileUtils::handleReopenCase: Reopening for read");
+ long curReadPos = mReadPosition;
+ openForReading();
+ mReadPosition = curReadPos;
+ }
+
+ LOG(EJavaFile, EInfo, "NativeFileUtils::handleReopenCase: File Open");
+ LOG1(EJavaFile, EInfo, " Setting Read Offset: %ld", mReadPosition);
+ LOG1(EJavaFile, EInfo, " Setting Write Offset: %ld", mWritePosition);
+
+ mClosedTemporarily = false;
+}
+
+long NativeFileIOHandler::available()
+{
+ JELOG2(EJavaFile);
+ char* utf8Name = JavaCommonUtils::wstringToUtf8(mFileName);
+
+ struct stat fileStat;
+ int error = lstat(utf8Name, &fileStat);
+
+ if (error < 0)
+ {
+ int error = errno;
+ throw error;
+ }
+ long fileSize = fileStat.st_size;
+
+ if (mReadPosition > 0)
+ {
+ return (fileSize - mReadPosition);
+ }
+ else
+ {
+ return fileSize;
+ }
+}