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