FileExtensions.kt 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. /* _____ _
  2. * |_ _| |_ _ _ ___ ___ _ __ __ _
  3. * | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. * |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. *
  6. * Threema for Android
  7. * Copyright (c) 2024-2025 Threema GmbH
  8. *
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU Affero General Public License, version 3,
  11. * as published by the Free Software Foundation.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Affero General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License
  19. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. */
  21. package ch.threema.base
  22. import androidx.core.util.AtomicFile
  23. import ch.threema.annotation.SameThread
  24. import ch.threema.common.NoCloseOutputStream
  25. import java.io.DataOutputStream
  26. import java.io.File
  27. import java.io.IOException
  28. import java.io.OutputStream
  29. /**
  30. * Writes a file atomically, i.e., it is either fully written or not at all.
  31. * If the file or its parent directory did not previously exist, it will be created.
  32. * If the file did previously exist, it will be replaced.
  33. *
  34. * The output stream passed into [performWrite] does not need to be closed.
  35. */
  36. @SameThread
  37. fun File.writeAtomically(performWrite: (OutputStream) -> Unit) {
  38. val atomicKeyFile = AtomicFile(this)
  39. val fos = atomicKeyFile.startWrite()
  40. try {
  41. // Note: stream *must not* be closed explicitly (see AtomicFile documentation)
  42. val dos = NoCloseOutputStream(DataOutputStream(fos))
  43. performWrite(dos)
  44. dos.flush()
  45. } catch (e: IOException) {
  46. atomicKeyFile.failWrite(fos)
  47. throw e
  48. }
  49. atomicKeyFile.finishWrite(fos)
  50. }