filesystem.h (53349B)
1 // Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #pragma once 23 24 #include "memory.h" 25 #include "io.h" 26 #include <inttypes.h> 27 #include "time.h" 28 #include "function.h" 29 #include "hash.h" 30 31 namespace kj { 32 33 template <typename T> 34 class Vector; 35 36 class PathPtr; 37 38 class Path { 39 // A Path identifies a file in a directory tree. 40 // 41 // In KJ, we avoid representing paths as plain strings because this can lead to path injection 42 // bugs as well as numerous kinds of bugs relating to path parsing edge cases. The Path class's 43 // interface is designed to "make it hard to screw up". 44 // 45 // A "Path" is in fact a list of strings, each string being one component of the path (as would 46 // normally be separated by '/'s). Path components are not allowed to contain '/' nor '\0', nor 47 // are they allowed to be the special names "", ".", nor "..". 48 // 49 // If you explicitly want to parse a path that contains '/'s, ".", and "..", you must use 50 // parse() and/or eval(). However, users of this interface are encouraged to avoid parsing 51 // paths at all, and instead express paths as string arrays. 52 // 53 // Note that when using the Path class, ".." is always canonicalized in path space without 54 // consulting the actual filesystem. This means that "foo/some-symlink/../bar" is exactly 55 // equivalent to "foo/bar". This differs from the kernel's behavior when resolving paths passed 56 // to system calls: the kernel would have resolved "some-symlink" to its target physical path, 57 // and then would have interpreted ".." relative to that. In practice, the kernel's behavior is 58 // rarely what the user or programmer intended, hence canonicalizing in path space produces a 59 // better result. 60 // 61 // Path objects are "immutable": functions that "modify" the path return a new path. However, 62 // if the path being operated on is an rvalue, copying can be avoided. Hence it makes sense to 63 // write code like: 64 // 65 // Path p = ...; 66 // p = kj::mv(p).append("bar"); // in-place update, avoids string copying 67 68 public: 69 Path(decltype(nullptr)); // empty path 70 71 explicit Path(StringPtr name); 72 explicit Path(String&& name); 73 // Create a Path containing only one component. `name` is a single filename; it cannot contain 74 // '/' nor '\0' nor can it be exactly "" nor "." nor "..". 75 // 76 // If you want to allow '/'s and such, you must call Path::parse(). We force you to do this to 77 // prevent path injection bugs where you didn't consider what would happen if the path contained 78 // a '/'. 79 80 explicit Path(std::initializer_list<StringPtr> parts); 81 explicit Path(ArrayPtr<const StringPtr> parts); 82 explicit Path(Array<String> parts); 83 // Construct a path from an array. Note that this means you can do: 84 // 85 // Path{"foo", "bar", "baz"} // equivalent to Path::parse("foo/bar/baz") 86 87 KJ_DISALLOW_COPY(Path); 88 Path(Path&&) = default; 89 Path& operator=(Path&&) = default; 90 91 Path clone() const; 92 93 static Path parse(StringPtr path); 94 // Parses a path in traditional format. Components are separated by '/'. Any use of "." or 95 // ".." will be canonicalized (if they can't be canonicalized, e.g. because the path starts with 96 // "..", an exception is thrown). Multiple consecutive '/'s will be collapsed. A leading '/' 97 // is NOT accepted -- if that is a problem, you probably want `eval()`. Trailing '/'s are 98 // ignored. 99 100 Path append(Path&& suffix) const&; 101 Path append(Path&& suffix) &&; 102 Path append(PathPtr suffix) const&; 103 Path append(PathPtr suffix) &&; 104 Path append(StringPtr suffix) const&; 105 Path append(StringPtr suffix) &&; 106 Path append(String&& suffix) const&; 107 Path append(String&& suffix) &&; 108 // Create a new path by appending the given path to this path. 109 // 110 // `suffix` cannot contain '/' characters. Instead, you can append an array: 111 // 112 // path.append({"foo", "bar"}) 113 // 114 // Or, use Path::parse(): 115 // 116 // path.append(Path::parse("foo//baz/../bar")) 117 118 Path eval(StringPtr pathText) const&; 119 Path eval(StringPtr pathText) &&; 120 // Evaluates a traditional path relative to this one. `pathText` is parsed like `parse()` would, 121 // except that: 122 // - It can contain leading ".." components that traverse up the tree. 123 // - It can have a leading '/' which completely replaces the current path. 124 // 125 // THE NAME OF THIS METHOD WAS CHOSEN TO INSPIRE FEAR. 126 // 127 // Instead of using `path.eval(str)`, always consider whether you really want 128 // `path.append(Path::parse(str))`. The former is much riskier than the latter in terms of path 129 // injection vulnerabilities. 130 131 PathPtr basename() const&; 132 Path basename() &&; 133 // Get the last component of the path. (Use `basename()[0]` to get just the string.) 134 135 PathPtr parent() const&; 136 Path parent() &&; 137 // Get the parent path. 138 139 String toString(bool absolute = false) const; 140 // Converts the path to a traditional path string, appropriate to pass to a unix system call. 141 // Never throws. 142 143 const String& operator[](size_t i) const&; 144 String operator[](size_t i) &&; 145 size_t size() const; 146 const String* begin() const; 147 const String* end() const; 148 PathPtr slice(size_t start, size_t end) const&; 149 Path slice(size_t start, size_t end) &&; 150 // A Path can be accessed as an array of strings. 151 152 bool operator==(PathPtr other) const; 153 bool operator!=(PathPtr other) const; 154 bool operator< (PathPtr other) const; 155 bool operator> (PathPtr other) const; 156 bool operator<=(PathPtr other) const; 157 bool operator>=(PathPtr other) const; 158 // Compare path components lexically. 159 160 bool operator==(const Path& other) const; 161 bool operator!=(const Path& other) const; 162 bool operator< (const Path& other) const; 163 bool operator> (const Path& other) const; 164 bool operator<=(const Path& other) const; 165 bool operator>=(const Path& other) const; 166 167 uint hashCode() const; 168 // Can use in HashMap. 169 170 bool startsWith(PathPtr prefix) const; 171 bool endsWith(PathPtr suffix) const; 172 // Compare prefix / suffix. 173 174 Path evalWin32(StringPtr pathText) const&; 175 Path evalWin32(StringPtr pathText) &&; 176 // Evaluates a Win32-style path, as might be written by a user. Differences from `eval()` 177 // include: 178 // 179 // - Backslashes can be used as path separators. 180 // - Absolute paths begin with a drive letter followed by a colon. The drive letter, including 181 // the colon, will become the first component of the path, e.g. "c:\foo" becomes {"c:", "foo"}. 182 // - A network path like "\\host\share\path" is parsed as {"host", "share", "path"}. 183 184 Path evalNative(StringPtr pathText) const&; 185 Path evalNative(StringPtr pathText) &&; 186 // Alias for either eval() or evalWin32() depending on the target platform. Use this when you are 187 // parsing a path provided by a user and you want the user to be able to use the "natural" format 188 // for their platform. 189 190 String toWin32String(bool absolute = false) const; 191 // Converts the path to a Win32 path string, as you might display to a user. 192 // 193 // This is meant for display. For making Win32 system calls, consider `toWin32Api()` instead. 194 // 195 // If `absolute` is true, the path is expected to be an absolute path, meaning the first 196 // component is a drive letter, namespace, or network host name. These are converted to their 197 // regular Win32 format -- i.e. this method does the reverse of `evalWin32()`. 198 // 199 // This throws if the path would have unexpected special meaning or is otherwise invalid on 200 // Windows, such as if it contains backslashes (within a path component), colons, or special 201 // names like "con". 202 203 String toNativeString(bool absolute = false) const; 204 // Alias for either toString() or toWin32String() depending on the target platform. Use this when 205 // you are formatting a path to display to a user and you want to present it in the "natural" 206 // format for the user's platform. 207 208 Array<wchar_t> forWin32Api(bool absolute) const; 209 // Like toWin32String, but additionally: 210 // - Converts the path to UTF-16, with a NUL terminator included. 211 // - For absolute paths, adds the "\\?\" prefix which opts into permitting paths longer than 212 // MAX_PATH, and turns off relative path processing (which KJ paths already handle in userspace 213 // anyway). 214 // 215 // This method is good to use when making a Win32 API call, e.g.: 216 // 217 // DeleteFileW(path.forWin32Api(true).begin()); 218 219 static Path parseWin32Api(ArrayPtr<const wchar_t> text); 220 // Parses an absolute path as returned by a Win32 API call like GetFinalPathNameByHandle() or 221 // GetCurrentDirectory(). A "\\?\" prefix is optional but understood if present. 222 // 223 // Since such Win32 API calls generally return a length, this function inputs an array slice. 224 // The slice should not include any NUL terminator. 225 226 private: 227 Array<String> parts; 228 229 // TODO(perf): Consider unrolling one element from `parts`, so that a one-element path doesn't 230 // require allocation of an array. 231 232 enum { ALREADY_CHECKED }; 233 Path(Array<String> parts, decltype(ALREADY_CHECKED)); 234 235 friend class PathPtr; 236 237 static String stripNul(String input); 238 static void validatePart(StringPtr part); 239 static void evalPart(Vector<String>& parts, ArrayPtr<const char> part); 240 static Path evalImpl(Vector<String>&& parts, StringPtr path); 241 static Path evalWin32Impl(Vector<String>&& parts, StringPtr path, bool fromApi = false); 242 static size_t countParts(StringPtr path); 243 static size_t countPartsWin32(StringPtr path); 244 static bool isWin32Drive(ArrayPtr<const char> part); 245 static bool isNetbiosName(ArrayPtr<const char> part); 246 static bool isWin32Special(StringPtr part); 247 }; 248 249 class PathPtr { 250 // Points to a Path or a slice of a Path, but doesn't own it. 251 // 252 // PathPtr is to Path as ArrayPtr is to Array and StringPtr is to String. 253 254 public: 255 PathPtr(decltype(nullptr)); 256 PathPtr(const Path& path); 257 258 Path clone(); 259 Path append(Path&& suffix) const; 260 Path append(PathPtr suffix) const; 261 Path append(StringPtr suffix) const; 262 Path append(String&& suffix) const; 263 Path eval(StringPtr pathText) const; 264 PathPtr basename() const; 265 PathPtr parent() const; 266 String toString(bool absolute = false) const; 267 const String& operator[](size_t i) const; 268 size_t size() const; 269 const String* begin() const; 270 const String* end() const; 271 PathPtr slice(size_t start, size_t end) const; 272 bool operator==(PathPtr other) const; 273 bool operator!=(PathPtr other) const; 274 bool operator< (PathPtr other) const; 275 bool operator> (PathPtr other) const; 276 bool operator<=(PathPtr other) const; 277 bool operator>=(PathPtr other) const; 278 uint hashCode() const; 279 bool startsWith(PathPtr prefix) const; 280 bool endsWith(PathPtr suffix) const; 281 Path evalWin32(StringPtr pathText) const; 282 Path evalNative(StringPtr pathText) const; 283 String toWin32String(bool absolute = false) const; 284 String toNativeString(bool absolute = false) const; 285 Array<wchar_t> forWin32Api(bool absolute) const; 286 // Equivalent to the corresponding methods of `Path`. 287 288 private: 289 ArrayPtr<const String> parts; 290 291 explicit PathPtr(ArrayPtr<const String> parts); 292 293 String toWin32StringImpl(bool absolute, bool forApi) const; 294 295 friend class Path; 296 }; 297 298 // ======================================================================================= 299 // The filesystem API 300 // 301 // This API is strictly synchronous because, unfortunately, there's no such thing as asynchronous 302 // filesystem access in practice. The filesystem drivers on Linux are written to assume they can 303 // block. The AIO API is only actually asynchronous for reading/writing the raw file blocks, but if 304 // the filesystem needs to be involved (to allocate blocks, update metadata, etc.) that will block. 305 // It's best to imagine that the filesystem is just another tier of memory that happens to be 306 // slower than RAM (which is slower than L3 cache, which is slower than L2, which is slower than 307 // L1). You can't do asynchronous RAM access so why asynchronous filesystem? The only way to 308 // parallelize these is using threads. 309 // 310 // All KJ filesystem objects are thread-safe, and so all methods are marked "const" (even write 311 // methods). Of course, if you concurrently write the same bytes of a file from multiple threads, 312 // it's unspecified which write will "win". 313 314 class FsNode { 315 // Base class for filesystem node types. 316 317 public: 318 Own<const FsNode> clone() const; 319 // Creates a new object of exactly the same type as this one, pointing at exactly the same 320 // external object. 321 // 322 // Under the hood, this will call dup(), so the FD number will not be the same. 323 324 virtual Maybe<int> getFd() const { return nullptr; } 325 // Get the underlying Unix file descriptor, if any. Returns nullptr if this object actually isn't 326 // wrapping a file descriptor. 327 328 virtual Maybe<void*> getWin32Handle() const { return nullptr; } 329 // Get the underlying Win32 HANDLE, if any. Returns nullptr if this object actually isn't 330 // wrapping a handle. 331 332 enum class Type { 333 FILE, 334 DIRECTORY, 335 SYMLINK, 336 BLOCK_DEVICE, 337 CHARACTER_DEVICE, 338 NAMED_PIPE, 339 SOCKET, 340 OTHER, 341 }; 342 343 struct Metadata { 344 Type type = Type::FILE; 345 346 uint64_t size = 0; 347 // Logical size of the file. 348 349 uint64_t spaceUsed = 0; 350 // Physical size of the file on disk. May be smaller for sparse files, or larger for 351 // pre-allocated files. 352 353 Date lastModified = UNIX_EPOCH; 354 // Last modification time of the file. 355 356 uint linkCount = 1; 357 // Number of hard links pointing to this node. 358 359 uint64_t hashCode = 0; 360 // Hint which can be used to determine if two FsNode instances point to the same underlying 361 // file object. If two FsNodes report different hashCodes, then they are not the same object. 362 // If they report the same hashCode, then they may or may not be the same object. 363 // 364 // The Unix filesystem implementation builds the hashCode based on st_dev and st_ino of 365 // `struct stat`. However, note that some filesystems -- especially FUSE-based -- may not fill 366 // in st_ino. 367 // 368 // The Windows filesystem implementation builds the hashCode based on dwVolumeSerialNumber and 369 // dwFileIndex{Low,High} of the BY_HANDLE_FILE_INFORMATION structure. However, these are again 370 // not guaranteed to be unique on all filesystems. In particular the documentation says that 371 // ReFS uses 128-bit identifiers which can't be represented here, and again virtual filesystems 372 // may often not report real identifiers. 373 // 374 // Of course, the process of hashing values into a single hash code can also cause collisions 375 // even if the filesystem reports reliable information. 376 // 377 // Additionally note that this value is not reliable when returned by `lstat()`. You should 378 // actually open the object, then call `stat()` on the opened object. 379 380 // Not currently included: 381 // - Access control info: Differs wildly across platforms, and KJ prefers capabilities anyway. 382 // - Other timestamps: Differs across platforms. 383 // - Device number: If you care, you're probably doing platform-specific stuff anyway. 384 385 Metadata() = default; 386 Metadata(Type type, uint64_t size, uint64_t spaceUsed, Date lastModified, uint linkCount, 387 uint64_t hashCode) 388 : type(type), size(size), spaceUsed(spaceUsed), lastModified(lastModified), 389 linkCount(linkCount), hashCode(hashCode) {} 390 // TODO(cleanup): This constructor is redundant in C++14, but needed in C++11. 391 }; 392 393 virtual Metadata stat() const = 0; 394 395 virtual void sync() const = 0; 396 virtual void datasync() const = 0; 397 // Maps to fsync() and fdatasync() system calls. 398 // 399 // Also, when creating or overwriting a file, the first call to sync() atomically links the file 400 // into the filesystem (*after* syncing the data), so than incomplete data is never visible to 401 // other processes. (In practice this works by writing into a temporary file and then rename()ing 402 // it.) 403 404 protected: 405 virtual Own<const FsNode> cloneFsNode() const = 0; 406 // Implements clone(). Required to return an object with exactly the same type as this one. 407 // Hence, every subclass must implement this. 408 }; 409 410 class ReadableFile: public FsNode { 411 public: 412 Own<const ReadableFile> clone() const; 413 414 String readAllText() const; 415 // Read all text in the file and return as a big string. 416 417 Array<byte> readAllBytes() const; 418 // Read all bytes in the file and return as a big byte array. 419 // 420 // This differs from mmap() in that the read is performed all at once. Future changes to the file 421 // do not affect the returned copy. Consider using mmap() instead, particularly for large files. 422 423 virtual size_t read(uint64_t offset, ArrayPtr<byte> buffer) const = 0; 424 // Fills `buffer` with data starting at `offset`. Returns the number of bytes actually read -- 425 // the only time this is less than `buffer.size()` is when EOF occurs mid-buffer. 426 427 virtual Array<const byte> mmap(uint64_t offset, uint64_t size) const = 0; 428 // Maps the file to memory read-only. The returned array always has exactly the requested size. 429 // Depending on the capabilities of the OS and filesystem, the mapping may or may not reflect 430 // changes that happen to the file after mmap() returns. 431 // 432 // Multiple calls to mmap() on the same file may or may not return the same mapping (it is 433 // immutable, so there's no possibility of interference). 434 // 435 // If the file cannot be mmap()ed, an implementation may choose to allocate a buffer on the heap, 436 // read into it, and return that. This should only happen if a real mmap() is impossible. 437 // 438 // The returned array is always exactly the size requested. However, accessing bytes beyond the 439 // current end of the file may raise SIGBUS, or may simply return zero. 440 441 virtual Array<byte> mmapPrivate(uint64_t offset, uint64_t size) const = 0; 442 // Like mmap() but returns a view that the caller can modify. Modifications will not be written 443 // to the underlying file. Every call to this method returns a unique mapping. Changes made to 444 // the underlying file by other clients may or may not be reflected in the mapping -- in fact, 445 // some changes may be reflected while others aren't, even within the same mapping. 446 // 447 // In practice this is often implemented using copy-on-write pages. When you first write to a 448 // page, a copy is made. Hence, changes to the underlying file within that page stop being 449 // reflected in the mapping. 450 }; 451 452 class AppendableFile: public FsNode, public OutputStream { 453 public: 454 Own<const AppendableFile> clone() const; 455 456 // All methods are inherited. 457 }; 458 459 class WritableFileMapping { 460 public: 461 virtual ArrayPtr<byte> get() const = 0; 462 // Gets the mapped bytes. The returned array can be modified, and those changes may be written to 463 // the underlying file, but there is no guarantee that they are written unless you subsequently 464 // call changed(). 465 466 virtual void changed(ArrayPtr<byte> slice) const = 0; 467 // Notifies the implementation that the given bytes have changed. For some implementations this 468 // may be a no-op while for others it may be necessary in order for the changes to be written 469 // back at all. 470 // 471 // `slice` must be a slice of `bytes()`. 472 473 virtual void sync(ArrayPtr<byte> slice) const = 0; 474 // Implies `changed()`, and then waits until the range has actually been written to disk before 475 // returning. 476 // 477 // `slice` must be a slice of `bytes()`. 478 // 479 // On Windows, this calls FlushViewOfFile(). The documentation for this function implies that in 480 // some circumstances, to fully sync to physical disk, you may need to call FlushFileBuffers() on 481 // the file HANDLE as well. The documentation is not very clear on when and why this is needed. 482 // If you believe your program needs this, you can accomplish it by calling `.sync()` on the File 483 // object after calling `.sync()` on the WritableFileMapping. 484 }; 485 486 class File: public ReadableFile { 487 public: 488 Own<const File> clone() const; 489 490 void writeAll(ArrayPtr<const byte> bytes) const; 491 void writeAll(StringPtr text) const; 492 // Completely replace the file with the given bytes or text. 493 494 virtual void write(uint64_t offset, ArrayPtr<const byte> data) const = 0; 495 // Write the given data starting at the given offset in the file. 496 497 virtual void zero(uint64_t offset, uint64_t size) const = 0; 498 // Write zeros to the file, starting at `offset` and continuing for `size` bytes. If the platform 499 // supports it, this will "punch a hole" in the file, such that blocks that are entirely zeros 500 // do not take space on disk. 501 502 virtual void truncate(uint64_t size) const = 0; 503 // Set the file end pointer to `size`. If `size` is less than the current size, data past the end 504 // is truncated. If `size` is larger than the current size, zeros are added to the end of the 505 // file. If the platform supports it, blocks containing all-zeros will not be stored to disk. 506 507 virtual Own<const WritableFileMapping> mmapWritable(uint64_t offset, uint64_t size) const = 0; 508 // Like ReadableFile::mmap() but returns a mapping for which any changes will be immediately 509 // visible in other mappings of the file on the same system and will eventually be written back 510 // to the file. 511 512 virtual size_t copy(uint64_t offset, const ReadableFile& from, uint64_t fromOffset, 513 uint64_t size) const; 514 // Copies bytes from one file to another. 515 // 516 // Copies `size` bytes or to EOF, whichever comes first. Returns the number of bytes actually 517 // copied. Hint: Pass kj::maxValue for `size` to always copy to EOF. 518 // 519 // The copy is not atomic. Concurrent writes may lead to garbage results. 520 // 521 // The default implementation performs a series of reads and writes. Subclasses can often provide 522 // superior implementations that offload the work to the OS or even implement copy-on-write. 523 }; 524 525 class ReadableDirectory: public FsNode { 526 // Read-only subset of `Directory`. 527 528 public: 529 Own<const ReadableDirectory> clone() const; 530 531 virtual Array<String> listNames() const = 0; 532 // List the contents of this directory. Does NOT include "." nor "..". 533 534 struct Entry { 535 FsNode::Type type; 536 String name; 537 538 inline bool operator< (const Entry& other) const { return name < other.name; } 539 inline bool operator> (const Entry& other) const { return name > other.name; } 540 inline bool operator<=(const Entry& other) const { return name <= other.name; } 541 inline bool operator>=(const Entry& other) const { return name >= other.name; } 542 // Convenience comparison operators to sort entries by name. 543 }; 544 545 virtual Array<Entry> listEntries() const = 0; 546 // List the contents of the directory including the type of each file. On some platforms and 547 // filesystems, this is just as fast as listNames(), but on others it may require stat()ing each 548 // file. 549 550 virtual bool exists(PathPtr path) const = 0; 551 // Does the specified path exist? 552 // 553 // If the path is a symlink, the symlink is followed and the return value indicates if the target 554 // exists. If you want to know if the symlink exists, use lstat(). (This implies that listNames() 555 // may return names for which exists() reports false.) 556 557 FsNode::Metadata lstat(PathPtr path) const; 558 virtual Maybe<FsNode::Metadata> tryLstat(PathPtr path) const = 0; 559 // Gets metadata about the path. If the path is a symlink, it is not followed -- the metadata 560 // describes the symlink itself. `tryLstat()` returns null if the path doesn't exist. 561 562 Own<const ReadableFile> openFile(PathPtr path) const; 563 virtual Maybe<Own<const ReadableFile>> tryOpenFile(PathPtr path) const = 0; 564 // Open a file for reading. 565 // 566 // `tryOpenFile()` returns null if the path doesn't exist. Other errors still throw exceptions. 567 568 Own<const ReadableDirectory> openSubdir(PathPtr path) const; 569 virtual Maybe<Own<const ReadableDirectory>> tryOpenSubdir(PathPtr path) const = 0; 570 // Opens a subdirectory. 571 // 572 // `tryOpenSubdir()` returns null if the path doesn't exist. Other errors still throw exceptions. 573 574 String readlink(PathPtr path) const; 575 virtual Maybe<String> tryReadlink(PathPtr path) const = 0; 576 // If `path` is a symlink, reads and returns the link contents. 577 // 578 // Note that tryReadlink() differs subtly from tryOpen*(). For example, tryOpenFile() throws if 579 // the path is not a file (e.g. if it's a directory); it only returns null if the path doesn't 580 // exist at all. tryReadlink() returns null if either the path doesn't exist, or if it does exist 581 // but isn't a symlink. This is because if it were to throw instead, then almost every real-world 582 // use case of tryReadlink() would be forced to perform an lstat() first for the sole purpose of 583 // checking if it is a link, wasting a syscall and a path traversal. 584 // 585 // See Directory::symlink() for warnings about symlinks. 586 }; 587 588 enum class WriteMode { 589 // Mode for opening a file (or directory) for write. 590 // 591 // (To open a file or directory read-only, do not specify a mode.) 592 // 593 // WriteMode is a bitfield. Hence, it overloads the bitwise logic operators. To check if a 594 // particular bit is set in a bitfield, use kj::has(), like: 595 // 596 // if (kj::has(mode, WriteMode::MUST_EXIST)) { 597 // requireExists(path); 598 // } 599 // 600 // (`if (mode & WriteMode::MUST_EXIST)` doesn't work because WriteMode is an enum class, which 601 // cannot be converted to bool. Alas, C++ does not allow you to define a conversion operator 602 // on an enum type, so we can't define a conversion to bool.) 603 604 // ----------------------------------------- 605 // Core flags 606 // 607 // At least one of CREATE or MODIFY must be specified. Optionally, the two flags can be combined 608 // with a bitwise-OR. 609 610 CREATE = 1, 611 // Create a new empty file. 612 // 613 // When not combined with MODIFY, if the file already exists (including as a broken symlink), 614 // tryOpenFile() returns null (and openFile() throws). 615 // 616 // When combined with MODIFY, if the path already exists, it will be opened as if CREATE hadn't 617 // been specified at all. If the path refers to a broken symlink, the file at the target of the 618 // link will be created (if its parent directory exists). 619 620 MODIFY = 2, 621 // Modify an existing file. 622 // 623 // When not combined with CREATE, if the file doesn't exist (including if it is a broken symlink), 624 // tryOpenFile() returns null (and openFile() throws). 625 // 626 // When combined with CREATE, if the path doesn't exist, it will be created as if MODIFY hadn't 627 // been specified at all. If the path refers to a broken symlink, the file at the target of the 628 // link will be created (if its parent directory exists). 629 630 // ----------------------------------------- 631 // Additional flags 632 // 633 // Any number of these may be OR'd with the core flags. 634 635 CREATE_PARENT = 4, 636 // Indicates that if the target node's parent directory doesn't exist, it should be created 637 // automatically, along with its parent, and so on. This creation is NOT atomic. 638 // 639 // This bit only makes sense with CREATE or REPLACE. 640 641 EXECUTABLE = 8, 642 // Mark this file executable, if this is a meaningful designation on the host platform. 643 644 PRIVATE = 16, 645 // Indicates that this file is sensitive and should have permissions masked so that it is only 646 // accessible by the current user. 647 // 648 // When this is not used, the platform's default access control settings are used. On Unix, 649 // that usually means the umask is applied. On Windows, it means permissions are inherited from 650 // the parent. 651 }; 652 653 inline constexpr WriteMode operator|(WriteMode a, WriteMode b) { 654 return static_cast<WriteMode>(static_cast<uint>(a) | static_cast<uint>(b)); 655 } 656 inline constexpr WriteMode operator&(WriteMode a, WriteMode b) { 657 return static_cast<WriteMode>(static_cast<uint>(a) & static_cast<uint>(b)); 658 } 659 inline constexpr WriteMode operator+(WriteMode a, WriteMode b) { 660 return static_cast<WriteMode>(static_cast<uint>(a) | static_cast<uint>(b)); 661 } 662 inline constexpr WriteMode operator-(WriteMode a, WriteMode b) { 663 return static_cast<WriteMode>(static_cast<uint>(a) & ~static_cast<uint>(b)); 664 } 665 template <typename T, typename = EnableIf<__is_enum(T)>> 666 bool has(T haystack, T needle) { 667 return (static_cast<__underlying_type(T)>(haystack) & 668 static_cast<__underlying_type(T)>(needle)) == 669 static_cast<__underlying_type(T)>(needle); 670 } 671 672 enum class TransferMode { 673 // Specifies desired behavior for Directory::transfer(). 674 675 MOVE, 676 // The node is moved to the new location, i.e. the old location is deleted. If possible, this 677 // move is performed without copying, otherwise it is performed as a copy followed by a delete. 678 679 LINK, 680 // The new location becomes a synonym for the old location (a "hard link"). Filesystems have 681 // varying support for this -- typically, it is not supported on directories. 682 683 COPY 684 // The new location becomes a copy of the old. 685 // 686 // Some filesystems may implement this in terms of copy-on-write. 687 // 688 // If the filesystem supports sparse files, COPY takes sparseness into account -- it will punch 689 // holes in the target file where holes exist in the source file. 690 }; 691 692 class Directory: public ReadableDirectory { 693 // Refers to a specific directory on disk. 694 // 695 // A `Directory` object *only* provides access to children of the directory, not parents. That 696 // is, you cannot open the file "..", nor jump to the root directory with "/". 697 // 698 // On OSs that support it, a `Directory` is backed by an open handle to the directory node. This 699 // means: 700 // - If the directory is renamed on-disk, the `Directory` object still points at it. 701 // - Opening files in the directory only requires the OS to traverse the path from the directory 702 // to the file; it doesn't have to re-traverse all the way from the filesystem root. 703 // 704 // On Windows, a `Directory` object holds a lock on the underlying directory such that it cannot 705 // be renamed nor deleted while the object exists. This is necessary because Windows does not 706 // fully support traversing paths relative to file handles (it does for some operations but not 707 // all), so the KJ filesystem implementation is forced to remember the full path and needs to 708 // ensure that the path is not invalidated. If, in the future, Windows fully supports 709 // handle-relative paths, KJ may stop locking directories in this way, so do not rely on this 710 // behavior. 711 712 public: 713 Own<const Directory> clone() const; 714 715 template <typename T> 716 class Replacer { 717 // Implements an atomic replacement of a file or directory, allowing changes to be made to 718 // storage in a way that avoids losing data in a power outage and prevents other processes 719 // from observing content in an inconsistent state. 720 // 721 // `T` may be `File` or `Directory`. For readability, the text below describes replacing a 722 // file, but the logic is the same for directories. 723 // 724 // When you call `Directory::replaceFile()`, a temporary file is created, but the specified 725 // path is not yet touched. You may call `get()` to obtain the temporary file object, through 726 // which you may initialize its content, knowing that no other process can see it yet. The file 727 // is atomically moved to its final path when you call `commit()`. If you destroy the Replacer 728 // without calling commit(), the temporary file is deleted. 729 // 730 // Note that most operating systems sadly do not support creating a truly unnamed temporary file 731 // and then linking it in later. Moreover, the file cannot necessarily be created in the system 732 // temporary directory because it might not be on the same filesystem as the target. Therefore, 733 // the replacement file may initially be created in the same directory as its eventual target. 734 // The implementation of Directory will choose a name that is unique and "hidden" according to 735 // the conventions of the filesystem. Additionally, the implementation of Directory will avoid 736 // returning these temporary files from its list*() methods, in order to avoid observable 737 // inconsistencies across platforms. 738 public: 739 explicit Replacer(WriteMode mode); 740 741 virtual const T& get() = 0; 742 // Gets the File or Directory representing the replacement data. Fill in this object before 743 // calling commit(). 744 745 void commit(); 746 virtual bool tryCommit() = 0; 747 // Commit the replacement. 748 // 749 // `tryCommit()` may return false based on the CREATE/MODIFY bits passed as the WriteMode when 750 // the replacement was initiated. (If CREATE but not MODIFY was used, tryCommit() returns 751 // false to indicate that the target file already existed. If MODIFY but not CREATE was used, 752 // tryCommit() returns false to indicate that the file didn't exist.) 753 // 754 // `commit()` is atomic, meaning that there is no point in time at which other processes 755 // observing the file will see it in an intermediate state -- they will either see the old 756 // content or the complete new content. This includes in the case of a power outage or machine 757 // failure: on recovery, the file will either be in the old state or the new state, but not in 758 // some intermediate state. 759 // 760 // It's important to note that a power failure *after commit() returns* can still revert the 761 // file to its previous state. That is, `commit()` does NOT guarantee that, upon return, the 762 // new content is durable. In order to guarantee this, you must call `sync()` on the immediate 763 // parent directory of the replaced file. 764 // 765 // Note that, sadly, not all filesystems / platforms are capable of supporting all of the 766 // guarantees documented above. In such cases, commit() will make a best-effort attempt to do 767 // what it claims. Some examples of possible problems include: 768 // - Any guarantees about durability through a power outage probably require a journaling 769 // filesystem. 770 // - Many platforms do not support atomically replacing a non-empty directory. Linux does as 771 // of kernel 3.15 (via the renameat2() syscall using RENAME_EXCHANGE). Where not supported, 772 // the old directory will be moved away just before the replacement is moved into place. 773 // - Many platforms do not support atomically requiring the existence or non-existence of a 774 // file before replacing it. In these cases, commit() may have to perform the check as a 775 // separate step, with a small window for a race condition. 776 // - Many platforms do not support "unlinking" a non-empty directory, meaning that a replaced 777 // directory will need to be deconstructed by deleting all contents. If another process has 778 // the directory open when it is replaced, that process will observe the contents 779 // disappearing after the replacement (actually, a swap) has taken place. This differs from 780 // files, where a process that has opened a file before it is replaced will continue see the 781 // file's old content unchanged after the replacement. 782 // - On Windows, there are multiple ways to replace one file with another in a single system 783 // call, but none are documented as being atomic. KJ always uses `MoveFileEx()` with 784 // MOVEFILE_REPLACE_EXISTING. While the alternative `ReplaceFile()` is attractive for many 785 // reasons, it has the critical problem that it cannot be used when the source file has open 786 // file handles, which is generally the case when using Replacer. 787 788 protected: 789 const WriteMode mode; 790 }; 791 792 using ReadableDirectory::openFile; 793 using ReadableDirectory::openSubdir; 794 using ReadableDirectory::tryOpenFile; 795 using ReadableDirectory::tryOpenSubdir; 796 797 Own<const File> openFile(PathPtr path, WriteMode mode) const; 798 virtual Maybe<Own<const File>> tryOpenFile(PathPtr path, WriteMode mode) const = 0; 799 // Open a file for writing. 800 // 801 // `tryOpenFile()` returns null if the path is required to exist but doesn't (MODIFY or REPLACE) 802 // or if the path is required not to exist but does (CREATE or RACE). These are the only cases 803 // where it returns null -- all other types of errors (like "access denied") throw exceptions. 804 805 virtual Own<Replacer<File>> replaceFile(PathPtr path, WriteMode mode) const = 0; 806 // Construct a file which, when ready, will be atomically moved to `path`, replacing whatever 807 // is there already. See `Replacer<T>` for detalis. 808 // 809 // The `CREATE` and `MODIFY` bits of `mode` are not enforced until commit time, hence 810 // `replaceFile()` has no "try" variant. 811 812 virtual Own<const File> createTemporary() const = 0; 813 // Create a temporary file backed by this directory's filesystem, but which isn't linked into 814 // the directory tree. The file is deleted from disk when all references to it have been dropped. 815 816 Own<AppendableFile> appendFile(PathPtr path, WriteMode mode) const; 817 virtual Maybe<Own<AppendableFile>> tryAppendFile(PathPtr path, WriteMode mode) const = 0; 818 // Opens the file for appending only. Useful for log files. 819 // 820 // If the underlying filesystem supports it, writes to the file will always be appended even if 821 // other writers are writing to the same file at the same time -- however, some implementations 822 // may instead assume that no other process is changing the file size between writes. 823 824 Own<const Directory> openSubdir(PathPtr path, WriteMode mode) const; 825 virtual Maybe<Own<const Directory>> tryOpenSubdir(PathPtr path, WriteMode mode) const = 0; 826 // Opens a subdirectory for writing. 827 828 virtual Own<Replacer<Directory>> replaceSubdir(PathPtr path, WriteMode mode) const = 0; 829 // Construct a directory which, when ready, will be atomically moved to `path`, replacing 830 // whatever is there already. See `Replacer<T>` for detalis. 831 // 832 // The `CREATE` and `MODIFY` bits of `mode` are not enforced until commit time, hence 833 // `replaceSubdir()` has no "try" variant. 834 835 void symlink(PathPtr linkpath, StringPtr content, WriteMode mode) const; 836 virtual bool trySymlink(PathPtr linkpath, StringPtr content, WriteMode mode) const = 0; 837 // Create a symlink. `content` is the raw text which will be written into the symlink node. 838 // How this text is interpreted is entirely dependent on the filesystem. Note in particular that: 839 // - Windows will require a path that uses backslashes as the separator. 840 // - InMemoryDirectory does not support symlinks containing "..". 841 // 842 // Unfortunately under many implementations symlink() can be used to break out of the directory 843 // by writing an absolute path or utilizing "..". Do not call this method with a value for 844 // `target` that you don't trust. 845 // 846 // `mode` must be CREATE or REPLACE, not MODIFY. CREATE_PARENT is honored but EXECUTABLE and 847 // PRIVATE have no effect. `trySymlink()` returns false in CREATE mode when the target already 848 // exists. 849 850 void transfer(PathPtr toPath, WriteMode toMode, 851 PathPtr fromPath, TransferMode mode) const; 852 void transfer(PathPtr toPath, WriteMode toMode, 853 const Directory& fromDirectory, PathPtr fromPath, 854 TransferMode mode) const; 855 virtual bool tryTransfer(PathPtr toPath, WriteMode toMode, 856 const Directory& fromDirectory, PathPtr fromPath, 857 TransferMode mode) const; 858 virtual Maybe<bool> tryTransferTo(const Directory& toDirectory, PathPtr toPath, WriteMode toMode, 859 PathPtr fromPath, TransferMode mode) const; 860 // Move, link, or copy a file/directory tree from one location to another. 861 // 862 // Filesystems vary in what kinds of transfers are allowed, especially for TransferMode::LINK, 863 // and whether TransferMode::MOVE is implemented as an actual move vs. copy+delete. 864 // 865 // tryTransfer() returns false if the source location didn't exist, or when `toMode` is CREATE 866 // and the target already exists. The default implementation implements only TransferMode::COPY. 867 // 868 // tryTransferTo() exists to implement double-dispatch. It should be called as a fallback by 869 // implementations of tryTransfer() in cases where the target directory would otherwise fail or 870 // perform a pessimal transfer. The default implementation returns nullptr, which the caller 871 // should interpret as: "I don't have any special optimizations; do the obvious thing." 872 // 873 // `toMode` controls how the target path is created. CREATE_PARENT is honored but EXECUTABLE and 874 // PRIVATE have no effect. 875 876 void remove(PathPtr path) const; 877 virtual bool tryRemove(PathPtr path) const = 0; 878 // Deletes/unlinks the given path. If the path names a directory, it is recursively deleted. 879 // 880 // tryRemove() returns false in the specific case that the path doesn't exist. remove() would 881 // throw in this case. In all other error cases (like "access denied"), tryRemove() still throws; 882 // it is only "does not exist" that produces a false return. 883 884 // TODO(someday): 885 // - Support sockets? There's no openat()-like interface for sockets, so it's hard to support 886 // them currently. Also you'd probably want to use them with the async library. 887 // - Support named pipes? Unclear if there's a use case that isn't better-served by sockets. 888 // Then again, they can be openat()ed. 889 // - Support watching for changes (inotify). Probably also requires the async library. Also 890 // lacks openat()-like semantics. 891 // - xattrs -- linux-specific 892 // - chown/chmod/etc. -- unix-specific, ACLs, eww 893 // - set timestamps -- only needed by archiving programs/ 894 // - advisory locks 895 // - sendfile? 896 // - fadvise and such 897 898 private: 899 static void commitFailed(WriteMode mode); 900 }; 901 902 class Filesystem { 903 public: 904 virtual const Directory& getRoot() const = 0; 905 // Get the filesystem's root directory, as of the time the Filesystem object was created. 906 907 virtual const Directory& getCurrent() const = 0; 908 // Get the filesystem's current directory, as of the time the Filesystem object was created. 909 910 virtual PathPtr getCurrentPath() const = 0; 911 // Get the path from the root to the current directory, as of the time the Filesystem object was 912 // created. Note that because a `Directory` does not provide access to its parent, if you want to 913 // follow `..` from the current directory, you must use `getCurrentPath().eval("..")` or 914 // `getCurrentPath().parent()`. 915 // 916 // This function attempts to determine the path as it appeared in the user's shell before this 917 // program was started. That means, if the user had `cd`ed into a symlink, the path through that 918 // symlink is returned, *not* the canonical path. 919 // 920 // Because of this, there is an important difference between how the operating system interprets 921 // "../foo" and what you get when you write `getCurrentPath().eval("../foo")`: The former 922 // will interpret ".." relative to the directory's canonical path, whereas the latter will 923 // interpret it relative to the path shown in the user's shell. In practice, the latter is 924 // almost always what the user wants! But the former behavior is what almost all commands do 925 // in practice, and it leads to confusion. KJ commands should implement the behavior the user 926 // expects. 927 }; 928 929 // ======================================================================================= 930 931 Own<File> newInMemoryFile(const Clock& clock); 932 Own<Directory> newInMemoryDirectory(const Clock& clock); 933 // Construct file and directory objects which reside in-memory. 934 // 935 // InMemoryFile has the following special properties: 936 // - The backing store is not sparse and never gets smaller even if you truncate the file. 937 // - While a non-private memory mapping exists, the backing store cannot get larger. Any operation 938 // which would expand it will throw. 939 // 940 // InMemoryDirectory has the following special properties: 941 // - Symlinks are processed using Path::parse(). This implies tha a symlink cannot point to a 942 // parent directory -- InMemoryDirectory does not know its parent. 943 // - link() can link directory nodes in addition to files. 944 // - link() and rename() accept any kind of Directory as `fromDirectory` -- it doesn't need to be 945 // another InMemoryDirectory. However, for rename(), the from path must be a directory. 946 947 Own<AppendableFile> newFileAppender(Own<const File> inner); 948 // Creates an AppendableFile by wrapping a File. Note that this implementation assumes it is the 949 // only writer. A correct implementation should always append to the file even if other writes 950 // are happening simultaneously, as is achieved with the O_APPEND flag to open(2), but that 951 // behavior is not possible to emulate on top of `File`. 952 953 #if _WIN32 954 typedef AutoCloseHandle OsFileHandle; 955 #else 956 typedef AutoCloseFd OsFileHandle; 957 #endif 958 959 Own<ReadableFile> newDiskReadableFile(OsFileHandle fd); 960 Own<AppendableFile> newDiskAppendableFile(OsFileHandle fd); 961 Own<File> newDiskFile(OsFileHandle fd); 962 Own<ReadableDirectory> newDiskReadableDirectory(OsFileHandle fd); 963 Own<Directory> newDiskDirectory(OsFileHandle fd); 964 // Wrap a file descriptor (or Windows HANDLE) as various filesystem types. 965 966 Own<Filesystem> newDiskFilesystem(); 967 // Get at implementation of `Filesystem` representing the real filesystem. 968 // 969 // DO NOT CALL THIS except at the top level of your program, e.g. in main(). Anywhere else, you 970 // should instead have your caller pass in a Filesystem object, or a specific Directory object, 971 // or whatever it is that your code needs. This ensures that your code supports dependency 972 // injection, which makes it more reusable and testable. 973 // 974 // newDiskFilesystem() reads the current working directory at the time it is called. The returned 975 // object is not affected by subsequent calls to chdir(). 976 977 // ======================================================================================= 978 // inline implementation details 979 980 inline Path::Path(decltype(nullptr)): parts(nullptr) {} 981 inline Path::Path(std::initializer_list<StringPtr> parts) 982 : Path(arrayPtr(parts.begin(), parts.end())) {} 983 inline Path::Path(Array<String> parts, decltype(ALREADY_CHECKED)) 984 : parts(kj::mv(parts)) {} 985 inline Path Path::clone() const { return PathPtr(*this).clone(); } 986 inline Path Path::append(Path&& suffix) const& { return PathPtr(*this).append(kj::mv(suffix)); } 987 inline Path Path::append(PathPtr suffix) const& { return PathPtr(*this).append(suffix); } 988 inline Path Path::append(StringPtr suffix) const& { return append(Path(suffix)); } 989 inline Path Path::append(StringPtr suffix) && { return kj::mv(*this).append(Path(suffix)); } 990 inline Path Path::append(String&& suffix) const& { return append(Path(kj::mv(suffix))); } 991 inline Path Path::append(String&& suffix) && { return kj::mv(*this).append(Path(kj::mv(suffix))); } 992 inline Path Path::eval(StringPtr pathText) const& { return PathPtr(*this).eval(pathText); } 993 inline PathPtr Path::basename() const& { return PathPtr(*this).basename(); } 994 inline PathPtr Path::parent() const& { return PathPtr(*this).parent(); } 995 inline const String& Path::operator[](size_t i) const& { return parts[i]; } 996 inline String Path::operator[](size_t i) && { return kj::mv(parts[i]); } 997 inline size_t Path::size() const { return parts.size(); } 998 inline const String* Path::begin() const { return parts.begin(); } 999 inline const String* Path::end() const { return parts.end(); } 1000 inline PathPtr Path::slice(size_t start, size_t end) const& { 1001 return PathPtr(*this).slice(start, end); 1002 } 1003 inline bool Path::operator==(PathPtr other) const { return PathPtr(*this) == other; } 1004 inline bool Path::operator!=(PathPtr other) const { return PathPtr(*this) != other; } 1005 inline bool Path::operator< (PathPtr other) const { return PathPtr(*this) < other; } 1006 inline bool Path::operator> (PathPtr other) const { return PathPtr(*this) > other; } 1007 inline bool Path::operator<=(PathPtr other) const { return PathPtr(*this) <= other; } 1008 inline bool Path::operator>=(PathPtr other) const { return PathPtr(*this) >= other; } 1009 inline bool Path::operator==(const Path& other) const { return PathPtr(*this) == PathPtr(other); } 1010 inline bool Path::operator!=(const Path& other) const { return PathPtr(*this) != PathPtr(other); } 1011 inline bool Path::operator< (const Path& other) const { return PathPtr(*this) < PathPtr(other); } 1012 inline bool Path::operator> (const Path& other) const { return PathPtr(*this) > PathPtr(other); } 1013 inline bool Path::operator<=(const Path& other) const { return PathPtr(*this) <= PathPtr(other); } 1014 inline bool Path::operator>=(const Path& other) const { return PathPtr(*this) >= PathPtr(other); } 1015 inline uint Path::hashCode() const { return kj::hashCode(parts); } 1016 inline bool Path::startsWith(PathPtr prefix) const { return PathPtr(*this).startsWith(prefix); } 1017 inline bool Path::endsWith (PathPtr suffix) const { return PathPtr(*this).endsWith (suffix); } 1018 inline String Path::toString(bool absolute) const { return PathPtr(*this).toString(absolute); } 1019 inline Path Path::evalWin32(StringPtr pathText) const& { 1020 return PathPtr(*this).evalWin32(pathText); 1021 } 1022 inline String Path::toWin32String(bool absolute) const { 1023 return PathPtr(*this).toWin32String(absolute); 1024 } 1025 inline Array<wchar_t> Path::forWin32Api(bool absolute) const { 1026 return PathPtr(*this).forWin32Api(absolute); 1027 } 1028 1029 inline PathPtr::PathPtr(decltype(nullptr)): parts(nullptr) {} 1030 inline PathPtr::PathPtr(const Path& path): parts(path.parts) {} 1031 inline PathPtr::PathPtr(ArrayPtr<const String> parts): parts(parts) {} 1032 inline Path PathPtr::append(StringPtr suffix) const { return append(Path(suffix)); } 1033 inline Path PathPtr::append(String&& suffix) const { return append(Path(kj::mv(suffix))); } 1034 inline const String& PathPtr::operator[](size_t i) const { return parts[i]; } 1035 inline size_t PathPtr::size() const { return parts.size(); } 1036 inline const String* PathPtr::begin() const { return parts.begin(); } 1037 inline const String* PathPtr::end() const { return parts.end(); } 1038 inline PathPtr PathPtr::slice(size_t start, size_t end) const { 1039 return PathPtr(parts.slice(start, end)); 1040 } 1041 inline bool PathPtr::operator!=(PathPtr other) const { return !(*this == other); } 1042 inline bool PathPtr::operator> (PathPtr other) const { return other < *this; } 1043 inline bool PathPtr::operator<=(PathPtr other) const { return !(other < *this); } 1044 inline bool PathPtr::operator>=(PathPtr other) const { return !(*this < other); } 1045 inline uint PathPtr::hashCode() const { return kj::hashCode(parts); } 1046 inline String PathPtr::toWin32String(bool absolute) const { 1047 return toWin32StringImpl(absolute, false); 1048 } 1049 1050 #if _WIN32 1051 inline Path Path::evalNative(StringPtr pathText) const& { 1052 return evalWin32(pathText); 1053 } 1054 inline Path Path::evalNative(StringPtr pathText) && { 1055 return kj::mv(*this).evalWin32(pathText); 1056 } 1057 inline String Path::toNativeString(bool absolute) const { 1058 return toWin32String(absolute); 1059 } 1060 inline Path PathPtr::evalNative(StringPtr pathText) const { 1061 return evalWin32(pathText); 1062 } 1063 inline String PathPtr::toNativeString(bool absolute) const { 1064 return toWin32String(absolute); 1065 } 1066 #else 1067 inline Path Path::evalNative(StringPtr pathText) const& { 1068 return eval(pathText); 1069 } 1070 inline Path Path::evalNative(StringPtr pathText) && { 1071 return kj::mv(*this).eval(pathText); 1072 } 1073 inline String Path::toNativeString(bool absolute) const { 1074 return toString(absolute); 1075 } 1076 inline Path PathPtr::evalNative(StringPtr pathText) const { 1077 return eval(pathText); 1078 } 1079 inline String PathPtr::toNativeString(bool absolute) const { 1080 return toString(absolute); 1081 } 1082 #endif // _WIN32, else 1083 1084 inline Own<const FsNode> FsNode::clone() const { return cloneFsNode(); } 1085 inline Own<const ReadableFile> ReadableFile::clone() const { 1086 return cloneFsNode().downcast<const ReadableFile>(); 1087 } 1088 inline Own<const AppendableFile> AppendableFile::clone() const { 1089 return cloneFsNode().downcast<const AppendableFile>(); 1090 } 1091 inline Own<const File> File::clone() const { return cloneFsNode().downcast<const File>(); } 1092 inline Own<const ReadableDirectory> ReadableDirectory::clone() const { 1093 return cloneFsNode().downcast<const ReadableDirectory>(); 1094 } 1095 inline Own<const Directory> Directory::clone() const { 1096 return cloneFsNode().downcast<const Directory>(); 1097 } 1098 1099 inline void Directory::transfer( 1100 PathPtr toPath, WriteMode toMode, PathPtr fromPath, TransferMode mode) const { 1101 return transfer(toPath, toMode, *this, fromPath, mode); 1102 } 1103 1104 template <typename T> 1105 inline Directory::Replacer<T>::Replacer(WriteMode mode): mode(mode) {} 1106 1107 template <typename T> 1108 void Directory::Replacer<T>::commit() { 1109 if (!tryCommit()) commitFailed(mode); 1110 } 1111 1112 } // namespace kj