Seregon/zftpd

Zero-copy FTP/HTTP Daemon compatible with all POSIX systems

C/11.0 KB/No license
include/pal_fileio.h
zftpd / include / pal_fileio.h
1/*
2MIT License
3 
4Copyright (c) 2026 Seregon
5 
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12 
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15 
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24 
25/**
26 * @file pal_fileio.h
27 * @brief Platform-agnostic file I/O with zero-copy support
28 *
29 * @author SeregonWar
30 * @version 1.0.0
31 * @date 2026-02-13
32 *
33 * OPTIMIZATION: Zero-copy file transfer via sendfile() where supported
34 * FALLBACK: Buffered read/write for platforms without sendfile()
35 *
36 */
37 
38#ifndef PAL_FILEIO_H
39#define PAL_FILEIO_H
40 
41#include "ftp_types.h"
42#include <sys/stat.h>
43#include <sys/types.h>
44 
45/*===========================================================================*
46 * FILE PERMISSIONS
47 *===========================================================================*/
48 
49#ifndef FILE_PERM
50#define FILE_PERM 0666 /**< Default file permissions (rw-rw-rw-) */
51#endif
52 
53#ifndef DIR_PERM
54#define DIR_PERM 0777 /**< Default directory permissions (rwxrwxrwx) */
55#endif
56 
57/*===========================================================================*
58 * SENDFILE CAPABILITY DETECTION
59 *===========================================================================*/
60 
61#if defined(__linux__)
62#define HAS_SENDFILE 1
63#include <sys/sendfile.h>
64#elif defined(__FreeBSD__) || defined(PLATFORM_PS4) || defined(PLATFORM_PS5)
65#define HAS_SENDFILE 1
66#include <sys/uio.h>
67#else
68#define HAS_SENDFILE 0
69#endif
70 
71/*===========================================================================*
72 * ZERO-COPY FILE TRANSFER
73 *===========================================================================*/
74 
75/**
76 * @brief Send file data via socket (zero-copy where supported)
77 *
78 * OPTIMIZATION: Uses sendfile() syscall when available for zero-copy
79 * kernel-to-socket transfer without userspace buffering.
80 *
81 * PERFORMANCE:
82 * - Zero-copy: ~950 MB/s on PS4, ~118 MB/s on PS5 (network-limited)
83 * - Buffered: ~300-400 MB/s (userspace copy overhead)
84 *
85 * @param sock_fd Socket file descriptor (destination)
86 * @param file_fd File descriptor (source)
87 * @param offset Starting offset in file (updated on return)
88 * @param count Number of bytes to send
89 *
90 * @return Number of bytes sent on success, negative error code on failure
91 * @retval >0 Number of bytes successfully sent
92 * @retval 0 End of file reached
93 * @retval -1 I/O error (check errno)
94 *
95 * @pre sock_fd >= 0 (valid socket)
96 * @pre file_fd >= 0 (valid file)
97 * @pre offset != NULL
98 * @pre *offset >= 0
99 * @pre count > 0
100 *
101 * @post *offset updated by number of bytes sent
102 *
103 * @note Thread-safety: Safe if file descriptors not shared
104 * @note WCET: Unbounded (depends on network/disk I/O)
105 *
106 * @warning Non-blocking sockets may return partial writes (EAGAIN)
107 * @warning Caller must handle partial transfers in loop
108 */
109ssize_t pal_sendfile(int sock_fd, int file_fd, off_t *offset, size_t count);
110 
111/*===========================================================================*
112 * FILE OPERATIONS
113 *===========================================================================*/
114 
115/**
116 * @brief Safe file open with validation
117 *
118 * @param path File path (null-terminated)
119 * @param flags Open flags (O_RDONLY, O_WRONLY, O_RDWR, etc.)
120 * @param mode Permission mode (for O_CREAT)
121 *
122 * @return File descriptor on success, negative error code on failure
123 * @retval >=0 Valid file descriptor
124 * @retval <0 Error code
125 *
126 * @pre path != NULL
127 * @pre strlen(path) < FTP_PATH_MAX
128 *
129 * @note Thread-safety: Safe (kernel-level synchronization)
130 * @note Caller must close file descriptor when done
131 */
132int pal_file_open(const char *path, int flags, mode_t mode);
133 
134/**
135 * @brief Safe file close
136 *
137 * @param fd File descriptor
138 *
139 * @return FTP_OK on success, negative error code on failure
140 *
141 * @pre fd >= 0
142 *
143 * @post File descriptor is invalid after successful close
144 *
145 * @note Thread-safety: Safe if fd not shared
146 */
147ftp_error_t pal_file_close(int fd);
148 
149/**
150 * @brief Get file status
151 *
152 * @param path File path
153 * @param st Output stat structure
154 *
155 * @return FTP_OK on success, negative error code on failure
156 *
157 * @pre path != NULL
158 * @pre st != NULL
159 *
160 * @post On success, st contains file metadata
161 *
162 * @note Thread-safety: Safe (kernel-level synchronization)
163 */
164ftp_error_t pal_file_stat(const char *path, struct stat *st);
165 
166/**
167 * @brief Get file status from descriptor
168 *
169 * @param fd File descriptor
170 * @param st Output stat structure
171 *
172 * @return FTP_OK on success, negative error code on failure
173 *
174 * @pre fd >= 0
175 * @pre st != NULL
176 */
177ftp_error_t pal_file_fstat(int fd, struct stat *st);
178 
179/**
180 * @brief Read file data
181 *
182 * @param fd File descriptor
183 * @param buffer Output buffer
184 * @param count Number of bytes to read
185 *
186 * @return Number of bytes read on success, negative on error
187 * @retval >0 Bytes read
188 * @retval 0 End of file
189 * @retval <0 Error code
190 *
191 * @pre fd >= 0
192 * @pre buffer != NULL
193 * @pre count > 0
194 *
195 * @note May return less than count bytes (not an error)
196 */
197ssize_t pal_file_read(int fd, void *buffer, size_t count);
198 
199/**
200 * @brief Write file data
201 *
202 * @param fd File descriptor
203 * @param buffer Input buffer
204 * @param count Number of bytes to write
205 *
206 * @return Number of bytes written on success, negative on error
207 *
208 * @pre fd >= 0
209 * @pre buffer != NULL
210 * @pre count > 0
211 *
212 * @note May return less than count bytes (disk full, etc.)
213 */
214ssize_t pal_file_write(int fd, const void *buffer, size_t count);
215 
216ssize_t pal_file_write_all(int fd, const void *buffer, size_t count);
217 
218/**
219 * @brief Seek to file position
220 *
221 * @param fd File descriptor
222 * @param offset Offset in bytes
223 * @param whence SEEK_SET, SEEK_CUR, or SEEK_END
224 *
225 * @return New file position on success, negative on error
226 *
227 * @pre fd >= 0
228 */
229off_t pal_file_seek(int fd, off_t offset, int whence);
230 
231/**
232 * @brief Truncate file to specified length
233 *
234 * @param fd File descriptor
235 * @param len New file length
236 *
237 * @return FTP_OK on success, negative error code on failure
238 *
239 * @pre fd >= 0
240 * @pre len >= 0
241 */
242ftp_error_t pal_file_truncate(int fd, off_t len);
243 
244/**
245 * @brief Delete file
246 *
247 * @param path File path
248 *
249 * @return FTP_OK on success, negative error code on failure
250 *
251 * @pre path != NULL
252 */
253ftp_error_t pal_file_delete(const char *path);
254 
255/**
256 * @brief Rename/move file
257 *
258 * @param old_path Source path
259 * @param new_path Destination path
260 *
261 * @return FTP_OK on success, negative error code on failure
262 *
263 * @pre old_path != NULL
264 * @pre new_path != NULL
265 */
266ftp_error_t pal_file_rename(const char *old_path, const char *new_path);
267 
268/**
269 * @brief Recursively copy file or directory
270 *
271 * @param src Source path
272 * @param dst Destination path
273 * @param keep_src If 0, delete source after successful copy (move)
274 *
275 * @return FTP_OK on success, negative error code on failure
276 */
277ftp_error_t pal_file_copy_recursive(const char *src, const char *dst,
278 int keep_src);
279 
280/*===========================================================================*
281 * COPY PROGRESS CALLBACK
282 *
283 * Invoked after each read/write chunk during file copy.
284 *
285 * bytes_copied : cumulative bytes written so far (across all files)
286 * user_data : opaque pointer passed by the caller
287 *
288 * Return: 0 = continue
289 * -1 = cancel (copy will abort and return FTP_ERR_CANCELLED)
290 *===========================================================================*/
291 
292typedef int (*pal_copy_progress_cb_t)(uint64_t bytes_copied, void *user_data);
293 
294/**
295 * @brief Recursively copy with progress reporting
296 *
297 * Same as pal_file_copy_recursive() but invokes cb after each I/O chunk.
298 */
299ftp_error_t pal_file_copy_recursive_ex(const char *src, const char *dst,
300 int keep_src, pal_copy_progress_cb_t cb,
301 void *user_data, int *out_errno);
302 
303/*===========================================================================*
304 * DIRECTORY OPERATIONS
305 *===========================================================================*/
306 
307/**
308 * @brief Create directory
309 *
310 * @param path Directory path
311 * @param mode Permission mode
312 *
313 * @return FTP_OK on success, negative error code on failure
314 *
315 * @pre path != NULL
316 */
317ftp_error_t pal_dir_create(const char *path, mode_t mode);
318 
319/**
320 * @brief Remove directory
321 *
322 * @param path Directory path
323 *
324 * @return FTP_OK on success, negative error code on failure
325 *
326 * @pre path != NULL
327 *
328 * @note Directory must be empty
329 */
330ftp_error_t pal_dir_remove(const char *path);
331ftp_error_t pal_dir_remove_recursive_pub(const char *path);
332 
333/**
334 * @brief Check if path exists
335 *
336 * @param path File or directory path
337 *
338 * @return 1 if exists, 0 if not, negative on error
339 *
340 * @pre path != NULL
341 */
342int pal_path_exists(const char *path);
343 
344/**
345 * @brief Check if path is a directory
346 *
347 * @param path Path to check
348 *
349 * @return 1 if directory, 0 if not, negative on error
350 *
351 * @pre path != NULL
352 */
353int pal_path_is_directory(const char *path);
354 
355/**
356 * @brief Check if path is a regular file
357 *
358 * @param path Path to check
359 *
360 * @return 1 if regular file, 0 if not, negative on error
361 *
362 * @pre path != NULL
363 */
364int pal_path_is_file(const char *path);
365 
366#endif /* PAL_FILEIO_H */
367