1 // Copyright (c) 2013, Thomas Goyne <plorkyeran@aegisub.org> 2 // 3 // Permission to use, copy, modify, and distribute this software for any 4 // purpose with or without fee is hereby granted, provided that the above 5 // copyright notice and this permission notice appear in all copies. 6 // 7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 // 15 // Aegisub Project http://www.aegisub.org/ 16 17 #include <libaegisub/exception.h> 18 #include <libaegisub/fs_fwd.h> 19 20 #include <boost/filesystem/path.hpp> 21 #include <cstdint> 22 #include <ctime> 23 #include <iterator> 24 #include <memory> 25 #include <string> 26 27 #undef CreateDirectory 28 29 namespace agi { 30 namespace fs { 31 /// Define a filesystem error which takes a path or a string 32 #define DEFINE_FS_EXCEPTION(type, base, message) \ 33 struct type : public base { \ 34 type(path const& p) : base(message + p.string()) { } \ 35 type(std::string const& s) : base(s) { } \ 36 const char *GetName() const { return ""; } \ 37 Exception *Copy() const { return new type(*this); } \ 38 } 39 40 /// @class agi::FileSystemError 41 /// @extends agi::Exception 42 /// @brief Base class for errors related to the file system 43 /// 44 /// This base class can not be instantiated. 45 /// File system errors do not support inner exceptions, as they 46 /// are always originating causes for errors. 47 DEFINE_EXCEPTION(FileSystemError, Exception); 48 49 /// A file can't be accessed for some reason 50 DEFINE_FS_EXCEPTION(FileNotAccessible, FileSystemError, "File is not accessible: "); 51 52 /// A file can't be accessed because there's no file by the given name 53 DEFINE_FS_EXCEPTION(FileNotFound, FileNotAccessible, "File not found: "); 54 55 /// An error of some unknown type has occured 56 DEFINE_EXCEPTION(FileSystemUnknownError, FileSystemError);; 57 58 /// The path exists, but isn't a file 59 DEFINE_FS_EXCEPTION(NotAFile, FileNotAccessible, "Path is not a file (and should be): "); 60 61 /// The path exists, but isn't a directory 62 DEFINE_FS_EXCEPTION(NotADirectory, FileNotAccessible, "Path is not a directory (and should be): "); 63 64 /// The given path is too long for the filesystem 65 DEFINE_FS_EXCEPTION(PathTooLog, FileSystemError, "Path is too long: "); 66 67 /// Insufficient free space to complete operation 68 DEFINE_FS_EXCEPTION(DriveFull, FileSystemError, "Insufficient free space to write file: "); 69 70 /// Base class for access denied errors 71 DEFINE_FS_EXCEPTION(AccessDenied, FileNotAccessible, "Access denied to path: "); 72 73 /// Trying to read the file gave an access denied error 74 DEFINE_FS_EXCEPTION(ReadDenied, AccessDenied, "Access denied when trying to read: "); 75 76 /// Trying to write the file gave an access denied error 77 DEFINE_FS_EXCEPTION(WriteDenied, AccessDenied, "Access denied when trying to write: "); 78 79 /// File exists and cannot be overwritten due to being read-only 80 DEFINE_FS_EXCEPTION(ReadOnlyFile, WriteDenied, "File is read-only: "); 81 82 bool Exists(path const& p); 83 bool FileExists(path const& file); 84 bool DirectoryExists(path const& dir); 85 86 /// Get the local-charset encoded shortname for a file 87 /// 88 /// This is purely for compatibility with external libraries which do 89 /// not support unicode filenames on Windows. On all other platforms, 90 /// it is a no-op. 91 std::string ShortName(path const& file_path); 92 93 /// Check for amount of free space on a path 94 uintmax_t FreeSpace(path const& dir_path); 95 96 /// Get the size in bytes of the file at path 97 /// 98 /// @throws agi::FileNotFound if path does not exist 99 /// @throws agi::acs::NotAFile if path is a directory 100 /// @throws agi::acs::Read if path exists but could not be read 101 uintmax_t Size(path const& file_path); 102 103 /// Get the modification time of the file at path 104 /// 105 /// @throws agi::FileNotFound if path does not exist 106 /// @throws agi::acs::NotAFile if path is a directory 107 /// @throws agi::acs::Read if path exists but could not be read 108 time_t ModifiedTime(path const& file_path); 109 110 /// Create a directory and all required intermediate directories 111 /// @throws agi::acs::Write if the directory could not be created. 112 /// 113 /// Trying to create a directory which already exists is not an error. 114 bool CreateDirectory(path const& dir_path); 115 116 /// Touch the given path 117 /// 118 /// Creates the file if it does not exist, or updates the modified 119 /// time if it does 120 void Touch(path const& file_path); 121 122 /// Rename a file or directory 123 /// @param from Source path 124 /// @param to Destination path 125 void Rename(path const& from, path const& to); 126 127 /// Copy a file 128 /// @param from Source path 129 /// @param to Destination path 130 /// 131 /// The destination path will be created if it does not exist. 132 void Copy(path const& from, path const& to); 133 134 /// Delete a file 135 /// @param path Path to file to delete 136 /// @throws agi::FileNotAccessibleError if file exists but could not be deleted 137 bool Remove(path const& file); 138 139 /// Check if the file has the given extension 140 /// @param p Path to check 141 /// @param ext Case-insensitive extension, without leading dot 142 bool HasExtension(path const& p, std::string const& ext); 143 144 agi::fs::path Canonicalize(agi::fs::path const& path); 145 146 class DirectoryIterator { 147 struct PrivData; 148 std::shared_ptr<PrivData> privdata; 149 std::string value; 150 public: 151 typedef path value_type; 152 typedef path* pointer; 153 typedef path& reference; 154 typedef size_t difference_type; 155 typedef std::forward_iterator_tag iterator_category; 156 157 bool operator==(DirectoryIterator const&) const; 158 bool operator!=(DirectoryIterator const& rhs) const { return !(*this == rhs); } 159 DirectoryIterator& operator++(); 160 std::string const& operator*() const { return value; } 161 162 DirectoryIterator(path const& p, std::string const& filter); 163 DirectoryIterator(); 164 ~DirectoryIterator(); 165 166 template<typename T> void GetAll(T& cont); 167 }; 168 begin(DirectoryIterator & it)169 inline DirectoryIterator& begin(DirectoryIterator &it) { return it; } end(DirectoryIterator &)170 inline DirectoryIterator end(DirectoryIterator &) { return DirectoryIterator(); } 171 172 template<typename T> GetAll(T & cont)173 inline void DirectoryIterator::GetAll(T& cont) { 174 copy(*this, end(*this), std::back_inserter(cont)); 175 } 176 } 177 } 178