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/macros/config.h" 18 #include "src/errno/libc_errno.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