bool CryptoManager::decrypt(ISC_STATUS* sv, Ods::pag* page) { // Code calling us is not ready to process exceptions correctly // Therefore use old (status vector based) method try { if (page->pag_flags & Ods::crypted_page) { if (!cryptPlugin) { // We are invoked from shared cache manager, i.e. no valid attachment in tdbb // Therefore create system temporary attachment like in crypt thread to be able to work with locks UserId user; user.usr_user_name = "(Crypt plugin loader)"; Jrd::Attachment* const attachment = Jrd::Attachment::create(&dbb); RefPtr<SysAttachment> jAtt(new SysAttachment(attachment)); attachment->att_interface = jAtt; attachment->att_filename = dbb.dbb_filename; attachment->att_user = &user; BackgroundContextHolder tdbb(&dbb, attachment, sv, FB_FUNCTION); // Lock crypt state takeStateLock(tdbb); Header hdr(tdbb, LCK_read); crypt = hdr->hdr_flags & Ods::hdr_encrypted; process = hdr->hdr_flags & Ods::hdr_crypt_process; if (crypt || process) { loadPlugin(hdr->hdr_crypt_plugin); } if (!cryptPlugin) { (Arg::Gds(isc_decrypt_error)).raise(); return false; } } LocalStatus status; cryptPlugin->decrypt(&status, dbb.dbb_page_size - sizeof(Ods::pag), &page[1], &page[1]); if (!status.isSuccess()) { memcpy(sv, status.get(), sizeof(ISC_STATUS_ARRAY)); return false; } } return true; } catch (const Exception& ex) { ex.stuff_exception(sv); } return false; }
void CryptoManager::blockingAstChangeCryptState() { AsyncContextHolder tdbb(&dbb, FB_FUNCTION); fb_assert(stateLock); LCK_release(tdbb, stateLock); needLock = true; }
int Database::blocking_ast_sweep(void* ast_object) { Database* dbb = static_cast<Database*>(ast_object); AsyncContextHolder tdbb(dbb, FB_FUNCTION); if ((dbb->dbb_flags & DBB_sweep_starting) && !(dbb->dbb_flags & DBB_sweep_in_progress)) { dbb->dbb_flags &= ~DBB_sweep_starting; LCK_release(tdbb, dbb->dbb_sweep_lock); } return 0; }
int GlobalRWLock::blocking_ast_cached_lock(void* ast_object) { GlobalRWLock* globalRWLock = static_cast<GlobalRWLock*>(ast_object); try { Firebird::MutexLockGuard counterGuard(globalRWLock->counterMutex); if (!globalRWLock->cachedLock) return 0; Database* dbb = globalRWLock->cachedLock->lck_dbb; AstContextHolder tdbb(dbb); if (globalRWLock->cachedLock) globalRWLock->blockingAstHandler(tdbb); } catch (const Firebird::Exception&) {} // no-op return 0; }
void CryptoManager::cryptThread() { ISC_STATUS_ARRAY status_vector; try { // Try to take crypt mutex // If can't take that mutex - nothing to do, cryptThread already runs in our process MutexEnsureUnlock guard(cryptThreadMtx, FB_FUNCTION); if (!guard.tryEnter()) { return; } // establish context UserId user; user.usr_user_name = "(Crypt thread)"; Jrd::Attachment* const attachment = Jrd::Attachment::create(&dbb); RefPtr<SysAttachment> jAtt(new SysAttachment(attachment)); attachment->att_interface = jAtt; attachment->att_filename = dbb.dbb_filename; attachment->att_user = &user; BackgroundContextHolder tdbb(&dbb, attachment, status_vector, FB_FUNCTION); tdbb->tdbb_quantum = SWEEP_QUANTUM; ULONG lastPage = getLastPage(tdbb); ULONG runpage = 1; Stack<ULONG> pages; // Take exclusive threadLock // If can't take that lock - nothing to do, cryptThread already runs somewhere if (!LCK_lock(tdbb, threadLock, LCK_EX, LCK_NO_WAIT)) { return; } bool lckRelease = false; try { do { // Check is there some job to do while ((runpage = currentPage.exchangeAdd(+1)) < lastPage) { // forced terminate if (down) { break; } // nbackup state check if (dbb.dbb_backup_manager && dbb.dbb_backup_manager->getState() != nbak_state_normal) { if (currentPage.exchangeAdd(-1) >= lastPage) { // currentPage was set to last page by thread, closing database break; } THD_sleep(100); continue; } // scheduling if (--tdbb->tdbb_quantum < 0) { JRD_reschedule(tdbb, SWEEP_QUANTUM, true); } // writing page to disk will change it's crypt status in usual way WIN window(DB_PAGE_SPACE, runpage); Ods::pag* page = CCH_FETCH(tdbb, &window, LCK_write, pag_undefined); if (page && page->pag_type <= pag_max && (bool(page->pag_flags & Ods::crypted_page) != crypt) && Ods::pag_crypt_page[page->pag_type]) { CCH_MARK(tdbb, &window); pages.push(runpage); } CCH_RELEASE_TAIL(tdbb, &window); // sometimes save currentPage into DB header ++runpage; if ((runpage & 0x3FF) == 0) { writeDbHeader(tdbb, runpage, pages); } } // At this moment of time all pages with number < lastpage // are guaranteed to change crypt state. Check for added pages. lastPage = getLastPage(tdbb); // forced terminate if (down) { break; } } while (runpage < lastPage); // Finalize crypt if (!down) { writeDbHeader(tdbb, 0, pages); } // Release exclusive lock on StartCryptThread lckRelease = true; LCK_release(tdbb, threadLock); } catch (const Exception&) { try { if (!lckRelease) { // try to save current state of crypt thread if (!down) { writeDbHeader(tdbb, runpage, pages); } // Release exclusive lock on StartCryptThread LCK_release(tdbb, threadLock); } } catch (const Exception&) { } throw; } } catch (const Exception& ex) { // Error during context creation - we can't even release lock iscLogException("Crypt thread:", ex); } }