1 /*
2  * Copyright (C) 2020 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 #define LOG_TAG "StorageManager"
18 #include <android-base/file.h>
19 #include <android-base/logging.h>
20 #include <android-base/properties.h>
21 #include <android-base/unique_fd.h>
22 #include <fcntl.h>
23 #include <linux/fs.h>
24 
25 #include <nativehelper/JNIHelp.h>
26 #include "core_jni_helpers.h"
27 #include "filesystem_utils.h"
28 
29 namespace android {
30 
android_os_storage_StorageManager_setQuotaProjectId(JNIEnv * env,jobject self,jstring path,jlong projectId)31 jboolean android_os_storage_StorageManager_setQuotaProjectId(JNIEnv* env, jobject self,
32                                                              jstring path, jlong projectId) {
33     struct fsxattr fsx;
34     ScopedUtfChars utf_chars_path(env, path);
35 
36     static bool sdcardFsSupported = IsSdcardfsUsed();
37     if (sdcardFsSupported) {
38         // sdcardfs doesn't support project ID quota tracking and takes care of quota
39         // in a different way.
40         return JNI_TRUE;
41     }
42 
43     if (projectId > UINT32_MAX) {
44         LOG(ERROR) << "Invalid project id: " << projectId;
45         return JNI_FALSE;
46     }
47 
48     android::base::unique_fd fd(
49             TEMP_FAILURE_RETRY(open(utf_chars_path.c_str(), O_RDONLY | O_CLOEXEC)));
50     if (fd == -1) {
51         PLOG(ERROR) << "Failed to open " << utf_chars_path.c_str() << " to set project id.";
52         return JNI_FALSE;
53     }
54 
55     int ret = ioctl(fd, FS_IOC_FSGETXATTR, &fsx);
56     if (ret == -1) {
57         PLOG(ERROR) << "Failed to get extended attributes for " << utf_chars_path.c_str()
58                     << " to get project id.";
59         return JNI_FALSE;
60     }
61 
62     fsx.fsx_projid = projectId;
63     ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
64     if (ret == -1) {
65         PLOG(ERROR) << "Failed to set extended attributes for " << utf_chars_path.c_str()
66                     << " to set project id.";
67         return JNI_FALSE;
68     }
69 
70     return JNI_TRUE;
71 }
72 
73 // ----------------------------------------------------------------------------
74 
75 static const JNINativeMethod gStorageManagerMethods[] = {
76         {"setQuotaProjectId", "(Ljava/lang/String;J)Z",
77          (void*)android_os_storage_StorageManager_setQuotaProjectId},
78 };
79 
80 const char* const kStorageManagerPathName = "android/os/storage/StorageManager";
81 
register_android_os_storage_StorageManager(JNIEnv * env)82 int register_android_os_storage_StorageManager(JNIEnv* env) {
83     return RegisterMethodsOrDie(env, kStorageManagerPathName, gStorageManagerMethods,
84                                 NELEM(gStorageManagerMethods));
85 }
86 
87 }; // namespace android
88