1/*
2 * Copyright (c) 2023-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#ifndef OHOS_FILEMGMT_DENTRY_META_FILE_H
17#define OHOS_FILEMGMT_DENTRY_META_FILE_H
18
19#include <atomic>
20#include <functional>
21#include <list>
22#include <map>
23#include <memory>
24#include <mutex>
25#include <string>
26#include <sys/stat.h>
27#include <vector>
28
29#include "unique_fd.h"
30
31namespace OHOS {
32namespace FileManagement {
33
34const std::string RECYCLE_NAME = ".trash";
35const std::string RECYCLE_CLOUD_ID = ".trash";
36const std::string ROOT_CLOUD_ID = "rootId";
37const unsigned int STAT_MODE_DIR = 0771;
38constexpr int32_t LOCAL = 1;
39constexpr uint32_t MAX_META_FILE_NUM = 100;
40constexpr uint32_t MAX_CLOUDDISK_META_FILE_NUM = 150;
41
42struct MetaBase;
43class MetaFile {
44public:
45    MetaFile() = delete;
46    ~MetaFile();
47    using CloudDiskMetaFileCallBack = std::function<void(MetaBase &)>;
48    explicit MetaFile(uint32_t userId, const std::string &path);
49    explicit MetaFile(uint32_t userId, const std::string &bundleName, const std::string &parentCloudId);
50    int32_t DoLookupAndUpdate(const std::string &name, CloudDiskMetaFileCallBack updateFunc);
51    int32_t DoLookupAndRemove(MetaBase &metaBase);
52    int32_t DoCreate(const MetaBase &base);
53    int32_t HandleFileByFd(unsigned long &endBlock, uint32_t &level);
54    int32_t DoRemove(const MetaBase &base);
55    int32_t DoUpdate(const MetaBase &base);
56    int32_t DoRename(const MetaBase &oldBase, const std::string &newName);
57    int32_t DoRename(MetaBase &metaBase, const std::string &newName, std::shared_ptr<MetaFile> newMetaFile);
58    int32_t DoLookup(MetaBase &base);
59    int32_t LoadChildren(std::vector<MetaBase> &bases);
60
61    static std::string GetParentDir(const std::string &path);
62    static std::string GetFileName(const std::string &path);
63
64private:
65    std::mutex mtx_{};
66    std::string path_{};
67    std::string cacheFile_{};
68    std::string bundleName_{};
69    std::string cloudId_{};
70    std::string name_{};
71    UniqueFd fd_{};
72    uint32_t userId_{};
73    std::shared_ptr<MetaFile> parentMetaFile_{nullptr};
74};
75
76class CloudDiskMetaFile {
77public:
78    CloudDiskMetaFile() = delete;
79    ~CloudDiskMetaFile();
80    using CloudDiskMetaFileCallBack = std::function<void(MetaBase &)>;
81    explicit CloudDiskMetaFile(uint32_t userId, const std::string &bundleName, const std::string &cloudId);
82
83    int32_t DoLookupAndUpdate(const std::string &name, CloudDiskMetaFileCallBack updateFunc);
84    int32_t DoChildUpdate(const std::string &name, CloudDiskMetaFileCallBack updateFunc);
85    int32_t DoLookupAndRemove(MetaBase &metaBase);
86    int32_t DoCreate(const MetaBase &base);
87    int32_t HandleFileByFd(unsigned long &endBlock, uint32_t &level);
88    int32_t DoRemove(const MetaBase &base);
89    int32_t DoUpdate(const MetaBase &base);
90    int32_t DoRename(MetaBase &metaBase, const std::string &newName,
91        std::shared_ptr<CloudDiskMetaFile> newMetaFile);
92    int32_t DoLookup(MetaBase &base);
93    int32_t LoadChildren(std::vector<MetaBase> &bases);
94    std::string GetDentryFilePath();
95
96private:
97    std::mutex mtx_{};
98    std::string path_{};
99    std::string cacheFile_{};
100    std::string bundleName_{};
101    std::string cloudId_{};
102    std::string name_{};
103    UniqueFd fd_{};
104    uint32_t userId_{};
105    std::shared_ptr<MetaFile> parentMetaFile_{nullptr};
106};
107
108enum {
109    NEED_UPLOAD = 0,
110    NO_UPLOAD,
111};
112
113enum {
114    FILE_TYPE_CONTENT = 0,
115    FILE_TYPE_THUMBNAIL,
116    FILE_TYPE_LCD,
117};
118
119enum {
120    POSITION_UNKNOWN = 0,
121    POSITION_LOCAL = 0x01,
122    POSITION_CLOUD = 0x02,
123    POSITION_LOCAL_AND_CLOUD = POSITION_LOCAL | POSITION_CLOUD,
124};
125
126typedef std::pair<uint32_t, std::string> MetaFileKey;
127typedef std::pair<MetaFileKey, std::shared_ptr<CloudDiskMetaFile>> CloudDiskMetaFileListEle;
128typedef std::pair<MetaFileKey, std::shared_ptr<MetaFile>> MetaFileListEle;
129
130class MetaFileMgr {
131public:
132    static MetaFileMgr& GetInstance();
133    /* recordId is hex string of 256 bits, convert to u8 cloudId[32] to kernel */
134    static std::string RecordIdToCloudId(const std::string hexStr);
135    static std::string CloudIdToRecordId(const std::string cloudId);
136    std::shared_ptr<MetaFile> GetMetaFile(uint32_t userId, const std::string &path);
137    std::shared_ptr<CloudDiskMetaFile> GetCloudDiskMetaFile(uint32_t userId, const std::string &bundleName,
138        const std::string &cloudId);
139    void ClearAll();
140    void CloudDiskClearAll();
141    void Clear(uint32_t userId, const std::string &bundleName, const std::string &cloudId);
142    int32_t CreateRecycleDentry(uint32_t userId, const std::string &bundleName);
143    int32_t MoveIntoRecycleDentryfile(uint32_t userId, const std::string &bundleName,
144        const std::string &name, const std::string &parentCloudId, int64_t rowId);
145    int32_t RemoveFromRecycleDentryfile(uint32_t userId, const std::string &bundleName,
146        const std::string &name, const std::string &parentCloudId, int64_t rowId);
147private:
148    MetaFileMgr() = default;
149    ~MetaFileMgr() = default;
150    MetaFileMgr(const MetaFileMgr &m) = delete;
151    const MetaFileMgr &operator=(const MetaFileMgr &m) = delete;
152
153    std::recursive_mutex mtx_{};
154    std::mutex cloudDiskMutex_{};
155    std::list<MetaFileListEle> metaFileList_;
156    std::map<MetaFileKey, std::list<MetaFileListEle>::iterator> metaFiles_;
157    std::list<CloudDiskMetaFileListEle> cloudDiskMetaFileList_;
158    std::map<MetaFileKey, std::list<CloudDiskMetaFileListEle>::iterator> cloudDiskMetaFile_;
159};
160
161struct MetaBase {
162    MetaBase(const std::string &name) : name(name) {}
163    MetaBase(const std::string &name, const std::string &cloudId) : name(name), cloudId(cloudId) {}
164    MetaBase() = default;
165    inline bool operator!=(const MetaBase &other) const
166    {
167        return !operator==(other);
168    }
169    inline bool operator==(const MetaBase &other) const
170    {
171        return other.cloudId == cloudId && other.name == name && other.size == size;
172    }
173    uint64_t atime{0};
174    uint64_t mtime{0};
175    uint64_t size{0};
176    uint32_t mode{S_IFREG};
177    uint8_t position{POSITION_LOCAL};
178    uint8_t fileType{FILE_TYPE_CONTENT};
179    uint8_t noUpload{NEED_UPLOAD};
180    std::string name{};
181    std::string cloudId{};
182    off_t nextOff{0};
183    bool hasDownloaded{false};
184};
185
186struct BitOps {
187    static const uint8_t BIT_PER_BYTE = 8;
188    static int TestBit(uint32_t nr, const uint8_t addr[])
189    {
190        return 1 & (addr[nr / BIT_PER_BYTE] >> (nr & (BIT_PER_BYTE - 1)));
191    }
192
193    static void ClearBit(uint32_t nr, uint8_t addr[])
194    {
195        addr[nr / BIT_PER_BYTE] &= ~(1UL << ((nr) % BIT_PER_BYTE));
196    }
197
198    static void SetBit(uint32_t nr, uint8_t addr[])
199    {
200        addr[nr / BIT_PER_BYTE] |= (1UL << ((nr) % BIT_PER_BYTE));
201    }
202
203    static uint32_t FindNextBit(const uint8_t addr[], uint32_t maxSlots, uint32_t start)
204    {
205        while (start < maxSlots) {
206            if (BitOps::TestBit(start, addr)) {
207                return start;
208            }
209            start++;
210        }
211        return maxSlots;
212    }
213
214    static uint32_t FindNextZeroBit(const uint8_t addr[], uint32_t maxSlots, uint32_t start)
215    {
216        while (start < maxSlots) {
217            if (!BitOps::TestBit(start, addr)) {
218                return start;
219            }
220            start++;
221        }
222        return maxSlots;
223    }
224};
225
226struct MetaHelper {
227    static void SetFileType(struct HmdfsDentry *de, uint8_t fileType);
228    static void SetPosition(struct HmdfsDentry *de, uint8_t position);
229    static void SetNoUpload(struct HmdfsDentry *de, uint8_t noUpload);
230    static uint8_t GetFileType(const struct HmdfsDentry *de);
231    static uint8_t GetPosition(const struct HmdfsDentry *de);
232    static uint8_t GetNoUpload(const struct HmdfsDentry *de);
233};
234} // namespace FileManagement
235} // namespace OHOS
236
237#endif // META_FILE_H
238