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 "src/__support/CPP/new.h" 11 #include "src/__support/File/file.h" 12 13 #include "src/errno/libc_errno.h" 14 #include <stdio.h> 15 #include <stdlib.h> 16 17 namespace __llvm_libc { 18 19 namespace { 20 21 class CookieFile : public __llvm_libc::File { 22 void *cookie; 23 cookie_io_functions_t ops; 24 25 static FileIOResult cookie_write(File *f, const void *data, size_t size); 26 static FileIOResult cookie_read(File *f, void *data, size_t size); 27 static ErrorOr<long> cookie_seek(File *f, long offset, int whence); 28 static int cookie_close(File *f); 29 static int cookie_flush(File *); 30 31 public: 32 CookieFile(void *c, cookie_io_functions_t cops, uint8_t *buffer, 33 size_t bufsize, File::ModeFlags mode) 34 : File(&cookie_write, &cookie_read, &CookieFile::cookie_seek, 35 &cookie_close, &cookie_flush, &cleanup_file<CookieFile>, buffer, 36 bufsize, 0 /* default buffering mode */, 37 true /* File owns buffer */, mode), 38 cookie(c), ops(cops) {} 39 }; 40 41 FileIOResult CookieFile::cookie_write(File *f, const void *data, size_t size) { 42 auto cookie_file = reinterpret_cast<CookieFile *>(f); 43 if (cookie_file->ops.write == nullptr) 44 return 0; 45 return cookie_file->ops.write(cookie_file->cookie, 46 reinterpret_cast<const char *>(data), size); 47 } 48 49 FileIOResult CookieFile::cookie_read(File *f, void *data, size_t size) { 50 auto cookie_file = reinterpret_cast<CookieFile *>(f); 51 if (cookie_file->ops.read == nullptr) 52 return 0; 53 return cookie_file->ops.read(cookie_file->cookie, 54 reinterpret_cast<char *>(data), size); 55 } 56 57 ErrorOr<long> CookieFile::cookie_seek(File *f, long offset, int whence) { 58 auto cookie_file = reinterpret_cast<CookieFile *>(f); 59 if (cookie_file->ops.seek == nullptr) { 60 return Error(EINVAL); 61 } 62 off64_t offset64 = offset; 63 int result = cookie_file->ops.seek(cookie_file->cookie, &offset64, whence); 64 if (result == 0) 65 return offset64; 66 else 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 return cookie_file->ops.close(cookie_file->cookie); 75 } 76 77 int CookieFile::cookie_flush(File *) { return 0; } 78 79 } // anonymous namespace 80 81 LLVM_LIBC_FUNCTION(::FILE *, fopencookie, 82 (void *cookie, const char *mode, 83 cookie_io_functions_t ops)) { 84 uint8_t *buffer; 85 { 86 AllocChecker ac; 87 buffer = new (ac) uint8_t[File::DEFAULT_BUFFER_SIZE]; 88 if (!ac) 89 return nullptr; 90 } 91 AllocChecker ac; 92 auto *file = new (ac) CookieFile( 93 cookie, ops, buffer, File::DEFAULT_BUFFER_SIZE, File::mode_flags(mode)); 94 if (!ac) 95 return nullptr; 96 return reinterpret_cast<::FILE *>(file); 97 } 98 99 } // namespace __llvm_libc 100