• 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 #include "meta_file.h"
17 
18 #include <ctime>
19 #include <fcntl.h>
20 #include <iomanip>
21 #include <sstream>
22 #include <sys/stat.h>
23 
24 #include "cloud_file_utils.h"
25 #include "dfs_error.h"
26 #include "file_utils.h"
27 #include "securec.h"
28 #include "string_ex.h"
29 #include "sys/xattr.h"
30 #include "utils_directory.h"
31 #include "utils_log.h"
32 
33 namespace OHOS {
34 namespace FileManagement {
35 constexpr uint32_t DENTRYGROUP_SIZE = 4096;
36 constexpr uint32_t DENTRY_NAME_LEN = 8;
37 constexpr uint32_t DENTRY_RESERVED_LENGTH = 4;
38 constexpr uint32_t DENTRY_PER_GROUP = 52;
39 constexpr uint32_t DENTRY_BITMAP_LENGTH = 7;
40 constexpr uint32_t DENTRY_GROUP_RESERVED = 32;
41 constexpr uint32_t CLOUD_RECORD_ID_LEN = 33;
42 constexpr uint32_t DENTRYGROUP_HEADER = 4096;
43 constexpr uint32_t MAX_BUCKET_LEVEL = 63;
44 constexpr uint32_t BUCKET_BLOCKS = 2;
45 constexpr uint32_t BITS_PER_BYTE = 8;
46 constexpr uint32_t HMDFS_SLOT_LEN_BITS = 3;
47 constexpr uint64_t DELTA = 0x9E3779B9; /* Hashing code copied from f2fs */
48 constexpr uint64_t HMDFS_HASH_COL_BIT = (0x1ULL) << 63;
49 constexpr uint32_t FILE_TYPE_OFFSET = 2;
50 
51 #pragma pack(push, 1)
52 struct HmdfsDentry {
53     uint32_t hash{0};
54     uint16_t mode{0};
55     uint16_t namelen{0};
56     uint64_t size{0};
57     uint64_t mtime{0};
58     uint64_t atime{0};
59     uint8_t recordId[CLOUD_RECORD_ID_LEN]{0};
60 };
61 
62 struct HmdfsDentryGroup {
63     uint8_t dentryVersion;
64     uint8_t bitmap[DENTRY_BITMAP_LENGTH];
65     struct HmdfsDentry nsl[DENTRY_PER_GROUP];
66     uint8_t fileName[DENTRY_PER_GROUP][DENTRY_NAME_LEN];
67     uint8_t reserved[DENTRY_GROUP_RESERVED];
68 };
69 #pragma pack(pop)
70 
SetFileType(struct HmdfsDentry * de,uint8_t fileType)71 void MetaHelper::SetFileType(struct HmdfsDentry *de, uint8_t fileType)
72 {
73 }
74 
SetPosition(struct HmdfsDentry * de,uint8_t position)75 void MetaHelper::SetPosition(struct HmdfsDentry *de, uint8_t position)
76 {
77 }
78 
GetFileType(const struct HmdfsDentry * de)79 uint8_t MetaHelper::GetFileType(const struct HmdfsDentry *de)
80 {
81     return 0;
82 }
83 
GetPosition(const struct HmdfsDentry * de)84 uint8_t MetaHelper::GetPosition(const struct HmdfsDentry *de)
85 {
86     return 0;
87 }
88 
GetCloudDiskDentryFileByPath(uint32_t userId,const std::string & bundleName,const std::string & cloudId)89 static std::string GetCloudDiskDentryFileByPath(uint32_t userId, const std::string &bundleName,
90     const std::string &cloudId)
91 {
92     std::string cacheDir =
93         "/data/service/el2/" + std::to_string(userId) +
94         "/hmdfs/cloud/data/" + bundleName + "/" +
95         std::to_string(CloudDisk::CloudFileUtils::GetBucketId(cloudId)) + "/";
96     std::string dentryFileName = MetaFileMgr::GetInstance().CloudIdToRecordId(cloudId);
97     Storage::DistributedFile::Utils::ForceCreateDirectory(cacheDir, STAT_MODE_DIR);
98     return cacheDir + dentryFileName;
99 }
100 
CloudDiskMetaFile(uint32_t userId,const std::string & bundleName,const std::string & cloudId)101 CloudDiskMetaFile::CloudDiskMetaFile(uint32_t userId, const std::string &bundleName, const std::string &cloudId)
102 {
103 }
104 
GetDentryFilePath()105 std::string CloudDiskMetaFile::GetDentryFilePath()
106 {
107     return cacheFile_;
108 }
109 
DoLookupAndUpdate(const std::string & name,CloudDiskMetaFileCallBack callback)110 int32_t CloudDiskMetaFile::DoLookupAndUpdate(const std::string &name, CloudDiskMetaFileCallBack callback)
111 {
112     if (name == "mock") {
113         return E_RDB;
114     }
115     return E_OK;
116 }
117 
DoChildUpdate(const std::string & name,CloudDiskMetaFileCallBack callback)118 int32_t CloudDiskMetaFile::DoChildUpdate(const std::string &name, CloudDiskMetaFileCallBack callback)
119 {
120     if (name == "mock") {
121         return E_RDB;
122     }
123     return E_OK;
124 }
125 
DoLookupAndRemove(MetaBase & metaBase)126 int32_t CloudDiskMetaFile::DoLookupAndRemove(MetaBase &metaBase)
127 {
128     /* lookup and remove in parent */
129     int32_t ret = DoLookup(metaBase);
130     if (ret == E_OK) {
131         ret = DoRemove(metaBase);
132         if (ret != E_OK) {
133             LOGE("remove dentry file failed, ret %{public}d", ret);
134             return ret;
135         }
136         return E_OK;
137     }
138     return E_OK;
139 }
140 
~CloudDiskMetaFile()141 CloudDiskMetaFile::~CloudDiskMetaFile()
142 {
143 }
144 
IsDotDotdot(const std::string & name)145 static bool IsDotDotdot(const std::string &name)
146 {
147     return name == "." || name == "..";
148 }
149 
Str2HashBuf(const char * msg,size_t len,uint32_t * buf,int num)150 static void Str2HashBuf(const char *msg, size_t len, uint32_t *buf, int num)
151 {
152     uint32_t pad = static_cast<uint32_t>(len) | (static_cast<uint32_t>(len) << 8);
153     pad |= pad << 16; /* hash pad length 16 */
154 
155     uint32_t val = pad;
156     len = std::min(len, static_cast<size_t>(num * sizeof(int)));
157     for (uint32_t i = 0; i < len; i++) {
158         if ((i % sizeof(int)) == 0) {
159             val = pad;
160         }
161         uint8_t c = static_cast<uint8_t>(tolower(msg[i]));
162         val = c + (val << 8); /* hash shift size 8 */
163         if ((i % 4) == 3) {   /* msg size 4, shift when 3 */
164             *buf++ = val;
165             val = pad;
166             num--;
167         }
168     }
169     if (--num >= 0) {
170         *buf++ = val;
171     }
172     while (--num >= 0) {
173         *buf++ = pad;
174     }
175 }
176 
TeaTransform(uint32_t buf[4],uint32_t const in[])177 static void TeaTransform(uint32_t buf[4], uint32_t const in[]) __attribute__((no_sanitize("unsigned-integer-overflow")))
178 {
179     int n = 16;           /* transform total rounds 16 */
180     uint32_t a = in[0];   /* transform input pos 0 */
181     uint32_t b = in[1];   /* transform input pos 1 */
182     uint32_t c = in[2];   /* transform input pos 2 */
183     uint32_t d = in[3];   /* transform input pos 3 */
184     uint32_t b0 = buf[0]; /* buf pos 0 */
185     uint32_t b1 = buf[1]; /* buf pos 1 */
186     uint32_t sum = 0;
187 
188     do {
189         sum += DELTA;
190         b0 += ((b1 << 4) + a) ^ (b1 + sum) ^ ((b1 >> 5) + b); /* tea transform width 4 and 5 */
191         b1 += ((b0 << 4) + c) ^ (b0 + sum) ^ ((b0 >> 5) + d); /* tea transform width 4 and 5 */
192     } while (--n);
193 
194     buf[0] += b0;
195     buf[1] += b1;
196 }
197 
DentryHash(const std::string & name)198 static uint32_t DentryHash(const std::string &name)
199 {
200     if (IsDotDotdot(name)) {
201         return 0;
202     }
203 
204     constexpr int inLen = 8;      /* hash input buf size 8 */
205     constexpr int bufLen = 4;     /* hash output buf size 4 */
206     uint32_t in[inLen];
207     uint32_t buf[bufLen];
208     auto len = name.length();
209     constexpr decltype(len) hashWidth = 16; /* hash operation width 4 */
210     const char *p = name.c_str();
211 
212     buf[0] = 0x67452301; /* hash magic 1 */
213     buf[1] = 0xefcdab89; /* hash magic 2 */
214     buf[2] = 0x98badcfe; /* hash magic 3 */
215     buf[3] = 0x10325476; /* hash magic 4 */
216 
217     bool loopFlag = true;
218     while (loopFlag) {
219         Str2HashBuf(p, len, in, bufLen);
220         TeaTransform(buf, in);
221 
222         if (len <= hashWidth) {
223             break;
224         }
225 
226         p += hashWidth;
227         len -= hashWidth;
228     };
229     uint32_t hash = buf[0];
230     uint32_t hmdfsHash = hash & ~HMDFS_HASH_COL_BIT;
231 
232     return hmdfsHash;
233 }
234 
GetDentrySlots(size_t nameLen)235 static inline uint32_t GetDentrySlots(size_t nameLen)
236 {
237     return static_cast<uint32_t>((nameLen + BITS_PER_BYTE - 1) >> HMDFS_SLOT_LEN_BITS);
238 }
239 
GetDentryGroupPos(size_t bidx)240 static inline off_t GetDentryGroupPos(size_t bidx)
241 {
242     return bidx * DENTRYGROUP_SIZE + DENTRYGROUP_HEADER;
243 }
244 
GetDentryGroupCnt(uint64_t size)245 static inline uint64_t GetDentryGroupCnt(uint64_t size)
246 {
247     return (size >= DENTRYGROUP_HEADER) ? ((size - DENTRYGROUP_HEADER) / DENTRYGROUP_SIZE) : 0;
248 }
249 
GetOverallBucket(uint32_t level)250 static uint32_t GetOverallBucket(uint32_t level)
251 {
252     if (level >= MAX_BUCKET_LEVEL) {
253         LOGD("level = %{public}d overflow", level);
254         return 0;
255     }
256     uint64_t buckets = (1ULL << (level + 1)) - 1;
257     return static_cast<uint32_t>(buckets);
258 }
259 
GetDcacheFileSize(uint32_t level)260 static size_t GetDcacheFileSize(uint32_t level)
261 {
262     size_t buckets = GetOverallBucket(level);
263     return buckets * DENTRYGROUP_SIZE * BUCKET_BLOCKS + DENTRYGROUP_HEADER;
264 }
265 
GetBucketaddr(uint32_t level,uint32_t buckoffset)266 static uint32_t GetBucketaddr(uint32_t level, uint32_t buckoffset)
267 {
268     if (level >= MAX_BUCKET_LEVEL) {
269         return 0;
270     }
271 
272     uint64_t curLevelMaxBucks = (1ULL << level);
273     if (buckoffset >= curLevelMaxBucks) {
274         return 0;
275     }
276 
277     return static_cast<uint32_t>(curLevelMaxBucks) + buckoffset - 1;
278 }
279 
GetBucketByLevel(uint32_t level)280 static uint32_t GetBucketByLevel(uint32_t level)
281 {
282     if (level >= MAX_BUCKET_LEVEL) {
283         LOGD("level = %{public}d overflow", level);
284         return 0;
285     }
286 
287     uint64_t buckets = (1ULL << level);
288     return static_cast<uint32_t>(buckets);
289 }
290 
RoomForFilename(const uint8_t bitmap[],size_t slots,uint32_t maxSlots)291 static uint32_t RoomForFilename(const uint8_t bitmap[], size_t slots, uint32_t maxSlots)
292 {
293     uint32_t bitStart = 0;
294     bool loopFlag = true;
295     while (loopFlag) {
296         uint32_t zeroStart = BitOps::FindNextZeroBit(bitmap, maxSlots, bitStart);
297         if (zeroStart >= maxSlots) {
298             return maxSlots;
299         }
300 
301         uint32_t zeroEnd = BitOps::FindNextBit(bitmap, maxSlots, zeroStart);
302         if (zeroEnd - zeroStart >= slots) {
303             return zeroStart;
304         }
305 
306         bitStart = zeroEnd + 1;
307         if (zeroEnd + 1 >= maxSlots) {
308             return maxSlots;
309         }
310     }
311     return 0;
312 }
313 
UpdateDentry(HmdfsDentryGroup & d,const MetaBase & base,uint32_t nameHash,uint32_t bitPos)314 static void UpdateDentry(HmdfsDentryGroup &d, const MetaBase &base, uint32_t nameHash, uint32_t bitPos)
315 {
316     HmdfsDentry *de;
317     const std::string name = base.name;
318     uint32_t slots = GetDentrySlots(name.length());
319 
320     de = &d.nsl[bitPos];
321     de->hash = nameHash;
322     de->namelen = name.length();
323     auto ret = memcpy_s(d.fileName[bitPos], slots * DENTRY_NAME_LEN, name.c_str(), name.length());
324     if (ret != 0) {
325         LOGE("memcpy_s failed, dstLen = %{public}d, srcLen = %{public}zu", slots * DENTRY_NAME_LEN, name.length());
326     }
327     de->atime = base.atime;
328     de->mtime = base.mtime;
329     de->size = base.size;
330     de->mode = base.mode;
331     MetaHelper::SetPosition(de, base.position);
332     MetaHelper::SetFileType(de, base.fileType);
333     (void) memset_s(de->recordId, CLOUD_RECORD_ID_LEN, 0, CLOUD_RECORD_ID_LEN);
334     ret = memcpy_s(de->recordId, CLOUD_RECORD_ID_LEN, base.cloudId.c_str(), base.cloudId.length());
335     if (ret != 0) {
336         LOGE("memcpy_s failed, dstLen = %{public}d, srcLen = %{public}zu", CLOUD_RECORD_ID_LEN, base.cloudId.length());
337     }
338 
339     for (uint32_t i = 0; i < slots; i++) {
340         BitOps::SetBit(bitPos + i, d.bitmap);
341         if (i) {
342             (de + i)->namelen = 0;
343         }
344     }
345 }
346 
HandleFileByFd(unsigned long & endBlock,uint32_t & level)347 int32_t CloudDiskMetaFile::HandleFileByFd(unsigned long &endBlock, uint32_t &level)
348 {
349     return E_OK;
350 }
351 
GetBidxFromLevel(uint32_t level,uint32_t namehash)352 static unsigned long GetBidxFromLevel(uint32_t level, uint32_t namehash)
353 {
354     uint32_t bucket = GetBucketByLevel(level);
355     if (bucket == 0) {
356         return 0;
357     }
358     return BUCKET_BLOCKS * GetBucketaddr(level, namehash % bucket);
359 }
360 
DoCreate(const MetaBase & base)361 int32_t CloudDiskMetaFile::DoCreate(const MetaBase &base)
362 {
363     return E_OK;
364 }
365 
366 struct DcacheLookupCtx {
367     int fd{-1};
368     std::string name{};
369     uint32_t hash{0};
370     uint32_t bidx{0};
371     std::unique_ptr<HmdfsDentryGroup> page{nullptr};
372 };
373 
InitDcacheLookupCtx(DcacheLookupCtx * ctx,const MetaBase & base,int fd)374 static void InitDcacheLookupCtx(DcacheLookupCtx *ctx, const MetaBase &base, int fd)
375 {
376     ctx->fd = fd;
377     ctx->name = base.name;
378     ctx->bidx = 0;
379     ctx->page = nullptr;
380     ctx->hash = DentryHash(ctx->name);
381 }
382 
FindDentryPage(uint64_t index,DcacheLookupCtx * ctx)383 static std::unique_ptr<HmdfsDentryGroup> FindDentryPage(uint64_t index, DcacheLookupCtx *ctx)
384 {
385     auto dentryBlk = std::make_unique<HmdfsDentryGroup>();
386 
387     off_t pos = GetDentryGroupPos(index);
388     ssize_t size = FileUtils::ReadFile(ctx->fd, pos, DENTRYGROUP_SIZE, dentryBlk.get());
389     if (size != DENTRYGROUP_SIZE) {
390         return nullptr;
391     }
392     return dentryBlk;
393 }
394 
FindInBlock(HmdfsDentryGroup & dentryBlk,uint32_t namehash,const std::string & name)395 static HmdfsDentry *FindInBlock(HmdfsDentryGroup &dentryBlk, uint32_t namehash, const std::string &name)
396 {
397     int maxLen = 0;
398     uint32_t bitPos = 0;
399     HmdfsDentry *de = nullptr;
400 
401     while (bitPos < DENTRY_PER_GROUP) {
402         if (!BitOps::TestBit(bitPos, dentryBlk.bitmap)) {
403             bitPos++;
404             maxLen++;
405             continue;
406         }
407         de = &dentryBlk.nsl[bitPos];
408         if (!de->namelen) {
409             bitPos++;
410             continue;
411         }
412 
413         if (de->hash == namehash && de->namelen == name.length() &&
414             !memcmp(name.c_str(), dentryBlk.fileName[bitPos], de->namelen)) {
415             return de;
416         }
417         maxLen = 0;
418         bitPos += GetDentrySlots(de->namelen);
419     }
420 
421     return nullptr;
422 }
423 
InLevel(uint32_t level,DcacheLookupCtx * ctx)424 static HmdfsDentry *InLevel(uint32_t level, DcacheLookupCtx *ctx)
425     __attribute__((no_sanitize("unsigned-integer-overflow")))
426 {
427     HmdfsDentry *de = nullptr;
428 
429     uint32_t nbucket = GetBucketByLevel(level);
430     if (nbucket == 0) {
431         return de;
432     }
433 
434     uint32_t bidx = GetBucketaddr(level, ctx->hash % nbucket) * BUCKET_BLOCKS;
435     uint32_t endBlock = bidx + BUCKET_BLOCKS;
436 
437     for (; bidx < endBlock; bidx++) {
438         auto dentryBlk = FindDentryPage(bidx, ctx);
439         if (dentryBlk == nullptr) {
440             break;
441         }
442 
443         de = FindInBlock(*dentryBlk, ctx->hash, ctx->name);
444         if (de != nullptr) {
445             ctx->page = std::move(dentryBlk);
446             break;
447         }
448     }
449     ctx->bidx = bidx;
450     return de;
451 }
452 
FindDentry(DcacheLookupCtx * ctx)453 static HmdfsDentry *FindDentry(DcacheLookupCtx *ctx)
454 {
455     for (uint32_t level = 0; level < MAX_BUCKET_LEVEL; level++) {
456         HmdfsDentry *de = InLevel(level, ctx);
457         if (de != nullptr) {
458             return de;
459         }
460     }
461     return nullptr;
462 }
463 
DoRemove(const MetaBase & base)464 int32_t CloudDiskMetaFile::DoRemove(const MetaBase &base)
465 {
466     return E_OK;
467 }
468 
DoLookup(MetaBase & base)469 int32_t CloudDiskMetaFile::DoLookup(MetaBase &base)
470 {
471     if (base.name == "mock") {
472         return EINVAL;
473     }
474     return E_OK;
475 }
476 
DoUpdate(const MetaBase & base)477 int32_t CloudDiskMetaFile::DoUpdate(const MetaBase &base)
478 {
479     return E_OK;
480 }
481 
DoRename(MetaBase & metaBase,const std::string & newName,std::shared_ptr<CloudDiskMetaFile> newMetaFile)482 int32_t CloudDiskMetaFile::DoRename(MetaBase &metaBase, const std::string &newName,
483     std::shared_ptr<CloudDiskMetaFile> newMetaFile)
484 {
485     if (newName == "mock") {
486         return EINVAL;
487     }
488     return E_OK;
489 }
490 
DecodeDentrys(const HmdfsDentryGroup & dentryGroup,std::vector<MetaBase> & bases)491 static int32_t DecodeDentrys(const HmdfsDentryGroup &dentryGroup, std::vector<MetaBase> &bases)
492 {
493     return 0;
494 }
495 
LoadChildren(std::vector<MetaBase> & bases)496 int32_t CloudDiskMetaFile::LoadChildren(std::vector<MetaBase> &bases)
497 {
498     return E_OK;
499 }
500 
Clear(uint32_t userId,const std::string & bundleName,const std::string & cloudId)501 void MetaFileMgr::Clear(uint32_t userId, const std::string &bundleName,
502     const std::string &cloudId)
503 {
504     std::lock_guard<std::mutex> lock(cloudDiskMutex_);
505     MetaFileKey key(userId, cloudId + bundleName);
506     cloudDiskMetaFile_.erase(key);
507     cloudDiskMetaFileList_.remove_if([key](CloudDiskMetaFileListEle &item) { return item.first == key; });
508 }
509 
CloudDiskClearAll()510 void MetaFileMgr::CloudDiskClearAll()
511 {
512     std::lock_guard<std::mutex> lock(cloudDiskMutex_);
513     cloudDiskMetaFile_.clear();
514     cloudDiskMetaFileList_.clear();
515 }
516 
GetCloudDiskMetaFile(uint32_t userId,const std::string & bundleName,const std::string & cloudId)517 std::shared_ptr<CloudDiskMetaFile> MetaFileMgr::GetCloudDiskMetaFile(uint32_t userId, const std::string &bundleName,
518     const std::string &cloudId)
519 {
520     std::shared_ptr<CloudDiskMetaFile> mFile = nullptr;
521     std::lock_guard<std::mutex> lock(cloudDiskMutex_);
522     MetaFileKey key(userId, cloudId + bundleName);
523     auto it = cloudDiskMetaFile_.find(key);
524     if (it != cloudDiskMetaFile_.end()) {
525         cloudDiskMetaFileList_.splice(cloudDiskMetaFileList_.begin(), cloudDiskMetaFileList_, it->second);
526         mFile = it->second->second;
527     } else {
528         if (cloudDiskMetaFile_.size() == MAX_META_FILE_NUM) {
529             auto deleteKey = cloudDiskMetaFileList_.back().first;
530             cloudDiskMetaFile_.erase(deleteKey);
531             cloudDiskMetaFileList_.pop_back();
532         }
533         mFile = std::make_shared<CloudDiskMetaFile>(userId, bundleName, cloudId);
534         cloudDiskMetaFileList_.emplace_front(key, mFile);
535         cloudDiskMetaFile_[key] = cloudDiskMetaFileList_.begin();
536     }
537     return mFile;
538 }
539 
CreateRecycleDentry(uint32_t userId,const std::string & bundleName)540 int32_t MetaFileMgr::CreateRecycleDentry(uint32_t userId, const std::string &bundleName)
541 {
542     if (bundleName != "com.ohos.photos") {
543         return EINVAL;
544     }
545     return E_OK;
546 }
547 
MoveIntoRecycleDentryfile(uint32_t userId,const std::string & bundleName,const std::string & name,const std::string & parentCloudId,int64_t rowId)548 int32_t MetaFileMgr::MoveIntoRecycleDentryfile(uint32_t userId, const std::string &bundleName, const std::string &name,
549     const std::string &parentCloudId, int64_t rowId)
550 {
551     if (parentCloudId == "mock") {
552         return E_RDB;
553     }
554     return E_OK;
555 }
556 
RemoveFromRecycleDentryfile(uint32_t userId,const std::string & bundleName,const struct RestoreInfo & restoreInfo)557 int32_t MetaFileMgr::RemoveFromRecycleDentryfile(uint32_t userId, const std::string &bundleName,
558     const struct RestoreInfo &restoreInfo)
559 {
560     if (restoreInfo.parentCloudId == "mock") {
561         return E_RDB;
562     }
563     return E_OK;
564 }
565 
GetNewName(std::shared_ptr<CloudDiskMetaFile> metaFile,const std::string & oldName,std::string & newName)566 int32_t MetaFileMgr::GetNewName(std::shared_ptr<CloudDiskMetaFile> metaFile, const std::string &oldName,
567     std::string &newName)
568 {
569     return E_OK;
570 }
571 } // namespace FileManagement
572 } // namespace OHOS