• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #define MLOG_TAG "MediaFuseDaemon"
17 #include "media_fuse_daemon.h"
18 
19 #include <fcntl.h>
20 #define FUSE_USE_VERSION 34
21 #include <fuse.h>
22 #include <thread>
23 #include <unistd.h>
24 
25 #include "dfx_const.h"
26 #include "dfx_timer.h"
27 #include "media_log.h"
28 #include "medialibrary_errno.h"
29 #include "medialibrary_operation.h"
30 #include "media_fuse_manager.h"
31 
32 namespace OHOS {
33 namespace Media {
34 using namespace std;
35 
36 static constexpr int32_t FUSE_CFG_MAX_THREADS = 5;
37 // LCOV_EXCL_START
GetAttr(const char * path,struct stat * stbuf,struct fuse_file_info * fi)38 static int GetAttr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
39 {
40     return MediaFuseManager::GetInstance().DoGetAttr(path, stbuf);
41 }
42 
Open(const char * path,struct fuse_file_info * fi)43 static int Open(const char *path, struct fuse_file_info *fi)
44 {
45     int fd = -1;
46     fuse_context *ctx = fuse_get_context();
47     CHECK_AND_RETURN_RET_LOG(ctx != nullptr, -ENOENT, "get file context failed");
48     DfxTimer dfxTimer(
49         DfxType::FUSE_OPEN, static_cast<int32_t>(OperationObject::FILESYSTEM_PHOTO), OPEN_FILE_TIME_OUT, true);
50     dfxTimer.SetCallerUid(ctx->uid);
51 
52     int32_t err = MediaFuseManager::GetInstance().DoOpen(path, fi->flags, fd);
53     CHECK_AND_RETURN_RET_LOG(err == 0, err, "Open file failed, path = %{private}s", path);
54 
55     fi->fh = static_cast<uint64_t>(fd);
56     return 0;
57 }
58 
Read(const char * path,char * buf,size_t size,off_t offset,struct fuse_file_info * fi)59 static int Read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
60 {
61     fuse_context *ctx = fuse_get_context();
62     CHECK_AND_RETURN_RET_LOG(ctx != nullptr, -ENOENT, "get file context failed");
63     DfxTimer dfxTimer(
64         DfxType::FUSE_READ, static_cast<int32_t>(OperationObject::FILESYSTEM_PHOTO), COMMON_TIME_OUT, true);
65     dfxTimer.SetCallerUid(ctx->uid);
66 
67     int res = pread(fi->fh, buf, size, offset);
68     CHECK_AND_RETURN_RET_LOG(res != -1, -errno, "Read file failed, errno = %{public}d", errno);
69 
70     return res;
71 }
72 
Write(const char * path,const char * buf,size_t size,off_t offset,struct fuse_file_info * fi)73 static int Write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
74 {
75     fuse_context *ctx = fuse_get_context();
76     CHECK_AND_RETURN_RET_LOG(ctx != nullptr, -ENOENT, "get file context failed");
77     DfxTimer dfxTimer(
78         DfxType::FUSE_WRITE, static_cast<int32_t>(OperationObject::FILESYSTEM_PHOTO), COMMON_TIME_OUT, true);
79     dfxTimer.SetCallerUid(ctx->uid);
80 
81     int res = pwrite(fi->fh, buf, size, offset);
82     CHECK_AND_RETURN_RET_LOG(res != -1, -errno, "Read file failed, errno = %{public}d", errno);
83 
84     return res;
85 }
86 
Release(const char * path,struct fuse_file_info * fi)87 static int Release(const char *path, struct fuse_file_info *fi)
88 {
89     fuse_context *ctx = fuse_get_context();
90     CHECK_AND_RETURN_RET_LOG(ctx != nullptr, -ENOENT, "get file context failed");
91     DfxTimer dfxTimer(
92         DfxType::FUSE_RELEASE, static_cast<int32_t>(OperationObject::FILESYSTEM_PHOTO), COMMON_TIME_OUT, true);
93     dfxTimer.SetCallerUid(ctx->uid);
94 
95     int32_t err = MediaFuseManager::GetInstance().DoRelease(path, fi->fh);
96     return err;
97 }
98 
99 static const struct fuse_operations high_ops = {
100     .getattr    = GetAttr,
101     .open       = Open,
102     .read       = Read,
103     .write      = Write,
104     .release    = Release,
105 };
106 
StartFuse()107 int32_t MediaFuseDaemon::StartFuse()
108 {
109     int ret = E_OK;
110 
111     bool expect = false;
112     CHECK_AND_RETURN_RET_LOG(isRunning_.compare_exchange_strong(expect, true), E_FAIL,
113         "Fuse daemon is already running");
114 
115     std::thread([this]() {
116         DaemonThread();
117     }).detach();
118 
119     return ret;
120 }
121 
DaemonThread()122 void MediaFuseDaemon::DaemonThread()
123 {
124     struct fuse_args args = FUSE_ARGS_INIT(0, nullptr);
125     struct fuse *fuse_default = nullptr;
126     struct fuse_loop_config *loop_config = nullptr;
127     string name("mediaFuseDaemon");
128     pthread_setname_np(pthread_self(), name.c_str());
129     do {
130         CHECK_AND_BREAK_ERR_LOG(!fuse_opt_add_arg(&args, "-odebug"), "fuse_opt_add_arg failed");
131         fuse_set_log_func([](enum fuse_log_level level, const char *fmt, va_list ap) {
132             char *str = nullptr;
133             CHECK_AND_RETURN_LOG(vasprintf(&str, fmt, ap) >= 0, "FUSE: log failed");
134             MEDIA_ERR_LOG("FUSE: %{public}s", str);
135             free(str);
136         });
137 
138         fuse_default = fuse_new(&args, &high_ops, sizeof(high_ops), nullptr);
139         CHECK_AND_BREAK_ERR_LOG(fuse_default != nullptr, "fuse_new failed");
140         CHECK_AND_BREAK_ERR_LOG(fuse_mount(fuse_default, mountpoint_.c_str()) == 0,
141             "fuse_mount failed, mountpoint_ = %{private}s", mountpoint_.c_str());
142 
143         loop_config = fuse_loop_cfg_create();
144         CHECK_AND_BREAK_ERR_LOG(loop_config != nullptr, "fuse_loop_cfg_create failed");
145         fuse_loop_cfg_set_max_threads(loop_config, FUSE_CFG_MAX_THREADS);
146         MEDIA_INFO_LOG("Starting fuse ...");
147         fuse_loop_mt(fuse_default, loop_config);
148         MEDIA_INFO_LOG("Ending fuse ...");
149     } while (false);
150 
151     fuse_opt_free_args(&args);
152     if (loop_config) {
153         fuse_loop_cfg_destroy(loop_config);
154     }
155     if (fuse_default) {
156         fuse_unmount(fuse_default);
157         fuse_destroy(fuse_default);
158     }
159     MEDIA_INFO_LOG("Ended fuse");
160 }
161 // LCOV_EXCL_STOP
162 } // namespace Media
163 } // namespace OHOS
164 
165