13f4cbf05Sopenharmony_ci/* 23f4cbf05Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 33f4cbf05Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43f4cbf05Sopenharmony_ci * you may not use this file except in compliance with the License. 53f4cbf05Sopenharmony_ci * You may obtain a copy of the License at 63f4cbf05Sopenharmony_ci * 73f4cbf05Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83f4cbf05Sopenharmony_ci * 93f4cbf05Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103f4cbf05Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113f4cbf05Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123f4cbf05Sopenharmony_ci * See the License for the specific language governing permissions and 133f4cbf05Sopenharmony_ci * limitations under the License. 143f4cbf05Sopenharmony_ci */ 153f4cbf05Sopenharmony_ci#include "mapped_file.h" 163f4cbf05Sopenharmony_ci 173f4cbf05Sopenharmony_ci#include <fcntl.h> 183f4cbf05Sopenharmony_ci#include <sys/stat.h> 193f4cbf05Sopenharmony_ci#include <sys/mman.h> 203f4cbf05Sopenharmony_ci#include <unistd.h> 213f4cbf05Sopenharmony_ci#include "common_mapped_file_errors.h" 223f4cbf05Sopenharmony_ci#include "errors.h" 233f4cbf05Sopenharmony_ci#include "file_ex.h" 243f4cbf05Sopenharmony_ci#include "utils_log.h" 253f4cbf05Sopenharmony_ci 263f4cbf05Sopenharmony_cinamespace OHOS { 273f4cbf05Sopenharmony_cinamespace Utils { 283f4cbf05Sopenharmony_cioff_t MappedFile::pageSize_ = static_cast<off_t>(sysconf(_SC_PAGESIZE)); 293f4cbf05Sopenharmony_ci 303f4cbf05Sopenharmony_ciMappedFile::MappedFile(std::string& path, MapMode mode, off_t offset, off_t size, const char *hint) 313f4cbf05Sopenharmony_ci :path_(path), size_(size), offset_(offset), mode_(mode), hint_(hint) {} 323f4cbf05Sopenharmony_ci 333f4cbf05Sopenharmony_cibool MappedFile::ValidMappedSize(off_t& targetSize, const struct stat& stb) 343f4cbf05Sopenharmony_ci{ 353f4cbf05Sopenharmony_ci off_t max = RoundSize(stb.st_size) - offset_; // Avoid mapped size excessing 363f4cbf05Sopenharmony_ci // that of the file more than a page, 373f4cbf05Sopenharmony_ci if (max > 0) { // since write operation on it may raise signal 7. 383f4cbf05Sopenharmony_ci targetSize = targetSize > max ? max : targetSize; 393f4cbf05Sopenharmony_ci } else { 403f4cbf05Sopenharmony_ci return false; 413f4cbf05Sopenharmony_ci } 423f4cbf05Sopenharmony_ci 433f4cbf05Sopenharmony_ci return true; 443f4cbf05Sopenharmony_ci} 453f4cbf05Sopenharmony_cibool MappedFile::NormalizePath() 463f4cbf05Sopenharmony_ci{ 473f4cbf05Sopenharmony_ci char canonicalPath[PATH_MAX]; 483f4cbf05Sopenharmony_ci if (realpath(path_.c_str(), canonicalPath) == nullptr) { 493f4cbf05Sopenharmony_ci if (errno != ENOENT) { 503f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s get realpath failed.", __FUNCTION__); 513f4cbf05Sopenharmony_ci return false; 523f4cbf05Sopenharmony_ci } 533f4cbf05Sopenharmony_ci } else { 543f4cbf05Sopenharmony_ci path_ = canonicalPath; 553f4cbf05Sopenharmony_ci } 563f4cbf05Sopenharmony_ci 573f4cbf05Sopenharmony_ci return true; 583f4cbf05Sopenharmony_ci} 593f4cbf05Sopenharmony_ci 603f4cbf05Sopenharmony_cibool MappedFile::NormalizeSize() 613f4cbf05Sopenharmony_ci{ 623f4cbf05Sopenharmony_ci if (size_ == 0 || size_ < DEFAULT_LENGTH) { 633f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Failed. Invalid mapping size: %{public}lld", 643f4cbf05Sopenharmony_ci __FUNCTION__, static_cast<long long>(size_)); 653f4cbf05Sopenharmony_ci return false; 663f4cbf05Sopenharmony_ci } 673f4cbf05Sopenharmony_ci 683f4cbf05Sopenharmony_ci errno = 0; 693f4cbf05Sopenharmony_ci if (!NormalizePath()) { 703f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s normalize path failed. %{public}s", __FUNCTION__, strerror(errno)); 713f4cbf05Sopenharmony_ci return false; 723f4cbf05Sopenharmony_ci } 733f4cbf05Sopenharmony_ci if (!FileExists(path_)) { 743f4cbf05Sopenharmony_ci if ((mode_ & MapMode::CREATE_IF_ABSENT) == MapMode::DEFAULT) { 753f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Failed. %{public}s", __FUNCTION__, strerror(errno)); 763f4cbf05Sopenharmony_ci return false; 773f4cbf05Sopenharmony_ci } 783f4cbf05Sopenharmony_ci 793f4cbf05Sopenharmony_ci if (size_ == DEFAULT_LENGTH) { 803f4cbf05Sopenharmony_ci size_ = PageSize(); 813f4cbf05Sopenharmony_ci } 823f4cbf05Sopenharmony_ci 833f4cbf05Sopenharmony_ci isNewFile_ = true; 843f4cbf05Sopenharmony_ci } else { 853f4cbf05Sopenharmony_ci struct stat stb = {0}; 863f4cbf05Sopenharmony_ci // Calculate specified mapping size 873f4cbf05Sopenharmony_ci if (stat(path_.c_str(), &stb) != 0) { 883f4cbf05Sopenharmony_ci UTILS_LOGW("%{public}s: Failed. Get file size failed! Mapped size will be that of a page.", __FUNCTION__); 893f4cbf05Sopenharmony_ci size_ = PageSize(); 903f4cbf05Sopenharmony_ci } 913f4cbf05Sopenharmony_ci 923f4cbf05Sopenharmony_ci if (size_ == DEFAULT_LENGTH) { 933f4cbf05Sopenharmony_ci size_ = stb.st_size; 943f4cbf05Sopenharmony_ci } 953f4cbf05Sopenharmony_ci 963f4cbf05Sopenharmony_ci // Get valid size 973f4cbf05Sopenharmony_ci if (!ValidMappedSize(size_, stb)) { 983f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Failed. Invalid params. Specified size: %{public}lld, File size: %{public}lld", \ 993f4cbf05Sopenharmony_ci __FUNCTION__, static_cast<long long>(size_), static_cast<long long>(stb.st_size)); 1003f4cbf05Sopenharmony_ci return false; 1013f4cbf05Sopenharmony_ci } 1023f4cbf05Sopenharmony_ci } 1033f4cbf05Sopenharmony_ci 1043f4cbf05Sopenharmony_ci return true; 1053f4cbf05Sopenharmony_ci} 1063f4cbf05Sopenharmony_ci 1073f4cbf05Sopenharmony_civoid MappedFile::NormalizeMode() 1083f4cbf05Sopenharmony_ci{ 1093f4cbf05Sopenharmony_ci mode_ &= (MapMode::PRIVATE | MapMode::READ_ONLY | MapMode::CREATE_IF_ABSENT); 1103f4cbf05Sopenharmony_ci 1113f4cbf05Sopenharmony_ci openFlag_ = O_CLOEXEC; 1123f4cbf05Sopenharmony_ci if (mode_ == MapMode::DEFAULT) { 1133f4cbf05Sopenharmony_ci mapFlag_ = MAP_SHARED; 1143f4cbf05Sopenharmony_ci mapProt_ = PROT_READ | PROT_WRITE; 1153f4cbf05Sopenharmony_ci openFlag_ |= O_RDWR; 1163f4cbf05Sopenharmony_ci } else { 1173f4cbf05Sopenharmony_ci if ((mode_ & MapMode::PRIVATE) != MapMode::DEFAULT) { 1183f4cbf05Sopenharmony_ci mapFlag_ = MAP_PRIVATE; 1193f4cbf05Sopenharmony_ci } else { 1203f4cbf05Sopenharmony_ci mapFlag_ = MAP_SHARED; 1213f4cbf05Sopenharmony_ci } 1223f4cbf05Sopenharmony_ci 1233f4cbf05Sopenharmony_ci if ((mode_ & MapMode::READ_ONLY) != MapMode::DEFAULT) { 1243f4cbf05Sopenharmony_ci mapProt_ = PROT_READ; 1253f4cbf05Sopenharmony_ci openFlag_ |= O_RDONLY; 1263f4cbf05Sopenharmony_ci } else { 1273f4cbf05Sopenharmony_ci mapProt_ = PROT_READ | PROT_WRITE; 1283f4cbf05Sopenharmony_ci openFlag_ |= O_RDWR; 1293f4cbf05Sopenharmony_ci } 1303f4cbf05Sopenharmony_ci 1313f4cbf05Sopenharmony_ci if ((mode_ & MapMode::CREATE_IF_ABSENT) != MapMode::DEFAULT) { 1323f4cbf05Sopenharmony_ci openFlag_ |= O_CREAT; 1333f4cbf05Sopenharmony_ci } 1343f4cbf05Sopenharmony_ci } 1353f4cbf05Sopenharmony_ci} 1363f4cbf05Sopenharmony_ci 1373f4cbf05Sopenharmony_ciErrCode MappedFile::Normalize() 1383f4cbf05Sopenharmony_ci{ 1393f4cbf05Sopenharmony_ci if (isNormed_) { 1403f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Already normalized.", __FUNCTION__); 1413f4cbf05Sopenharmony_ci return ERR_INVALID_OPERATION; 1423f4cbf05Sopenharmony_ci } 1433f4cbf05Sopenharmony_ci 1443f4cbf05Sopenharmony_ci // resolve params for mapping region 1453f4cbf05Sopenharmony_ci // offset 1463f4cbf05Sopenharmony_ci if (offset_ < 0 || (offset_ % PageSize() != 0)) { 1473f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Failed. Invalid offset: %{public}lld", __FUNCTION__, static_cast<long long>(offset_)); 1483f4cbf05Sopenharmony_ci return ERR_INVALID_VALUE; 1493f4cbf05Sopenharmony_ci } 1503f4cbf05Sopenharmony_ci 1513f4cbf05Sopenharmony_ci // size 1523f4cbf05Sopenharmony_ci if (!NormalizeSize()) { 1533f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Failed. Cannot normalize size.", __FUNCTION__); 1543f4cbf05Sopenharmony_ci return ERR_INVALID_VALUE; 1553f4cbf05Sopenharmony_ci } 1563f4cbf05Sopenharmony_ci 1573f4cbf05Sopenharmony_ci // Set open flags, mapping types and protections 1583f4cbf05Sopenharmony_ci NormalizeMode(); 1593f4cbf05Sopenharmony_ci 1603f4cbf05Sopenharmony_ci isNormed_ = true; 1613f4cbf05Sopenharmony_ci return MAPPED_FILE_ERR_OK; 1623f4cbf05Sopenharmony_ci} 1633f4cbf05Sopenharmony_ci 1643f4cbf05Sopenharmony_cibool MappedFile::OpenFile() 1653f4cbf05Sopenharmony_ci{ 1663f4cbf05Sopenharmony_ci int fd = open(path_.c_str(), openFlag_, S_IRWXU | S_IRGRP | S_IROTH); 1673f4cbf05Sopenharmony_ci if (fd == -1) { 1683f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Failed. Cannot open file - %{public}s.", __FUNCTION__, strerror(errno)); 1693f4cbf05Sopenharmony_ci return false; 1703f4cbf05Sopenharmony_ci } 1713f4cbf05Sopenharmony_ci 1723f4cbf05Sopenharmony_ci if (isNewFile_) { 1733f4cbf05Sopenharmony_ci if (!NormalizePath()) { 1743f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s normalize path failed. %{public}s", __FUNCTION__, strerror(errno)); 1753f4cbf05Sopenharmony_ci return false; 1763f4cbf05Sopenharmony_ci } 1773f4cbf05Sopenharmony_ci if (ftruncate(fd, EndOffset() + 1) == -1) { 1783f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. Cannot change file size: %{public}s.", __FUNCTION__, strerror(errno)); 1793f4cbf05Sopenharmony_ci if (close(fd) == -1) { 1803f4cbf05Sopenharmony_ci UTILS_LOGW("%{public}s: Failed. Cannot close the file: %{public}s.", \ 1813f4cbf05Sopenharmony_ci __FUNCTION__, strerror(errno)); 1823f4cbf05Sopenharmony_ci } 1833f4cbf05Sopenharmony_ci if (unlink(path_.c_str()) == -1) { 1843f4cbf05Sopenharmony_ci UTILS_LOGW("%{public}s: Failed. Cannot unlink the file: %{public}s.", \ 1853f4cbf05Sopenharmony_ci __FUNCTION__, strerror(errno)); 1863f4cbf05Sopenharmony_ci } 1873f4cbf05Sopenharmony_ci return false; 1883f4cbf05Sopenharmony_ci } 1893f4cbf05Sopenharmony_ci isNewFile_ = false; 1903f4cbf05Sopenharmony_ci } 1913f4cbf05Sopenharmony_ci 1923f4cbf05Sopenharmony_ci fd_ = fd; 1933f4cbf05Sopenharmony_ci return true; 1943f4cbf05Sopenharmony_ci} 1953f4cbf05Sopenharmony_ci 1963f4cbf05Sopenharmony_ciErrCode MappedFile::Map() 1973f4cbf05Sopenharmony_ci{ 1983f4cbf05Sopenharmony_ci if (isMapped_) { 1993f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. Already mapped.", __FUNCTION__); 2003f4cbf05Sopenharmony_ci return ERR_INVALID_OPERATION; 2013f4cbf05Sopenharmony_ci } 2023f4cbf05Sopenharmony_ci 2033f4cbf05Sopenharmony_ci // Normalize params 2043f4cbf05Sopenharmony_ci ErrCode res = Normalize(); 2053f4cbf05Sopenharmony_ci if (res != MAPPED_FILE_ERR_OK && res != ERR_INVALID_OPERATION) { 2063f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Normalize Failed.", __FUNCTION__); 2073f4cbf05Sopenharmony_ci return res; 2083f4cbf05Sopenharmony_ci } 2093f4cbf05Sopenharmony_ci 2103f4cbf05Sopenharmony_ci // Open file to get its fd 2113f4cbf05Sopenharmony_ci if (fd_ == -1) { 2123f4cbf05Sopenharmony_ci if (!OpenFile()) { 2133f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Open Failed.", __FUNCTION__); 2143f4cbf05Sopenharmony_ci return MAPPED_FILE_ERR_FAILED; 2153f4cbf05Sopenharmony_ci } 2163f4cbf05Sopenharmony_ci } 2173f4cbf05Sopenharmony_ci 2183f4cbf05Sopenharmony_ci // Try map 2193f4cbf05Sopenharmony_ci void* data = MAP_FAILED; 2203f4cbf05Sopenharmony_ci do { 2213f4cbf05Sopenharmony_ci data = mmap(reinterpret_cast<void*>(const_cast<char *>(hint_)), 2223f4cbf05Sopenharmony_ci static_cast<size_t>(size_), 2233f4cbf05Sopenharmony_ci mapProt_, 2243f4cbf05Sopenharmony_ci mapFlag_, 2253f4cbf05Sopenharmony_ci fd_, 2263f4cbf05Sopenharmony_ci offset_); 2273f4cbf05Sopenharmony_ci if (data == MAP_FAILED && hint_ != nullptr) { 2283f4cbf05Sopenharmony_ci UTILS_LOGW("%{public}s: Mapping Failed. %{public}s, retry with a null hint.", \ 2293f4cbf05Sopenharmony_ci __FUNCTION__, strerror(errno)); 2303f4cbf05Sopenharmony_ci hint_ = nullptr; 2313f4cbf05Sopenharmony_ci } else { 2323f4cbf05Sopenharmony_ci break; 2333f4cbf05Sopenharmony_ci } 2343f4cbf05Sopenharmony_ci } while (true); 2353f4cbf05Sopenharmony_ci 2363f4cbf05Sopenharmony_ci if (data == MAP_FAILED) { 2373f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Mapping Failed. %{public}s", __FUNCTION__, strerror(errno)); 2383f4cbf05Sopenharmony_ci return MAPPED_FILE_ERR_FAILED; 2393f4cbf05Sopenharmony_ci } 2403f4cbf05Sopenharmony_ci 2413f4cbf05Sopenharmony_ci rStart_ = reinterpret_cast<char*>(data); 2423f4cbf05Sopenharmony_ci // set region boundary. 2433f4cbf05Sopenharmony_ci rEnd_ = rStart_ + (RoundSize(size_) - 1LL); 2443f4cbf05Sopenharmony_ci // set segment start 2453f4cbf05Sopenharmony_ci data_ = rStart_; 2463f4cbf05Sopenharmony_ci isMapped_ = true; 2473f4cbf05Sopenharmony_ci 2483f4cbf05Sopenharmony_ci return MAPPED_FILE_ERR_OK; 2493f4cbf05Sopenharmony_ci} 2503f4cbf05Sopenharmony_ci 2513f4cbf05Sopenharmony_ciErrCode MappedFile::Unmap() 2523f4cbf05Sopenharmony_ci{ 2533f4cbf05Sopenharmony_ci if (!isMapped_) { 2543f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. Already unmapped.", __FUNCTION__); 2553f4cbf05Sopenharmony_ci return ERR_INVALID_OPERATION; 2563f4cbf05Sopenharmony_ci } 2573f4cbf05Sopenharmony_ci 2583f4cbf05Sopenharmony_ci if (!isNormed_) { 2593f4cbf05Sopenharmony_ci UTILS_LOGW("%{public}s. Try unmapping with params changed.", __FUNCTION__); 2603f4cbf05Sopenharmony_ci } 2613f4cbf05Sopenharmony_ci 2623f4cbf05Sopenharmony_ci if (munmap(rStart_, static_cast<size_t>(size_)) == -1) { 2633f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. %{public}s.", __FUNCTION__, strerror(errno)); 2643f4cbf05Sopenharmony_ci return MAPPED_FILE_ERR_FAILED; 2653f4cbf05Sopenharmony_ci } 2663f4cbf05Sopenharmony_ci 2673f4cbf05Sopenharmony_ci rStart_ = nullptr; 2683f4cbf05Sopenharmony_ci rEnd_ = nullptr; 2693f4cbf05Sopenharmony_ci data_ = nullptr; 2703f4cbf05Sopenharmony_ci isMapped_ = false; 2713f4cbf05Sopenharmony_ci return MAPPED_FILE_ERR_OK; 2723f4cbf05Sopenharmony_ci} 2733f4cbf05Sopenharmony_ci 2743f4cbf05Sopenharmony_cibool MappedFile::SyncFileSize(off_t newSize) 2753f4cbf05Sopenharmony_ci{ 2763f4cbf05Sopenharmony_ci if (newSize > size_) { 2773f4cbf05Sopenharmony_ci struct stat stb = {0}; 2783f4cbf05Sopenharmony_ci if (stat(path_.c_str(), &stb) != 0) { 2793f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. Cannot get file size: %{public}s.", __FUNCTION__, strerror(errno)); 2803f4cbf05Sopenharmony_ci return false; 2813f4cbf05Sopenharmony_ci } else if (offset_ + newSize <= stb.st_size) { 2823f4cbf05Sopenharmony_ci UTILS_LOGW("%{public}s: Failed. Unextend file size, no need to sync.", __FUNCTION__); 2833f4cbf05Sopenharmony_ci } else { 2843f4cbf05Sopenharmony_ci if (ftruncate(fd_, offset_ + newSize) == -1) { 2853f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. Cannot extend file size: %{public}s.", __FUNCTION__, strerror(errno)); 2863f4cbf05Sopenharmony_ci return false; 2873f4cbf05Sopenharmony_ci } 2883f4cbf05Sopenharmony_ci } 2893f4cbf05Sopenharmony_ci } 2903f4cbf05Sopenharmony_ci 2913f4cbf05Sopenharmony_ci return true; 2923f4cbf05Sopenharmony_ci} 2933f4cbf05Sopenharmony_ci 2943f4cbf05Sopenharmony_ciErrCode MappedFile::Resize(off_t newSize, bool sync) 2953f4cbf05Sopenharmony_ci{ 2963f4cbf05Sopenharmony_ci if (newSize == DEFAULT_LENGTH) { 2973f4cbf05Sopenharmony_ci struct stat stb = {0}; 2983f4cbf05Sopenharmony_ci if (stat(path_.c_str(), &stb) != 0) { 2993f4cbf05Sopenharmony_ci UTILS_LOGW("%{public}s: Failed. Get file size failed! Mapped size will be that of a page.", __FUNCTION__); 3003f4cbf05Sopenharmony_ci newSize = PageSize(); 3013f4cbf05Sopenharmony_ci } 3023f4cbf05Sopenharmony_ci 3033f4cbf05Sopenharmony_ci if (newSize == DEFAULT_LENGTH) { 3043f4cbf05Sopenharmony_ci newSize = stb.st_size; 3053f4cbf05Sopenharmony_ci } 3063f4cbf05Sopenharmony_ci } 3073f4cbf05Sopenharmony_ci 3083f4cbf05Sopenharmony_ci if (newSize == 0 || newSize < DEFAULT_LENGTH || newSize == size_) { 3093f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. Cannot remap with the same /negative size.", __FUNCTION__); 3103f4cbf05Sopenharmony_ci return ERR_INVALID_OPERATION; 3113f4cbf05Sopenharmony_ci } 3123f4cbf05Sopenharmony_ci 3133f4cbf05Sopenharmony_ci if (!isMapped_) { 3143f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. Invalid status. mapped:%{public}d, normed:%{public}d", \ 3153f4cbf05Sopenharmony_ci __FUNCTION__, isMapped_, isNormed_); 3163f4cbf05Sopenharmony_ci return ERR_INVALID_OPERATION; 3173f4cbf05Sopenharmony_ci } 3183f4cbf05Sopenharmony_ci 3193f4cbf05Sopenharmony_ci if (sync) { 3203f4cbf05Sopenharmony_ci if (!SyncFileSize(newSize)) { 3213f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Sync Failed.", __FUNCTION__); 3223f4cbf05Sopenharmony_ci return MAPPED_FILE_ERR_FAILED; 3233f4cbf05Sopenharmony_ci } 3243f4cbf05Sopenharmony_ci } else { 3253f4cbf05Sopenharmony_ci struct stat stb = {0}; 3263f4cbf05Sopenharmony_ci if (stat(path_.c_str(), &stb) != 0) { 3273f4cbf05Sopenharmony_ci UTILS_LOGW("%{public}s: Failed. Cannot get file size: %{public}s.", __FUNCTION__, strerror(errno)); 3283f4cbf05Sopenharmony_ci return ERR_INVALID_OPERATION; 3293f4cbf05Sopenharmony_ci } 3303f4cbf05Sopenharmony_ci 3313f4cbf05Sopenharmony_ci if (!ValidMappedSize(newSize, stb)) { 3323f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. Invalid params.", __FUNCTION__); 3333f4cbf05Sopenharmony_ci return ERR_INVALID_VALUE; 3343f4cbf05Sopenharmony_ci } 3353f4cbf05Sopenharmony_ci } 3363f4cbf05Sopenharmony_ci 3373f4cbf05Sopenharmony_ci void* newData = mremap(rStart_, static_cast<size_t>(size_), static_cast<size_t>(newSize), MREMAP_MAYMOVE); 3383f4cbf05Sopenharmony_ci if (newData == MAP_FAILED) { 3393f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. %{public}s", __FUNCTION__, strerror(errno)); 3403f4cbf05Sopenharmony_ci return MAPPED_FILE_ERR_FAILED; 3413f4cbf05Sopenharmony_ci } 3423f4cbf05Sopenharmony_ci 3433f4cbf05Sopenharmony_ci rStart_ = reinterpret_cast<char*>(newData); 3443f4cbf05Sopenharmony_ci size_ = newSize; 3453f4cbf05Sopenharmony_ci // set region boundary. 3463f4cbf05Sopenharmony_ci rEnd_ = rStart_ + RoundSize(size_) - 1; 3473f4cbf05Sopenharmony_ci // set segment start. 3483f4cbf05Sopenharmony_ci data_ = rStart_; 3493f4cbf05Sopenharmony_ci 3503f4cbf05Sopenharmony_ci return MAPPED_FILE_ERR_OK; 3513f4cbf05Sopenharmony_ci} 3523f4cbf05Sopenharmony_ci 3533f4cbf05Sopenharmony_ciErrCode MappedFile::Resize() 3543f4cbf05Sopenharmony_ci{ 3553f4cbf05Sopenharmony_ci if (isMapped_) { 3563f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. No param changes detected or unmapping required before resize.", __FUNCTION__); 3573f4cbf05Sopenharmony_ci return ERR_INVALID_OPERATION; 3583f4cbf05Sopenharmony_ci } 3593f4cbf05Sopenharmony_ci 3603f4cbf05Sopenharmony_ci int res = Map(); 3613f4cbf05Sopenharmony_ci if (res != MAPPED_FILE_ERR_OK) { 3623f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. Remapping failed.", __FUNCTION__); 3633f4cbf05Sopenharmony_ci return res; 3643f4cbf05Sopenharmony_ci } 3653f4cbf05Sopenharmony_ci 3663f4cbf05Sopenharmony_ci return MAPPED_FILE_ERR_OK; 3673f4cbf05Sopenharmony_ci} 3683f4cbf05Sopenharmony_ci 3693f4cbf05Sopenharmony_ciErrCode MappedFile::TurnNext() 3703f4cbf05Sopenharmony_ci{ 3713f4cbf05Sopenharmony_ci if (!isNormed_) { 3723f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. Cannot turnNext with params changed.", __FUNCTION__); 3733f4cbf05Sopenharmony_ci return ERR_INVALID_OPERATION; 3743f4cbf05Sopenharmony_ci } 3753f4cbf05Sopenharmony_ci 3763f4cbf05Sopenharmony_ci struct stat stb = {0}; 3773f4cbf05Sopenharmony_ci int ret = stat(path_.c_str(), &stb); 3783f4cbf05Sopenharmony_ci if (ret != 0) { 3793f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. Get file size failed.", __FUNCTION__); 3803f4cbf05Sopenharmony_ci return MAPPED_FILE_ERR_FAILED; 3813f4cbf05Sopenharmony_ci } 3823f4cbf05Sopenharmony_ci if (EndOffset() + 1 >= stb.st_size) { 3833f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. No contents remained.", __FUNCTION__); 3843f4cbf05Sopenharmony_ci return ERR_INVALID_OPERATION; 3853f4cbf05Sopenharmony_ci } 3863f4cbf05Sopenharmony_ci 3873f4cbf05Sopenharmony_ci // save original params 3883f4cbf05Sopenharmony_ci off_t oldSize = size_; 3893f4cbf05Sopenharmony_ci off_t oldOff = offset_; 3903f4cbf05Sopenharmony_ci const char* oldHint = hint_; 3913f4cbf05Sopenharmony_ci 3923f4cbf05Sopenharmony_ci // if mapped, rStart_ and rEnd_ are viable 3933f4cbf05Sopenharmony_ci if (isMapped_) { 3943f4cbf05Sopenharmony_ci char* curEnd = End(); 3953f4cbf05Sopenharmony_ci // case 1: remap needed 3963f4cbf05Sopenharmony_ci if (curEnd == rEnd_) { 3973f4cbf05Sopenharmony_ci // check if larger than exact file size. 3983f4cbf05Sopenharmony_ci if (EndOffset() + 1 + size_ > stb.st_size) { 3993f4cbf05Sopenharmony_ci size_ = stb.st_size - EndOffset() - 1; 4003f4cbf05Sopenharmony_ci } 4013f4cbf05Sopenharmony_ci isNormed_ = false; 4023f4cbf05Sopenharmony_ci hint_ = rStart_; 4033f4cbf05Sopenharmony_ci offset_ += oldSize; 4043f4cbf05Sopenharmony_ci 4053f4cbf05Sopenharmony_ci ErrCode res = Unmap(); 4063f4cbf05Sopenharmony_ci if (res == MAPPED_FILE_ERR_OK) { 4073f4cbf05Sopenharmony_ci res = Resize(); 4083f4cbf05Sopenharmony_ci } 4093f4cbf05Sopenharmony_ci if (res != MAPPED_FILE_ERR_OK) { 4103f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s Failed. Fail to UnMap/Resize.", __FUNCTION__); 4113f4cbf05Sopenharmony_ci // restore 4123f4cbf05Sopenharmony_ci offset_ = oldOff; 4133f4cbf05Sopenharmony_ci size_ = oldSize; 4143f4cbf05Sopenharmony_ci hint_ = oldHint; 4153f4cbf05Sopenharmony_ci isNormed_ = true; 4163f4cbf05Sopenharmony_ci } 4173f4cbf05Sopenharmony_ci return res; 4183f4cbf05Sopenharmony_ci } 4193f4cbf05Sopenharmony_ci 4203f4cbf05Sopenharmony_ci // case 2: no need to remap, but to adjust boundary. 4213f4cbf05Sopenharmony_ci if (curEnd + oldSize > rEnd_) { // otherwise keep original "size_" 4223f4cbf05Sopenharmony_ci size_ = rEnd_ - curEnd; 4233f4cbf05Sopenharmony_ci } 4243f4cbf05Sopenharmony_ci data_ += oldSize; 4253f4cbf05Sopenharmony_ci offset_ += oldSize; 4263f4cbf05Sopenharmony_ci return MAPPED_FILE_ERR_OK; 4273f4cbf05Sopenharmony_ci } 4283f4cbf05Sopenharmony_ci 4293f4cbf05Sopenharmony_ci // if not mapped, turnNext() will set offset to next page of PageSize() 4303f4cbf05Sopenharmony_ci offset_ += PageSize(); 4313f4cbf05Sopenharmony_ci isNormed_ = false; 4323f4cbf05Sopenharmony_ci 4333f4cbf05Sopenharmony_ci return MAPPED_FILE_ERR_OK; 4343f4cbf05Sopenharmony_ci} 4353f4cbf05Sopenharmony_ci 4363f4cbf05Sopenharmony_civoid MappedFile::Reset() 4373f4cbf05Sopenharmony_ci{ 4383f4cbf05Sopenharmony_ci isNormed_ = false; 4393f4cbf05Sopenharmony_ci isMapped_ = false; 4403f4cbf05Sopenharmony_ci isNewFile_ = false; 4413f4cbf05Sopenharmony_ci 4423f4cbf05Sopenharmony_ci rStart_ = nullptr; 4433f4cbf05Sopenharmony_ci rEnd_ = nullptr; 4443f4cbf05Sopenharmony_ci data_ = nullptr; 4453f4cbf05Sopenharmony_ci path_ = ""; 4463f4cbf05Sopenharmony_ci size_ = DEFAULT_LENGTH; 4473f4cbf05Sopenharmony_ci offset_ = 0; 4483f4cbf05Sopenharmony_ci mode_ = MapMode::DEFAULT; 4493f4cbf05Sopenharmony_ci fd_ = -1; 4503f4cbf05Sopenharmony_ci mapProt_ = 0; 4513f4cbf05Sopenharmony_ci mapFlag_ = 0; 4523f4cbf05Sopenharmony_ci openFlag_ = 0; 4533f4cbf05Sopenharmony_ci hint_ = nullptr; 4543f4cbf05Sopenharmony_ci} 4553f4cbf05Sopenharmony_ci 4563f4cbf05Sopenharmony_ciErrCode MappedFile::Clear(bool force) 4573f4cbf05Sopenharmony_ci{ 4583f4cbf05Sopenharmony_ci if (isMapped_) { 4593f4cbf05Sopenharmony_ci ErrCode res = Unmap(); 4603f4cbf05Sopenharmony_ci if (!force && res != MAPPED_FILE_ERR_OK) { 4613f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s failed. UnMapping Failed.", __FUNCTION__); 4623f4cbf05Sopenharmony_ci return res; 4633f4cbf05Sopenharmony_ci } 4643f4cbf05Sopenharmony_ci } 4653f4cbf05Sopenharmony_ci 4663f4cbf05Sopenharmony_ci if (fd_ != -1 && close(fd_) == -1) { 4673f4cbf05Sopenharmony_ci UTILS_LOGD("%{public}s: Failed. Cannot close the file: %{public}s.", \ 4683f4cbf05Sopenharmony_ci __FUNCTION__, strerror(errno)); 4693f4cbf05Sopenharmony_ci return MAPPED_FILE_ERR_FAILED; 4703f4cbf05Sopenharmony_ci } 4713f4cbf05Sopenharmony_ci Reset(); 4723f4cbf05Sopenharmony_ci return MAPPED_FILE_ERR_OK; 4733f4cbf05Sopenharmony_ci} 4743f4cbf05Sopenharmony_ci 4753f4cbf05Sopenharmony_ciMappedFile::~MappedFile() 4763f4cbf05Sopenharmony_ci{ 4773f4cbf05Sopenharmony_ci if (isMapped_) { 4783f4cbf05Sopenharmony_ci ErrCode res = Unmap(); 4793f4cbf05Sopenharmony_ci if (res != MAPPED_FILE_ERR_OK) { 4803f4cbf05Sopenharmony_ci UTILS_LOGW("%{public}s: File unmapping failed, it will be automatically \ 4813f4cbf05Sopenharmony_ci unmapped when the process is terminated.", __FUNCTION__); 4823f4cbf05Sopenharmony_ci } 4833f4cbf05Sopenharmony_ci } 4843f4cbf05Sopenharmony_ci 4853f4cbf05Sopenharmony_ci if (fd_ != -1 && close(fd_) == -1) { 4863f4cbf05Sopenharmony_ci UTILS_LOGE("%{public}s: Failed. Cannot close the file: %{public}s.", \ 4873f4cbf05Sopenharmony_ci __FUNCTION__, strerror(errno)); 4883f4cbf05Sopenharmony_ci } 4893f4cbf05Sopenharmony_ci} 4903f4cbf05Sopenharmony_ci 4913f4cbf05Sopenharmony_ciMappedFile::MappedFile(MappedFile&& other) noexcept 4923f4cbf05Sopenharmony_ci : data_(other.data_), rStart_(other.rStart_), rEnd_(other.rEnd_), isMapped_(other.isMapped_), 4933f4cbf05Sopenharmony_ci isNormed_(other.isNormed_), isNewFile_(other.isNewFile_), path_(std::move(other.path_)), size_(other.size_), 4943f4cbf05Sopenharmony_ci offset_(other.offset_), mode_(other.mode_), fd_(other.fd_), mapProt_(other.mapProt_), mapFlag_(other.mapFlag_), 4953f4cbf05Sopenharmony_ci openFlag_(other.openFlag_), hint_(other.hint_) 4963f4cbf05Sopenharmony_ci{ 4973f4cbf05Sopenharmony_ci other.Reset(); 4983f4cbf05Sopenharmony_ci} 4993f4cbf05Sopenharmony_ci 5003f4cbf05Sopenharmony_ciMappedFile& MappedFile::operator=(MappedFile&& other) noexcept 5013f4cbf05Sopenharmony_ci{ 5023f4cbf05Sopenharmony_ci Clear(true); 5033f4cbf05Sopenharmony_ci 5043f4cbf05Sopenharmony_ci data_ = other.data_; 5053f4cbf05Sopenharmony_ci rStart_ = other.rStart_; 5063f4cbf05Sopenharmony_ci rEnd_ = other.rEnd_; 5073f4cbf05Sopenharmony_ci isMapped_ = other.isMapped_; 5083f4cbf05Sopenharmony_ci isNormed_ = other.isNormed_; 5093f4cbf05Sopenharmony_ci isNewFile_ = other.isNewFile_; 5103f4cbf05Sopenharmony_ci path_ = other.path_; 5113f4cbf05Sopenharmony_ci size_ = other.size_; 5123f4cbf05Sopenharmony_ci offset_ = other.offset_; 5133f4cbf05Sopenharmony_ci mode_ = other.mode_; 5143f4cbf05Sopenharmony_ci fd_ = other.fd_; 5153f4cbf05Sopenharmony_ci mapProt_ = other.mapProt_; 5163f4cbf05Sopenharmony_ci mapFlag_ = other.mapFlag_; 5173f4cbf05Sopenharmony_ci openFlag_ = other.openFlag_; 5183f4cbf05Sopenharmony_ci hint_ = other.hint_; 5193f4cbf05Sopenharmony_ci 5203f4cbf05Sopenharmony_ci other.Reset(); 5213f4cbf05Sopenharmony_ci 5223f4cbf05Sopenharmony_ci return *this; 5233f4cbf05Sopenharmony_ci} 5243f4cbf05Sopenharmony_ci 5253f4cbf05Sopenharmony_cibool MappedFile::ChangeOffset(off_t val) 5263f4cbf05Sopenharmony_ci{ 5273f4cbf05Sopenharmony_ci if (offset_ != val) { 5283f4cbf05Sopenharmony_ci if (!isMapped_ || Unmap() == MAPPED_FILE_ERR_OK) { 5293f4cbf05Sopenharmony_ci offset_ = val; 5303f4cbf05Sopenharmony_ci isNormed_ = false; 5313f4cbf05Sopenharmony_ci 5323f4cbf05Sopenharmony_ci return true; 5333f4cbf05Sopenharmony_ci } 5343f4cbf05Sopenharmony_ci 5353f4cbf05Sopenharmony_ci UTILS_LOGW("%{public}s: Change params failed. Unmapping failed.", __FUNCTION__); 5363f4cbf05Sopenharmony_ci } 5373f4cbf05Sopenharmony_ci return false; 5383f4cbf05Sopenharmony_ci} 5393f4cbf05Sopenharmony_ci 5403f4cbf05Sopenharmony_cibool MappedFile::ChangeSize(off_t val) 5413f4cbf05Sopenharmony_ci{ 5423f4cbf05Sopenharmony_ci if ((val > 0 || val == DEFAULT_LENGTH) && size_ != val) { 5433f4cbf05Sopenharmony_ci if (!isMapped_ || Unmap() == MAPPED_FILE_ERR_OK) { 5443f4cbf05Sopenharmony_ci size_ = val; 5453f4cbf05Sopenharmony_ci isNormed_ = false; 5463f4cbf05Sopenharmony_ci 5473f4cbf05Sopenharmony_ci return true; 5483f4cbf05Sopenharmony_ci } 5493f4cbf05Sopenharmony_ci 5503f4cbf05Sopenharmony_ci UTILS_LOGW("%{public}s: Change params failed. Unmapping failed.", __FUNCTION__); 5513f4cbf05Sopenharmony_ci } 5523f4cbf05Sopenharmony_ci return false; 5533f4cbf05Sopenharmony_ci} 5543f4cbf05Sopenharmony_ci 5553f4cbf05Sopenharmony_cibool MappedFile::ChangePath(const std::string& val) 5563f4cbf05Sopenharmony_ci{ 5573f4cbf05Sopenharmony_ci if (path_ != val) { 5583f4cbf05Sopenharmony_ci if (!isMapped_ || Unmap() == MAPPED_FILE_ERR_OK) { 5593f4cbf05Sopenharmony_ci if (fd_ != -1 && close(fd_) == -1) { 5603f4cbf05Sopenharmony_ci UTILS_LOGW("%{public}s: Failed. Cannot close the file: %{public}s.", \ 5613f4cbf05Sopenharmony_ci __FUNCTION__, strerror(errno)); 5623f4cbf05Sopenharmony_ci return false; 5633f4cbf05Sopenharmony_ci } 5643f4cbf05Sopenharmony_ci path_ = val; 5653f4cbf05Sopenharmony_ci isNormed_ = false; 5663f4cbf05Sopenharmony_ci fd_ = -1; 5673f4cbf05Sopenharmony_ci 5683f4cbf05Sopenharmony_ci return true; 5693f4cbf05Sopenharmony_ci } else { 5703f4cbf05Sopenharmony_ci UTILS_LOGW("%{public}s: Change params failed. Unmapping failed.", __FUNCTION__); 5713f4cbf05Sopenharmony_ci } 5723f4cbf05Sopenharmony_ci } 5733f4cbf05Sopenharmony_ci return false; 5743f4cbf05Sopenharmony_ci} 5753f4cbf05Sopenharmony_ci 5763f4cbf05Sopenharmony_cibool MappedFile::ChangeHint(const char* val) 5773f4cbf05Sopenharmony_ci{ 5783f4cbf05Sopenharmony_ci if (hint_ != val) { 5793f4cbf05Sopenharmony_ci if (!isMapped_ || Unmap() == MAPPED_FILE_ERR_OK) { 5803f4cbf05Sopenharmony_ci hint_ = val; 5813f4cbf05Sopenharmony_ci isNormed_ = false; 5823f4cbf05Sopenharmony_ci 5833f4cbf05Sopenharmony_ci return true; 5843f4cbf05Sopenharmony_ci } else { 5853f4cbf05Sopenharmony_ci UTILS_LOGW("%{public}s: Change params failed. Unmapping failed.", __FUNCTION__); 5863f4cbf05Sopenharmony_ci } 5873f4cbf05Sopenharmony_ci } 5883f4cbf05Sopenharmony_ci return false; 5893f4cbf05Sopenharmony_ci} 5903f4cbf05Sopenharmony_ci 5913f4cbf05Sopenharmony_cibool MappedFile::ChangeMode(MapMode val) 5923f4cbf05Sopenharmony_ci{ 5933f4cbf05Sopenharmony_ci if (mode_ != val) { 5943f4cbf05Sopenharmony_ci if (!isMapped_ || Unmap() == MAPPED_FILE_ERR_OK) { 5953f4cbf05Sopenharmony_ci mode_ = val; 5963f4cbf05Sopenharmony_ci isNormed_ = false; 5973f4cbf05Sopenharmony_ci 5983f4cbf05Sopenharmony_ci return true; 5993f4cbf05Sopenharmony_ci } else { 6003f4cbf05Sopenharmony_ci UTILS_LOGW("%{public}s: Change params failed. Unmapping failed.", __FUNCTION__); 6013f4cbf05Sopenharmony_ci } 6023f4cbf05Sopenharmony_ci } 6033f4cbf05Sopenharmony_ci return false; 6043f4cbf05Sopenharmony_ci} 6053f4cbf05Sopenharmony_ci 6063f4cbf05Sopenharmony_ci} // namespace Utils 6073f4cbf05Sopenharmony_ci} // namespace OHOS