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
20namespace dart {
21namespace bin {
22
23// Forward declaration.
24class FileHandle;
25
26class 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
51class 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
344class 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