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 |