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 #ifndef OHOS_FILEMGMT_BACKUP_BACKUP_TAR_FILE_H
17 #define OHOS_FILEMGMT_BACKUP_BACKUP_TAR_FILE_H
18 
19 #include <map>
20 #include <memory>
21 #include <string>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25 #include <vector>
26 
27 namespace OHOS::FileManagement::Backup {
28 namespace {
29 const uint32_t TMAGIC_LEN = 6;
30 const uint32_t TNAME_LEN = 100;
31 const uint32_t TMODE_LEN = 8;
32 const uint32_t TUID_LEN = 8;
33 const uint32_t TGID_LEN = 8;
34 const uint32_t TSIZE_LEN = 12;
35 const uint32_t MTIME_LEN = 12;
36 const uint32_t CHKSUM_LEN = 8;
37 const uint32_t VERSION_LEN = 2;
38 const uint32_t NAME_LEN = 32;
39 const uint32_t MAJOR_LEN = 8;
40 const uint32_t MINOR_LEN = 8;
41 const uint32_t PREFIX_LEN = 155;
42 const uint32_t PADDING_LEN = 12;
43 const uint32_t TMODE_BASE = 100;
44 const uint32_t TUID_BASE = 108;
45 const uint32_t TGID_BASE = 116;
46 const uint32_t TSIZE_BASE = 124;
47 const uint32_t TMTIME_BASE = 136;
48 const uint32_t CHKSUM_BASE = 148;
49 const uint32_t BLOCK_SIZE = 512;
50 const off_t READ_BUFF_SIZE = 512 * 1024;
51 const uint8_t BLANK_SPACE = 0x20;
52 const uint64_t MB_TO_BYTE = 1024 * 1024;
53 const std::string TMAGIC = "ustar";
54 const char REGTYPE = '0';   // regular file
55 const char AREGTYPE = '\0'; // regular file
56 const char SYMTYPE = '2';   // reserved
57 const char DIRTYPE = '5';   // directory
58 const char GNUTYPE_LONGNAME = 'L';
59 const int ERR_NO_PERMISSION = 13;
60 } // namespace
61 
62 // 512 bytes
63 using TarHeader = struct {
64     char name[TNAME_LEN];
65     char mode[TMODE_LEN];
66     char uid[TUID_LEN];
67     char gid[TGID_LEN];
68     char size[TSIZE_LEN];
69     char mtime[MTIME_LEN];
70     char chksum[CHKSUM_LEN];
71     char typeFlag;
72     char linkName[TNAME_LEN];
73     char magic[TMAGIC_LEN];
74     char version[VERSION_LEN];
75     char uname[NAME_LEN];
76     char gname[NAME_LEN];
77     char devMajor[MAJOR_LEN];
78     char devMinor[MINOR_LEN];
79     char prefix[PREFIX_LEN];
80     char pad[PADDING_LEN];
81 };
82 using TarMap = std::map<std::string, std::tuple<std::string, struct stat, bool>>;
83 class TarFile {
84 public:
85     static TarFile &GetInstance();
86 
87     bool Packet(const std::vector<std::string> &srcFiles,
88                 const std::string &tarFileName,
89                 const std::string &pkPath,
90                 TarMap &tarMap,
91                 std::function<void(std::string, int)> reportCb);
92 
93     /**
94      * @brief set packet mode
95      *
96      * @param isReset 是否每次重置 tarMap_
97      */
98     void SetPacketMode(bool isReset);
99 
100 private:
TarFile()101     TarFile() {}
102     ~TarFile() = default;
103     TarFile(const TarFile &instance) = delete;
104     TarFile &operator=(const TarFile &instance) = delete;
105 
106     /**
107      * @brief traversal file
108      *
109      * @param filename 文件名
110      * @return true 遍历成功
111      * @return false 遍历失败
112      */
113     bool TraversalFile(std::string &fileName, int &err);
114 
115     /**
116      * @brief add files to the tar package
117      *
118      * @param filename 文件名
119      * @param st 文件参数结构体
120      */
121     bool AddFile(std::string &fileName, const struct stat &st, int &err);
122 
123     /**
124      * @brief write files to content
125      *
126      * @param filename 文件名
127      * @param size 文件大小
128      */
129     bool WriteFileContent(const std::string &fileName, off_t size, int &err);
130 
131     /**
132      * @brief split write
133      *
134      * @param ioBuffer 写入的文件信息
135      * @param read 读取文件
136      */
137     off_t SplitWriteAll(const std::vector<uint8_t> &ioBuffer, off_t read);
138 
139     /**
140      * @brief creaat split tarfile
141      */
142     bool CreateSplitTarFile();
143 
144     /**
145      * @brief complete block
146      *
147      * @param size 完成的块大小
148      */
149     bool CompleteBlock(off_t size);
150 
151     /**
152      * @brief fill split tailblocks
153      */
154     bool FillSplitTailBlocks();
155 
156     /**
157      * @brief set check sum
158      *
159      * @param hdr tar文件结构体
160      */
161     void SetCheckSum(TarHeader &hdr);
162 
163     /**
164      * @brief fill owner name
165      *
166      * @param hdr tar文件结构体
167      * @param st  文件结构体
168      */
169     void FillOwnerName(TarHeader &hdr, const struct stat &st);
170 
171     /**
172      * @brief write long name
173      *
174      * @param name  文件名
175      * @param type  文件类型
176      */
177     bool WriteLongName(std::string &name, char type);
178 
179     /**
180      * @brief read files
181      *
182      * @param fd 文件描述符
183      * @param iobuffer  文件信息数组
184      * @param size  文件大小
185      */
186     off_t ReadAll(int fd, std::vector<uint8_t> &ioBuffer, off_t size);
187 
188     /**
189      * @brief write files
190      *
191      * @param buffer 文件内容数组
192      * @param len  长度
193      */
194     int WriteAll(const std::vector<uint8_t> &buffer, size_t len);
195 
196     /**
197      * @brief write tar header to tar file
198      *
199      * @param header tar文件头结构体
200      */
201     int WriteTarHeader(TarHeader &header);
202 
203     /**
204      * @brief Character conversion
205      *
206      * @param len  长度
207      * @param val  需要转换的值
208      */
209     std::string I2Ocs(int len, off_t val);
210 
211     /**
212      * @brief Character conversion
213      *
214      * @param st   文件信息结构体
215      * @param hdr  tar包文件头
216      */
217     bool I2OcsConvert(const struct stat &st, TarHeader &hdr, std::string &fileName);
218 
219     bool ToAddFile(std::string &path, int &err);
220 
221 private:
222     uint32_t fileCount_ {0};
223     TarMap tarMap_ {};
224 
225     std::string rootPath_ {};
226     std::string packagePath_ {};
227     std::string baseTarName_ {};
228     std::string tarFileName_ {};
229 
230     std::vector<uint8_t> ioBuffer_ {};
231 
232     FILE *currentTarFile_ {nullptr};
233     std::string currentTarName_ {};
234     off_t currentTarFileSize_ {0};
235     uint32_t tarFileCount_ {0};
236 
237     std::string currentFileName_ {};
238 
239     bool isReset_ = false;
240 };
241 } // namespace OHOS::FileManagement::Backup
242 
243 #endif // OHOS_FILEMGMT_BACKUP_BACKUP_TAR_FILE_H