1 /*
<lambda>null2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.permission.access.util
18 
19 import android.os.FileUtils
20 import android.util.AtomicFile
21 import android.util.Slog
22 import com.android.server.security.FileIntegrity;
23 import java.io.File
24 import java.io.FileInputStream
25 import java.io.FileNotFoundException
26 import java.io.FileOutputStream
27 import java.io.IOException
28 
29 /** Read from an [AtomicFile], fallback to reserve file to read the data. */
30 @Throws(Exception::class)
readWithReserveCopynull31 inline fun AtomicFile.readWithReserveCopy(block: (FileInputStream) -> Unit) {
32     try {
33         openRead().use(block)
34     } catch (e: FileNotFoundException) {
35         throw e
36     } catch (e: Exception) {
37         Slog.wtf("AccessPersistence", "Failed to read $this", e)
38         val reserveFile = File(baseFile.parentFile, baseFile.name + ".reservecopy")
39         try {
40             AtomicFile(reserveFile).openRead().use(block)
41         } catch (e2: Exception) {
42             Slog.e("AccessPersistence", "Failed to read $reserveFile", e2)
43             throw e
44         }
45     }
46 }
47 
48 /** Write to actual file and reserve file. */
49 @Throws(IOException::class)
writeWithReserveCopynull50 inline fun AtomicFile.writeWithReserveCopy(block: (FileOutputStream) -> Unit) {
51     writeInlined(block)
52     val reserveFile = File(baseFile.parentFile, baseFile.name + ".reservecopy")
53     reserveFile.delete()
54     try {
55         FileInputStream(baseFile).use { inputStream ->
56             FileOutputStream(reserveFile).use { outputStream ->
57                 FileUtils.copy(inputStream, outputStream)
58                 outputStream.fd.sync()
59             }
60         }
61     } catch (e: Exception) {
62         Slog.e("AccessPersistence", "Failed to write $reserveFile", e)
63     }
64     try {
65         FileIntegrity.setUpFsVerity(baseFile)
66         FileIntegrity.setUpFsVerity(reserveFile)
67     } catch (e: Exception) {
68         Slog.e("AccessPersistence", "Failed to verity-protect runtime-permissions", e)
69     }
70 }
71 
72 /** Write to an [AtomicFile] and close everything safely when done. */
73 @Throws(IOException::class)
74 // Renamed to writeInlined() to avoid conflict with the hidden AtomicFile.write() that isn't inline.
writeInlinednull75 inline fun AtomicFile.writeInlined(block: (FileOutputStream) -> Unit) {
76     startWrite().use {
77         try {
78             block(it)
79             finishWrite(it)
80         } catch (t: Throwable) {
81             failWrite(it)
82             throw t
83         }
84     }
85 }
86