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 33namespace OHOS { 34namespace FileManagement { 35constexpr uint32_t DENTRYGROUP_SIZE = 4096; 36constexpr uint32_t DENTRY_NAME_LEN = 8; 37constexpr uint32_t DENTRY_RESERVED_LENGTH = 4; 38constexpr uint32_t DENTRY_PER_GROUP = 52; 39constexpr uint32_t DENTRY_BITMAP_LENGTH = 7; 40constexpr uint32_t DENTRY_GROUP_RESERVED = 32; 41constexpr uint32_t CLOUD_RECORD_ID_LEN = 33; 42constexpr uint32_t DENTRYGROUP_HEADER = 4096; 43constexpr uint32_t MAX_BUCKET_LEVEL = 63; 44constexpr uint32_t BUCKET_BLOCKS = 2; 45constexpr uint32_t BITS_PER_BYTE = 8; 46constexpr uint32_t HMDFS_SLOT_LEN_BITS = 3; 47constexpr uint32_t FILE_TYPE_OFFSET = 2; 48constexpr uint32_t NO_UPLOAD_OFFSET = 4; 49 50#pragma pack(push, 1) 51struct HmdfsDentry { 52 uint32_t hash{0}; 53 uint16_t mode{0}; 54 uint16_t namelen{0}; 55 uint64_t size{0}; 56 uint64_t mtime{0}; 57 uint64_t atime{0}; 58 uint8_t recordId[CLOUD_RECORD_ID_LEN]{0}; 59 uint8_t flags{0}; 60 /* reserved bytes for long term extend, total 60 bytes */ 61 uint8_t reserved[DENTRY_RESERVED_LENGTH]; 62}; 63 64struct HmdfsDentryGroup { 65 uint8_t dentryVersion; 66 uint8_t bitmap[DENTRY_BITMAP_LENGTH]; 67 struct HmdfsDentry nsl[DENTRY_PER_GROUP]; 68 uint8_t fileName[DENTRY_PER_GROUP][DENTRY_NAME_LEN]; 69 uint8_t reserved[DENTRY_GROUP_RESERVED]; 70}; 71static_assert(sizeof(HmdfsDentryGroup) == DENTRYGROUP_SIZE); 72 73struct HmdfsDcacheHeader { 74 uint64_t dcacheCrtime{0}; 75 uint64_t dcacheCrtimeNsec{0}; 76 77 uint64_t dentryCtime{0}; 78 uint64_t dentryCtimeNsec{0}; 79 80 uint64_t dentryCount{0}; 81}; 82#pragma pack(pop) 83 84void MetaHelper::SetFileType(struct HmdfsDentry *de, uint8_t fileType) 85{ 86 de->flags &= 0x13; 87 de->flags |= (fileType << FILE_TYPE_OFFSET); 88} 89 90void MetaHelper::SetPosition(struct HmdfsDentry *de, uint8_t position) 91{ 92 de->flags &= 0xFC; 93 de->flags |= position; 94} 95 96void MetaHelper::SetNoUpload(struct HmdfsDentry *de, uint8_t noUpload) 97{ 98 de->flags &= 0xEF; 99 de->flags |= (noUpload << NO_UPLOAD_OFFSET); 100} 101 102uint8_t MetaHelper::GetNoUpload(const struct HmdfsDentry *de) 103{ 104 return (de->flags & 0x10) >> NO_UPLOAD_OFFSET; 105} 106 107uint8_t MetaHelper::GetFileType(const struct HmdfsDentry *de) 108{ 109 return (de->flags & 0xC) >> FILE_TYPE_OFFSET; 110} 111 112uint8_t MetaHelper::GetPosition(const struct HmdfsDentry *de) 113{ 114 return de->flags & 0x3; 115} 116 117static std::string GetCloudDiskDentryFileByPath(uint32_t userId, const std::string &bundleName, 118 const std::string &cloudId) 119{ 120 std::string cacheDir = 121 "/data/service/el2/" + std::to_string(userId) + 122 "/hmdfs/cloud/data/" + bundleName + "/" + 123 std::to_string(CloudDisk::CloudFileUtils::GetBucketId(cloudId)) + "/"; 124 std::string dentryFileName = MetaFileMgr::GetInstance().CloudIdToRecordId(cloudId); 125 Storage::DistributedFile::Utils::ForceCreateDirectory(cacheDir, STAT_MODE_DIR); 126 return cacheDir + dentryFileName; 127} 128 129CloudDiskMetaFile::CloudDiskMetaFile(uint32_t userId, const std::string &bundleName, const std::string &cloudId) 130{ 131 userId_ = userId; 132 bundleName_ = bundleName; 133 cloudId_ = cloudId; 134 cacheFile_ = GetCloudDiskDentryFileByPath(userId_, bundleName_, cloudId_); 135 fd_ = UniqueFd{open(cacheFile_.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)}; 136 LOGD("CloudDiskMetaFile cloudId=%{public}s, path=%{public}s", cloudId_.c_str(), GetAnonyString(cacheFile_).c_str()); 137 LOGD("CloudDiskMetaFile fd=%{public}d, errno :%{public}d", fd_.Get(), errno); 138 139 HmdfsDcacheHeader header{}; 140 (void)FileUtils::ReadFile(fd_, 0, sizeof(header), &header); 141} 142 143std::string CloudDiskMetaFile::GetDentryFilePath() 144{ 145 return cacheFile_; 146} 147 148int32_t CloudDiskMetaFile::DoLookupAndUpdate(const std::string &name, CloudDiskMetaFileCallBack callback) 149{ 150 MetaBase m(name); 151 /* lookup and create in parent */ 152 int32_t ret = DoLookup(m); 153 if (ret != E_OK) { 154 callback(m); 155 ret = DoCreate(m); 156 if (ret != E_OK) { 157 LOGE("create dentry file failed, ret %{public}d", ret); 158 return ret; 159 } 160 return ret; 161 } else { 162 callback(m); 163 ret = DoUpdate(m); 164 if (ret != E_OK) { 165 LOGE("update dentry file failed, ret %{public}d", ret); 166 return ret; 167 } 168 } 169 return E_OK; 170} 171 172int32_t CloudDiskMetaFile::DoChildUpdate(const std::string &name, CloudDiskMetaFileCallBack callback) 173{ 174 MetaBase m(name); 175 /* lookup and update */ 176 int32_t ret = DoLookup(m); 177 if (ret != E_OK) { 178 LOGE("lookup dentry file failed, ret %{public}d", ret); 179 return ret; 180 } else { 181 callback(m); 182 ret = DoUpdate(m); 183 if (ret != E_OK) { 184 LOGE("update dentry file failed, ret %{public}d", ret); 185 return ret; 186 } 187 } 188 return E_OK; 189} 190 191int32_t CloudDiskMetaFile::DoLookupAndRemove(MetaBase &metaBase) 192{ 193 /* lookup and remove in parent */ 194 int32_t ret = DoLookup(metaBase); 195 if (ret == E_OK) { 196 ret = DoRemove(metaBase); 197 if (ret != E_OK) { 198 LOGE("remove dentry file failed, ret %{public}d", ret); 199 return ret; 200 } 201 return E_OK; 202 } 203 return E_OK; 204} 205 206CloudDiskMetaFile::~CloudDiskMetaFile() 207{ 208} 209 210static inline uint32_t GetDentrySlots(size_t nameLen) 211{ 212 return static_cast<uint32_t>((nameLen + BITS_PER_BYTE - 1) >> HMDFS_SLOT_LEN_BITS); 213} 214 215static inline off_t GetDentryGroupPos(size_t bidx) 216{ 217 return bidx * DENTRYGROUP_SIZE + DENTRYGROUP_HEADER; 218} 219 220static inline uint64_t GetDentryGroupCnt(uint64_t size) 221{ 222 return (size >= DENTRYGROUP_HEADER) ? ((size - DENTRYGROUP_HEADER) / DENTRYGROUP_SIZE) : 0; 223} 224 225static uint32_t GetOverallBucket(uint32_t level) 226{ 227 if (level >= MAX_BUCKET_LEVEL) { 228 LOGD("level = %{public}d overflow", level); 229 return 0; 230 } 231 uint64_t buckets = (1ULL << (level + 1)) - 1; 232 return static_cast<uint32_t>(buckets); 233} 234 235static size_t GetDcacheFileSize(uint32_t level) 236{ 237 size_t buckets = GetOverallBucket(level); 238 return buckets * DENTRYGROUP_SIZE * BUCKET_BLOCKS + DENTRYGROUP_HEADER; 239} 240 241static uint32_t GetBucketaddr(uint32_t level, uint32_t buckoffset) 242{ 243 if (level >= MAX_BUCKET_LEVEL) { 244 return 0; 245 } 246 247 uint64_t curLevelMaxBucks = (1ULL << level); 248 if (buckoffset >= curLevelMaxBucks) { 249 return 0; 250 } 251 252 return static_cast<uint32_t>(curLevelMaxBucks) + buckoffset - 1; 253} 254 255static uint32_t GetBucketByLevel(uint32_t level) 256{ 257 if (level >= MAX_BUCKET_LEVEL) { 258 LOGD("level = %{public}d overflow", level); 259 return 0; 260 } 261 262 uint64_t buckets = (1ULL << level); 263 return static_cast<uint32_t>(buckets); 264} 265 266static uint32_t RoomForFilename(const uint8_t bitmap[], size_t slots, uint32_t maxSlots) 267{ 268 uint32_t bitStart = 0; 269 bool loopFlag = true; 270 while (loopFlag) { 271 uint32_t zeroStart = BitOps::FindNextZeroBit(bitmap, maxSlots, bitStart); 272 if (zeroStart >= maxSlots) { 273 return maxSlots; 274 } 275 276 uint32_t zeroEnd = BitOps::FindNextBit(bitmap, maxSlots, zeroStart); 277 if (zeroEnd - zeroStart >= slots) { 278 return zeroStart; 279 } 280 281 bitStart = zeroEnd + 1; 282 if (zeroEnd + 1 >= maxSlots) { 283 return maxSlots; 284 } 285 } 286 return 0; 287} 288 289static bool UpdateDentry(HmdfsDentryGroup &d, const MetaBase &base, uint32_t nameHash, uint32_t bitPos) 290{ 291 HmdfsDentry *de; 292 const std::string name = base.name; 293 uint32_t slots = GetDentrySlots(name.length()); 294 295 de = &d.nsl[bitPos]; 296 de->hash = nameHash; 297 de->namelen = name.length(); 298 auto ret = memcpy_s(d.fileName[bitPos], slots * DENTRY_NAME_LEN, name.c_str(), name.length()); 299 if (ret != 0) { 300 LOGE("memcpy_s failed, dstLen = %{public}d, srcLen = %{public}zu", slots * DENTRY_NAME_LEN, name.length()); 301 return false; 302 } 303 de->atime = base.atime; 304 de->mtime = base.mtime; 305 de->size = base.size; 306 de->mode = base.mode; 307 MetaHelper::SetPosition(de, base.position); 308 MetaHelper::SetFileType(de, base.fileType); 309 MetaHelper::SetNoUpload(de, base.noUpload); 310 (void) memset_s(de->recordId, CLOUD_RECORD_ID_LEN, 0, CLOUD_RECORD_ID_LEN); 311 ret = memcpy_s(de->recordId, CLOUD_RECORD_ID_LEN, base.cloudId.c_str(), base.cloudId.length()); 312 if (ret != 0) { 313 LOGE("memcpy_s failed, dstLen = %{public}d, srcLen = %{public}zu", CLOUD_RECORD_ID_LEN, base.cloudId.length()); 314 return false; 315 } 316 317 for (uint32_t i = 0; i < slots; i++) { 318 BitOps::SetBit(bitPos + i, d.bitmap); 319 if (i) { 320 (de + i)->namelen = 0; 321 } 322 } 323 return true; 324} 325 326int32_t CloudDiskMetaFile::HandleFileByFd(unsigned long &endBlock, uint32_t &level) 327{ 328 struct stat fileStat; 329 int err = fstat(fd_, &fileStat); 330 if (err < 0) { 331 return EINVAL; 332 } 333 if ((endBlock > GetDentryGroupCnt(fileStat.st_size)) && 334 ftruncate(fd_, GetDcacheFileSize(level))) { 335 return ENOENT; 336 } 337 return E_OK; 338} 339 340static unsigned long GetBidxFromLevel(uint32_t level, uint32_t namehash) 341{ 342 uint32_t bucket = GetBucketByLevel(level); 343 if (bucket == 0) { 344 return 0; 345 } 346 return BUCKET_BLOCKS * GetBucketaddr(level, namehash % bucket); 347} 348 349int32_t CloudDiskMetaFile::DoCreate(const MetaBase &base) 350{ 351 if (fd_ < 0) { 352 LOGE("bad metafile fd"); 353 return EINVAL; 354 } 355 off_t pos = 0; 356 uint32_t level = 0; 357 uint32_t bitPos = 0; 358 unsigned long bidx = 0; 359 HmdfsDentryGroup dentryBlk = {0}; 360 std::unique_lock<std::mutex> lock(mtx_); 361 FileRangeLock fileLock(fd_, 0, 0); 362 uint32_t namehash = CloudDisk::CloudFileUtils::DentryHash(base.name); 363 bool found = false; 364 while (!found) { 365 if (level == MAX_BUCKET_LEVEL) { 366 return ENOSPC; 367 } 368 bidx = GetBidxFromLevel(level, namehash); 369 unsigned long endBlock = bidx + BUCKET_BLOCKS; 370 int32_t ret = HandleFileByFd(endBlock, level); 371 if (ret != E_OK) { 372 return ret; 373 } 374 for (; bidx < endBlock; bidx++) { 375 pos = GetDentryGroupPos(bidx); 376 if (FileUtils::ReadFile(fd_, pos, DENTRYGROUP_SIZE, &dentryBlk) != DENTRYGROUP_SIZE) { 377 return ENOENT; 378 } 379 bitPos = RoomForFilename(dentryBlk.bitmap, GetDentrySlots(base.name.length()), DENTRY_PER_GROUP); 380 if (bitPos < DENTRY_PER_GROUP) { 381 found = true; 382 break; 383 } 384 } 385 ++level; 386 } 387 pos = GetDentryGroupPos(bidx); 388 if (!UpdateDentry(dentryBlk, base, namehash, bitPos)) { 389 LOGI("UpdateDentry fail, stop write."); 390 return EINVAL; 391 } 392 int size = FileUtils::WriteFile(fd_, &dentryBlk, pos, DENTRYGROUP_SIZE); 393 if (size != DENTRYGROUP_SIZE) { 394 LOGD("WriteFile failed, size %{public}d != %{public}d", size, DENTRYGROUP_SIZE); 395 return EINVAL; 396 } 397 return E_OK; 398} 399 400struct DcacheLookupCtx { 401 int fd{-1}; 402 std::string name{}; 403 uint32_t hash{0}; 404 uint32_t bidx{0}; 405 std::unique_ptr<HmdfsDentryGroup> page{nullptr}; 406}; 407 408static void InitDcacheLookupCtx(DcacheLookupCtx *ctx, const MetaBase &base, int fd) 409{ 410 ctx->fd = fd; 411 ctx->name = base.name; 412 ctx->bidx = 0; 413 ctx->page = nullptr; 414 ctx->hash = CloudDisk::CloudFileUtils::DentryHash(ctx->name); 415} 416 417static std::unique_ptr<HmdfsDentryGroup> FindDentryPage(uint64_t index, DcacheLookupCtx *ctx) 418{ 419 auto dentryBlk = std::make_unique<HmdfsDentryGroup>(); 420 421 off_t pos = GetDentryGroupPos(index); 422 ssize_t size = FileUtils::ReadFile(ctx->fd, pos, DENTRYGROUP_SIZE, dentryBlk.get()); 423 if (size != DENTRYGROUP_SIZE) { 424 return nullptr; 425 } 426 return dentryBlk; 427} 428 429static HmdfsDentry *FindInBlock(HmdfsDentryGroup &dentryBlk, uint32_t namehash, const std::string &name) 430{ 431 int maxLen = 0; 432 uint32_t bitPos = 0; 433 HmdfsDentry *de = nullptr; 434 435 while (bitPos < DENTRY_PER_GROUP) { 436 if (!BitOps::TestBit(bitPos, dentryBlk.bitmap)) { 437 bitPos++; 438 maxLen++; 439 continue; 440 } 441 de = &dentryBlk.nsl[bitPos]; 442 if (!de->namelen) { 443 bitPos++; 444 continue; 445 } 446 447 if (de->hash == namehash && de->namelen == name.length() && 448 !memcmp(name.c_str(), dentryBlk.fileName[bitPos], de->namelen)) { 449 return de; 450 } 451 maxLen = 0; 452 bitPos += GetDentrySlots(de->namelen); 453 } 454 455 return nullptr; 456} 457 458static HmdfsDentry *InLevel(uint32_t level, DcacheLookupCtx *ctx) 459 __attribute__((no_sanitize("unsigned-integer-overflow"))) 460{ 461 HmdfsDentry *de = nullptr; 462 463 uint32_t nbucket = GetBucketByLevel(level); 464 if (nbucket == 0) { 465 return de; 466 } 467 468 uint32_t bidx = GetBucketaddr(level, ctx->hash % nbucket) * BUCKET_BLOCKS; 469 uint32_t endBlock = bidx + BUCKET_BLOCKS; 470 471 for (; bidx < endBlock; bidx++) { 472 auto dentryBlk = FindDentryPage(bidx, ctx); 473 if (dentryBlk == nullptr) { 474 break; 475 } 476 477 de = FindInBlock(*dentryBlk, ctx->hash, ctx->name); 478 if (de != nullptr) { 479 ctx->page = std::move(dentryBlk); 480 break; 481 } 482 } 483 ctx->bidx = bidx; 484 return de; 485} 486 487static HmdfsDentry *FindDentry(DcacheLookupCtx *ctx) 488{ 489 for (uint32_t level = 0; level < MAX_BUCKET_LEVEL; level++) { 490 HmdfsDentry *de = InLevel(level, ctx); 491 if (de != nullptr) { 492 return de; 493 } 494 } 495 return nullptr; 496} 497 498int32_t CloudDiskMetaFile::DoRemove(const MetaBase &base) 499{ 500 if (fd_ < 0) { 501 LOGE("bad metafile fd"); 502 return EINVAL; 503 } 504 505 std::unique_lock<std::mutex> lock(mtx_); 506 FileRangeLock fileLock(fd_, 0, 0); 507 DcacheLookupCtx ctx; 508 InitDcacheLookupCtx(&ctx, base, fd_); 509 HmdfsDentry *de = FindDentry(&ctx); 510 if (de == nullptr) { 511 LOGE("find dentry failed"); 512 return ENOENT; 513 } 514 515 uint32_t bitPos = (de - ctx.page->nsl); 516 uint32_t slots = GetDentrySlots(de->namelen); 517 for (uint32_t i = 0; i < slots; i++) { 518 BitOps::ClearBit(bitPos + i, ctx.page->bitmap); 519 } 520 521 off_t ipos = GetDentryGroupPos(ctx.bidx); 522 ssize_t size = FileUtils::WriteFile(fd_, ctx.page.get(), ipos, sizeof(HmdfsDentryGroup)); 523 if (size != sizeof(HmdfsDentryGroup)) { 524 LOGE("WriteFile failed!, ret = %{public}zd", size); 525 return EIO; 526 } 527 528 return E_OK; 529} 530 531int32_t CloudDiskMetaFile::DoLookup(MetaBase &base) 532{ 533 if (fd_ < 0) { 534 LOGE("bad metafile fd"); 535 return EINVAL; 536 } 537 538 std::unique_lock<std::mutex> lock(mtx_); 539 FileRangeLock fileLock(fd_, 0, 0); 540 struct DcacheLookupCtx ctx; 541 InitDcacheLookupCtx(&ctx, base, fd_); 542 struct HmdfsDentry *de = FindDentry(&ctx); 543 if (de == nullptr) { 544 LOGD("find dentry failed"); 545 return ENOENT; 546 } 547 548 base.size = de->size; 549 base.atime = de->atime; 550 base.mtime = de->mtime; 551 base.mode = de->mode; 552 base.position = MetaHelper::GetPosition(de); 553 base.fileType = MetaHelper::GetFileType(de); 554 base.noUpload = MetaHelper::GetNoUpload(de); 555 base.cloudId = std::string(reinterpret_cast<const char *>(de->recordId), CLOUD_RECORD_ID_LEN); 556 return E_OK; 557} 558 559int32_t CloudDiskMetaFile::DoUpdate(const MetaBase &base) 560{ 561 if (fd_ < 0) { 562 LOGE("bad metafile fd"); 563 return EINVAL; 564 } 565 566 std::unique_lock<std::mutex> lock(mtx_); 567 FileRangeLock fileLock(fd_, 0, 0); 568 struct DcacheLookupCtx ctx; 569 InitDcacheLookupCtx(&ctx, base, fd_); 570 struct HmdfsDentry *de = FindDentry(&ctx); 571 if (de == nullptr) { 572 LOGD("find dentry failed"); 573 return ENOENT; 574 } 575 576 de->atime = base.atime; 577 de->mtime = base.mtime; 578 de->size = base.size; 579 de->mode = base.mode; 580 MetaHelper::SetPosition(de, base.position); 581 MetaHelper::SetFileType(de, base.fileType); 582 MetaHelper::SetNoUpload(de, base.noUpload); 583 auto ret = memcpy_s(de->recordId, CLOUD_RECORD_ID_LEN, base.cloudId.c_str(), base.cloudId.length()); 584 if (ret != 0) { 585 LOGE("memcpy_s failed, dstLen = %{public}d, srcLen = %{public}zu", CLOUD_RECORD_ID_LEN, base.cloudId.length()); 586 } 587 588 off_t ipos = GetDentryGroupPos(ctx.bidx); 589 ssize_t size = FileUtils::WriteFile(fd_, ctx.page.get(), ipos, sizeof(struct HmdfsDentryGroup)); 590 if (size != sizeof(struct HmdfsDentryGroup)) { 591 LOGE("write failed, ret = %{public}zd", size); 592 return EIO; 593 } 594 return E_OK; 595} 596 597int32_t CloudDiskMetaFile::DoRename(MetaBase &metaBase, const std::string &newName, 598 std::shared_ptr<CloudDiskMetaFile> newMetaFile) 599{ 600 std::string oldName = metaBase.name; 601 metaBase.name = newName; 602 int32_t ret = newMetaFile->DoCreate(metaBase); 603 if (ret != E_OK) { 604 LOGE("create dentry failed, ret = %{public}d", ret); 605 return ret; 606 } 607 metaBase.name = oldName; 608 ret = DoRemove(metaBase); 609 if (ret != E_OK) { 610 LOGE("remove dentry failed, ret = %{public}d", ret); 611 metaBase.name = newName; 612 (void)newMetaFile->DoRemove(metaBase); 613 return ret; 614 } 615 return E_OK; 616} 617 618static int32_t DecodeDentrys(const HmdfsDentryGroup &dentryGroup, std::vector<MetaBase> &bases) 619{ 620 for (uint32_t i = 0; i < DENTRY_PER_GROUP; i++) { 621 int len = dentryGroup.nsl[i].namelen; 622 if (!BitOps::TestBit(i, dentryGroup.bitmap) || len == 0 || len >= PATH_MAX) { 623 continue; 624 } 625 626 std::string name(reinterpret_cast<const char *>(dentryGroup.fileName[i]), len); 627 628 MetaBase base(name); 629 base.mode = dentryGroup.nsl[i].mode; 630 base.mtime = dentryGroup.nsl[i].mtime; 631 base.size = dentryGroup.nsl[i].size; 632 base.position = MetaHelper::GetPosition(&dentryGroup.nsl[i]); 633 base.fileType = MetaHelper::GetFileType(&dentryGroup.nsl[i]); 634 base.cloudId = std::string(reinterpret_cast<const char *>(dentryGroup.nsl[i].recordId), CLOUD_RECORD_ID_LEN); 635 bases.emplace_back(base); 636 } 637 return 0; 638} 639 640int32_t CloudDiskMetaFile::LoadChildren(std::vector<MetaBase> &bases) 641{ 642 if (fd_ < 0) { 643 LOGE("bad metafile fd"); 644 return EINVAL; 645 } 646 647 std::lock_guard<std::mutex> lock(mtx_); 648 FileRangeLock fileLock(fd_, 0, 0); 649 struct stat fileStat; 650 int ret = fstat(fd_, &fileStat); 651 if (ret != E_OK) { 652 return EINVAL; 653 } 654 655 uint64_t fileSize = static_cast<uint64_t>(fileStat.st_size); 656 uint64_t groupCnt = GetDentryGroupCnt(fileSize); 657 HmdfsDentryGroup dentryGroup; 658 659 for (uint64_t i = 1; i < groupCnt + 1; i++) { 660 uint64_t off = i * sizeof(HmdfsDentryGroup); 661 FileUtils::ReadFile(fd_, off, sizeof(HmdfsDentryGroup), &dentryGroup); 662 DecodeDentrys(dentryGroup, bases); 663 } 664 return E_OK; 665} 666 667void MetaFileMgr::Clear(uint32_t userId, const std::string &bundleName, 668 const std::string &cloudId) 669{ 670 std::lock_guard<std::mutex> lock(cloudDiskMutex_); 671 MetaFileKey key(userId, cloudId + bundleName); 672 cloudDiskMetaFile_.erase(key); 673 cloudDiskMetaFileList_.remove_if([key](CloudDiskMetaFileListEle &item) { return item.first == key; }); 674} 675 676void MetaFileMgr::CloudDiskClearAll() 677{ 678 std::lock_guard<std::mutex> lock(cloudDiskMutex_); 679 cloudDiskMetaFile_.clear(); 680 cloudDiskMetaFileList_.clear(); 681} 682 683std::shared_ptr<CloudDiskMetaFile> MetaFileMgr::GetCloudDiskMetaFile(uint32_t userId, const std::string &bundleName, 684 const std::string &cloudId) 685{ 686 std::shared_ptr<CloudDiskMetaFile> mFile = nullptr; 687 std::lock_guard<std::mutex> lock(cloudDiskMutex_); 688 MetaFileKey key(userId, cloudId + bundleName); 689 auto it = cloudDiskMetaFile_.find(key); 690 if (it != cloudDiskMetaFile_.end()) { 691 cloudDiskMetaFileList_.splice(cloudDiskMetaFileList_.begin(), cloudDiskMetaFileList_, it->second); 692 mFile = it->second->second; 693 } else { 694 if (cloudDiskMetaFile_.size() == MAX_CLOUDDISK_META_FILE_NUM) { 695 auto deleteKey = cloudDiskMetaFileList_.back().first; 696 cloudDiskMetaFile_.erase(deleteKey); 697 cloudDiskMetaFileList_.pop_back(); 698 } 699 mFile = std::make_shared<CloudDiskMetaFile>(userId, bundleName, cloudId); 700 cloudDiskMetaFileList_.emplace_front(key, mFile); 701 cloudDiskMetaFile_[key] = cloudDiskMetaFileList_.begin(); 702 } 703 return mFile; 704} 705 706int32_t MetaFileMgr::CreateRecycleDentry(uint32_t userId, const std::string &bundleName) 707{ 708 MetaBase metaBase(RECYCLE_NAME); 709 auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(userId, bundleName, ROOT_CLOUD_ID); 710 int32_t ret = metaFile->DoLookup(metaBase); 711 if (ret != 0) { 712 metaBase.cloudId = RECYCLE_CLOUD_ID; 713 metaBase.mode = S_IFDIR | STAT_MODE_DIR; 714 metaBase.position = static_cast<uint8_t>(LOCAL); 715 ret = metaFile->DoCreate(metaBase); 716 if (ret != 0) { 717 return ret; 718 } 719 } 720 return 0; 721} 722 723int32_t MetaFileMgr::MoveIntoRecycleDentryfile(uint32_t userId, const std::string &bundleName, const std::string &name, 724 const std::string &parentCloudId, int64_t rowId) 725{ 726 MetaBase metaBase(name); 727 auto srcMetaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(userId, bundleName, parentCloudId); 728 auto dstMetaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(userId, bundleName, RECYCLE_CLOUD_ID); 729 std::string uniqueName = name + "_" + std::to_string(rowId); 730 int32_t ret = srcMetaFile->DoLookup(metaBase); 731 if (ret != E_OK) { 732 LOGE("lookup src metafile failed, ret = %{public}d", ret); 733 return ret; 734 } 735 metaBase.name = uniqueName; 736 ret = dstMetaFile->DoCreate(metaBase); 737 if (ret != E_OK) { 738 LOGE("lookup and remove dentry failed, ret = %{public}d", ret); 739 return ret; 740 } 741 metaBase.name = name; 742 ret = srcMetaFile->DoLookupAndRemove(metaBase); 743 if (ret != E_OK) { 744 LOGE("lookup and remove dentry failed, ret = %{public}d", ret); 745 metaBase.name = uniqueName; 746 (void)dstMetaFile->DoLookupAndRemove(metaBase); 747 return ret; 748 } 749 return E_OK; 750} 751 752int32_t MetaFileMgr::RemoveFromRecycleDentryfile(uint32_t userId, const std::string &bundleName, 753 const std::string &name, const std::string &parentCloudId, int64_t rowId) 754{ 755 auto srcMetaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(userId, bundleName, RECYCLE_CLOUD_ID); 756 auto dstMetaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(userId, bundleName, parentCloudId); 757 std::string uniqueName = name + "_" + std::to_string(rowId); 758 MetaBase metaBase(uniqueName); 759 int32_t ret = srcMetaFile->DoLookup(metaBase); 760 if (ret != E_OK) { 761 LOGE("lookup and update dentry failed, ret = %{public}d", ret); 762 return ret; 763 } 764 metaBase.name = name; 765 ret = dstMetaFile->DoCreate(metaBase); 766 if (ret != E_OK) { 767 LOGE("lookup and remove dentry failed, ret = %{public}d", ret); 768 return ret; 769 } 770 metaBase.name = uniqueName; 771 ret = srcMetaFile->DoLookupAndRemove(metaBase); 772 if (ret != E_OK) { 773 LOGE("lookup and remove dentry failed, ret = %{public}d", ret); 774 metaBase.name = name; 775 (void)dstMetaFile->DoLookupAndRemove(metaBase); 776 return ret; 777 } 778 return E_OK; 779} 780} // namespace FileManagement 781} // namespace OHOS 782