1*4ef02da0SSiva Chandra Reddy //===--- Implementation of a platform independent file data structure -----===// 2*4ef02da0SSiva Chandra Reddy // 3*4ef02da0SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*4ef02da0SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information. 5*4ef02da0SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*4ef02da0SSiva Chandra Reddy // 7*4ef02da0SSiva Chandra Reddy //===----------------------------------------------------------------------===// 8*4ef02da0SSiva Chandra Reddy 9*4ef02da0SSiva Chandra Reddy #include "file.h" 10*4ef02da0SSiva Chandra Reddy 11*4ef02da0SSiva Chandra Reddy #include "src/__support/CPP/ArrayRef.h" 12*4ef02da0SSiva Chandra Reddy 13*4ef02da0SSiva Chandra Reddy #include <errno.h> 14*4ef02da0SSiva Chandra Reddy #include <stdlib.h> 15*4ef02da0SSiva Chandra Reddy 16*4ef02da0SSiva Chandra Reddy namespace __llvm_libc { 17*4ef02da0SSiva Chandra Reddy 18*4ef02da0SSiva Chandra Reddy size_t File::write(const void *data, size_t len) { 19*4ef02da0SSiva Chandra Reddy FileLock lock(this); 20*4ef02da0SSiva Chandra Reddy 21*4ef02da0SSiva Chandra Reddy if (!write_allowed()) { 22*4ef02da0SSiva Chandra Reddy errno = EBADF; 23*4ef02da0SSiva Chandra Reddy err = true; 24*4ef02da0SSiva Chandra Reddy return 0; 25*4ef02da0SSiva Chandra Reddy } 26*4ef02da0SSiva Chandra Reddy 27*4ef02da0SSiva Chandra Reddy prev_op = FileOp::WRITE; 28*4ef02da0SSiva Chandra Reddy 29*4ef02da0SSiva Chandra Reddy cpp::ArrayRef<uint8_t> dataref(data, len); 30*4ef02da0SSiva Chandra Reddy cpp::MutableArrayRef<uint8_t> bufref(buf, bufsize); 31*4ef02da0SSiva Chandra Reddy 32*4ef02da0SSiva Chandra Reddy const size_t used = pos; 33*4ef02da0SSiva Chandra Reddy const size_t bufspace = bufsize - pos; 34*4ef02da0SSiva Chandra Reddy const size_t write_size = bufspace > len ? len : bufspace; 35*4ef02da0SSiva Chandra Reddy // TODO: Replace the for loop below with a call to internal memcpy. 36*4ef02da0SSiva Chandra Reddy for (size_t i = 0; i < write_size; ++i) 37*4ef02da0SSiva Chandra Reddy bufref[pos + i] = dataref[i]; 38*4ef02da0SSiva Chandra Reddy pos += write_size; 39*4ef02da0SSiva Chandra Reddy if (len < bufspace) 40*4ef02da0SSiva Chandra Reddy return len; 41*4ef02da0SSiva Chandra Reddy 42*4ef02da0SSiva Chandra Reddy // If the control reaches beyond this point, it means that |data| 43*4ef02da0SSiva Chandra Reddy // is more than what can be accomodated in the buffer. So, we first 44*4ef02da0SSiva Chandra Reddy // flush out the buffer. 45*4ef02da0SSiva Chandra Reddy size_t bytes_written = platform_write(this, buf, bufsize); 46*4ef02da0SSiva Chandra Reddy pos = 0; // Buffer is now empty so reset pos to the beginning. 47*4ef02da0SSiva Chandra Reddy if (bytes_written < bufsize) { 48*4ef02da0SSiva Chandra Reddy err = true; 49*4ef02da0SSiva Chandra Reddy // If less bytes were written than expected, then there are two 50*4ef02da0SSiva Chandra Reddy // possibilities. 51*4ef02da0SSiva Chandra Reddy // 1. None of the bytes from |data| were flushed out. 52*4ef02da0SSiva Chandra Reddy if (bytes_written <= used) 53*4ef02da0SSiva Chandra Reddy return 0; 54*4ef02da0SSiva Chandra Reddy // 2. Some of the bytes from |data| were written 55*4ef02da0SSiva Chandra Reddy return bytes_written - used; 56*4ef02da0SSiva Chandra Reddy } 57*4ef02da0SSiva Chandra Reddy 58*4ef02da0SSiva Chandra Reddy // If the remaining bytes from |data| can fit in the buffer, write 59*4ef02da0SSiva Chandra Reddy // into it. Else, write it directly to the platform stream. 60*4ef02da0SSiva Chandra Reddy size_t remaining = len - write_size; 61*4ef02da0SSiva Chandra Reddy if (remaining <= len) { 62*4ef02da0SSiva Chandra Reddy // TODO: Replace the for loop below with a call to internal memcpy. 63*4ef02da0SSiva Chandra Reddy for (size_t i = 0; i < remaining; ++i) 64*4ef02da0SSiva Chandra Reddy bufref[i] = dataref[i]; 65*4ef02da0SSiva Chandra Reddy pos += remaining; 66*4ef02da0SSiva Chandra Reddy return len; 67*4ef02da0SSiva Chandra Reddy } 68*4ef02da0SSiva Chandra Reddy 69*4ef02da0SSiva Chandra Reddy size_t transferred = 70*4ef02da0SSiva Chandra Reddy platform_write(this, dataref.data() + write_size, remaining); 71*4ef02da0SSiva Chandra Reddy if (transferred < remaining) { 72*4ef02da0SSiva Chandra Reddy err = true; 73*4ef02da0SSiva Chandra Reddy return write_size + transferred; 74*4ef02da0SSiva Chandra Reddy } 75*4ef02da0SSiva Chandra Reddy return len; 76*4ef02da0SSiva Chandra Reddy } 77*4ef02da0SSiva Chandra Reddy 78*4ef02da0SSiva Chandra Reddy size_t File::read(void *data, size_t len) { 79*4ef02da0SSiva Chandra Reddy FileLock lock(this); 80*4ef02da0SSiva Chandra Reddy 81*4ef02da0SSiva Chandra Reddy if (!read_allowed()) { 82*4ef02da0SSiva Chandra Reddy errno = EBADF; 83*4ef02da0SSiva Chandra Reddy err = true; 84*4ef02da0SSiva Chandra Reddy return 0; 85*4ef02da0SSiva Chandra Reddy } 86*4ef02da0SSiva Chandra Reddy 87*4ef02da0SSiva Chandra Reddy prev_op = FileOp::READ; 88*4ef02da0SSiva Chandra Reddy 89*4ef02da0SSiva Chandra Reddy cpp::MutableArrayRef<uint8_t> bufref(buf, bufsize); 90*4ef02da0SSiva Chandra Reddy cpp::MutableArrayRef<uint8_t> dataref(data, len); 91*4ef02da0SSiva Chandra Reddy 92*4ef02da0SSiva Chandra Reddy // Because read_limit is always greater than equal to pos, 93*4ef02da0SSiva Chandra Reddy // available_data is never a wrapped around value. 94*4ef02da0SSiva Chandra Reddy size_t available_data = read_limit - pos; 95*4ef02da0SSiva Chandra Reddy if (len <= available_data) { 96*4ef02da0SSiva Chandra Reddy // TODO: Replace the for loop below with a call to internal memcpy. 97*4ef02da0SSiva Chandra Reddy for (size_t i = 0; i < len; ++i) 98*4ef02da0SSiva Chandra Reddy dataref[i] = bufref[i + pos]; 99*4ef02da0SSiva Chandra Reddy pos += len; 100*4ef02da0SSiva Chandra Reddy return len; 101*4ef02da0SSiva Chandra Reddy } 102*4ef02da0SSiva Chandra Reddy 103*4ef02da0SSiva Chandra Reddy // Copy all of the available data. 104*4ef02da0SSiva Chandra Reddy // TODO: Replace the for loop with a call to internal memcpy. 105*4ef02da0SSiva Chandra Reddy for (size_t i = 0; i < available_data; ++i) 106*4ef02da0SSiva Chandra Reddy dataref[i] = bufref[i + pos]; 107*4ef02da0SSiva Chandra Reddy read_limit = pos = 0; // Reset the pointers. 108*4ef02da0SSiva Chandra Reddy 109*4ef02da0SSiva Chandra Reddy size_t to_fetch = len - available_data; 110*4ef02da0SSiva Chandra Reddy if (to_fetch > bufsize) { 111*4ef02da0SSiva Chandra Reddy size_t fetched_size = platform_read(this, data, to_fetch); 112*4ef02da0SSiva Chandra Reddy if (fetched_size < to_fetch) { 113*4ef02da0SSiva Chandra Reddy if (errno == 0) 114*4ef02da0SSiva Chandra Reddy eof = true; 115*4ef02da0SSiva Chandra Reddy else 116*4ef02da0SSiva Chandra Reddy err = true; 117*4ef02da0SSiva Chandra Reddy return available_data + fetched_size; 118*4ef02da0SSiva Chandra Reddy } 119*4ef02da0SSiva Chandra Reddy return len; 120*4ef02da0SSiva Chandra Reddy } 121*4ef02da0SSiva Chandra Reddy 122*4ef02da0SSiva Chandra Reddy // Fetch and buffer another buffer worth of data. 123*4ef02da0SSiva Chandra Reddy size_t fetched_size = platform_read(this, buf, bufsize); 124*4ef02da0SSiva Chandra Reddy read_limit += fetched_size; 125*4ef02da0SSiva Chandra Reddy size_t transfer_size = fetched_size >= to_fetch ? to_fetch : fetched_size; 126*4ef02da0SSiva Chandra Reddy for (size_t i = 0; i < transfer_size; ++i) 127*4ef02da0SSiva Chandra Reddy dataref[i] = bufref[i]; 128*4ef02da0SSiva Chandra Reddy pos += transfer_size; 129*4ef02da0SSiva Chandra Reddy if (fetched_size < to_fetch) { 130*4ef02da0SSiva Chandra Reddy if (errno == 0) 131*4ef02da0SSiva Chandra Reddy eof = true; 132*4ef02da0SSiva Chandra Reddy else 133*4ef02da0SSiva Chandra Reddy err = true; 134*4ef02da0SSiva Chandra Reddy } 135*4ef02da0SSiva Chandra Reddy return transfer_size + available_data; 136*4ef02da0SSiva Chandra Reddy } 137*4ef02da0SSiva Chandra Reddy 138*4ef02da0SSiva Chandra Reddy int File::seek(long offset, int whence) { 139*4ef02da0SSiva Chandra Reddy FileLock lock(this); 140*4ef02da0SSiva Chandra Reddy if (prev_op == FileOp::WRITE && pos > 0) { 141*4ef02da0SSiva Chandra Reddy size_t transferred_size = platform_write(this, buf, pos); 142*4ef02da0SSiva Chandra Reddy if (transferred_size < pos) { 143*4ef02da0SSiva Chandra Reddy err = true; 144*4ef02da0SSiva Chandra Reddy return -1; 145*4ef02da0SSiva Chandra Reddy } 146*4ef02da0SSiva Chandra Reddy } 147*4ef02da0SSiva Chandra Reddy pos = read_limit = 0; 148*4ef02da0SSiva Chandra Reddy prev_op = FileOp::SEEK; 149*4ef02da0SSiva Chandra Reddy // Reset the eof flag as a seek might move the file positon to some place 150*4ef02da0SSiva Chandra Reddy // readable. 151*4ef02da0SSiva Chandra Reddy eof = false; 152*4ef02da0SSiva Chandra Reddy return platform_seek(this, offset, whence); 153*4ef02da0SSiva Chandra Reddy } 154*4ef02da0SSiva Chandra Reddy 155*4ef02da0SSiva Chandra Reddy int File::flush() { 156*4ef02da0SSiva Chandra Reddy FileLock lock(this); 157*4ef02da0SSiva Chandra Reddy if (prev_op == FileOp::WRITE && pos > 0) { 158*4ef02da0SSiva Chandra Reddy size_t transferred_size = platform_write(this, buf, pos); 159*4ef02da0SSiva Chandra Reddy if (transferred_size < pos) { 160*4ef02da0SSiva Chandra Reddy err = true; 161*4ef02da0SSiva Chandra Reddy return -1; 162*4ef02da0SSiva Chandra Reddy } 163*4ef02da0SSiva Chandra Reddy pos = 0; 164*4ef02da0SSiva Chandra Reddy return platform_flush(this); 165*4ef02da0SSiva Chandra Reddy } 166*4ef02da0SSiva Chandra Reddy return 0; 167*4ef02da0SSiva Chandra Reddy } 168*4ef02da0SSiva Chandra Reddy 169*4ef02da0SSiva Chandra Reddy int File::close() { 170*4ef02da0SSiva Chandra Reddy { 171*4ef02da0SSiva Chandra Reddy FileLock lock(this); 172*4ef02da0SSiva Chandra Reddy if (prev_op == FileOp::WRITE && pos > 0) { 173*4ef02da0SSiva Chandra Reddy size_t transferred_size = platform_write(this, buf, pos); 174*4ef02da0SSiva Chandra Reddy if (transferred_size < pos) { 175*4ef02da0SSiva Chandra Reddy err = true; 176*4ef02da0SSiva Chandra Reddy return -1; 177*4ef02da0SSiva Chandra Reddy } 178*4ef02da0SSiva Chandra Reddy } 179*4ef02da0SSiva Chandra Reddy if (platform_close(this) != 0) 180*4ef02da0SSiva Chandra Reddy return -1; 181*4ef02da0SSiva Chandra Reddy if (own_buf) 182*4ef02da0SSiva Chandra Reddy free(buf); 183*4ef02da0SSiva Chandra Reddy } 184*4ef02da0SSiva Chandra Reddy free(this); 185*4ef02da0SSiva Chandra Reddy return 0; 186*4ef02da0SSiva Chandra Reddy } 187*4ef02da0SSiva Chandra Reddy 188*4ef02da0SSiva Chandra Reddy void File::set_buffer(void *buffer, size_t size, bool owned) { 189*4ef02da0SSiva Chandra Reddy if (own_buf) 190*4ef02da0SSiva Chandra Reddy free(buf); 191*4ef02da0SSiva Chandra Reddy buf = buffer; 192*4ef02da0SSiva Chandra Reddy bufsize = size; 193*4ef02da0SSiva Chandra Reddy own_buf = owned; 194*4ef02da0SSiva Chandra Reddy } 195*4ef02da0SSiva Chandra Reddy 196*4ef02da0SSiva Chandra Reddy File::ModeFlags File::mode_flags(const char *mode) { 197*4ef02da0SSiva Chandra Reddy // First character in |mode| should be 'a', 'r' or 'w'. 198*4ef02da0SSiva Chandra Reddy if (*mode != 'a' && *mode != 'r' && *mode != 'w') 199*4ef02da0SSiva Chandra Reddy return 0; 200*4ef02da0SSiva Chandra Reddy 201*4ef02da0SSiva Chandra Reddy // There should be exaclty one main mode ('a', 'r' or 'w') character. 202*4ef02da0SSiva Chandra Reddy // If there are more than one main mode characters listed, then 203*4ef02da0SSiva Chandra Reddy // we will consider |mode| as incorrect and return 0; 204*4ef02da0SSiva Chandra Reddy int main_mode_count = 0; 205*4ef02da0SSiva Chandra Reddy 206*4ef02da0SSiva Chandra Reddy ModeFlags flags = 0; 207*4ef02da0SSiva Chandra Reddy for (; *mode != '\0'; ++mode) { 208*4ef02da0SSiva Chandra Reddy switch (*mode) { 209*4ef02da0SSiva Chandra Reddy case 'r': 210*4ef02da0SSiva Chandra Reddy flags |= static_cast<ModeFlags>(OpenMode::READ); 211*4ef02da0SSiva Chandra Reddy ++main_mode_count; 212*4ef02da0SSiva Chandra Reddy break; 213*4ef02da0SSiva Chandra Reddy case 'w': 214*4ef02da0SSiva Chandra Reddy flags |= static_cast<ModeFlags>(OpenMode::WRITE); 215*4ef02da0SSiva Chandra Reddy ++main_mode_count; 216*4ef02da0SSiva Chandra Reddy break; 217*4ef02da0SSiva Chandra Reddy case '+': 218*4ef02da0SSiva Chandra Reddy flags |= (static_cast<ModeFlags>(OpenMode::WRITE) | 219*4ef02da0SSiva Chandra Reddy static_cast<ModeFlags>(OpenMode::READ)); 220*4ef02da0SSiva Chandra Reddy break; 221*4ef02da0SSiva Chandra Reddy case 'b': 222*4ef02da0SSiva Chandra Reddy flags |= static_cast<ModeFlags>(ContentType::BINARY); 223*4ef02da0SSiva Chandra Reddy break; 224*4ef02da0SSiva Chandra Reddy case 'a': 225*4ef02da0SSiva Chandra Reddy flags |= static_cast<ModeFlags>(OpenMode::APPEND); 226*4ef02da0SSiva Chandra Reddy ++main_mode_count; 227*4ef02da0SSiva Chandra Reddy break; 228*4ef02da0SSiva Chandra Reddy case 'x': 229*4ef02da0SSiva Chandra Reddy flags |= static_cast<ModeFlags>(CreateType::EXCLUSIVE); 230*4ef02da0SSiva Chandra Reddy break; 231*4ef02da0SSiva Chandra Reddy default: 232*4ef02da0SSiva Chandra Reddy return 0; 233*4ef02da0SSiva Chandra Reddy } 234*4ef02da0SSiva Chandra Reddy } 235*4ef02da0SSiva Chandra Reddy 236*4ef02da0SSiva Chandra Reddy if (main_mode_count != 1) 237*4ef02da0SSiva Chandra Reddy return 0; 238*4ef02da0SSiva Chandra Reddy 239*4ef02da0SSiva Chandra Reddy return flags; 240*4ef02da0SSiva Chandra Reddy } 241*4ef02da0SSiva Chandra Reddy 242*4ef02da0SSiva Chandra Reddy } // namespace __llvm_libc 243