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