1/*
2 * Copyright (c) 2021-2022 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 "ecmascript/dfx/hprof/file_stream.h"
17
18#include <cerrno>
19#include <climits>
20#include <cstdio>
21#include <cstdlib>
22#include <cstring>
23#include <ios>
24#include <ostream>
25#include <unistd.h>
26
27#include "ecmascript/log_wrapper.h"
28
29namespace panda::ecmascript {
30FileStream::FileStream(const std::string &fileName)
31{
32    Initialize(fileName);
33}
34
35FileStream::~FileStream()
36{
37    EndOfStream();
38}
39
40void FileStream::EndOfStream()
41{
42    if (fileStream_.is_open()) {
43        fileStream_.close();
44    }
45}
46
47bool FileStream::Good()
48{
49    return fileStream_.good();
50}
51
52void FileStream::Initialize(const std::string &fileName)
53{
54    // check file name
55    std::pair<bool, std::string> realPath = FilePathValid(fileName);
56    if (!realPath.first) {
57        LOG_ECMA(ERROR) << "FileStream: check file path failed";
58        return;
59    }
60
61    fileStream_.open(realPath.second.c_str(), std::ios::out);
62    if (fileStream_.fail()) {
63        LOG_ECMA(ERROR) << "FileStream: open file failed";
64    }
65}
66
67std::pair<bool, std::string> FileStream::FilePathValid(const std::string &fileName)
68{
69    if (fileName.empty() || fileName.size() > PATH_MAX) {
70        return std::make_pair(false, "");
71    }
72    char resolvedPath[PATH_MAX] = {0};
73    auto result = realpath(fileName.c_str(), resolvedPath);
74    if (result == resolvedPath || errno == ENOENT) {
75        return std::make_pair(true, std::string(resolvedPath));
76    }
77    return std::make_pair(false, "");
78}
79
80// Writes the chunk of data into the stream
81bool FileStream::WriteChunk(char *data, int32_t size)
82{
83    if (fileStream_.fail()) {
84        return false;
85    }
86
87    std::string str(data, size);
88
89    fileStream_ << str;
90
91    return true;
92}
93
94void FileDescriptorStream::EndOfStream()
95{
96    if (Good()) {
97        close(fd_);
98    }
99}
100
101bool FileDescriptorStream::Good()
102{
103    return fd_ > 0;
104}
105
106// Writes the chunk of data into the stream
107bool FileDescriptorStream::WriteChunk(char *data, int32_t size)
108{
109    if (fd_ < 0) {
110        return false;
111    }
112
113    std::string str(data, size);
114    int ret = dprintf(fd_, "%s", str.c_str());
115    if (ret < 0) {
116        LOG_ECMA(ERROR) << "Write FD print failed, ret" << ret;
117        return false;
118    }
119    ret = fsync(fd_);
120    if (ret < 0) {
121        LOG_ECMA(ERROR) << "Write FD file failed, ret" << ret;
122        return false;
123    }
124    return true;
125}
126
127bool FileDescriptorStream::WriteBinBlock(char *data, int32_t size)
128{
129    if (fd_ < 0) {
130        return false;
131    }
132    ssize_t written = write(fd_, data, size);
133    if (written == -1) {
134        perror("write");
135        return false;
136    }
137    return true;
138}
139}
140