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::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; }
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 }
void File::Copy (const FilePath &sourcePath, const FilePath &destinationPath, bool preserveTimestamps) { File source; source.Open (sourcePath); File destination; destination.Open (destinationPath, CreateWrite); SecureBuffer buffer (OptimalReadSize); uint64 len; while ((len = source.Read (buffer)) > 0) { destination.Write (buffer, static_cast <size_t> (len)); } if (preserveTimestamps) { destination.Flush(); #ifndef TC_WINDOWS struct stat statData; throw_sys_sub_if (stat (string (sourcePath).c_str(), &statData) == -1, wstring (sourcePath)); struct utimbuf u; u.actime = statData.st_atime; u.modtime = statData.st_mtime; throw_sys_sub_if (utime (string (destinationPath).c_str(), &u) == -1, wstring (destinationPath)); #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 } } } }
MountedFilesystemList CoreSolaris::GetMountedFilesystems (const DevicePath &devicePath, const DirectoryPath &mountPoint) const { MountedFilesystemList mountedFilesystems; FILE *mtab = fopen ("/etc/mnttab", "r"); throw_sys_sub_if (!mtab, "/etc/mnttab"); finally_do_arg (FILE *, mtab, { fclose (finally_arg); });
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)); }
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::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)); }
FilesystemPathType::Enum FilesystemPath::GetType () const { // Strip trailing directory separator wstring path = Path; size_t pos = path.find_last_not_of (L'/'); if (path.size() > 2 && pos != path.size() - 1) path = path.substr (0, pos + 1); struct stat statData; throw_sys_sub_if (stat (StringConverter::ToSingle (path).c_str(), &statData) != 0, Path); if (S_ISREG (statData.st_mode)) return FilesystemPathType::File; if (S_ISDIR (statData.st_mode)) return FilesystemPathType::Directory; if (S_ISCHR (statData.st_mode)) return FilesystemPathType::CharacterDevice; if (S_ISBLK (statData.st_mode)) return FilesystemPathType::BlockDevice; if (S_ISLNK (statData.st_mode)) return FilesystemPathType::SymbolickLink; return FilesystemPathType::Unknown; }
void CoreService::ProcessElevatedRequests () { int pid = fork(); throw_sys_if (pid == -1); if (pid == 0) { try { int f = open ("/dev/null", 0); throw_sys_sub_if (f == -1, "/dev/null"); throw_sys_if (dup2 (f, STDERR_FILENO) == -1); // Wait for sync code while (true) { byte b; throw_sys_if (read (STDIN_FILENO, &b, 1) != 1); if (b != 0x00) continue; throw_sys_if (read (STDIN_FILENO, &b, 1) != 1); if (b != 0x11) continue; throw_sys_if (read (STDIN_FILENO, &b, 1) != 1); if (b == 0x22) break; } ElevatedPrivileges = true; ProcessRequests (STDIN_FILENO, STDOUT_FILENO); _exit (0); } catch (exception &e) { #ifdef DEBUG SystemLog::WriteException (e); #endif } catch (...) { } _exit (1); } }
FilePathList Directory::GetFilePaths (const DirectoryPath &path, bool regularFilesOnly) { DIR *dir = opendir (string (path).c_str()); throw_sys_sub_if (!dir, wstring (path)); finally_do_arg (DIR*, dir, { closedir (finally_arg); });
shared_ptr <VolumeInfo> CoreUnix::MountVolume (MountOptions &options) { CoalesceSlotNumberAndMountPoint (options); if (IsVolumeMounted (*options.Path)) throw VolumeAlreadyMounted (SRC_POS); Cipher::EnableHwSupport (!options.NoHardwareCrypto); shared_ptr <Volume> volume; while (true) { try { volume = OpenVolume ( options.Path, options.PreserveTimestamps, options.Password, options.Keyfiles, options.Protection, options.ProtectionPassword, options.ProtectionKeyfiles, options.SharedAccessAllowed, VolumeType::Unknown, options.UseBackupHeaders, options.PartitionInSystemEncryptionScope ); options.Password.reset(); } catch (SystemException &e) { if (options.Protection != VolumeProtection::ReadOnly && (e.GetErrorCode() == EROFS || e.GetErrorCode() == EACCES || e.GetErrorCode() == EPERM)) { // Read-only filesystem options.Protection = VolumeProtection::ReadOnly; continue; } throw; } break; } if (options.Path->IsDevice()) { if (volume->GetFile()->GetDeviceSectorSize() != volume->GetSectorSize()) throw ParameterIncorrect (SRC_POS); #if defined (TC_LINUX) if (volume->GetSectorSize() != TC_SECTOR_SIZE_LEGACY) { if (options.Protection == VolumeProtection::HiddenVolumeReadOnly) throw UnsupportedSectorSizeHiddenVolumeProtection(); if (options.NoKernelCrypto) throw UnsupportedSectorSizeNoKernelCrypto(); } #endif } // Find a free mount point for FUSE service MountedFilesystemList mountedFilesystems = GetMountedFilesystems (); string fuseMountPoint; for (int i = 1; true; i++) { stringstream path; path << GetTempDirectory() << "/" << GetFuseMountDirPrefix() << i; FilesystemPath fsPath (path.str()); bool inUse = false; foreach_ref (const MountedFilesystem &mf, mountedFilesystems) { if (mf.MountPoint == path.str()) { inUse = true; break; } } if (!inUse) { try { if (fsPath.IsDirectory()) fsPath.Delete(); throw_sys_sub_if (mkdir (path.str().c_str(), S_IRUSR | S_IXUSR) == -1, path.str()); fuseMountPoint = fsPath; break; } catch (...) { if (i > 255) throw TemporaryDirectoryFailure (SRC_POS, StringConverter::ToWide (path.str())); } } } try { FuseService::Mount (volume, options.SlotNumber, fuseMountPoint); } catch (...) { try { DirectoryPath (fuseMountPoint).Delete(); } catch (...) { } throw; } try { // Create a mount directory if a default path has been specified bool mountDirCreated = false; string mountPoint; if (!options.NoFilesystem && options.MountPoint) { mountPoint = *options.MountPoint; #ifndef TC_MACOSX if (mountPoint.find (GetDefaultMountPointPrefix()) == 0 && !options.MountPoint->IsDirectory()) { Directory::Create (*options.MountPoint); try { throw_sys_sub_if (chown (mountPoint.c_str(), GetRealUserId(), GetRealGroupId()) == -1, mountPoint); } catch (ParameterIncorrect&) { } mountDirCreated = true; } #endif } try { try { MountVolumeNative (volume, options, fuseMountPoint); } catch (NotApplicable&) { MountAuxVolumeImage (fuseMountPoint, options); } } catch (...) { if (mountDirCreated) remove (mountPoint.c_str()); throw; } } catch (...) { try { VolumeInfoList mountedVolumes = GetMountedVolumes (*options.Path); if (mountedVolumes.size() > 0) { shared_ptr <VolumeInfo> mountedVolume (mountedVolumes.front()); DismountVolume (mountedVolume); } } catch (...) { } throw; } VolumeInfoList mountedVolumes = GetMountedVolumes (*options.Path); if (mountedVolumes.size() != 1) throw ParameterIncorrect (SRC_POS); VolumeEventArgs eventArgs (mountedVolumes.front()); VolumeMountedEvent.Raise (eventArgs); return mountedVolumes.front(); }
void FilesystemPath::Delete () const { throw_sys_sub_if (remove (string (*this).c_str()) == -1, Path); }
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; }
void File::Flush () const { if_debug (ValidateState()); throw_sys_sub_if (fsync (FileHandle) != 0, wstring (Path)); }
void File::SeekAt (uint64 position) const { if_debug (ValidateState()); throw_sys_sub_if (lseek (FileHandle, position, SEEK_SET) == -1, wstring (Path)); }