summaryrefslogtreecommitdiff
path: root/indra/llfilesystem/llfilesystem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llfilesystem/llfilesystem.cpp')
-rw-r--r--indra/llfilesystem/llfilesystem.cpp326
1 files changed, 326 insertions, 0 deletions
diff --git a/indra/llfilesystem/llfilesystem.cpp b/indra/llfilesystem/llfilesystem.cpp
new file mode 100644
index 0000000000..4c836c8838
--- /dev/null
+++ b/indra/llfilesystem/llfilesystem.cpp
@@ -0,0 +1,326 @@
+/**
+ * @file filesystem.h
+ * @brief Simulate local file system operations.
+ * @Note The initial implementation does actually use standard C++
+ * file operations but eventually, there will be another
+ * layer that caches and manages file meta data too.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "lldir.h"
+#include "llfilesystem.h"
+#include "llfasttimer.h"
+#include "lldiskcache.h"
+
+const S32 LLFileSystem::READ = 0x00000001;
+const S32 LLFileSystem::WRITE = 0x00000002;
+const S32 LLFileSystem::READ_WRITE = 0x00000003; // LLFileSystem::READ & LLFileSystem::WRITE
+const S32 LLFileSystem::APPEND = 0x00000006; // 0x00000004 & LLFileSystem::WRITE
+
+static LLTrace::BlockTimerStatHandle FTM_VFILE_WAIT("VFile Wait");
+
+LLFileSystem::LLFileSystem(const LLUUID& file_id, const LLAssetType::EType file_type, S32 mode)
+{
+ mFileType = file_type;
+ mFileID = file_id;
+ mPosition = 0;
+ mBytesRead = 0;
+ mMode = mode;
+
+ // This block of code was originally called in the read() method but after comments here:
+ // https://bitbucket.org/lindenlab/viewer/commits/e28c1b46e9944f0215a13cab8ee7dded88d7fc90#comment-10537114
+ // we decided to follow Henri's suggestion and move the code to update the last access time here.
+ if (mode == LLFileSystem::READ)
+ {
+ // build the filename (TODO: we do this in a few places - perhaps we should factor into a single function)
+ std::string id;
+ mFileID.toString(id);
+ const std::string extra_info = "";
+ const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id, mFileType, extra_info);
+
+ // update the last access time for the file if it exists - this is required
+ // even though we are reading and not writing because this is the
+ // way the cache works - it relies on a valid "last accessed time" for
+ // each file so it knows how to remove the oldest, unused files
+ bool exists = gDirUtilp->fileExists(filename);
+ if (exists)
+ {
+ LLDiskCache::getInstance()->updateFileAccessTime(filename);
+ }
+ }
+}
+
+LLFileSystem::~LLFileSystem()
+{
+}
+
+// static
+bool LLFileSystem::getExists(const LLUUID& file_id, const LLAssetType::EType file_type)
+{
+ std::string id_str;
+ file_id.toString(id_str);
+ const std::string extra_info = "";
+ const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id_str, file_type, extra_info);
+
+ llifstream file(filename, std::ios::binary);
+ if (file.is_open())
+ {
+ file.seekg(0, std::ios::end);
+ return file.tellg() > 0;
+ }
+ return false;
+}
+
+// static
+bool LLFileSystem::removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_error /*= 0*/)
+{
+ std::string id_str;
+ file_id.toString(id_str);
+ const std::string extra_info = "";
+ const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id_str, file_type, extra_info);
+
+ LLFile::remove(filename.c_str(), suppress_error);
+
+ return true;
+}
+
+// static
+bool LLFileSystem::renameFile(const LLUUID& old_file_id, const LLAssetType::EType old_file_type,
+ const LLUUID& new_file_id, const LLAssetType::EType new_file_type)
+{
+ std::string old_id_str;
+ old_file_id.toString(old_id_str);
+ const std::string extra_info = "";
+ const std::string old_filename = LLDiskCache::getInstance()->metaDataToFilepath(old_id_str, old_file_type, extra_info);
+
+ std::string new_id_str;
+ new_file_id.toString(new_id_str);
+ const std::string new_filename = LLDiskCache::getInstance()->metaDataToFilepath(new_id_str, new_file_type, extra_info);
+
+ // Rename needs the new file to not exist.
+ LLFileSystem::removeFile(new_file_id, new_file_type, ENOENT);
+
+ if (LLFile::rename(old_filename, new_filename) != 0)
+ {
+ // We would like to return FALSE here indicating the operation
+ // failed but the original code does not and doing so seems to
+ // break a lot of things so we go with the flow...
+ //return FALSE;
+ LL_WARNS() << "Failed to rename " << old_file_id << " to " << new_id_str << " reason: " << strerror(errno) << LL_ENDL;
+ }
+
+ return TRUE;
+}
+
+// static
+S32 LLFileSystem::getFileSize(const LLUUID& file_id, const LLAssetType::EType file_type)
+{
+ std::string id_str;
+ file_id.toString(id_str);
+ const std::string extra_info = "";
+ const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id_str, file_type, extra_info);
+
+ S32 file_size = 0;
+ llifstream file(filename, std::ios::binary);
+ if (file.is_open())
+ {
+ file.seekg(0, std::ios::end);
+ file_size = file.tellg();
+ }
+
+ return file_size;
+}
+
+BOOL LLFileSystem::read(U8* buffer, S32 bytes)
+{
+ BOOL success = FALSE;
+
+ std::string id;
+ mFileID.toString(id);
+ const std::string extra_info = "";
+ const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id, mFileType, extra_info);
+
+ llifstream file(filename, std::ios::binary);
+ if (file.is_open())
+ {
+ file.seekg(mPosition, std::ios::beg);
+
+ file.read((char*)buffer, bytes);
+
+ if (file)
+ {
+ mBytesRead = bytes;
+ }
+ else
+ {
+ mBytesRead = file.gcount();
+ }
+
+ file.close();
+
+ mPosition += mBytesRead;
+ if (mBytesRead)
+ {
+ success = TRUE;
+ }
+ }
+
+ return success;
+}
+
+S32 LLFileSystem::getLastBytesRead()
+{
+ return mBytesRead;
+}
+
+BOOL LLFileSystem::eof()
+{
+ return mPosition >= getSize();
+}
+
+BOOL LLFileSystem::write(const U8* buffer, S32 bytes)
+{
+ std::string id_str;
+ mFileID.toString(id_str);
+ const std::string extra_info = "";
+ const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id_str, mFileType, extra_info);
+
+ BOOL success = FALSE;
+
+ if (mMode == APPEND)
+ {
+ llofstream ofs(filename, std::ios::app | std::ios::binary);
+ if (ofs)
+ {
+ ofs.write((const char*)buffer, bytes);
+
+ mPosition = ofs.tellp(); // <FS:Ansariel> Fix asset caching
+
+ success = TRUE;
+ }
+ }
+ // <FS:Ansariel> Fix asset caching
+ else if (mMode == READ_WRITE)
+ {
+ // Don't truncate if file already exists
+ llofstream ofs(filename, std::ios::in | std::ios::binary);
+ if (ofs)
+ {
+ ofs.seekp(mPosition, std::ios::beg);
+ ofs.write((const char*)buffer, bytes);
+ mPosition += bytes;
+ success = TRUE;
+ }
+ else
+ {
+ // File doesn't exist - open in write mode
+ ofs.open(filename, std::ios::binary);
+ if (ofs.is_open())
+ {
+ ofs.write((const char*)buffer, bytes);
+ mPosition += bytes;
+ success = TRUE;
+ }
+ }
+ }
+ // </FS:Ansariel>
+ else
+ {
+ llofstream ofs(filename, std::ios::binary);
+ if (ofs)
+ {
+ ofs.write((const char*)buffer, bytes);
+
+ mPosition += bytes;
+
+ success = TRUE;
+ }
+ }
+
+ return success;
+}
+
+BOOL LLFileSystem::seek(S32 offset, S32 origin)
+{
+ if (-1 == origin)
+ {
+ origin = mPosition;
+ }
+
+ S32 new_pos = origin + offset;
+
+ S32 size = getSize();
+
+ if (new_pos > size)
+ {
+ LL_WARNS() << "Attempt to seek past end of file" << LL_ENDL;
+
+ mPosition = size;
+ return FALSE;
+ }
+ else if (new_pos < 0)
+ {
+ LL_WARNS() << "Attempt to seek past beginning of file" << LL_ENDL;
+
+ mPosition = 0;
+ return FALSE;
+ }
+
+ mPosition = new_pos;
+ return TRUE;
+}
+
+S32 LLFileSystem::tell() const
+{
+ return mPosition;
+}
+
+S32 LLFileSystem::getSize()
+{
+ return LLFileSystem::getFileSize(mFileID, mFileType);
+}
+
+S32 LLFileSystem::getMaxSize()
+{
+ // offer up a huge size since we don't care what the max is
+ return INT_MAX;
+}
+
+BOOL LLFileSystem::rename(const LLUUID& new_id, const LLAssetType::EType new_type)
+{
+ LLFileSystem::renameFile(mFileID, mFileType, new_id, new_type);
+
+ mFileID = new_id;
+ mFileType = new_type;
+
+ return TRUE;
+}
+
+BOOL LLFileSystem::remove()
+{
+ LLFileSystem::removeFile(mFileID, mFileType);
+
+ return TRUE;
+}