| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "platform/globals.h" | 5 #include "platform/globals.h" |
| 6 #if defined(HOST_OS_LINUX) | 6 #if defined(HOST_OS_LINUX) |
| 7 | 7 |
| 8 #include "bin/file.h" | 8 #include "bin/file.h" |
| 9 | 9 |
| 10 #include <errno.h> // NOLINT | 10 #include <errno.h> // NOLINT |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 ~FileHandle() {} | 32 ~FileHandle() {} |
| 33 int fd() const { return fd_; } | 33 int fd() const { return fd_; } |
| 34 void set_fd(int fd) { fd_ = fd; } | 34 void set_fd(int fd) { fd_ = fd; } |
| 35 | 35 |
| 36 private: | 36 private: |
| 37 int fd_; | 37 int fd_; |
| 38 | 38 |
| 39 DISALLOW_COPY_AND_ASSIGN(FileHandle); | 39 DISALLOW_COPY_AND_ASSIGN(FileHandle); |
| 40 }; | 40 }; |
| 41 | 41 |
| 42 | |
| 43 File::~File() { | 42 File::~File() { |
| 44 if (!IsClosed() && handle_->fd() != STDOUT_FILENO && | 43 if (!IsClosed() && handle_->fd() != STDOUT_FILENO && |
| 45 handle_->fd() != STDERR_FILENO) { | 44 handle_->fd() != STDERR_FILENO) { |
| 46 Close(); | 45 Close(); |
| 47 } | 46 } |
| 48 delete handle_; | 47 delete handle_; |
| 49 } | 48 } |
| 50 | 49 |
| 51 | |
| 52 void File::Close() { | 50 void File::Close() { |
| 53 ASSERT(handle_->fd() >= 0); | 51 ASSERT(handle_->fd() >= 0); |
| 54 if (handle_->fd() == STDOUT_FILENO) { | 52 if (handle_->fd() == STDOUT_FILENO) { |
| 55 // If stdout, redirect fd to /dev/null. | 53 // If stdout, redirect fd to /dev/null. |
| 56 int null_fd = TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY)); | 54 int null_fd = TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY)); |
| 57 ASSERT(null_fd >= 0); | 55 ASSERT(null_fd >= 0); |
| 58 VOID_TEMP_FAILURE_RETRY(dup2(null_fd, handle_->fd())); | 56 VOID_TEMP_FAILURE_RETRY(dup2(null_fd, handle_->fd())); |
| 59 VOID_TEMP_FAILURE_RETRY(close(null_fd)); | 57 VOID_TEMP_FAILURE_RETRY(close(null_fd)); |
| 60 } else { | 58 } else { |
| 61 int err = TEMP_FAILURE_RETRY(close(handle_->fd())); | 59 int err = TEMP_FAILURE_RETRY(close(handle_->fd())); |
| 62 if (err != 0) { | 60 if (err != 0) { |
| 63 const int kBufferSize = 1024; | 61 const int kBufferSize = 1024; |
| 64 char error_buf[kBufferSize]; | 62 char error_buf[kBufferSize]; |
| 65 Log::PrintErr("%s\n", Utils::StrError(errno, error_buf, kBufferSize)); | 63 Log::PrintErr("%s\n", Utils::StrError(errno, error_buf, kBufferSize)); |
| 66 } | 64 } |
| 67 } | 65 } |
| 68 handle_->set_fd(kClosedFd); | 66 handle_->set_fd(kClosedFd); |
| 69 } | 67 } |
| 70 | 68 |
| 71 | |
| 72 intptr_t File::GetFD() { | 69 intptr_t File::GetFD() { |
| 73 return handle_->fd(); | 70 return handle_->fd(); |
| 74 } | 71 } |
| 75 | 72 |
| 76 | |
| 77 bool File::IsClosed() { | 73 bool File::IsClosed() { |
| 78 return handle_->fd() == kClosedFd; | 74 return handle_->fd() == kClosedFd; |
| 79 } | 75 } |
| 80 | 76 |
| 81 | |
| 82 MappedMemory* File::Map(MapType type, int64_t position, int64_t length) { | 77 MappedMemory* File::Map(MapType type, int64_t position, int64_t length) { |
| 83 ASSERT(handle_->fd() >= 0); | 78 ASSERT(handle_->fd() >= 0); |
| 84 ASSERT(length > 0); | 79 ASSERT(length > 0); |
| 85 int prot = PROT_NONE; | 80 int prot = PROT_NONE; |
| 86 switch (type) { | 81 switch (type) { |
| 87 case kReadOnly: | 82 case kReadOnly: |
| 88 prot = PROT_READ; | 83 prot = PROT_READ; |
| 89 break; | 84 break; |
| 90 case kReadExecute: | 85 case kReadExecute: |
| 91 prot = PROT_READ | PROT_EXEC; | 86 prot = PROT_READ | PROT_EXEC; |
| 92 break; | 87 break; |
| 93 default: | 88 default: |
| 94 return NULL; | 89 return NULL; |
| 95 } | 90 } |
| 96 void* addr = mmap(NULL, length, prot, MAP_PRIVATE, handle_->fd(), position); | 91 void* addr = mmap(NULL, length, prot, MAP_PRIVATE, handle_->fd(), position); |
| 97 if (addr == MAP_FAILED) { | 92 if (addr == MAP_FAILED) { |
| 98 return NULL; | 93 return NULL; |
| 99 } | 94 } |
| 100 return new MappedMemory(addr, length); | 95 return new MappedMemory(addr, length); |
| 101 } | 96 } |
| 102 | 97 |
| 103 | |
| 104 void MappedMemory::Unmap() { | 98 void MappedMemory::Unmap() { |
| 105 int result = munmap(address_, size_); | 99 int result = munmap(address_, size_); |
| 106 ASSERT(result == 0); | 100 ASSERT(result == 0); |
| 107 address_ = 0; | 101 address_ = 0; |
| 108 size_ = 0; | 102 size_ = 0; |
| 109 } | 103 } |
| 110 | 104 |
| 111 | |
| 112 int64_t File::Read(void* buffer, int64_t num_bytes) { | 105 int64_t File::Read(void* buffer, int64_t num_bytes) { |
| 113 ASSERT(handle_->fd() >= 0); | 106 ASSERT(handle_->fd() >= 0); |
| 114 return TEMP_FAILURE_RETRY(read(handle_->fd(), buffer, num_bytes)); | 107 return TEMP_FAILURE_RETRY(read(handle_->fd(), buffer, num_bytes)); |
| 115 } | 108 } |
| 116 | 109 |
| 117 | |
| 118 int64_t File::Write(const void* buffer, int64_t num_bytes) { | 110 int64_t File::Write(const void* buffer, int64_t num_bytes) { |
| 119 ASSERT(handle_->fd() >= 0); | 111 ASSERT(handle_->fd() >= 0); |
| 120 return TEMP_FAILURE_RETRY(write(handle_->fd(), buffer, num_bytes)); | 112 return TEMP_FAILURE_RETRY(write(handle_->fd(), buffer, num_bytes)); |
| 121 } | 113 } |
| 122 | 114 |
| 123 | |
| 124 bool File::VPrint(const char* format, va_list args) { | 115 bool File::VPrint(const char* format, va_list args) { |
| 125 // Measure. | 116 // Measure. |
| 126 va_list measure_args; | 117 va_list measure_args; |
| 127 va_copy(measure_args, args); | 118 va_copy(measure_args, args); |
| 128 intptr_t len = vsnprintf(NULL, 0, format, measure_args); | 119 intptr_t len = vsnprintf(NULL, 0, format, measure_args); |
| 129 va_end(measure_args); | 120 va_end(measure_args); |
| 130 | 121 |
| 131 char* buffer = reinterpret_cast<char*>(malloc(len + 1)); | 122 char* buffer = reinterpret_cast<char*>(malloc(len + 1)); |
| 132 | 123 |
| 133 // Print. | 124 // Print. |
| 134 va_list print_args; | 125 va_list print_args; |
| 135 va_copy(print_args, args); | 126 va_copy(print_args, args); |
| 136 vsnprintf(buffer, len + 1, format, print_args); | 127 vsnprintf(buffer, len + 1, format, print_args); |
| 137 va_end(print_args); | 128 va_end(print_args); |
| 138 | 129 |
| 139 bool result = WriteFully(buffer, len); | 130 bool result = WriteFully(buffer, len); |
| 140 free(buffer); | 131 free(buffer); |
| 141 return result; | 132 return result; |
| 142 } | 133 } |
| 143 | 134 |
| 144 int64_t File::Position() { | 135 int64_t File::Position() { |
| 145 ASSERT(handle_->fd() >= 0); | 136 ASSERT(handle_->fd() >= 0); |
| 146 return NO_RETRY_EXPECTED(lseek64(handle_->fd(), 0, SEEK_CUR)); | 137 return NO_RETRY_EXPECTED(lseek64(handle_->fd(), 0, SEEK_CUR)); |
| 147 } | 138 } |
| 148 | 139 |
| 149 | |
| 150 bool File::SetPosition(int64_t position) { | 140 bool File::SetPosition(int64_t position) { |
| 151 ASSERT(handle_->fd() >= 0); | 141 ASSERT(handle_->fd() >= 0); |
| 152 return NO_RETRY_EXPECTED(lseek64(handle_->fd(), position, SEEK_SET)) >= 0; | 142 return NO_RETRY_EXPECTED(lseek64(handle_->fd(), position, SEEK_SET)) >= 0; |
| 153 } | 143 } |
| 154 | 144 |
| 155 | |
| 156 bool File::Truncate(int64_t length) { | 145 bool File::Truncate(int64_t length) { |
| 157 ASSERT(handle_->fd() >= 0); | 146 ASSERT(handle_->fd() >= 0); |
| 158 return TEMP_FAILURE_RETRY(ftruncate64(handle_->fd(), length) != -1); | 147 return TEMP_FAILURE_RETRY(ftruncate64(handle_->fd(), length) != -1); |
| 159 } | 148 } |
| 160 | 149 |
| 161 | |
| 162 bool File::Flush() { | 150 bool File::Flush() { |
| 163 ASSERT(handle_->fd() >= 0); | 151 ASSERT(handle_->fd() >= 0); |
| 164 return NO_RETRY_EXPECTED(fsync(handle_->fd())) != -1; | 152 return NO_RETRY_EXPECTED(fsync(handle_->fd())) != -1; |
| 165 } | 153 } |
| 166 | 154 |
| 167 | |
| 168 bool File::Lock(File::LockType lock, int64_t start, int64_t end) { | 155 bool File::Lock(File::LockType lock, int64_t start, int64_t end) { |
| 169 ASSERT(handle_->fd() >= 0); | 156 ASSERT(handle_->fd() >= 0); |
| 170 ASSERT((end == -1) || (end > start)); | 157 ASSERT((end == -1) || (end > start)); |
| 171 struct flock fl; | 158 struct flock fl; |
| 172 switch (lock) { | 159 switch (lock) { |
| 173 case File::kLockUnlock: | 160 case File::kLockUnlock: |
| 174 fl.l_type = F_UNLCK; | 161 fl.l_type = F_UNLCK; |
| 175 break; | 162 break; |
| 176 case File::kLockShared: | 163 case File::kLockShared: |
| 177 case File::kLockBlockingShared: | 164 case File::kLockBlockingShared: |
| (...skipping 10 matching lines...) Expand all Loading... |
| 188 fl.l_start = start; | 175 fl.l_start = start; |
| 189 fl.l_len = end == -1 ? 0 : end - start; | 176 fl.l_len = end == -1 ? 0 : end - start; |
| 190 int cmd = F_SETLK; | 177 int cmd = F_SETLK; |
| 191 if ((lock == File::kLockBlockingShared) || | 178 if ((lock == File::kLockBlockingShared) || |
| 192 (lock == File::kLockBlockingExclusive)) { | 179 (lock == File::kLockBlockingExclusive)) { |
| 193 cmd = F_SETLKW; | 180 cmd = F_SETLKW; |
| 194 } | 181 } |
| 195 return TEMP_FAILURE_RETRY(fcntl(handle_->fd(), cmd, &fl)) != -1; | 182 return TEMP_FAILURE_RETRY(fcntl(handle_->fd(), cmd, &fl)) != -1; |
| 196 } | 183 } |
| 197 | 184 |
| 198 | |
| 199 int64_t File::Length() { | 185 int64_t File::Length() { |
| 200 ASSERT(handle_->fd() >= 0); | 186 ASSERT(handle_->fd() >= 0); |
| 201 struct stat64 st; | 187 struct stat64 st; |
| 202 if (TEMP_FAILURE_RETRY(fstat64(handle_->fd(), &st)) == 0) { | 188 if (TEMP_FAILURE_RETRY(fstat64(handle_->fd(), &st)) == 0) { |
| 203 return st.st_size; | 189 return st.st_size; |
| 204 } | 190 } |
| 205 return -1; | 191 return -1; |
| 206 } | 192 } |
| 207 | 193 |
| 208 | |
| 209 File* File::FileOpenW(const wchar_t* system_name, FileOpenMode mode) { | 194 File* File::FileOpenW(const wchar_t* system_name, FileOpenMode mode) { |
| 210 UNREACHABLE(); | 195 UNREACHABLE(); |
| 211 return NULL; | 196 return NULL; |
| 212 } | 197 } |
| 213 | 198 |
| 214 | |
| 215 File* File::Open(const char* name, FileOpenMode mode) { | 199 File* File::Open(const char* name, FileOpenMode mode) { |
| 216 // Report errors for non-regular files. | 200 // Report errors for non-regular files. |
| 217 struct stat64 st; | 201 struct stat64 st; |
| 218 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { | 202 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { |
| 219 // Only accept regular files, character devices, and pipes. | 203 // Only accept regular files, character devices, and pipes. |
| 220 if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) { | 204 if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) { |
| 221 errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT; | 205 errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT; |
| 222 return NULL; | 206 return NULL; |
| 223 } | 207 } |
| 224 } | 208 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 242 if ((((mode & kWrite) != 0) && ((mode & kTruncate) == 0)) || | 226 if ((((mode & kWrite) != 0) && ((mode & kTruncate) == 0)) || |
| 243 (((mode & kWriteOnly) != 0) && ((mode & kTruncate) == 0))) { | 227 (((mode & kWriteOnly) != 0) && ((mode & kTruncate) == 0))) { |
| 244 int64_t position = NO_RETRY_EXPECTED(lseek64(fd, 0, SEEK_END)); | 228 int64_t position = NO_RETRY_EXPECTED(lseek64(fd, 0, SEEK_END)); |
| 245 if (position < 0) { | 229 if (position < 0) { |
| 246 return NULL; | 230 return NULL; |
| 247 } | 231 } |
| 248 } | 232 } |
| 249 return new File(new FileHandle(fd)); | 233 return new File(new FileHandle(fd)); |
| 250 } | 234 } |
| 251 | 235 |
| 252 | |
| 253 File* File::OpenStdio(int fd) { | 236 File* File::OpenStdio(int fd) { |
| 254 return ((fd < 0) || (2 < fd)) ? NULL : new File(new FileHandle(fd)); | 237 return ((fd < 0) || (2 < fd)) ? NULL : new File(new FileHandle(fd)); |
| 255 } | 238 } |
| 256 | 239 |
| 257 | |
| 258 bool File::Exists(const char* name) { | 240 bool File::Exists(const char* name) { |
| 259 struct stat64 st; | 241 struct stat64 st; |
| 260 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { | 242 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { |
| 261 // Everything but a directory and a link is a file to Dart. | 243 // Everything but a directory and a link is a file to Dart. |
| 262 return !S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode); | 244 return !S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode); |
| 263 } else { | 245 } else { |
| 264 return false; | 246 return false; |
| 265 } | 247 } |
| 266 } | 248 } |
| 267 | 249 |
| 268 | |
| 269 bool File::Create(const char* name) { | 250 bool File::Create(const char* name) { |
| 270 int fd = | 251 int fd = |
| 271 TEMP_FAILURE_RETRY(open64(name, O_RDONLY | O_CREAT | O_CLOEXEC, 0666)); | 252 TEMP_FAILURE_RETRY(open64(name, O_RDONLY | O_CREAT | O_CLOEXEC, 0666)); |
| 272 if (fd < 0) { | 253 if (fd < 0) { |
| 273 return false; | 254 return false; |
| 274 } | 255 } |
| 275 // File.create returns a File, so we shouldn't be giving the illusion that the | 256 // File.create returns a File, so we shouldn't be giving the illusion that the |
| 276 // call has created a file or that a file already exists if there is already | 257 // call has created a file or that a file already exists if there is already |
| 277 // an entity at the same path that is a directory or a link. | 258 // an entity at the same path that is a directory or a link. |
| 278 bool is_file = true; | 259 bool is_file = true; |
| 279 struct stat64 st; | 260 struct stat64 st; |
| 280 if (TEMP_FAILURE_RETRY(fstat64(fd, &st)) == 0) { | 261 if (TEMP_FAILURE_RETRY(fstat64(fd, &st)) == 0) { |
| 281 if (S_ISDIR(st.st_mode)) { | 262 if (S_ISDIR(st.st_mode)) { |
| 282 errno = EISDIR; | 263 errno = EISDIR; |
| 283 is_file = false; | 264 is_file = false; |
| 284 } else if (S_ISLNK(st.st_mode)) { | 265 } else if (S_ISLNK(st.st_mode)) { |
| 285 errno = ENOENT; | 266 errno = ENOENT; |
| 286 is_file = false; | 267 is_file = false; |
| 287 } | 268 } |
| 288 } | 269 } |
| 289 FDUtils::SaveErrorAndClose(fd); | 270 FDUtils::SaveErrorAndClose(fd); |
| 290 return is_file; | 271 return is_file; |
| 291 } | 272 } |
| 292 | 273 |
| 293 | |
| 294 bool File::CreateLink(const char* name, const char* target) { | 274 bool File::CreateLink(const char* name, const char* target) { |
| 295 return NO_RETRY_EXPECTED(symlink(target, name)) == 0; | 275 return NO_RETRY_EXPECTED(symlink(target, name)) == 0; |
| 296 } | 276 } |
| 297 | 277 |
| 298 | |
| 299 File::Type File::GetType(const char* pathname, bool follow_links) { | 278 File::Type File::GetType(const char* pathname, bool follow_links) { |
| 300 struct stat64 entry_info; | 279 struct stat64 entry_info; |
| 301 int stat_success; | 280 int stat_success; |
| 302 if (follow_links) { | 281 if (follow_links) { |
| 303 stat_success = TEMP_FAILURE_RETRY(stat64(pathname, &entry_info)); | 282 stat_success = TEMP_FAILURE_RETRY(stat64(pathname, &entry_info)); |
| 304 } else { | 283 } else { |
| 305 stat_success = TEMP_FAILURE_RETRY(lstat64(pathname, &entry_info)); | 284 stat_success = TEMP_FAILURE_RETRY(lstat64(pathname, &entry_info)); |
| 306 } | 285 } |
| 307 if (stat_success == -1) { | 286 if (stat_success == -1) { |
| 308 return File::kDoesNotExist; | 287 return File::kDoesNotExist; |
| 309 } | 288 } |
| 310 if (S_ISDIR(entry_info.st_mode)) { | 289 if (S_ISDIR(entry_info.st_mode)) { |
| 311 return File::kIsDirectory; | 290 return File::kIsDirectory; |
| 312 } | 291 } |
| 313 if (S_ISREG(entry_info.st_mode)) { | 292 if (S_ISREG(entry_info.st_mode)) { |
| 314 return File::kIsFile; | 293 return File::kIsFile; |
| 315 } | 294 } |
| 316 if (S_ISLNK(entry_info.st_mode)) { | 295 if (S_ISLNK(entry_info.st_mode)) { |
| 317 return File::kIsLink; | 296 return File::kIsLink; |
| 318 } | 297 } |
| 319 return File::kDoesNotExist; | 298 return File::kDoesNotExist; |
| 320 } | 299 } |
| 321 | 300 |
| 322 | |
| 323 static bool CheckTypeAndSetErrno(const char* name, | 301 static bool CheckTypeAndSetErrno(const char* name, |
| 324 File::Type expected, | 302 File::Type expected, |
| 325 bool follow_links) { | 303 bool follow_links) { |
| 326 File::Type actual = File::GetType(name, follow_links); | 304 File::Type actual = File::GetType(name, follow_links); |
| 327 if (actual == expected) { | 305 if (actual == expected) { |
| 328 return true; | 306 return true; |
| 329 } | 307 } |
| 330 switch (actual) { | 308 switch (actual) { |
| 331 case File::kIsDirectory: | 309 case File::kIsDirectory: |
| 332 errno = EISDIR; | 310 errno = EISDIR; |
| 333 break; | 311 break; |
| 334 case File::kDoesNotExist: | 312 case File::kDoesNotExist: |
| 335 errno = ENOENT; | 313 errno = ENOENT; |
| 336 break; | 314 break; |
| 337 default: | 315 default: |
| 338 errno = EINVAL; | 316 errno = EINVAL; |
| 339 break; | 317 break; |
| 340 } | 318 } |
| 341 return false; | 319 return false; |
| 342 } | 320 } |
| 343 | 321 |
| 344 | |
| 345 bool File::Delete(const char* name) { | 322 bool File::Delete(const char* name) { |
| 346 return CheckTypeAndSetErrno(name, kIsFile, true) && | 323 return CheckTypeAndSetErrno(name, kIsFile, true) && |
| 347 (NO_RETRY_EXPECTED(unlink(name)) == 0); | 324 (NO_RETRY_EXPECTED(unlink(name)) == 0); |
| 348 } | 325 } |
| 349 | 326 |
| 350 | |
| 351 bool File::DeleteLink(const char* name) { | 327 bool File::DeleteLink(const char* name) { |
| 352 return CheckTypeAndSetErrno(name, kIsLink, false) && | 328 return CheckTypeAndSetErrno(name, kIsLink, false) && |
| 353 (NO_RETRY_EXPECTED(unlink(name)) == 0); | 329 (NO_RETRY_EXPECTED(unlink(name)) == 0); |
| 354 } | 330 } |
| 355 | 331 |
| 356 | |
| 357 bool File::Rename(const char* old_path, const char* new_path) { | 332 bool File::Rename(const char* old_path, const char* new_path) { |
| 358 return CheckTypeAndSetErrno(old_path, kIsFile, true) && | 333 return CheckTypeAndSetErrno(old_path, kIsFile, true) && |
| 359 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); | 334 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); |
| 360 } | 335 } |
| 361 | 336 |
| 362 | |
| 363 bool File::RenameLink(const char* old_path, const char* new_path) { | 337 bool File::RenameLink(const char* old_path, const char* new_path) { |
| 364 return CheckTypeAndSetErrno(old_path, kIsLink, false) && | 338 return CheckTypeAndSetErrno(old_path, kIsLink, false) && |
| 365 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); | 339 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); |
| 366 } | 340 } |
| 367 | 341 |
| 368 | |
| 369 bool File::Copy(const char* old_path, const char* new_path) { | 342 bool File::Copy(const char* old_path, const char* new_path) { |
| 370 if (!CheckTypeAndSetErrno(old_path, kIsFile, true)) { | 343 if (!CheckTypeAndSetErrno(old_path, kIsFile, true)) { |
| 371 return false; | 344 return false; |
| 372 } | 345 } |
| 373 struct stat64 st; | 346 struct stat64 st; |
| 374 if (TEMP_FAILURE_RETRY(stat64(old_path, &st)) != 0) { | 347 if (TEMP_FAILURE_RETRY(stat64(old_path, &st)) != 0) { |
| 375 return false; | 348 return false; |
| 376 } | 349 } |
| 377 int old_fd = TEMP_FAILURE_RETRY(open64(old_path, O_RDONLY | O_CLOEXEC)); | 350 int old_fd = TEMP_FAILURE_RETRY(open64(old_path, O_RDONLY | O_CLOEXEC)); |
| 378 if (old_fd < 0) { | 351 if (old_fd < 0) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 409 VOID_TEMP_FAILURE_RETRY(close(old_fd)); | 382 VOID_TEMP_FAILURE_RETRY(close(old_fd)); |
| 410 VOID_TEMP_FAILURE_RETRY(close(new_fd)); | 383 VOID_TEMP_FAILURE_RETRY(close(new_fd)); |
| 411 if (result < 0) { | 384 if (result < 0) { |
| 412 VOID_NO_RETRY_EXPECTED(unlink(new_path)); | 385 VOID_NO_RETRY_EXPECTED(unlink(new_path)); |
| 413 errno = e; | 386 errno = e; |
| 414 return false; | 387 return false; |
| 415 } | 388 } |
| 416 return true; | 389 return true; |
| 417 } | 390 } |
| 418 | 391 |
| 419 | |
| 420 static bool StatHelper(const char* name, struct stat64* st) { | 392 static bool StatHelper(const char* name, struct stat64* st) { |
| 421 if (TEMP_FAILURE_RETRY(stat64(name, st)) != 0) { | 393 if (TEMP_FAILURE_RETRY(stat64(name, st)) != 0) { |
| 422 return false; | 394 return false; |
| 423 } | 395 } |
| 424 // Signal an error if it's a directory. | 396 // Signal an error if it's a directory. |
| 425 if (S_ISDIR(st->st_mode)) { | 397 if (S_ISDIR(st->st_mode)) { |
| 426 errno = EISDIR; | 398 errno = EISDIR; |
| 427 return false; | 399 return false; |
| 428 } | 400 } |
| 429 // Otherwise assume the caller knows what it's doing. | 401 // Otherwise assume the caller knows what it's doing. |
| 430 return true; | 402 return true; |
| 431 } | 403 } |
| 432 | 404 |
| 433 | |
| 434 int64_t File::LengthFromPath(const char* name) { | 405 int64_t File::LengthFromPath(const char* name) { |
| 435 struct stat64 st; | 406 struct stat64 st; |
| 436 if (!StatHelper(name, &st)) { | 407 if (!StatHelper(name, &st)) { |
| 437 return -1; | 408 return -1; |
| 438 } | 409 } |
| 439 return st.st_size; | 410 return st.st_size; |
| 440 } | 411 } |
| 441 | 412 |
| 442 | |
| 443 static int64_t TimespecToMilliseconds(const struct timespec& t) { | 413 static int64_t TimespecToMilliseconds(const struct timespec& t) { |
| 444 return static_cast<int64_t>(t.tv_sec) * 1000L + | 414 return static_cast<int64_t>(t.tv_sec) * 1000L + |
| 445 static_cast<int64_t>(t.tv_nsec) / 1000000L; | 415 static_cast<int64_t>(t.tv_nsec) / 1000000L; |
| 446 } | 416 } |
| 447 | 417 |
| 448 | |
| 449 void File::Stat(const char* name, int64_t* data) { | 418 void File::Stat(const char* name, int64_t* data) { |
| 450 struct stat64 st; | 419 struct stat64 st; |
| 451 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { | 420 if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) { |
| 452 if (S_ISREG(st.st_mode)) { | 421 if (S_ISREG(st.st_mode)) { |
| 453 data[kType] = kIsFile; | 422 data[kType] = kIsFile; |
| 454 } else if (S_ISDIR(st.st_mode)) { | 423 } else if (S_ISDIR(st.st_mode)) { |
| 455 data[kType] = kIsDirectory; | 424 data[kType] = kIsDirectory; |
| 456 } else if (S_ISLNK(st.st_mode)) { | 425 } else if (S_ISLNK(st.st_mode)) { |
| 457 data[kType] = kIsLink; | 426 data[kType] = kIsLink; |
| 458 } else { | 427 } else { |
| 459 data[kType] = kDoesNotExist; | 428 data[kType] = kDoesNotExist; |
| 460 } | 429 } |
| 461 data[kCreatedTime] = TimespecToMilliseconds(st.st_ctim); | 430 data[kCreatedTime] = TimespecToMilliseconds(st.st_ctim); |
| 462 data[kModifiedTime] = TimespecToMilliseconds(st.st_mtim); | 431 data[kModifiedTime] = TimespecToMilliseconds(st.st_mtim); |
| 463 data[kAccessedTime] = TimespecToMilliseconds(st.st_atim); | 432 data[kAccessedTime] = TimespecToMilliseconds(st.st_atim); |
| 464 data[kMode] = st.st_mode; | 433 data[kMode] = st.st_mode; |
| 465 data[kSize] = st.st_size; | 434 data[kSize] = st.st_size; |
| 466 } else { | 435 } else { |
| 467 data[kType] = kDoesNotExist; | 436 data[kType] = kDoesNotExist; |
| 468 } | 437 } |
| 469 } | 438 } |
| 470 | 439 |
| 471 | |
| 472 time_t File::LastModified(const char* name) { | 440 time_t File::LastModified(const char* name) { |
| 473 struct stat64 st; | 441 struct stat64 st; |
| 474 if (!StatHelper(name, &st)) { | 442 if (!StatHelper(name, &st)) { |
| 475 return -1; | 443 return -1; |
| 476 } | 444 } |
| 477 return st.st_mtime; | 445 return st.st_mtime; |
| 478 } | 446 } |
| 479 | 447 |
| 480 | |
| 481 time_t File::LastAccessed(const char* name) { | 448 time_t File::LastAccessed(const char* name) { |
| 482 struct stat64 st; | 449 struct stat64 st; |
| 483 if (!StatHelper(name, &st)) { | 450 if (!StatHelper(name, &st)) { |
| 484 return -1; | 451 return -1; |
| 485 } | 452 } |
| 486 return st.st_atime; | 453 return st.st_atime; |
| 487 } | 454 } |
| 488 | 455 |
| 489 | |
| 490 bool File::SetLastAccessed(const char* name, int64_t millis) { | 456 bool File::SetLastAccessed(const char* name, int64_t millis) { |
| 491 // First get the current times. | 457 // First get the current times. |
| 492 struct stat64 st; | 458 struct stat64 st; |
| 493 if (!StatHelper(name, &st)) { | 459 if (!StatHelper(name, &st)) { |
| 494 return false; | 460 return false; |
| 495 } | 461 } |
| 496 | 462 |
| 497 // Set the new time: | 463 // Set the new time: |
| 498 struct utimbuf times; | 464 struct utimbuf times; |
| 499 times.actime = millis / kMillisecondsPerSecond; | 465 times.actime = millis / kMillisecondsPerSecond; |
| 500 times.modtime = st.st_mtime; | 466 times.modtime = st.st_mtime; |
| 501 return utime(name, ×) == 0; | 467 return utime(name, ×) == 0; |
| 502 } | 468 } |
| 503 | 469 |
| 504 | |
| 505 bool File::SetLastModified(const char* name, int64_t millis) { | 470 bool File::SetLastModified(const char* name, int64_t millis) { |
| 506 // First get the current times. | 471 // First get the current times. |
| 507 struct stat64 st; | 472 struct stat64 st; |
| 508 if (!StatHelper(name, &st)) { | 473 if (!StatHelper(name, &st)) { |
| 509 return false; | 474 return false; |
| 510 } | 475 } |
| 511 | 476 |
| 512 // Set the new time: | 477 // Set the new time: |
| 513 struct utimbuf times; | 478 struct utimbuf times; |
| 514 times.actime = st.st_atime; | 479 times.actime = st.st_atime; |
| 515 times.modtime = millis / kMillisecondsPerSecond; | 480 times.modtime = millis / kMillisecondsPerSecond; |
| 516 return utime(name, ×) == 0; | 481 return utime(name, ×) == 0; |
| 517 } | 482 } |
| 518 | 483 |
| 519 | |
| 520 const char* File::LinkTarget(const char* pathname) { | 484 const char* File::LinkTarget(const char* pathname) { |
| 521 struct stat64 link_stats; | 485 struct stat64 link_stats; |
| 522 if (TEMP_FAILURE_RETRY(lstat64(pathname, &link_stats)) != 0) { | 486 if (TEMP_FAILURE_RETRY(lstat64(pathname, &link_stats)) != 0) { |
| 523 return NULL; | 487 return NULL; |
| 524 } | 488 } |
| 525 if (!S_ISLNK(link_stats.st_mode)) { | 489 if (!S_ISLNK(link_stats.st_mode)) { |
| 526 errno = ENOENT; | 490 errno = ENOENT; |
| 527 return NULL; | 491 return NULL; |
| 528 } | 492 } |
| 529 // Don't rely on the link_stats.st_size for the size of the link | 493 // Don't rely on the link_stats.st_size for the size of the link |
| 530 // target. For some filesystems, e.g. procfs, this value is always | 494 // target. For some filesystems, e.g. procfs, this value is always |
| 531 // 0. Also the link might have changed before the readlink call. | 495 // 0. Also the link might have changed before the readlink call. |
| 532 const int kBufferSize = PATH_MAX + 1; | 496 const int kBufferSize = PATH_MAX + 1; |
| 533 char target[kBufferSize]; | 497 char target[kBufferSize]; |
| 534 size_t target_size = | 498 size_t target_size = |
| 535 TEMP_FAILURE_RETRY(readlink(pathname, target, kBufferSize)); | 499 TEMP_FAILURE_RETRY(readlink(pathname, target, kBufferSize)); |
| 536 if (target_size <= 0) { | 500 if (target_size <= 0) { |
| 537 return NULL; | 501 return NULL; |
| 538 } | 502 } |
| 539 char* target_name = DartUtils::ScopedCString(target_size + 1); | 503 char* target_name = DartUtils::ScopedCString(target_size + 1); |
| 540 ASSERT(target_name != NULL); | 504 ASSERT(target_name != NULL); |
| 541 memmove(target_name, target, target_size); | 505 memmove(target_name, target, target_size); |
| 542 target_name[target_size] = '\0'; | 506 target_name[target_size] = '\0'; |
| 543 return target_name; | 507 return target_name; |
| 544 } | 508 } |
| 545 | 509 |
| 546 | |
| 547 bool File::IsAbsolutePath(const char* pathname) { | 510 bool File::IsAbsolutePath(const char* pathname) { |
| 548 return (pathname != NULL && pathname[0] == '/'); | 511 return (pathname != NULL && pathname[0] == '/'); |
| 549 } | 512 } |
| 550 | 513 |
| 551 | |
| 552 const char* File::GetCanonicalPath(const char* pathname) { | 514 const char* File::GetCanonicalPath(const char* pathname) { |
| 553 char* abs_path = NULL; | 515 char* abs_path = NULL; |
| 554 if (pathname != NULL) { | 516 if (pathname != NULL) { |
| 555 char* resolved_path = DartUtils::ScopedCString(PATH_MAX + 1); | 517 char* resolved_path = DartUtils::ScopedCString(PATH_MAX + 1); |
| 556 ASSERT(resolved_path != NULL); | 518 ASSERT(resolved_path != NULL); |
| 557 do { | 519 do { |
| 558 abs_path = realpath(pathname, resolved_path); | 520 abs_path = realpath(pathname, resolved_path); |
| 559 } while (abs_path == NULL && errno == EINTR); | 521 } while (abs_path == NULL && errno == EINTR); |
| 560 ASSERT(abs_path == NULL || IsAbsolutePath(abs_path)); | 522 ASSERT(abs_path == NULL || IsAbsolutePath(abs_path)); |
| 561 ASSERT(abs_path == NULL || (abs_path == resolved_path)); | 523 ASSERT(abs_path == NULL || (abs_path == resolved_path)); |
| 562 } | 524 } |
| 563 return abs_path; | 525 return abs_path; |
| 564 } | 526 } |
| 565 | 527 |
| 566 | |
| 567 const char* File::PathSeparator() { | 528 const char* File::PathSeparator() { |
| 568 return "/"; | 529 return "/"; |
| 569 } | 530 } |
| 570 | 531 |
| 571 | |
| 572 const char* File::StringEscapedPathSeparator() { | 532 const char* File::StringEscapedPathSeparator() { |
| 573 return "/"; | 533 return "/"; |
| 574 } | 534 } |
| 575 | 535 |
| 576 | |
| 577 File::StdioHandleType File::GetStdioHandleType(int fd) { | 536 File::StdioHandleType File::GetStdioHandleType(int fd) { |
| 578 ASSERT((0 <= fd) && (fd <= 2)); | 537 ASSERT((0 <= fd) && (fd <= 2)); |
| 579 struct stat64 buf; | 538 struct stat64 buf; |
| 580 int result = TEMP_FAILURE_RETRY(fstat64(fd, &buf)); | 539 int result = TEMP_FAILURE_RETRY(fstat64(fd, &buf)); |
| 581 if (result == -1) { | 540 if (result == -1) { |
| 582 return kOther; | 541 return kOther; |
| 583 } | 542 } |
| 584 if (S_ISCHR(buf.st_mode)) { | 543 if (S_ISCHR(buf.st_mode)) { |
| 585 return kTerminal; | 544 return kTerminal; |
| 586 } | 545 } |
| 587 if (S_ISFIFO(buf.st_mode)) { | 546 if (S_ISFIFO(buf.st_mode)) { |
| 588 return kPipe; | 547 return kPipe; |
| 589 } | 548 } |
| 590 if (S_ISSOCK(buf.st_mode)) { | 549 if (S_ISSOCK(buf.st_mode)) { |
| 591 return kSocket; | 550 return kSocket; |
| 592 } | 551 } |
| 593 if (S_ISREG(buf.st_mode)) { | 552 if (S_ISREG(buf.st_mode)) { |
| 594 return kFile; | 553 return kFile; |
| 595 } | 554 } |
| 596 return kOther; | 555 return kOther; |
| 597 } | 556 } |
| 598 | 557 |
| 599 | |
| 600 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { | 558 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { |
| 601 struct stat64 file_1_info; | 559 struct stat64 file_1_info; |
| 602 struct stat64 file_2_info; | 560 struct stat64 file_2_info; |
| 603 if ((TEMP_FAILURE_RETRY(lstat64(file_1, &file_1_info)) == -1) || | 561 if ((TEMP_FAILURE_RETRY(lstat64(file_1, &file_1_info)) == -1) || |
| 604 (TEMP_FAILURE_RETRY(lstat64(file_2, &file_2_info)) == -1)) { | 562 (TEMP_FAILURE_RETRY(lstat64(file_2, &file_2_info)) == -1)) { |
| 605 return File::kError; | 563 return File::kError; |
| 606 } | 564 } |
| 607 return ((file_1_info.st_ino == file_2_info.st_ino) && | 565 return ((file_1_info.st_ino == file_2_info.st_ino) && |
| 608 (file_1_info.st_dev == file_2_info.st_dev)) | 566 (file_1_info.st_dev == file_2_info.st_dev)) |
| 609 ? File::kIdentical | 567 ? File::kIdentical |
| 610 : File::kDifferent; | 568 : File::kDifferent; |
| 611 } | 569 } |
| 612 | 570 |
| 613 } // namespace bin | 571 } // namespace bin |
| 614 } // namespace dart | 572 } // namespace dart |
| 615 | 573 |
| 616 #endif // defined(HOST_OS_LINUX) | 574 #endif // defined(HOST_OS_LINUX) |
| OLD | NEW |