FileBase* FileTable::create_as(const id_type& id, int type) { if (is_readonly()) throw OSException(EROFS); if (m_opened.find(id) != m_opened.end() || m_closed.find(id) != m_closed.end()) throw OSException(EEXIST); std::shared_ptr<FileStream> data_fd, meta_fd; std::tie(data_fd, meta_fd) = m_fio->create(id); auto fb = btree_make_file_from_type( type, data_fd, meta_fd, m_master_key, id, is_auth_enabled(), m_block_size, m_iv_size); m_opened.emplace(id, fb); fb->setref(1); return fb.get(); }
QC_BASE_NAMESPACE_BEGIN //============================================================================== // ThreadLocal::ThreadLocal // /** Default constructor. Uses the operating-system's threading library to allocate a new thread-local variable. The value of the variable is automatically initialized to zero for every thread. */ //============================================================================== ThreadLocal::ThreadLocal() { #if defined(QC_WIN32_THREADS) m_key = ::TlsAlloc(); if(m_key == (DWORD)-1) { throw Win32Exception(::GetLastError()); } #elif defined(QC_POSIX_THREADS) int status = ::pthread_key_create(&m_key, 0); if(status != 0) { throw OSException(status, QC_T("pthread_key_create")); } #endif }
bool SimpleDirectory::add_entry(const std::string& name, const id_type& id, int type) { if (name.size() > MAX_FILENAME_LENGTH) throw OSException(ENAMETOOLONG); auto rv = m_table.emplace(name, std::make_pair(id, type)); if (rv.second) m_dirty = true; return rv.second; }
ssize_t FileBase::getxattr(const char* name, char* value, size_t size) { if (!name) throw OSException(EFAULT); auto true_size = fgetxattr_wrapper(file_descriptor(), name, value, size); if (true_size < 0) throw OSException(errno); if (!value) return true_size; byte meta[XATTR_IV_LENGTH + XATTR_MAC_LENGTH]; auto true_meta_size = fgetxattr_wrapper(m_meta_fd, name, meta, sizeof(meta)); if (true_meta_size < 0) { if (errno == ERANGE) errno = EIO; throw OSException(errno); } auto name_len = strlen(name); std::unique_ptr<byte[]> header(new byte[name_len + ID_LENGTH]); memcpy(header.get(), get_id().data(), ID_LENGTH); memcpy(header.get() + ID_LENGTH, name, name_len); byte* iv = meta; byte* mac = meta + XATTR_IV_LENGTH; byte* ciphertext = reinterpret_cast<byte*>(value); bool success = aes_gcm_decrypt(ciphertext, true_size, header.get(), name_len + ID_LENGTH, get_key().data(), get_key().size(), iv, XATTR_IV_LENGTH, mac, XATTR_MAC_LENGTH, value); if (m_check && !success) throw XattrVerificationException(get_id(), name); return true_size; }
void FileBase::removexattr(const char* name) { #ifdef __APPLE__ auto rc = ::fremovexattr(file_descriptor(), name, 0); #else auto rc = ::fremovexattr(file_descriptor(), name); #endif if (rc < 0) throw OSException(errno); }
ssize_t FileBase::listxattr(char* buffer, size_t size) { #ifdef __APPLE__ auto rc = ::flistxattr(file_descriptor(), buffer, size, 0); #else auto rc = ::flistxattr(file_descriptor(), buffer, size); #endif if (rc < 0) throw OSException(errno); return rc; }
void FileBase::setxattr(const char* name, const char* value, size_t size, int flags) { if (!name || !value) throw OSException(EFAULT); std::unique_ptr<byte[]> buffer(new byte[size]); byte* ciphertext = buffer.get(); byte meta[XATTR_MAC_LENGTH + XATTR_IV_LENGTH]; byte* iv = meta; byte* mac = iv + XATTR_IV_LENGTH; generate_random(iv, XATTR_IV_LENGTH); auto name_len = strlen(name); std::unique_ptr<byte[]> header(new byte[name_len + ID_LENGTH]); memcpy(header.get(), get_id().data(), ID_LENGTH); memcpy(header.get() + ID_LENGTH, name, name_len); aes_gcm_encrypt(value, size, header.get(), name_len + ID_LENGTH, get_key().data(), get_key().size(), iv, XATTR_IV_LENGTH, mac, XATTR_MAC_LENGTH, ciphertext); auto rc = fsetxattr_wrapper(file_descriptor(), name, ciphertext, size, flags); if (rc < 0) throw OSException(errno); rc = fsetxattr_wrapper(m_meta_fd, name, meta, sizeof(meta), flags); if (rc < 0) throw OSException(errno); }
bool BinaryFile::Save(const string& filename, const Buffer& buffer) { DWORD error = GetLastError(); HANDLE hFile = CreateFile(filename.Data(), GENERIC_WRITE, 0, 0,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); CHECK_SYS_ERROR(L"Error in binary file, open file for saving " + filename); DWORD read; WriteFile(hFile, (LPCVOID)buffer.StartPointer(), (DWORD)buffer.GetPosition(), &read, 0); CHECK_SYS_ERROR(L"Error in binary file, can't write data to file " + filename); if (read != buffer.GetPosition()) throw OSException(L"Error in binary file, written data is less than should be " + filename); CloseHandle(hFile); CHECK_SYS_ERROR(L"Saving binary file failed " + filename); return true; }
bool BinaryFile::Load(const string& filename, Buffer& buffer) { DWORD error = GetLastError(); HANDLE hFile = CreateFile(filename.Data(), GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); CHECK_SYS_ERROR(L"Error in binary file, can't load it " + filename); int size = GetFileSize(hFile, 0); buffer.SetSize(size); DWORD read; ReadFile(hFile, buffer.StartPointer(), size, &read, 0); CHECK_SYS_ERROR(L"Error in binary file, can't read data " + filename); if (read != size) throw OSException(L"Error in binary file, read data less than file contains, possible bad staff happenes " + filename); CloseHandle(hFile); CHECK_SYS_ERROR(L"Binary file load failed " + filename); return true; }
void CheckOSError(LONG code, const System::string& msg) { string error; if (code != S_OK) { HLOCAL hLocal = 0; if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS, 0, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), (PTSTR)&hLocal, 0, 0)) { LPVOID p = LocalLock(hLocal); error = string((wchar_t*)p) + string::Format(L"(Code: 0x%X) (MS Windows)", code); LocalFree(hLocal); } else { error = L"Unknown error from GetLastError()"; } throw OSException(error); } }
bool BinaryFile::Append(const string& filename, const Buffer& buffer) { DWORD error = GetLastError(); HANDLE hFile = CreateFile(filename.Data(), GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); CHECK_SYS_ERROR(L"Error in binary file, can't open file for appending it " + filename); DWORD offset = GetFileSize(hFile, 0); SetFilePointer(hFile, offset, 0, FILE_BEGIN); DWORD read; WriteFile(hFile, (LPCVOID)buffer.StartPointer(), (DWORD)buffer.GetPosition(), &read, 0); CHECK_SYS_ERROR(L"Error in binary file, can't write data to file " + filename); if (read != buffer.GetPosition()) throw OSException(L"Error in binary file, written data is less than should be in " + filename); CloseHandle(hFile); CHECK_SYS_ERROR(L"Failed to append a file " + filename); return true; }
FileBase* FileTable::open_as(const id_type& id, int type) { auto it = m_opened.find(id); if (it != m_opened.end()) { if (it->second->type() != type) throw OSException(FileBase::error_number_for_not(type)); it->second->incref(); return it->second.get(); } it = m_closed.find(id); if (it != m_closed.end()) { if (it->second->type() != type) { m_closed.erase(it); } else { auto fb = it->second; m_opened.emplace(*it); m_closed.erase(it); fb->setref(1); return fb.get(); } } std::shared_ptr<FileStream> data_fd, meta_fd; std::tie(data_fd, meta_fd) = m_fio->open(id); auto fb = btree_make_file_from_type( type, data_fd, meta_fd, m_master_key, id, is_auth_enabled(), m_block_size, m_iv_size); m_opened.emplace(id, fb); fb->setref(1); return fb.get(); }