1 | //===-- Implementation of fopencookie -------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "src/stdio/fopencookie.h" |
10 | #include "hdr/stdio_macros.h" |
11 | #include "hdr/types/FILE.h" |
12 | #include "hdr/types/cookie_io_functions_t.h" |
13 | #include "hdr/types/off_t.h" |
14 | #include "src/__support/CPP/new.h" |
15 | #include "src/__support/File/file.h" |
16 | |
17 | #include "src/__support/libc_errno.h" |
18 | #include "src/__support/macros/config.h" |
19 | |
20 | namespace LIBC_NAMESPACE_DECL { |
21 | |
22 | namespace { |
23 | |
24 | class CookieFile : public LIBC_NAMESPACE::File { |
25 | void *cookie; |
26 | cookie_io_functions_t ops; |
27 | |
28 | static FileIOResult cookie_write(File *f, const void *data, size_t size); |
29 | static FileIOResult cookie_read(File *f, void *data, size_t size); |
30 | static ErrorOr<off_t> cookie_seek(File *f, off_t offset, int whence); |
31 | static int cookie_close(File *f); |
32 | |
33 | public: |
34 | CookieFile(void *c, cookie_io_functions_t cops, uint8_t *buffer, |
35 | size_t bufsize, File::ModeFlags mode) |
36 | : File(&cookie_write, &cookie_read, &CookieFile::cookie_seek, |
37 | &cookie_close, buffer, bufsize, 0 /* default buffering mode */, |
38 | true /* File owns buffer */, mode), |
39 | cookie(c), ops(cops) {} |
40 | }; |
41 | |
42 | FileIOResult CookieFile::cookie_write(File *f, const void *data, size_t size) { |
43 | auto cookie_file = reinterpret_cast<CookieFile *>(f); |
44 | if (cookie_file->ops.write == nullptr) |
45 | return 0; |
46 | return static_cast<size_t>(cookie_file->ops.write( |
47 | cookie_file->cookie, reinterpret_cast<const char *>(data), size)); |
48 | } |
49 | |
50 | FileIOResult CookieFile::cookie_read(File *f, void *data, size_t size) { |
51 | auto cookie_file = reinterpret_cast<CookieFile *>(f); |
52 | if (cookie_file->ops.read == nullptr) |
53 | return 0; |
54 | return static_cast<size_t>(cookie_file->ops.read( |
55 | cookie_file->cookie, reinterpret_cast<char *>(data), size)); |
56 | } |
57 | |
58 | ErrorOr<off_t> CookieFile::cookie_seek(File *f, off_t offset, int whence) { |
59 | auto cookie_file = reinterpret_cast<CookieFile *>(f); |
60 | if (cookie_file->ops.seek == nullptr) { |
61 | return Error(EINVAL); |
62 | } |
63 | off64_t offset64 = offset; |
64 | int result = cookie_file->ops.seek(cookie_file->cookie, &offset64, whence); |
65 | if (result == 0) |
66 | return offset64; |
67 | return -1; |
68 | } |
69 | |
70 | int CookieFile::cookie_close(File *f) { |
71 | auto cookie_file = reinterpret_cast<CookieFile *>(f); |
72 | if (cookie_file->ops.close == nullptr) |
73 | return 0; |
74 | int retval = cookie_file->ops.close(cookie_file->cookie); |
75 | if (retval != 0) |
76 | return retval; |
77 | delete cookie_file; |
78 | return 0; |
79 | } |
80 | |
81 | } // anonymous namespace |
82 | |
83 | LLVM_LIBC_FUNCTION(::FILE *, fopencookie, |
84 | (void *cookie, const char *mode, |
85 | cookie_io_functions_t ops)) { |
86 | uint8_t *buffer; |
87 | { |
88 | AllocChecker ac; |
89 | buffer = new (ac) uint8_t[File::DEFAULT_BUFFER_SIZE]; |
90 | if (!ac) |
91 | return nullptr; |
92 | } |
93 | AllocChecker ac; |
94 | auto *file = new (ac) CookieFile( |
95 | cookie, ops, buffer, File::DEFAULT_BUFFER_SIZE, File::mode_flags(mode)); |
96 | if (!ac) |
97 | return nullptr; |
98 | return reinterpret_cast<::FILE *>(file); |
99 | } |
100 | |
101 | } // namespace LIBC_NAMESPACE_DECL |
102 | |