1 /*
2  +----------------------------------------------------------------------+
3  | Swoole                                                               |
4  +----------------------------------------------------------------------+
5  | This source file is subject to version 2.0 of the Apache license,    |
6  | that is bundled with this package in the file LICENSE, and is        |
7  | available through the world-wide-web at the following url:           |
8  | http://www.apache.org/licenses/LICENSE-2.0.html                      |
9  | If you did not receive a copy of the Apache2.0 license and are unable|
10  | to obtain it through the world-wide-web, please send a note to       |
11  | license@swoole.com so we can mail you a copy immediately.            |
12  +----------------------------------------------------------------------+
13  | Author: Tianfeng Han  <mikan.tenny@gmail.com>                        |
14  +----------------------------------------------------------------------+
15  */
16 
17 #include "swoole_file.h"
18 
swoole_tmpfile(char * filename)19 int swoole_tmpfile(char *filename) {
20 #if defined(HAVE_MKOSTEMP) && defined(HAVE_EPOLL)
21     int tmp_fd = mkostemp(filename, O_WRONLY | O_CREAT);
22 #else
23     int tmp_fd = mkstemp(filename);
24 #endif
25 
26     if (tmp_fd < 0) {
27         swoole_sys_warning("mkstemp(%s) failed", filename);
28         return SW_ERR;
29     } else {
30         return tmp_fd;
31     }
32 }
33 
34 namespace swoole {
35 
file_get_size(FILE * fp)36 ssize_t file_get_size(FILE *fp) {
37     fflush(fp);
38     return file_get_size(fileno(fp));
39 }
40 
file_get_size(const std::string & filename)41 ssize_t file_get_size(const std::string &filename) {
42     File file(filename, File::READ);
43     if (!file.ready()) {
44         swoole_set_last_error(errno);
45         return -1;
46     }
47     return file.get_size();
48 }
49 
file_get_size(int fd)50 ssize_t file_get_size(int fd) {
51     FileStatus file_stat;
52     if (fstat(fd, &file_stat) < 0) {
53         swoole_set_last_error(errno);
54         return -1;
55     }
56     if (!S_ISREG(file_stat.st_mode)) {
57         swoole_set_last_error(EISDIR);
58         return -1;
59     }
60     return file_stat.st_size;
61 }
62 
file_get_contents(const std::string & filename)63 std::shared_ptr<String> file_get_contents(const std::string &filename) {
64     File fp(filename, O_RDONLY);
65     if (!fp.ready()) {
66         swoole_sys_warning("open(%s) failed", filename.c_str());
67         return nullptr;
68     }
69 
70     ssize_t filesize = fp.get_size();
71     if (filesize < 0) {
72         return nullptr;
73     } else if (filesize == 0) {
74         swoole_error_log(SW_LOG_TRACE, SW_ERROR_FILE_EMPTY, "file[%s] is empty", filename.c_str());
75         return nullptr;
76     } else if (filesize > SW_MAX_FILE_CONTENT) {
77         swoole_error_log(SW_LOG_WARNING, SW_ERROR_FILE_TOO_LARGE, "file[%s] is too large", filename.c_str());
78         return nullptr;
79     }
80 
81     std::shared_ptr<String> content = std::make_shared<String>(filesize + 1);
82     ssize_t read_bytes = fp.read_all(content->str, filesize);
83     content->length = read_bytes;
84     content->str[read_bytes] = '\0';
85     return content;
86 }
87 
make_tmpfile()88 File make_tmpfile() {
89     char *tmpfile = sw_tg_buffer()->str;
90     size_t l = swoole_strlcpy(tmpfile, SwooleG.task_tmpfile.c_str(), SW_TASK_TMP_PATH_SIZE);
91     int tmp_fd = swoole_tmpfile(tmpfile);
92     if (tmp_fd < 0) {
93         return File(-1);
94     } else {
95         return File(tmp_fd, std::string(tmpfile, l));
96     }
97 }
98 
file_put_contents(const std::string & filename,const char * content,size_t length)99 bool file_put_contents(const std::string &filename, const char *content, size_t length) {
100     if (length <= 0) {
101         swoole_error_log(SW_LOG_TRACE, SW_ERROR_FILE_EMPTY, "content is empty");
102         return false;
103     }
104     if (length > SW_MAX_FILE_CONTENT) {
105         swoole_error_log(SW_LOG_WARNING, SW_ERROR_FILE_TOO_LARGE, "content is too large");
106         return false;
107     }
108     File file(filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
109     if (!file.ready()) {
110         swoole_sys_warning("open(%s) failed", filename.c_str());
111         return false;
112     }
113     return file.write_all(content, length);
114 }
115 
write_all(const void * data,size_t len)116 size_t File::write_all(const void *data, size_t len) {
117     size_t written_bytes = 0;
118     while (written_bytes < len) {
119         ssize_t n;
120         if (flags_ & APPEND) {
121             n = write((char *) data + written_bytes, len - written_bytes);
122         } else {
123             n = pwrite((char *) data + written_bytes, len - written_bytes, written_bytes);
124         }
125         if (n > 0) {
126             written_bytes += n;
127         } else if (n == 0) {
128             break;
129         } else {
130             if (errno == EINTR) {
131                 continue;
132             } else if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
133                 swoole_sys_warning("pwrite(%d, %p, %lu, %lu) failed", fd_, data, len - written_bytes, written_bytes);
134             }
135             break;
136         }
137     }
138     return written_bytes;
139 }
140 
read_all(void * buf,size_t len)141 size_t File::read_all(void *buf, size_t len) {
142     size_t read_bytes = 0;
143     while (read_bytes < len) {
144         ssize_t n = pread((char *) buf + read_bytes, len - read_bytes, read_bytes);
145         if (n > 0) {
146             read_bytes += n;
147         } else if (n == 0) {
148             break;
149         } else {
150             if (errno == EINTR) {
151                 continue;
152             } else if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
153                 swoole_sys_warning("pread(%d, %p, %lu, %lu) failed", fd_, buf, len - read_bytes, read_bytes);
154             }
155             break;
156         }
157     }
158     return read_bytes;
159 }
160 
read_content()161 std::shared_ptr<String> File::read_content() {
162     ssize_t n = 0;
163     std::shared_ptr<String> data = std::make_shared<String>(SW_BUFFER_SIZE_STD);
164     while (1) {
165         n = read(data->str + data->length, data->size - data->length);
166         if (n <= 0) {
167             return data;
168         } else {
169             if (!data->grow((size_t) n)) {
170                 return data;
171             }
172         }
173     }
174     return data;
175 }
176 
177 }  // namespace swoole
178