1 | // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
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. |
4 | |
5 | #ifndef RUNTIME_BIN_FILE_H_ |
6 | #define RUNTIME_BIN_FILE_H_ |
7 | |
8 | #include <stdio.h> |
9 | #include <stdlib.h> |
10 | #include <string.h> |
11 | #include <sys/types.h> |
12 | |
13 | #include "bin/builtin.h" |
14 | #include "bin/dartutils.h" |
15 | #include "bin/namespace.h" |
16 | #include "bin/reference_counting.h" |
17 | #include "platform/syslog.h" |
18 | #include "platform/utils.h" |
19 | |
20 | namespace dart { |
21 | namespace bin { |
22 | |
23 | // Forward declaration. |
24 | class FileHandle; |
25 | |
26 | class MappedMemory { |
27 | public: |
28 | MappedMemory(void* address, intptr_t size, bool should_unmap = true) |
29 | : should_unmap_(should_unmap), address_(address), size_(size) {} |
30 | ~MappedMemory() { |
31 | if (should_unmap_) Unmap(); |
32 | } |
33 | |
34 | void* address() const { return address_; } |
35 | intptr_t size() const { return size_; } |
36 | uword start() const { return reinterpret_cast<uword>(address()); } |
37 | |
38 | private: |
39 | void Unmap(); |
40 | |
41 | // False for mappings which reside inside another, and will be removed when |
42 | // the outer mapping is removed. |
43 | bool should_unmap_; |
44 | |
45 | void* address_; |
46 | intptr_t size_; |
47 | |
48 | DISALLOW_COPY_AND_ASSIGN(MappedMemory); |
49 | }; |
50 | |
51 | class File : public ReferenceCounted<File> { |
52 | public: |
53 | enum FileOpenMode { |
54 | kRead = 0, |
55 | kWrite = 1, |
56 | kTruncate = 1 << 2, |
57 | kWriteOnly = 1 << 3, |
58 | kWriteTruncate = kWrite | kTruncate, |
59 | kWriteOnlyTruncate = kWriteOnly | kTruncate |
60 | }; |
61 | |
62 | // These values have to be kept in sync with the mode values of |
63 | // FileMode.READ, FileMode.WRITE, FileMode.APPEND, |
64 | // FileMode.WRITE_ONLY and FileMode.WRITE_ONLY_APPEND in file.dart. |
65 | enum DartFileOpenMode { |
66 | kDartRead = 0, |
67 | kDartWrite = 1, |
68 | kDartAppend = 2, |
69 | kDartWriteOnly = 3, |
70 | kDartWriteOnlyAppend = 4 |
71 | }; |
72 | |
73 | enum Type { kIsFile = 0, kIsDirectory = 1, kIsLink = 2, kDoesNotExist = 3 }; |
74 | |
75 | enum Identical { kIdentical = 0, kDifferent = 1, kError = 2 }; |
76 | |
77 | enum StdioHandleType { |
78 | // These match the constants in stdio.dart. |
79 | kTerminal = 0, |
80 | kPipe = 1, |
81 | kFile = 2, |
82 | kSocket = 3, |
83 | kOther = 4, |
84 | kTypeError = 5 |
85 | }; |
86 | |
87 | enum FileStat { |
88 | // These match the constants in FileStat in file_system_entity.dart. |
89 | kType = 0, |
90 | kCreatedTime = 1, |
91 | kModifiedTime = 2, |
92 | kAccessedTime = 3, |
93 | kMode = 4, |
94 | kSize = 5, |
95 | kStatSize = 6 |
96 | }; |
97 | |
98 | enum LockType { |
99 | // These match the constants in FileStat in file_impl.dart. |
100 | kLockMin = 0, |
101 | kLockUnlock = 0, |
102 | kLockShared = 1, |
103 | kLockExclusive = 2, |
104 | kLockBlockingShared = 3, |
105 | kLockBlockingExclusive = 4, |
106 | kLockMax = 4 |
107 | }; |
108 | |
109 | intptr_t GetFD(); |
110 | |
111 | enum MapType { |
112 | kReadOnly = 0, |
113 | kReadExecute = 1, |
114 | kReadWrite = 2, |
115 | }; |
116 | |
117 | /// Maps or copies the file into memory. |
118 | /// |
119 | /// 'position' and 'length' should be page-aligned. |
120 | /// |
121 | /// If 'start' is zero, allocates virtual memory for the mapping. When the |
122 | /// returned 'MappedMemory' is destroyed, the mapping is removed. |
123 | /// |
124 | /// If 'start' is non-zero, it must point within a suitably sized existing |
125 | /// mapping. The returned 'MappedMemory' will not remove the mapping when it |
126 | /// is destroyed; rather, the mapping will be removed when the enclosing |
127 | /// mapping is removed. This mode is not supported on Fuchsia. |
128 | /// |
129 | /// If 'type' is 'kReadWrite', writes to the mapping are *not* copied back to |
130 | /// the file. |
131 | /// |
132 | /// 'position' + 'length' may be larger than the file size. In this case, the |
133 | /// extra memory is zero-filled. |
134 | MappedMemory* Map(MapType type, |
135 | int64_t position, |
136 | int64_t length, |
137 | void* start = nullptr); |
138 | |
139 | // Read/Write attempt to transfer num_bytes to/from buffer. It returns |
140 | // the number of bytes read/written. |
141 | int64_t Read(void* buffer, int64_t num_bytes); |
142 | int64_t Write(const void* buffer, int64_t num_bytes); |
143 | |
144 | // ReadFully and WriteFully do attempt to transfer num_bytes to/from |
145 | // the buffer. In the event of short accesses they will loop internally until |
146 | // the whole buffer has been transferred or an error occurs. If an error |
147 | // occurred the result will be set to false. |
148 | bool ReadFully(void* buffer, int64_t num_bytes); |
149 | bool WriteFully(const void* buffer, int64_t num_bytes); |
150 | bool WriteByte(uint8_t byte) { return WriteFully(&byte, 1); } |
151 | |
152 | bool Print(const char* format, ...) PRINTF_ATTRIBUTE(2, 3) { |
153 | va_list args; |
154 | va_start(args, format); |
155 | bool result = VPrint(format, args); |
156 | va_end(args); |
157 | return result; |
158 | } |
159 | bool VPrint(const char* format, va_list args); |
160 | |
161 | // Get the length of the file. Returns a negative value if the length cannot |
162 | // be determined (e.g. not seekable device). |
163 | int64_t Length(); |
164 | |
165 | // Get the current position in the file. |
166 | // Returns a negative value if position cannot be determined. |
167 | int64_t Position(); |
168 | |
169 | // Set the byte position in the file. |
170 | bool SetPosition(int64_t position); |
171 | |
172 | // Truncate (or extend) the file to the given length in bytes. |
173 | bool Truncate(int64_t length); |
174 | |
175 | // Flush contents of file. |
176 | bool Flush(); |
177 | |
178 | // Lock range of a file. |
179 | bool Lock(LockType lock, int64_t start, int64_t end); |
180 | |
181 | // Returns whether the file has been closed. |
182 | bool IsClosed(); |
183 | |
184 | // Calls the platform-specific functions to close the file. |
185 | void Close(); |
186 | |
187 | // Returns the finalizable handle for the File's Dart wrapper. |
188 | Dart_FinalizableHandle FinalizableHandle() const { |
189 | return finalizable_handle_; |
190 | } |
191 | |
192 | // Set the finalizable handle for the File's Dart wrapper. |
193 | void SetFinalizableHandle(Dart_FinalizableHandle handle) { |
194 | ASSERT(finalizable_handle_ == NULL); |
195 | finalizable_handle_ = handle; |
196 | } |
197 | |
198 | // Deletes the finalizable handle for the File's Dart wrapper. Call |
199 | // when the file is explicitly closed and the finalizer is no longer |
200 | // needed. |
201 | void DeleteFinalizableHandle(Dart_Isolate isolate, Dart_Handle strong_ref) { |
202 | Dart_DeleteFinalizableHandle(finalizable_handle_, strong_ref); |
203 | finalizable_handle_ = NULL; |
204 | } |
205 | |
206 | // Open the file with the given path. The file is always opened for |
207 | // reading. If mode contains kWrite the file is opened for both |
208 | // reading and writing. If mode contains kWrite and the file does |
209 | // not exist the file is created. The file is truncated to length 0 if |
210 | // mode contains kTruncate. |
211 | static File* Open(Namespace* namespc, const char* path, FileOpenMode mode); |
212 | |
213 | // Same as [File::Open], but attempts to convert uri to path before opening |
214 | // the file. If conversion fails, uri is treated as a path. |
215 | static File* OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode); |
216 | |
217 | // Attempts to convert the given [uri] to a file path. |
218 | static Utils::CStringUniquePtr UriToPath(const char* uri); |
219 | |
220 | // Create a file object for the specified stdio file descriptor |
221 | // (stdin, stout or stderr). |
222 | static File* OpenStdio(int fd); |
223 | |
224 | #if defined(HOST_OS_FUCHSIA) || defined(HOST_OS_LINUX) |
225 | static File* OpenFD(int fd); |
226 | #endif |
227 | |
228 | static bool Exists(Namespace* namespc, const char* path); |
229 | static bool ExistsUri(Namespace* namespc, const char* uri); |
230 | static bool Create(Namespace* namespc, const char* path); |
231 | static bool CreateLink(Namespace* namespc, |
232 | const char* path, |
233 | const char* target); |
234 | static bool Delete(Namespace* namespc, const char* path); |
235 | static bool DeleteLink(Namespace* namespc, const char* path); |
236 | static bool Rename(Namespace* namespc, |
237 | const char* old_path, |
238 | const char* new_path); |
239 | static bool RenameLink(Namespace* namespc, |
240 | const char* old_path, |
241 | const char* new_path); |
242 | static bool Copy(Namespace* namespc, |
243 | const char* old_path, |
244 | const char* new_path); |
245 | static int64_t LengthFromPath(Namespace* namespc, const char* path); |
246 | static void Stat(Namespace* namespc, const char* path, int64_t* data); |
247 | static time_t LastModified(Namespace* namespc, const char* path); |
248 | static bool SetLastModified(Namespace* namespc, |
249 | const char* path, |
250 | int64_t millis); |
251 | static time_t LastAccessed(Namespace* namespc, const char* path); |
252 | static bool SetLastAccessed(Namespace* namespc, |
253 | const char* path, |
254 | int64_t millis); |
255 | static bool IsAbsolutePath(const char* path); |
256 | static const char* PathSeparator(); |
257 | static const char* StringEscapedPathSeparator(); |
258 | static Type GetType(Namespace* namespc, const char* path, bool follow_links); |
259 | static Identical AreIdentical(Namespace* namespc_1, |
260 | const char* file_1, |
261 | Namespace* namespc_2, |
262 | const char* file_2); |
263 | static StdioHandleType GetStdioHandleType(int fd); |
264 | |
265 | // LinkTarget, GetCanonicalPath, and ReadLink may call Dart_ScopeAllocate. |
266 | // If dest and its size are provided, Dart String will not be created. |
267 | // The result will be populated into dest. |
268 | static const char* LinkTarget(Namespace* namespc, |
269 | const char* pathname, |
270 | char* dest = nullptr, |
271 | int dest_size = 0); |
272 | static const char* GetCanonicalPath(Namespace* namespc, |
273 | const char* path, |
274 | char* dest = nullptr, |
275 | int dest_size = 0); |
276 | // Link LinkTarget, but pathname must be absolute. |
277 | static const char* ReadLink(const char* pathname); |
278 | static intptr_t ReadLinkInto(const char* pathname, |
279 | char* result, |
280 | size_t result_size); |
281 | |
282 | // Cleans an input path, transforming it to out, according to the rules |
283 | // defined by "Lexical File Names in Plan 9 or Getting Dot-Dot Right", |
284 | // accessible at: https://9p.io/sys/doc/lexnames.html. |
285 | // Returns -1 if out isn't big enough, and the length of out otherwise. |
286 | static intptr_t CleanUnixPath(const char* in, char* out, intptr_t outlen); |
287 | |
288 | static FileOpenMode DartModeToFileMode(DartFileOpenMode mode); |
289 | |
290 | static CObject* ExistsRequest(const CObjectArray& request); |
291 | static CObject* CreateRequest(const CObjectArray& request); |
292 | static CObject* DeleteRequest(const CObjectArray& request); |
293 | static CObject* RenameRequest(const CObjectArray& request); |
294 | static CObject* CopyRequest(const CObjectArray& request); |
295 | static CObject* OpenRequest(const CObjectArray& request); |
296 | static CObject* ResolveSymbolicLinksRequest(const CObjectArray& request); |
297 | static CObject* CloseRequest(const CObjectArray& request); |
298 | static CObject* PositionRequest(const CObjectArray& request); |
299 | static CObject* SetPositionRequest(const CObjectArray& request); |
300 | static CObject* TruncateRequest(const CObjectArray& request); |
301 | static CObject* LengthRequest(const CObjectArray& request); |
302 | static CObject* LengthFromPathRequest(const CObjectArray& request); |
303 | static CObject* LastModifiedRequest(const CObjectArray& request); |
304 | static CObject* SetLastModifiedRequest(const CObjectArray& request); |
305 | static CObject* LastAccessedRequest(const CObjectArray& request); |
306 | static CObject* SetLastAccessedRequest(const CObjectArray& request); |
307 | static CObject* FlushRequest(const CObjectArray& request); |
308 | static CObject* ReadByteRequest(const CObjectArray& request); |
309 | static CObject* WriteByteRequest(const CObjectArray& request); |
310 | static CObject* ReadRequest(const CObjectArray& request); |
311 | static CObject* ReadIntoRequest(const CObjectArray& request); |
312 | static CObject* WriteFromRequest(const CObjectArray& request); |
313 | static CObject* CreateLinkRequest(const CObjectArray& request); |
314 | static CObject* DeleteLinkRequest(const CObjectArray& request); |
315 | static CObject* RenameLinkRequest(const CObjectArray& request); |
316 | static CObject* LinkTargetRequest(const CObjectArray& request); |
317 | static CObject* TypeRequest(const CObjectArray& request); |
318 | static CObject* IdenticalRequest(const CObjectArray& request); |
319 | static CObject* StatRequest(const CObjectArray& request); |
320 | static CObject* LockRequest(const CObjectArray& request); |
321 | |
322 | private: |
323 | explicit File(FileHandle* handle) |
324 | : ReferenceCounted(), handle_(handle), finalizable_handle_(NULL) {} |
325 | |
326 | ~File(); |
327 | |
328 | static File* FileOpenW(const wchar_t* system_name, FileOpenMode mode); |
329 | |
330 | static const int kClosedFd = -1; |
331 | |
332 | // FileHandle is an OS specific class which stores data about the file. |
333 | FileHandle* handle_; // OS specific handle for the file. |
334 | |
335 | // We retain the finalizable handle because we can do cleanup eagerly when |
336 | // Dart code calls closeSync(). In that case, we delete the finalizable |
337 | // handle so that the finalizer doesn't run. |
338 | Dart_FinalizableHandle finalizable_handle_; |
339 | |
340 | friend class ReferenceCounted<File>; |
341 | DISALLOW_COPY_AND_ASSIGN(File); |
342 | }; |
343 | |
344 | class UriDecoder { |
345 | public: |
346 | explicit UriDecoder(const char* uri); |
347 | ~UriDecoder(); |
348 | |
349 | const char* decoded() const { return decoded_; } |
350 | |
351 | private: |
352 | bool HexCharPairToByte(const char* pch, char* dest); |
353 | |
354 | char* decoded_; |
355 | const char* uri_; |
356 | |
357 | DISALLOW_COPY_AND_ASSIGN(UriDecoder); |
358 | }; |
359 | |
360 | } // namespace bin |
361 | } // namespace dart |
362 | |
363 | #endif // RUNTIME_BIN_FILE_H_ |
364 | |