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 #ifndef FRAMEWORKS_INNERKITSIMPL_ACCESSOR_INCLUDE_FILE_METADATA_STREAM_H 17 #define FRAMEWORKS_INNERKITSIMPL_ACCESSOR_INCLUDE_FILE_METADATA_STREAM_H 18 19 #include <cstddef> 20 #include <cstdint> 21 #include <fstream> 22 #include <memory> 23 #include <sys/stat.h> 24 #include <vector> 25 26 #include "metadata_stream.h" 27 28 namespace OHOS { 29 namespace Media { 30 #if defined(FRAMEWORKS_INNERKITSIMPL_ACCESSOR_INCLUDE_FILE_METADATA_STREAM_TESTS_PRIVATE) 31 #define FRAMEWORKS_INNERKITSIMPL_ACCESSOR_INCLUDE_FILE_METADATA_STREAM_PRIVATE_UNLESS_TESTED public 32 #else 33 #define FRAMEWORKS_INNERKITSIMPL_ACCESSOR_INCLUDE_FILE_METADATA_STREAM_PRIVATE_UNLESS_TESTED private 34 #endif 35 36 /** 37 * This is a helper class for FileMetadataStream. It is used for testing whether exceptions are 38 * properly handled during file read/write errors. 39 */ 40 class FileWrapper { 41 public: ~FileWrapper()42 virtual ~FileWrapper() {} 43 /* * 44 * @brief Simulates the fwrite function. 45 * @param src Pointer to the array of elements to be written. 46 * @param size Size in bytes of each element to be written. 47 * @param nmemb Number of elements, each one with a size of 'size' bytes. 48 * @param file Pointer to a FILE object that specifies an output stream. 49 * @return The total number of elements successfully written. 50 */ 51 virtual ssize_t FWrite(const void *src, size_t size, ssize_t nmemb, FILE *file); 52 53 /* * 54 * @brief Simulates the fread function. 55 * @param destv Pointer to a block of memory with a size of at least (size*nmemb) bytes. 56 * @param size Size in bytes of each element to be read. 57 * @param nmemb Number of elements, each one with a size of 'size' bytes. 58 * @param file Pointer to a FILE object that specifies an input stream. 59 * @return The total number of elements successfully read. 60 */ 61 virtual ssize_t FRead(void *destv, size_t size, ssize_t nmemb, FILE *file); 62 }; 63 64 /** 65 * @class FileMetadataStream 66 * @brief A class that represents a file-based image stream. 67 * @note This class is not thread-safe. If you need to use the same FileMetadataStream instance from multiple threads, 68 * you must ensure that all access to the instance is properly synchronized. 69 */ 70 class FileMetadataStream : public MetadataStream { 71 public: 72 /* * 73 * @brief Constructs a new FileMetadataStream object from a file descriptor. 74 * @param fileDescriptor The file descriptor. 75 */ 76 FileMetadataStream(int fileDescriptor, int originalFd = METADATA_STREAM_INVALID_FD); 77 78 /* * 79 * @brief Constructs a new FileMetadataStream object from a file path. 80 * @param filePath The file path. 81 */ 82 FileMetadataStream(const std::string &filePath, const std::string &originalPath = METADATA_STREAM_INVALID_PATH); 83 84 /* * 85 * @brief Destructs the FileMetadataStream object. 86 */ 87 virtual ~FileMetadataStream(); 88 89 /* * 90 * @brief Writes data to the FileMetadataStream. 91 * @param data The data to be written. 92 * @param size The size of the data. On a 32-bit system, the maximum size 93 * that can be written at once is 2GB. On a 64-bit system, the maximum size 94 * depends on the type of ssize_t. If ssize_t is 32-bit, the maximum size 95 * is 2GB. If ssize_t is 64-bit, the maximum size is 8ZB. 96 * @return The number of bytes written. Returns -1 if an error occurred 97 * during writing. 98 */ 99 virtual ssize_t Write(byte *data, ssize_t size) override; 100 101 /* * 102 * @brief Reads data from the FileMetadataStream. 103 * @param buf The buffer to store the data. 104 * @param size The size of the data. 105 * @return The number of bytes read. Returns -1 if a read error occurred 106 * or the pointer was not initialized. 107 */ 108 virtual ssize_t Read(byte *buf, ssize_t size) override; 109 110 /* * 111 * @brief Reads a byte from the FileMetadataStream. 112 * @return The byte read. 113 */ 114 virtual int ReadByte() override; 115 116 /* * 117 * @brief Seeks to a specific position in the FileMetadataStream. 118 * @param offset The offset. 119 * @param pos The starting position of the offset. 120 * @return The new position in the stream. Returns -1 if an error occurred during seeking. 121 */ 122 virtual long Seek(long offset, SeekPos pos) override; 123 124 /* * 125 * @brief Gets the current position in the FileMetadataStream. 126 * @return The current position. 127 */ 128 virtual long Tell() override; 129 130 /* * 131 * @brief Checks if the end of the FileMetadataStream has been reached. 132 * @return true if the end has been reached, false otherwise. 133 */ 134 virtual bool IsEof() override; 135 136 /* * 137 * @brief Checks if the FileMetadataStream is open. 138 * @return true if it is open, false otherwise. 139 */ 140 virtual bool IsOpen() override; 141 142 /* * 143 * @brief Opens the FileMetadataStream with a specific mode. 144 * The Open operation will reset the read and write position of the file. 145 * A file object can only be opened and closed once. 146 * If the file fails to open from the file descriptor or path, it will 147 * return false. If it fails to seek to the end of the file or restore 148 * the file position, it will return false. 149 * @param mode The mode to open the FileMetadataStream. It can be OpenMode::Read 150 * or OpenMode::ReadWrite. 151 * @return true if it opens successfully, false otherwise. 152 */ 153 virtual bool Open(OpenMode mode = OpenMode::ReadWrite) override; 154 155 /* * 156 * @brief Flushes the FileMetadataStream. 157 * The scenarios for using Flush are described in MetadataStream::Flush. 158 * @return true if it flushes successfully, false otherwise. 159 */ 160 virtual bool Flush() override; 161 162 /* * 163 * @brief Creates a memory map of the file. 164 * @param isWriteable If true, the created memory map will be writable; 165 * otherwise, it will be read-only. Writing to a read-only pointer will 166 * result in a segmentation fault. 167 * @return A pointer to the memory map if it is created successfully, 168 * nullptr otherwise. 169 */ 170 virtual byte *GetAddr(bool isWriteable = false) override; 171 172 /* * 173 * @brief Should call Open first. Transfers the content of the source 174 * MetadataStream to the current FileMetadataStream. 175 * Note the buffer size in CopyFrom is currently 4K. When reading from SSDs, 176 * reading only 4K at a time may not fully utilize the IO transfer capabilities. 177 * If performance issues are identified in later testing, this can be adjusted 178 * to a multiple of 4K. 179 * @param src The source MetadataStream. 180 */ 181 bool CopyFrom(MetadataStream &src) override; 182 183 /* * 184 * @brief Get the size of the FileMetadataStream. 185 * @return The size of the FileMetadataStream. 186 * @note If this function is called frequently, it is recommended to cache the size to improve performance. 187 */ 188 ssize_t GetSize() override; 189 190 private: 191 /* * 192 * @brief Closes the FileMetadataStream. 193 */ 194 virtual void Close() override; 195 196 /* * 197 * @brief Releases a memory map. 198 * @param mmap The pointer to the memory map that needs to be released. 199 * @return true if the memory map is released successfully, false otherwise. 200 */ 201 bool ReleaseAddr(); 202 203 /* * 204 * @brief Constructs a new FileMetadataStream object from a file path and a 205 * file wrapper. 206 * @param filePath The file path. 207 * @param fileWrapper The file wrapper. 208 */ 209 FileMetadataStream(const std::string &filePath, std::unique_ptr<FileWrapper> fileWrapper); 210 211 /* * 212 * @brief Opens the FileMetadataStream from a file descriptor. 213 * @param modeStr The mode string. 214 * @return true if it opens successfully, false otherwise. 215 */ 216 bool OpenFromFD(const char *modeStr); 217 218 /* * 219 * @brief Opens the FileMetadataStream from a file path. 220 * @param modeStr The mode string. 221 * @return true if it opens successfully, false otherwise. 222 */ 223 bool OpenFromPath(const char *modeStr); 224 225 /* * 226 * @brief Copies data from the source MetadataStream to the current file. 227 * @param src The source MetadataStream. 228 * @param totalBytesWritten The total number of bytes written to the current file. 229 * This function reads data from the source MetadataStream and writes it to the current file. 230 * It uses a temporary buffer of size min(IMAGE_STREAM_PAGE_SIZE, src.GetSize()). 231 * The function continues to read and write data until it reaches the end of the source MetadataStream. 232 * If a write operation fails, it handles the error and returns false. 233 * If a read operation fails and it's not because of reaching the end of the source MetadataStream, 234 * it returns false. 235 * @return true if the data is copied successfully, false otherwise. 236 */ 237 bool CopyDataFromSource(MetadataStream &src, ssize_t &totalBytesWritten); 238 239 /* * 240 * @brief Handles the error when writing data to the current file fails. 241 * @param src The source MetadataStream. 242 * @param src_cur The current position of the source MetadataStream. 243 */ 244 void HandleWriteError(MetadataStream &src, ssize_t src_cur); 245 246 /* * 247 * @brief Truncates the current file to the specified size. 248 * @param totalBytesWritten The new size of the file. 249 * @param src The source MetadataStream. 250 * @param src_cur The current position of the source MetadataStream. 251 * @return true if the file is truncated successfully, false otherwise. 252 */ 253 bool TruncateFile(size_t totalBytesWritten, MetadataStream &src, ssize_t src_cur); 254 bool ReadFromSourceAndWriteToFile(MetadataStream &src, byte *tempBuffer, ssize_t buffer_size, 255 ssize_t &totalBytesWritten); 256 257 /* * 258 * @brief Initializes the FileMetadataStream with a file path and a file descriptor. 259 * @param filePath The path of the file to be opened. Default is an empty string. 260 * @param fileDescriptor The file descriptor of the file to be opened. Default is -1. 261 */ 262 void Initialize(const std::string &filePath = "", int fileDescriptor = -1); 263 264 FILE *fp_; // File descriptor 265 int dupFD_; // Duplicated file descriptor 266 std::string filePath_; // File path 267 void *mappedMemory_; // Address of memory mapping 268 std::unique_ptr<FileWrapper> fileWrapper_; // File wrapper class, used for testing 269 270 enum { 271 INIT_FROM_FD, 272 INIT_FROM_PATH, 273 INIT_FROM_UNKNOWN, 274 } initPath_; 275 }; 276 } // namespace Media 277 } // namespace OHOS 278 #endif // FRAMEWORKS_INNERKITSIMPL_ACCESSOR_INCLUDE_FILE_METADATA_STREAM_H 279