• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #include "fuse_daemon.h"
17 
18 #include <securec.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 #include <vector>
23 
24 #include "dlp_link_file.h"
25 #include "dlp_link_manager.h"
26 #include "dlp_permission.h"
27 #include "dlp_permission_log.h"
28 
29 namespace OHOS {
30 namespace Security {
31 namespace DlpPermission {
32 namespace {
33 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_DLP_PERMISSION, "FuseDaemon"};
34 static constexpr int ROOT_INODE = 1;
35 static constexpr int DEFAULT_ATTR_TIMEOUT = 10000;
36 static constexpr int MAX_FILE_NAME_LEN = 256;
37 static constexpr int ROOT_INODE_ACCESS = 0711;
38 static constexpr uint32_t MAX_READ_DIR_BUF_SIZE = 100 * 1024;  // 100K
39 static constexpr const char* CUR_DIR = ".";
40 static constexpr const char* UPPER_DIR = "..";
41 static constexpr const char* DEFAULT_DLP_LINK_FILE = "default.dlp";
42 static constexpr const char* DEFAULT_DLP_LINK_FILE_PATH = "/mnt/data/fuse/default.dlp";
43 }  // namespace
44 
45 std::condition_variable FuseDaemon::daemonEnableCv_;
46 enum DaemonStatus FuseDaemon::daemonStatus_;
47 std::mutex FuseDaemon::daemonEnableMtx_;
48 struct stat FuseDaemon::rootFileStat_;
49 bool FuseDaemon::init_ = false;
50 static const int32_t INVALID_DLP_FD = -1;
51 
52 // caller need to check ino == ROOT_INODE
GetFileNode(fuse_ino_t ino)53 static DlpLinkFile* GetFileNode(fuse_ino_t ino)
54 {
55     return reinterpret_cast<DlpLinkFile*>(static_cast<uintptr_t>(ino));
56 }
57 
GetFileInode(DlpLinkFile * node)58 fuse_ino_t GetFileInode(DlpLinkFile* node)
59 {
60     return static_cast<fuse_ino_t>(reinterpret_cast<uintptr_t>(node));
61 }
62 
FuseDaemonLookup(fuse_req_t req,fuse_ino_t parent,const char * name)63 static void FuseDaemonLookup(fuse_req_t req, fuse_ino_t parent, const char* name)
64 {
65     if (name == nullptr) {
66         DLP_LOG_ERROR(LABEL, "Look up link file fail, name is null");
67         fuse_reply_err(req, ENOENT);
68         return;
69     }
70     DLP_LOG_DEBUG(LABEL, "Look up link file, name=%{private}s", name);
71 
72     if (parent != ROOT_INODE) {
73         DLP_LOG_ERROR(LABEL, "Look up link file fail, parent is not root inode");
74         fuse_reply_err(req, ENOENT);
75         return;
76     }
77 
78     struct fuse_entry_param fep;
79     (void)memset_s(&fep, sizeof(struct fuse_entry_param), 0, sizeof(struct fuse_entry_param));
80     if (!strcmp(name, ".") || !strcmp(name, "..")) {
81         fep.ino = ROOT_INODE;
82         fep.attr = *(FuseDaemon::GetRootFileStat());
83         fuse_reply_entry(req, &fep);
84         return;
85     }
86 
87     std::string nameStr = name;
88     DlpLinkFile* node = DlpLinkManager::GetInstance().LookUpDlpLinkFile(nameStr);
89     if (node == nullptr) {
90         DLP_LOG_ERROR(LABEL, "Look up link file fail, file %{public}s can not found", name);
91         fuse_reply_err(req, ENOENT);
92     } else {
93         DLP_LOG_DEBUG(LABEL, "Look up link file succ, file %{public}s found", name);
94         fep.ino = GetFileInode(node);
95         fep.attr = node->GetLinkStat();
96         fuse_reply_entry(req, &fep);
97     }
98 }
99 
UpdateCurrTimeStat(struct timespec * ts)100 void UpdateCurrTimeStat(struct timespec* ts)
101 {
102     clock_gettime(CLOCK_REALTIME, ts);
103 }
104 
FuseDaemonGetattr(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)105 static void FuseDaemonGetattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi)
106 {
107     (void)fi;
108 
109     if (ino == ROOT_INODE) {
110         struct stat* fileStat = FuseDaemon::GetRootFileStat();
111         fuse_reply_attr(req, fileStat, DEFAULT_ATTR_TIMEOUT);
112         return;
113     }
114 
115     DlpLinkFile* dlp = GetFileNode(ino);
116     if (dlp == nullptr) {
117         DLP_LOG_ERROR(LABEL, "Get link file attr fail, wrong ino");
118         fuse_reply_err(req, ENOENT);
119         return;
120     }
121 
122     struct stat fileStat = dlp->GetLinkStat();
123     fuse_reply_attr(req, &fileStat, DEFAULT_ATTR_TIMEOUT);
124 }
125 
126 // we will handle open flag later
FuseDaemonOpen(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)127 static void FuseDaemonOpen(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi)
128 {
129     if (ino == ROOT_INODE) {
130         DLP_LOG_ERROR(LABEL, "Open link file fail, can not open root dir");
131         fuse_reply_err(req, ENOENT);
132         return;
133     }
134 
135     DlpLinkFile* dlp = GetFileNode(ino);
136     if (dlp == nullptr) {
137         DLP_LOG_ERROR(LABEL, "Open link file fail, wrong ino");
138         fuse_reply_err(req, ENOENT);
139         return;
140     }
141     if ((fi != nullptr) && (static_cast<uint32_t>(fi->flags) & O_TRUNC) != 0) {
142         int32_t ret = dlp->Truncate(0);
143         if (ret != DLP_OK) {
144             DLP_LOG_ERROR(LABEL, "Open link file with truncate fail, ret=%{public}d", ret);
145             fuse_reply_err(req, EINVAL);
146             return;
147         }
148         DLP_LOG_INFO(LABEL, "Open link file with truncate succ");
149     }
150 
151     fuse_reply_open(req, fi);
152     dlp->UpdateAtimeStat();
153 }
154 
GetValidFileNode(fuse_req_t req,fuse_ino_t ino)155 static DlpLinkFile* GetValidFileNode(fuse_req_t req, fuse_ino_t ino)
156 {
157     if (ino == ROOT_INODE) {
158         fuse_reply_err(req, ENOENT);
159         return nullptr;
160     }
161     DlpLinkFile* dlp = GetFileNode(ino);
162     if (dlp == nullptr) {
163         fuse_reply_err(req, EBADF);
164         return nullptr;
165     }
166     return dlp;
167 }
168 
FuseDaemonRead(fuse_req_t req,fuse_ino_t ino,size_t size,off_t offset,struct fuse_file_info * fi)169 static void FuseDaemonRead(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, struct fuse_file_info* fi)
170 {
171     (void)fi;
172     if (offset < 0 || offset > DLP_MAX_CONTENT_SIZE) {
173         fuse_reply_err(req, EINVAL);
174         return;
175     }
176     if (size > DLP_FUSE_MAX_BUFFLEN) {
177         DLP_LOG_ERROR(LABEL, "Read link file fail, read size %{public}zu too large", size);
178         fuse_reply_err(req, EINVAL);
179         return;
180     }
181     DlpLinkFile* dlp = GetValidFileNode(req, ino);
182     if (dlp == nullptr) {
183         DLP_LOG_ERROR(LABEL, "Read link file fail, wrong ino");
184         return;
185     }
186 
187     char* buf = reinterpret_cast<char*>(malloc(size));
188     if (buf == nullptr) {
189         DLP_LOG_ERROR(LABEL, "Read link file fail, malloc %{public}zu buff fail", size);
190         fuse_reply_err(req, EINVAL);
191         return;
192     }
193     (void)memset_s(buf, size, 0, size);
194 
195     int32_t res = dlp->Read(static_cast<uint32_t>(offset), buf, static_cast<uint32_t>(size));
196     if (res < 0) {
197         fuse_reply_err(req, EIO);
198     } else {
199         fuse_reply_buf(req, buf, static_cast<size_t>(res));
200     }
201     DLP_LOG_DEBUG(LABEL, "Read file name %{private}s offset %{public}u size %{public}u res %{public}d",
202         dlp->GetLinkName().c_str(), static_cast<uint32_t>(offset), static_cast<uint32_t>(size), res);
203     free(buf);
204 }
205 
FuseDaemonWrite(fuse_req_t req,fuse_ino_t ino,const char * buf,size_t size,off_t off,struct fuse_file_info * fi)206 static void FuseDaemonWrite(
207     fuse_req_t req, fuse_ino_t ino, const char* buf, size_t size, off_t off, struct fuse_file_info* fi)
208 {
209     (void)fi;
210     if (off < 0 || off > DLP_MAX_CONTENT_SIZE) {
211         fuse_reply_err(req, EINVAL);
212         return;
213     }
214     if (size > DLP_FUSE_MAX_BUFFLEN) {
215         DLP_LOG_ERROR(LABEL, "Write link file fail, write size %{public}zu too large", size);
216         fuse_reply_err(req, EINVAL);
217         return;
218     }
219     DlpLinkFile* dlp = GetValidFileNode(req, ino);
220     if (dlp == nullptr) {
221         DLP_LOG_ERROR(LABEL, "Write link file fail, wrong ino");
222         return;
223     }
224     int32_t res = dlp->Write(static_cast<uint32_t>(off),
225         const_cast<void *>(static_cast<const void *>(buf)), static_cast<uint32_t>(size));
226     if (res < 0) {
227         fuse_reply_err(req, EIO);
228     } else {
229         fuse_reply_write(req, static_cast<size_t>(res));
230     }
231     DLP_LOG_DEBUG(LABEL, "Write file name %{private}s offset %{public}u size %{public}u res %{public}d",
232         dlp->GetLinkName().c_str(), static_cast<uint32_t>(off), static_cast<uint32_t>(size), res);
233 }
234 
FuseDaemonForget(fuse_req_t req,fuse_ino_t ino,uint64_t nlookup)235 static void FuseDaemonForget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
236 {
237     if (ino == ROOT_INODE) {
238         DLP_LOG_WARN(LABEL, "Forget root dir is forbidden");
239         fuse_reply_err(req, ENOENT);
240         return;
241     }
242 
243     DlpLinkFile* dlp = GetFileNode(ino);
244     if (dlp == nullptr) {
245         DLP_LOG_ERROR(LABEL, "Forgot link file fail, wrong ino");
246         fuse_reply_err(req, EBADF);
247         return;
248     }
249     DLP_LOG_DEBUG(LABEL, "Forget link file name %{private}s nlookup %{public}u",
250         dlp->GetLinkName().c_str(), static_cast<uint32_t>(nlookup));
251     if (dlp->SubAndCheckZeroRef(nlookup)) {
252         DLP_LOG_INFO(LABEL, "Link file reference is less than 0, delete link file ok");
253         delete dlp;
254     }
255 }
256 
AddDirentry(DirAddParams & param)257 static int AddDirentry(DirAddParams& param)
258 {
259     size_t shouldSize = fuse_add_direntry(param.req, nullptr, 0, param.entryName.c_str(), nullptr, 0);
260     if (shouldSize > param.bufLen) {
261         return -1;
262     }
263     param.curOff = param.nextOff;
264     size_t addSize = fuse_add_direntry(param.req, param.directBuf, param.bufLen,
265         param.entryName.c_str(), param.entryStat, param.curOff);
266     param.directBuf += addSize;
267     param.bufLen -= addSize;
268     param.nextOff += static_cast<int>(addSize);
269     return 0;
270 }
271 
AddRootDirentry(DirAddParams & params)272 static int AddRootDirentry(DirAddParams& params)
273 {
274     struct stat* rootStat = FuseDaemon::GetRootFileStat();
275     params.entryName = CUR_DIR;
276     params.entryStat = rootStat;
277 
278     if (AddDirentry(params) != 0) {
279         fuse_reply_err(params.req, EINVAL);
280         return -1;
281     }
282 
283     params.entryName = UPPER_DIR;
284     if (AddDirentry(params) != 0) {
285         fuse_reply_err(params.req, EINVAL);
286         return -1;
287     }
288     return 0;
289 }
290 
AddLinkFilesDirentry(DirAddParams & params)291 static int AddLinkFilesDirentry(DirAddParams& params)
292 {
293     std::vector<DlpLinkFileInfo> linkList;
294     DlpLinkManager::GetInstance().DumpDlpLinkFile(linkList);
295     int listSize = static_cast<int>(linkList.size());
296     for (int i = 0; i < listSize; i++) {
297         params.entryName = linkList[i].dlpLinkName;
298         params.entryStat = &linkList[i].fileStat;
299         if (AddDirentry(params) != 0) {
300             fuse_reply_err(params.req, EINVAL);
301             return -1;
302         }
303     }
304     return 0;
305 }
306 
FuseDaemonReadDir(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi)307 static void FuseDaemonReadDir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
308 {
309     (void)fi;
310     if (off < 0 || off > DLP_MAX_CONTENT_SIZE) {
311         fuse_reply_err(req, ENOTDIR);
312         return;
313     }
314 
315     if (ino != ROOT_INODE) {
316         fuse_reply_err(req, ENOTDIR);
317         return;
318     }
319     if (size > MAX_READ_DIR_BUF_SIZE) {
320         fuse_reply_err(req, EINVAL);
321         return;
322     }
323 
324     char* readBuf = reinterpret_cast<char*>(malloc(size));
325     if (readBuf == nullptr) {
326         fuse_reply_err(req, EFAULT);
327         return;
328     }
329     (void)memset_s(readBuf, size, 0, size);
330 
331     struct DirAddParams params;
332     params.req = req;
333     params.directBuf = readBuf;
334     params.bufLen = size;
335     params.nextOff = 0;
336 
337     if (AddRootDirentry(params) != 0) {
338         free(readBuf);
339         return;
340     }
341 
342     if (AddLinkFilesDirentry(params) != 0) {
343         free(readBuf);
344         return;
345     }
346 
347     if (params.curOff <= off) {
348         fuse_reply_buf(req, nullptr, 0);
349     } else {
350         fuse_reply_buf(req, readBuf + off, params.nextOff - off);
351     }
352     free(readBuf);
353 }
354 
FuseDaemonUpdateTime(fuse_req_t req,int toSet,DlpLinkFile * dlpLink)355 bool FuseDaemonUpdateTime(fuse_req_t req, int toSet, DlpLinkFile* dlpLink)
356 {
357     DLP_LOG_DEBUG(LABEL, "Set link file update time, type %{public}d", toSet);
358     bool isUpdateTime = false;
359     struct stat fileStat = dlpLink->GetFileStat();
360     if ((static_cast<uint32_t>(toSet) & FUSE_SET_ATTR_MTIME) != 0) {
361         UpdateCurrTimeStat(&fileStat.st_mtim);
362         isUpdateTime = true;
363     }
364     if ((static_cast<uint32_t>(toSet) & FUSE_SET_ATTR_CTIME) != 0) {
365         UpdateCurrTimeStat(&fileStat.st_ctim);
366         isUpdateTime = true;
367     }
368     if ((static_cast<uint32_t>(toSet) & FUSE_SET_ATTR_ATIME) != 0) {
369         UpdateCurrTimeStat(&fileStat.st_atim);
370         isUpdateTime = true;
371     }
372     if (isUpdateTime && (static_cast<uint32_t>(toSet) & FUSE_SET_ATTR_SIZE) == 0) {
373         fuse_reply_attr(req, &fileStat, DEFAULT_ATTR_TIMEOUT);
374         return false;
375     }
376     return true;
377 }
378 
FuseDaemonSetAttr(fuse_req_t req,fuse_ino_t ino,struct stat * attr,int toSet,struct fuse_file_info * fi)379 void FuseDaemonSetAttr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int toSet, struct fuse_file_info *fi)
380 {
381     (void)fi;
382     if (attr == nullptr) {
383         DLP_LOG_ERROR(LABEL, "Set link file attr fail, attr invalid");
384         fuse_reply_err(req, EINVAL);
385         return;
386     }
387 
388     if (ino == ROOT_INODE) {
389         DLP_LOG_ERROR(LABEL, "Set link file attr fail, cannot set attr on root inode");
390         fuse_reply_err(req, EACCES);
391         return;
392     }
393 
394     DlpLinkFile* dlpLink = GetFileNode(ino);
395     if (dlpLink == nullptr) {
396         DLP_LOG_ERROR(LABEL, "Set link file attr fail, wrong ino");
397         fuse_reply_err(req, ENOENT);
398         return;
399     }
400 
401     if (!FuseDaemonUpdateTime(req, toSet, dlpLink)) {
402         return;
403     }
404 
405     if ((static_cast<uint32_t>(toSet) & FUSE_SET_ATTR_SIZE) == 0) {
406         DLP_LOG_ERROR(LABEL, "Set link file attr fail, type %{public}d not support", toSet);
407         fuse_reply_err(req, EACCES);
408         return;
409     }
410 
411     if (attr->st_size < 0 || attr->st_size > DLP_MAX_CONTENT_SIZE) {
412         DLP_LOG_ERROR(LABEL, "Set link file attr fail, file size too large");
413         fuse_reply_err(req, EINVAL);
414         return;
415     }
416     int32_t ret = dlpLink->Truncate(static_cast<uint32_t>(attr->st_size));
417     if (ret != DLP_OK) {
418         DLP_LOG_ERROR(LABEL, "Set link file attr fail, errno is %{public}d", ret);
419         fuse_reply_err(req, EINVAL);
420         return;
421     }
422 
423     DLP_LOG_INFO(LABEL, "Set link file attr succ");
424     struct stat fileStat = dlpLink->GetLinkStat();
425     fuse_reply_attr(req, &fileStat, DEFAULT_ATTR_TIMEOUT);
426 }
427 
FuseDaemonInit(void * userdata,struct fuse_conn_info * conn)428 static void FuseDaemonInit(void *userdata, struct fuse_conn_info *conn)
429 {
430     (void)userdata;
431     if (conn == nullptr) {
432         DLP_LOG_ERROR(LABEL, "Fuse init, fuse conn info is null");
433         return;
434     }
435     conn->want |= FUSE_CAP_WRITEBACK_CACHE;
436 }
437 
438 struct fuse_lowlevel_ops FuseDaemon::fuseDaemonOper_ = {
439     .init = FuseDaemonInit,
440     .lookup = FuseDaemonLookup,
441     .forget = FuseDaemonForget,
442     .getattr = FuseDaemonGetattr,
443     .setattr = FuseDaemonSetAttr,
444     .open = FuseDaemonOpen,
445     .read = FuseDaemonRead,
446     .write = FuseDaemonWrite,
447     .readdir = FuseDaemonReadDir,
448 };
449 
GetRootFileStat()450 struct stat* FuseDaemon::GetRootFileStat()
451 {
452     return &FuseDaemon::rootFileStat_;
453 }
454 
InitRootFileStat(void)455 void FuseDaemon::InitRootFileStat(void)
456 {
457     (void)memset_s(&rootFileStat_, sizeof(rootFileStat_), 0, sizeof(rootFileStat_));
458     rootFileStat_.st_ino = ROOT_INODE;
459     rootFileStat_.st_mode = S_IFDIR | ROOT_INODE_ACCESS;
460     rootFileStat_.st_nlink = 1;
461     rootFileStat_.st_uid = getuid();
462     rootFileStat_.st_gid = getgid();
463     UpdateCurrTimeStat(&rootFileStat_.st_atim);
464     UpdateCurrTimeStat(&rootFileStat_.st_mtim);
465     UpdateCurrTimeStat(&rootFileStat_.st_ctim);
466 }
467 
NotifyDaemonEnable(void)468 void FuseDaemon::NotifyDaemonEnable(void)
469 {
470     std::unique_lock<std::mutex> lck(daemonEnableMtx_);
471     daemonStatus_ = DAEMON_ENABLE;
472     daemonEnableCv_.notify_all();
473 }
474 
NotifyDaemonDisable(void)475 void FuseDaemon::NotifyDaemonDisable(void)
476 {
477     std::unique_lock<std::mutex> lck(daemonEnableMtx_);
478     daemonStatus_ = DAEMON_DISABLE;
479     daemonEnableCv_.notify_all();
480 }
481 
WaitDaemonEnable(void)482 int FuseDaemon::WaitDaemonEnable(void)
483 {
484     DLP_LOG_INFO(LABEL, "Wait fuse fs daemon enable");
485     std::unique_lock<std::mutex> lck(daemonEnableMtx_);
486     if (daemonStatus_ == DAEMON_UNDEF) {
487         daemonEnableCv_.wait_for(lck, std::chrono::seconds(1));
488     }
489 
490     if (daemonStatus_ == DAEMON_ENABLE) {
491         DLP_LOG_INFO(LABEL, "Wait fuse fs daemon enable succ");
492         return 0;
493     }
494 
495     DLP_LOG_INFO(LABEL, "Wait fuse fs daemon enable fail, time out");
496     return -1;
497 }
498 
FuseFsDaemonThread(int fuseFd)499 void FuseDaemon::FuseFsDaemonThread(int fuseFd)
500 {
501     struct stat fileStat;
502     if (fstat(fuseFd, &fileStat) < 0) {
503         DLP_LOG_ERROR(LABEL, "Fuse fs daemon exit, %{public}d is wrong fd, errno %{public}d", fuseFd, errno);
504         NotifyDaemonDisable();
505         return;
506     }
507 
508     char mountPoint[MAX_FILE_NAME_LEN] = {0};
509     int ret = snprintf_s(mountPoint, sizeof(mountPoint), MAX_FILE_NAME_LEN, "/dev/fd/%d", fuseFd);
510     if (ret <= 0) {
511         DLP_LOG_ERROR(LABEL, "Fuse fs daemon exit, snprintf_s fail");
512         NotifyDaemonDisable();
513         return;
514     }
515 
516     struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
517     fuse_opt_add_arg(&args, mountPoint);
518 
519     struct fuse_session* se = fuse_session_new(&args, &fuseDaemonOper_, sizeof(fuseDaemonOper_), NULL);
520     if (se == NULL) {
521         DLP_LOG_ERROR(LABEL, "Fuse fs daemon exit, create fuse session fail");
522         NotifyDaemonDisable();
523         fuse_opt_free_args(&args);
524         return;
525     }
526 
527     if (fuse_session_mount(se, mountPoint) != 0) {
528         DLP_LOG_ERROR(LABEL, "Fuse fs daemon exit, mount fuse session fail");
529         NotifyDaemonDisable();
530         fuse_session_destroy(se);
531         fuse_opt_free_args(&args);
532         return;
533     }
534 
535     InitRootFileStat();
536     NotifyDaemonEnable();
537 
538     if (fuse_session_loop(se) != 0) {
539         DLP_LOG_ERROR(LABEL, "Fuse fs daemon exit, fuse session loop end");
540     }
541 
542     fuse_session_destroy(se);
543     fuse_opt_free_args(&args);
544 }
545 
NotifyKernelNoFlush(void)546 int FuseDaemon::NotifyKernelNoFlush(void)
547 {
548     std::shared_ptr<DlpFile> defaultfilePtr = std::make_shared<DlpFile>(INVALID_DLP_FD);
549     if (DlpLinkManager::GetInstance().AddDlpLinkFile(defaultfilePtr, DEFAULT_DLP_LINK_FILE) != DLP_OK) {
550         DLP_LOG_ERROR(LABEL, "Add default dlp file fail");
551         return -1;
552     }
553 
554     int defaultFd = open(DEFAULT_DLP_LINK_FILE_PATH, O_RDWR);
555     if (defaultFd == -1) {
556         DLP_LOG_ERROR(LABEL, "Open default dlp file fail");
557         DlpLinkManager::GetInstance().DeleteDlpLinkFile(defaultfilePtr);
558         return -1;
559     }
560 
561     // we need kernel to know that fs has no flush interface, close will trigger kernel flush
562     (void)close(defaultFd);
563     DlpLinkManager::GetInstance().DeleteDlpLinkFile(defaultfilePtr);
564     DLP_LOG_INFO(LABEL, "Notify kernel no flush succ");
565     return 0;
566 }
567 
InitFuseFs(int fuseDevFd)568 int FuseDaemon::InitFuseFs(int fuseDevFd)
569 {
570     if (init_) {
571         DLP_LOG_ERROR(LABEL, "Fuse fs has init already!");
572         return -1;
573     }
574     init_ = true;
575 
576     if (fuseDevFd < 0) {
577         DLP_LOG_ERROR(LABEL, "Init fuse fs fail: dev fd is error");
578         return -1;
579     }
580     daemonStatus_ = DAEMON_UNDEF;
581 
582     std::thread daemonThread(FuseFsDaemonThread, fuseDevFd);
583     daemonThread.detach();
584     int result = WaitDaemonEnable();
585     if (result == 0) {
586         std::thread notifyThread(NotifyKernelNoFlush);
587         notifyThread.detach();
588     }
589     return result;
590 }
591 }  // namespace DlpPermission
592 }  // namespace Security
593 }  // namespace OHOS
594