diff options
Diffstat (limited to 'Platform/Unix/File.cpp')
-rw-r--r-- | Platform/Unix/File.cpp | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/Platform/Unix/File.cpp b/Platform/Unix/File.cpp new file mode 100644 index 0000000..d69cb1d --- /dev/null +++ b/Platform/Unix/File.cpp @@ -0,0 +1,348 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <utime.h> + +#ifdef TC_LINUX +#include <sys/mount.h> +#endif + +#ifdef TC_BSD +#include <sys/disk.h> +#endif + +#ifdef TC_SOLARIS +#include <stropts.h> +#include <sys/dkio.h> +#endif + +#include <sys/file.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "Platform/File.h" +#include "Platform/TextReader.h" + +namespace TrueCrypt +{ +#if 0 +# define TC_TRACE_FILE_OPERATIONS + + static void TraceFileOperation (int fileHandle, FilePath filePath, bool write, uint64 length, int64 position = -1) + { + string path = filePath; + if (path.empty() || path.find ("truecrypt_aux_mnt") != string::npos) + return; + + stringstream s; + s << path << ": " << (write ? "W " : "R ") << (position == -1 ? lseek (fileHandle, 0, SEEK_CUR) : position) << " (" << length << ")"; + SystemLog::WriteError (s.str()); + } +#endif + + void File::Close () + { + if_debug (ValidateState()); + + if (!SharedHandle) + { + close (FileHandle); + FileIsOpen = false; + + if ((mFileOpenFlags & File::PreserveTimestamps) && Path.IsFile()) + { + struct utimbuf u; + u.actime = AccTime; + u.modtime = ModTime; + + try + { + throw_sys_sub_if (utime (string (Path).c_str(), &u) == -1, wstring (Path)); + } + catch (...) // Suppress errors to allow using read-only files + { +#ifdef DEBUG + throw; +#endif + } + } + } + } + + void File::Delete () + { + Close(); + Path.Delete(); + } + + + void File::Flush () const + { + if_debug (ValidateState()); + throw_sys_sub_if (fsync (FileHandle) != 0, wstring (Path)); + } + + uint32 File::GetDeviceSectorSize () const + { + if (Path.IsDevice()) + { +#ifdef TC_LINUX + int blockSize; + throw_sys_sub_if (ioctl (FileHandle, BLKSSZGET, &blockSize) == -1, wstring (Path)); + return blockSize; + +#elif defined (TC_MACOSX) + uint32 blockSize; + throw_sys_sub_if (ioctl (FileHandle, DKIOCGETBLOCKSIZE, &blockSize) == -1, wstring (Path)); + return blockSize; + +#elif defined (TC_FREEBSD) + u_int sectorSize; + throw_sys_sub_if (ioctl (FileHandle, DIOCGSECTORSIZE, §orSize) == -1, wstring (Path)); + return (uint32) sectorSize; + +#elif defined (TC_SOLARIS) + struct dk_minfo mediaInfo; + throw_sys_sub_if (ioctl (FileHandle, DKIOCGMEDIAINFO, &mediaInfo) == -1, wstring (Path)); + return mediaInfo.dki_lbsize; + +#else +# error GetDeviceSectorSize() +#endif + } + else + throw ParameterIncorrect (SRC_POS); + } + + uint64 File::GetPartitionDeviceStartOffset () const + { +#ifdef TC_LINUX + + // HDIO_GETGEO ioctl is limited by the size of long + TextReader tr ("/sys/block/" + string (Path.ToHostDriveOfPartition().ToBaseName()) + "/" + string (Path.ToBaseName()) + "/start"); + + string line; + tr.ReadLine (line); + return StringConverter::ToUInt64 (line) * GetDeviceSectorSize(); + +#elif defined (TC_MACOSX) + +#ifndef DKIOCGETBASE +# define DKIOCGETBASE _IOR('d', 73, uint64) +#endif + uint64 offset; + throw_sys_sub_if (ioctl (FileHandle, DKIOCGETBASE, &offset) == -1, wstring (Path)); + return offset; + +#elif defined (TC_SOLARIS) + + struct extpart_info partInfo; + throw_sys_sub_if (ioctl (FileHandle, DKIOCEXTPARTINFO, &partInfo) == -1, wstring (Path)); + return partInfo.p_start * GetDeviceSectorSize(); + +#else + throw NotImplemented (SRC_POS); +#endif + } + + uint64 File::Length () const + { + if_debug (ValidateState()); + + // BSD does not support seeking to the end of a device +#ifdef TC_BSD + if (Path.IsBlockDevice() || Path.IsCharacterDevice()) + { +# ifdef TC_MACOSX + uint32 blockSize; + uint64 blockCount; + throw_sys_sub_if (ioctl (FileHandle, DKIOCGETBLOCKSIZE, &blockSize) == -1, wstring (Path)); + throw_sys_sub_if (ioctl (FileHandle, DKIOCGETBLOCKCOUNT, &blockCount) == -1, wstring (Path)); + return blockCount * blockSize; +# else + uint64 mediaSize; + throw_sys_sub_if (ioctl (FileHandle, DIOCGMEDIASIZE, &mediaSize) == -1, wstring (Path)); + return mediaSize; +# endif + } +#endif + off_t current = lseek (FileHandle, 0, SEEK_CUR); + throw_sys_sub_if (current == -1, wstring (Path)); + SeekEnd (0); + uint64 length = lseek (FileHandle, 0, SEEK_CUR); + SeekAt (current); + return length; + } + + void File::Open (const FilePath &path, FileOpenMode mode, FileShareMode shareMode, FileOpenFlags flags) + { +#ifdef TC_LINUX + int sysFlags = O_LARGEFILE; +#else + int sysFlags = 0; +#endif + + switch (mode) + { + case CreateReadWrite: + sysFlags |= O_CREAT | O_TRUNC | O_RDWR; + break; + + case CreateWrite: + sysFlags |= O_CREAT | O_TRUNC | O_WRONLY; + break; + + case OpenRead: + sysFlags |= O_RDONLY; + break; + + case OpenWrite: + sysFlags |= O_WRONLY; + break; + + case OpenReadWrite: + sysFlags |= O_RDWR; + break; + + default: + throw ParameterIncorrect (SRC_POS); + } + + if ((flags & File::PreserveTimestamps) && path.IsFile()) + { + struct stat statData; + throw_sys_sub_if (stat (string (path).c_str(), &statData) == -1, wstring (path)); + AccTime = statData.st_atime; + ModTime = statData.st_mtime; + } + + FileHandle = open (string (path).c_str(), sysFlags, S_IRUSR | S_IWUSR); + throw_sys_sub_if (FileHandle == -1, wstring (path)); + +#if 0 // File locking is disabled to avoid remote filesystem locking issues + try + { + struct flock fl; + memset (&fl, 0, sizeof (fl)); + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + + switch (shareMode) + { + case ShareNone: + fl.l_type = F_WRLCK; + if (fcntl (FileHandle, F_SETLK, &fl) == -1) + throw_sys_sub_if (errno == EAGAIN || errno == EACCES, wstring (path)); + break; + + case ShareRead: + fl.l_type = F_RDLCK; + if (fcntl (FileHandle, F_SETLK, &fl) == -1) + throw_sys_sub_if (errno == EAGAIN || errno == EACCES, wstring (path)); + break; + + case ShareReadWrite: + fl.l_type = (mode == OpenRead ? F_RDLCK : F_WRLCK); + if (fcntl (FileHandle, F_GETLK, &fl) != -1 && fl.l_type != F_UNLCK) + { + errno = EAGAIN; + throw SystemException (SRC_POS, wstring (path)); + } + break; + + case ShareReadWriteIgnoreLock: + break; + + default: + throw ParameterIncorrect (SRC_POS); + } + } + catch (...) + { + close (FileHandle); + throw; + } +#endif // 0 + + Path = path; + mFileOpenFlags = flags; + FileIsOpen = true; + } + + uint64 File::Read (const BufferPtr &buffer) const + { + if_debug (ValidateState()); + +#ifdef TC_TRACE_FILE_OPERATIONS + TraceFileOperation (FileHandle, Path, false, buffer.Size()); +#endif + ssize_t bytesRead = read (FileHandle, buffer, buffer.Size()); + throw_sys_sub_if (bytesRead == -1, wstring (Path)); + + return bytesRead; + } + + uint64 File::ReadAt (const BufferPtr &buffer, uint64 position) const + { + if_debug (ValidateState()); + +#ifdef TC_TRACE_FILE_OPERATIONS + TraceFileOperation (FileHandle, Path, false, buffer.Size(), position); +#endif + ssize_t bytesRead = pread (FileHandle, buffer, buffer.Size(), position); + throw_sys_sub_if (bytesRead == -1, wstring (Path)); + + return bytesRead; + } + + void File::SeekAt (uint64 position) const + { + if_debug (ValidateState()); + throw_sys_sub_if (lseek (FileHandle, position, SEEK_SET) == -1, wstring (Path)); + } + + void File::SeekEnd (int offset) const + { + if_debug (ValidateState()); + + // BSD does not support seeking to the end of a device +#ifdef TC_BSD + if (Path.IsBlockDevice() || Path.IsCharacterDevice()) + { + SeekAt (Length() + offset); + return; + } +#endif + + throw_sys_sub_if (lseek (FileHandle, offset, SEEK_END) == -1, wstring (Path)); + } + + void File::Write (const ConstBufferPtr &buffer) const + { + if_debug (ValidateState()); + +#ifdef TC_TRACE_FILE_OPERATIONS + TraceFileOperation (FileHandle, Path, true, buffer.Size()); +#endif + throw_sys_sub_if (write (FileHandle, buffer, buffer.Size()) != (ssize_t) buffer.Size(), wstring (Path)); + } + + void File::WriteAt (const ConstBufferPtr &buffer, uint64 position) const + { + if_debug (ValidateState()); + +#ifdef TC_TRACE_FILE_OPERATIONS + TraceFileOperation (FileHandle, Path, true, buffer.Size(), position); +#endif + throw_sys_sub_if (pwrite (FileHandle, buffer, buffer.Size(), position) != (ssize_t) buffer.Size(), wstring (Path)); + } +} |