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#include "file_utils.h"
17
18#include <sys/types.h>
19#include <unistd.h>
20#include <fcntl.h>
21#include <unistd.h>
22
23#include "dfs_error.h"
24#include "utils_log.h"
25#include "xcollie_helper.h"
26
27namespace OHOS {
28namespace FileManagement {
29int64_t FileUtils::ReadFile(int fd, off_t offset, size_t size, void *data)
30{
31    if ((fd < 0) || (offset < 0) || (size < 0) || (data == nullptr)) {
32        LOGE("invalid params, fd %{public}d, offset %{public}d, size %{public}zu, or buf is null", fd,
33             static_cast<int>(offset), size);
34        return -1;
35    }
36
37    off_t err = lseek(fd, offset, SEEK_SET);
38    if (err < 0) {
39        return -errno;
40    }
41
42    size_t readLen = 0;
43    while (readLen < size) {
44        ssize_t ret = read(fd, data, size - readLen);
45        if (ret < 0) {
46            LOGE("read failed, errno %{public}d, fd=%{public}d", errno, fd);
47            return ret;
48        } else if (ret == 0) {
49            break;
50        }
51        readLen += ret;
52    }
53
54    return readLen;
55}
56
57int64_t FileUtils::WriteFile(int fd, const void *data, off_t offset, size_t size)
58{
59    if ((fd < 0) || (offset < 0) || (size < 0) || (data == nullptr)) {
60        LOGE("invalid params, fd %{public}d, offset %{public}d, size %{public}zu, or buf is null", fd,
61             static_cast<int>(offset), size);
62        return -1;
63    }
64
65    off_t err = lseek(fd, offset, SEEK_SET);
66    if (err < 0) {
67        return -errno;
68    }
69
70    size_t writeLen = 0;
71    while (writeLen < size) {
72        ssize_t ret = write(fd, data, size - writeLen);
73        if (ret <= 0) {
74            LOGE("write failed, errno %{public}d, fd=%{public}d", errno, fd);
75            return ret;
76        }
77        writeLen += ret;
78    }
79
80    return writeLen;
81}
82
83FileRangeLock::FileRangeLock(int fd, off_t offset, size_t size) : fd_(fd), offset_(offset), size_(size)
84{
85    const int DFX_DELAY_S = 5;
86    xcollieId_ = XCollieHelper::SetTimer("CloudSyncService_RangeLockTask", DFX_DELAY_S, nullptr, nullptr, true);
87    struct flock fl;
88    fl.l_type = F_WRLCK;
89    fl.l_whence = SEEK_SET;
90    fl.l_start = offset;
91    fl.l_len = static_cast<decltype(fl.l_len)>(size);
92    if (fcntl(fd, F_SETLKW, &fl) < 0) {
93        LOGE("fcntl set F_WRLCK failed: %{public}d", errno);
94        lockFailed_ = true;
95    }
96}
97
98FileRangeLock::~FileRangeLock()
99{
100    if (lockFailed_) {
101        XCollieHelper::CancelTimer(xcollieId_);
102        return;
103    }
104
105    struct flock fl;
106    fl.l_type = F_UNLCK;
107    fl.l_whence = SEEK_SET;
108    fl.l_start = offset_;
109    fl.l_len = static_cast<decltype(fl.l_len)>(size_);
110    if (fcntl(fd_, F_SETLKW, &fl) < 0) {
111        LOGE("fcntl F_UNLCK failed: %{public}d", errno);
112    }
113    XCollieHelper::CancelTimer(xcollieId_);
114}
115
116} // namespace FileManagement
117} // namespace OHOS
118