| // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | #ifndef RUNTIME_BIN_FILE_H_ | 
 | #define RUNTIME_BIN_FILE_H_ | 
 |  | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 | #include <sys/types.h> | 
 |  | 
 | #include "bin/builtin.h" | 
 | #include "bin/dartutils.h" | 
 | #include "bin/namespace.h" | 
 | #include "bin/reference_counting.h" | 
 | #include "platform/syslog.h" | 
 | #include "platform/utils.h" | 
 |  | 
 | namespace dart { | 
 | namespace bin { | 
 |  | 
 | // Forward declaration. | 
 | class FileHandle; | 
 |  | 
 | class MappedMemory { | 
 |  public: | 
 |   MappedMemory(void* address, intptr_t size, bool should_unmap = true) | 
 |       : should_unmap_(should_unmap), address_(address), size_(size) {} | 
 |   ~MappedMemory() { | 
 |     if (should_unmap_) Unmap(); | 
 |   } | 
 |  | 
 |   void* address() const { return address_; } | 
 |   intptr_t size() const { return size_; } | 
 |   uword start() const { return reinterpret_cast<uword>(address()); } | 
 |  | 
 |  private: | 
 |   void Unmap(); | 
 |  | 
 |   // False for mappings which reside inside another, and will be removed when | 
 |   // the outer mapping is removed. | 
 |   bool should_unmap_; | 
 |  | 
 |   void* address_; | 
 |   intptr_t size_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(MappedMemory); | 
 | }; | 
 |  | 
 | class File : public ReferenceCounted<File> { | 
 |  public: | 
 |   enum FileOpenMode { | 
 |     kRead = 0, | 
 |     kWrite = 1, | 
 |     kTruncate = 1 << 2, | 
 |     kWriteOnly = 1 << 3, | 
 |     kWriteTruncate = kWrite | kTruncate, | 
 |     kWriteOnlyTruncate = kWriteOnly | kTruncate | 
 |   }; | 
 |  | 
 |   // These values have to be kept in sync with the mode values of | 
 |   // FileMode.READ, FileMode.WRITE, FileMode.APPEND, | 
 |   // FileMode.WRITE_ONLY and FileMode.WRITE_ONLY_APPEND in file.dart. | 
 |   enum DartFileOpenMode { | 
 |     kDartRead = 0, | 
 |     kDartWrite = 1, | 
 |     kDartAppend = 2, | 
 |     kDartWriteOnly = 3, | 
 |     kDartWriteOnlyAppend = 4 | 
 |   }; | 
 |  | 
 |   enum Type { | 
 |     kIsFile = 0, | 
 |     kIsDirectory = 1, | 
 |     kIsLink = 2, | 
 |     kIsSock = 3,  // Unix Domain Socket. | 
 |     kIsPipe = 4,  // FIFO/Pipe. | 
 |     kDoesNotExist = 5 | 
 |   }; | 
 |  | 
 |   enum Identical { kIdentical = 0, kDifferent = 1, kError = 2 }; | 
 |  | 
 |   enum StdioHandleType { | 
 |     // These match the constants in stdio.dart. | 
 |     kTerminal = 0, | 
 |     kPipe = 1, | 
 |     kFile = 2, | 
 |     kSocket = 3, | 
 |     kOther = 4, | 
 |     kTypeError = 5 | 
 |   }; | 
 |  | 
 |   enum FileStat { | 
 |     // These match the constants in FileStat in file_system_entity.dart. | 
 |     kType = 0, | 
 |     kCreatedTime = 1, | 
 |     kModifiedTime = 2, | 
 |     kAccessedTime = 3, | 
 |     kMode = 4, | 
 |     kSize = 5, | 
 |     kStatSize = 6 | 
 |   }; | 
 |  | 
 |   enum LockType { | 
 |     // These match the constants in FileStat in file_impl.dart. | 
 |     kLockMin = 0, | 
 |     kLockUnlock = 0, | 
 |     kLockShared = 1, | 
 |     kLockExclusive = 2, | 
 |     kLockBlockingShared = 3, | 
 |     kLockBlockingExclusive = 4, | 
 |     kLockMax = 4 | 
 |   }; | 
 |  | 
 |   intptr_t GetFD(); | 
 |  | 
 |   enum MapType { | 
 |     kReadOnly = 0, | 
 |     kReadExecute = 1, | 
 |     kReadWrite = 2, | 
 |   }; | 
 |  | 
 |   /// Maps or copies the file into memory. | 
 |   /// | 
 |   /// 'position' and 'length' should be page-aligned. | 
 |   /// | 
 |   /// If 'start' is zero, allocates virtual memory for the mapping. When the | 
 |   /// returned 'MappedMemory' is destroyed, the mapping is removed. | 
 |   /// | 
 |   /// If 'start' is non-zero, it must point within a suitably sized existing | 
 |   /// mapping. The returned 'MappedMemory' will not remove the mapping when it | 
 |   /// is destroyed; rather, the mapping will be removed when the enclosing | 
 |   /// mapping is removed. This mode is not supported on Fuchsia. | 
 |   /// | 
 |   /// If 'type' is 'kReadWrite', writes to the mapping are *not* copied back to | 
 |   /// the file. | 
 |   /// | 
 |   /// 'position' + 'length' may be larger than the file size. In this case, the | 
 |   /// extra memory is zero-filled. | 
 |   MappedMemory* Map(MapType type, | 
 |                     int64_t position, | 
 |                     int64_t length, | 
 |                     void* start = nullptr); | 
 |  | 
 |   // Read/Write attempt to transfer num_bytes to/from buffer. It returns | 
 |   // the number of bytes read/written. | 
 |   int64_t Read(void* buffer, int64_t num_bytes); | 
 |   int64_t Write(const void* buffer, int64_t num_bytes); | 
 |  | 
 |   // ReadFully and WriteFully do attempt to transfer num_bytes to/from | 
 |   // the buffer. In the event of short accesses they will loop internally until | 
 |   // the whole buffer has been transferred or an error occurs. If an error | 
 |   // occurred the result will be set to false. | 
 |   bool ReadFully(void* buffer, int64_t num_bytes); | 
 |   bool WriteFully(const void* buffer, int64_t num_bytes); | 
 |   bool WriteByte(uint8_t byte) { return WriteFully(&byte, 1); } | 
 |  | 
 |   bool Print(const char* format, ...) PRINTF_ATTRIBUTE(2, 3) { | 
 |     va_list args; | 
 |     va_start(args, format); | 
 |     bool result = VPrint(format, args); | 
 |     va_end(args); | 
 |     return result; | 
 |   } | 
 |   bool VPrint(const char* format, va_list args); | 
 |  | 
 |   // Get the length of the file. Returns a negative value if the length cannot | 
 |   // be determined (e.g. not seekable device). | 
 |   int64_t Length(); | 
 |  | 
 |   // Get the current position in the file. | 
 |   // Returns a negative value if position cannot be determined. | 
 |   int64_t Position(); | 
 |  | 
 |   // Set the byte position in the file. | 
 |   bool SetPosition(int64_t position); | 
 |  | 
 |   // Truncate (or extend) the file to the given length in bytes. | 
 |   bool Truncate(int64_t length); | 
 |  | 
 |   // Flush contents of file. | 
 |   bool Flush(); | 
 |  | 
 |   // Lock range of a file. | 
 |   bool Lock(LockType lock, int64_t start, int64_t end); | 
 |  | 
 |   // Returns whether the file has been closed. | 
 |   bool IsClosed(); | 
 |  | 
 |   // Calls the platform-specific functions to close the file. | 
 |   void Close(); | 
 |  | 
 |   // Returns the finalizable handle for the File's Dart wrapper. | 
 |   Dart_FinalizableHandle FinalizableHandle() const { | 
 |     return finalizable_handle_; | 
 |   } | 
 |  | 
 |   // Set the finalizable handle for the File's Dart wrapper. | 
 |   void SetFinalizableHandle(Dart_FinalizableHandle handle) { | 
 |     ASSERT(finalizable_handle_ == NULL); | 
 |     finalizable_handle_ = handle; | 
 |   } | 
 |  | 
 |   // Deletes the finalizable handle for the File's Dart wrapper. Call | 
 |   // when the file is explicitly closed and the finalizer is no longer | 
 |   // needed. | 
 |   void DeleteFinalizableHandle(Dart_Isolate isolate, Dart_Handle strong_ref) { | 
 |     Dart_DeleteFinalizableHandle(finalizable_handle_, strong_ref); | 
 |     finalizable_handle_ = NULL; | 
 |   } | 
 |  | 
 |   // Open the file with the given path. The file is always opened for | 
 |   // reading. If mode contains kWrite the file is opened for both | 
 |   // reading and writing. If mode contains kWrite and the file does | 
 |   // not exist the file is created. The file is truncated to length 0 if | 
 |   // mode contains kTruncate. | 
 |   static File* Open(Namespace* namespc, const char* path, FileOpenMode mode); | 
 |  | 
 |   // Same as [File::Open], but attempts to convert uri to path before opening | 
 |   // the file. If conversion fails, uri is treated as a path. | 
 |   static File* OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode); | 
 |  | 
 |   // Attempts to convert the given [uri] to a file path. | 
 |   static Utils::CStringUniquePtr UriToPath(const char* uri); | 
 |  | 
 |   // Create a file object for the specified stdio file descriptor | 
 |   // (stdin, stout or stderr). | 
 |   static File* OpenStdio(int fd); | 
 |  | 
 | #if defined(DART_HOST_OS_FUCHSIA) || defined(DART_HOST_OS_LINUX) ||            \ | 
 |     defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_MACOS) | 
 |   static File* OpenFD(int fd); | 
 | #endif | 
 |  | 
 |   static bool Exists(Namespace* namespc, const char* path); | 
 |   static bool ExistsUri(Namespace* namespc, const char* uri); | 
 |   static bool Create(Namespace* namespc, const char* path); | 
 |   static bool CreateLink(Namespace* namespc, | 
 |                          const char* path, | 
 |                          const char* target); | 
 |   static bool Delete(Namespace* namespc, const char* path); | 
 |   static bool DeleteLink(Namespace* namespc, const char* path); | 
 |   static bool Rename(Namespace* namespc, | 
 |                      const char* old_path, | 
 |                      const char* new_path); | 
 |   static bool RenameLink(Namespace* namespc, | 
 |                          const char* old_path, | 
 |                          const char* new_path); | 
 |   static bool Copy(Namespace* namespc, | 
 |                    const char* old_path, | 
 |                    const char* new_path); | 
 |   static int64_t LengthFromPath(Namespace* namespc, const char* path); | 
 |   static void Stat(Namespace* namespc, const char* path, int64_t* data); | 
 |   static time_t LastModified(Namespace* namespc, const char* path); | 
 |   static bool SetLastModified(Namespace* namespc, | 
 |                               const char* path, | 
 |                               int64_t millis); | 
 |   static time_t LastAccessed(Namespace* namespc, const char* path); | 
 |   static bool SetLastAccessed(Namespace* namespc, | 
 |                               const char* path, | 
 |                               int64_t millis); | 
 |   static bool IsAbsolutePath(const char* path); | 
 |   static const char* PathSeparator(); | 
 |   static const char* StringEscapedPathSeparator(); | 
 |   static Type GetType(Namespace* namespc, const char* path, bool follow_links); | 
 |   static Identical AreIdentical(Namespace* namespc_1, | 
 |                                 const char* file_1, | 
 |                                 Namespace* namespc_2, | 
 |                                 const char* file_2); | 
 |   static StdioHandleType GetStdioHandleType(int fd); | 
 |  | 
 |   // LinkTarget, GetCanonicalPath, and ReadLink may call Dart_ScopeAllocate. | 
 |   // If dest and its size are provided, Dart String will not be created. | 
 |   // The result will be populated into dest. | 
 |   static const char* LinkTarget(Namespace* namespc, | 
 |                                 const char* pathname, | 
 |                                 char* dest = nullptr, | 
 |                                 int dest_size = 0); | 
 |   static const char* GetCanonicalPath(Namespace* namespc, | 
 |                                       const char* path, | 
 |                                       char* dest = nullptr, | 
 |                                       int dest_size = 0); | 
 |   // Link LinkTarget, but pathname must be absolute. | 
 |   static const char* ReadLink(const char* pathname); | 
 |   static intptr_t ReadLinkInto(const char* pathname, | 
 |                                char* result, | 
 |                                size_t result_size); | 
 |  | 
 |   // Cleans an input path, transforming it to out, according to the rules | 
 |   // defined by "Lexical File Names in Plan 9 or Getting Dot-Dot Right", | 
 |   // accessible at: https://9p.io/sys/doc/lexnames.html. | 
 |   // Returns -1 if out isn't big enough, and the length of out otherwise. | 
 |   static intptr_t CleanUnixPath(const char* in, char* out, intptr_t outlen); | 
 |  | 
 |   static FileOpenMode DartModeToFileMode(DartFileOpenMode mode); | 
 |  | 
 |   static CObject* ExistsRequest(const CObjectArray& request); | 
 |   static CObject* CreateRequest(const CObjectArray& request); | 
 |   static CObject* DeleteRequest(const CObjectArray& request); | 
 |   static CObject* RenameRequest(const CObjectArray& request); | 
 |   static CObject* CopyRequest(const CObjectArray& request); | 
 |   static CObject* OpenRequest(const CObjectArray& request); | 
 |   static CObject* ResolveSymbolicLinksRequest(const CObjectArray& request); | 
 |   static CObject* CloseRequest(const CObjectArray& request); | 
 |   static CObject* PositionRequest(const CObjectArray& request); | 
 |   static CObject* SetPositionRequest(const CObjectArray& request); | 
 |   static CObject* TruncateRequest(const CObjectArray& request); | 
 |   static CObject* LengthRequest(const CObjectArray& request); | 
 |   static CObject* LengthFromPathRequest(const CObjectArray& request); | 
 |   static CObject* LastModifiedRequest(const CObjectArray& request); | 
 |   static CObject* SetLastModifiedRequest(const CObjectArray& request); | 
 |   static CObject* LastAccessedRequest(const CObjectArray& request); | 
 |   static CObject* SetLastAccessedRequest(const CObjectArray& request); | 
 |   static CObject* FlushRequest(const CObjectArray& request); | 
 |   static CObject* ReadByteRequest(const CObjectArray& request); | 
 |   static CObject* WriteByteRequest(const CObjectArray& request); | 
 |   static CObject* ReadRequest(const CObjectArray& request); | 
 |   static CObject* ReadIntoRequest(const CObjectArray& request); | 
 |   static CObject* WriteFromRequest(const CObjectArray& request); | 
 |   static CObject* CreateLinkRequest(const CObjectArray& request); | 
 |   static CObject* DeleteLinkRequest(const CObjectArray& request); | 
 |   static CObject* RenameLinkRequest(const CObjectArray& request); | 
 |   static CObject* LinkTargetRequest(const CObjectArray& request); | 
 |   static CObject* TypeRequest(const CObjectArray& request); | 
 |   static CObject* IdenticalRequest(const CObjectArray& request); | 
 |   static CObject* StatRequest(const CObjectArray& request); | 
 |   static CObject* LockRequest(const CObjectArray& request); | 
 |  | 
 |  private: | 
 |   explicit File(FileHandle* handle) | 
 |       : ReferenceCounted(), handle_(handle), finalizable_handle_(NULL) {} | 
 |  | 
 |   ~File(); | 
 |  | 
 |   static File* FileOpenW(const wchar_t* system_name, FileOpenMode mode); | 
 |  | 
 |   static const int kClosedFd = -1; | 
 |  | 
 |   // FileHandle is an OS specific class which stores data about the file. | 
 |   FileHandle* handle_;  // OS specific handle for the file. | 
 |  | 
 |   // We retain the finalizable handle because we can do cleanup eagerly when | 
 |   // Dart code calls closeSync(). In that case, we delete the finalizable | 
 |   // handle so that the finalizer doesn't run. | 
 |   Dart_FinalizableHandle finalizable_handle_; | 
 |  | 
 |   friend class ReferenceCounted<File>; | 
 |   DISALLOW_COPY_AND_ASSIGN(File); | 
 | }; | 
 |  | 
 | class UriDecoder { | 
 |  public: | 
 |   explicit UriDecoder(const char* uri); | 
 |   ~UriDecoder(); | 
 |  | 
 |   const char* decoded() const { return decoded_; } | 
 |  | 
 |  private: | 
 |   bool HexCharPairToByte(const char* pch, char* dest); | 
 |  | 
 |   char* decoded_; | 
 |   const char* uri_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(UriDecoder); | 
 | }; | 
 |  | 
 | }  // namespace bin | 
 | }  // namespace dart | 
 |  | 
 | #endif  // RUNTIME_BIN_FILE_H_ |