3 * Copyright 2004--2006, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #ifndef TALK_BASE_FILEUTILS_H_
29 #define TALK_BASE_FILEUTILS_H_
34 #include "talk/base/win32.h"
36 #include <sys/types.h>
42 #include "talk/base/basictypes.h"
43 #include "talk/base/common.h"
44 #include "talk/base/scoped_ptr.h"
51 //////////////////////////
52 // Directory Iterator //
53 //////////////////////////
55 // A DirectoryIterator is created with a given directory. It originally points
56 // to the first file in the directory, and can be advanecd with Next(). This
57 // allows you to get information about each file.
59 class DirectoryIterator {
60 friend class Filesystem;
65 virtual ~DirectoryIterator();
67 // Starts traversing a directory
68 // dir is the directory to traverse
69 // returns true if the directory exists and is valid
70 // The iterator will point to the first entry in the directory
71 virtual bool Iterate(const Pathname &path);
73 // Advances to the next file
74 // returns true if there were more files in the directory.
77 // returns true if the file currently pointed to is a directory
78 virtual bool IsDirectory() const;
80 // returns the name of the file currently pointed to
81 virtual std::string Name() const;
83 // returns the size of the file currently pointed to
84 virtual size_t FileSize() const;
86 // returns the last modified time of the file currently pointed to
87 virtual time_t FileModifyTime() const;
89 // checks whether current file is a special directory file "." or ".."
91 std::string filename(Name());
92 return (filename.compare(".") == 0) || (filename.compare("..") == 0);
96 std::string directory_;
98 WIN32_FIND_DATA data_;
102 struct dirent *dirent_;
107 enum FileTimeType { FTT_CREATED, FTT_MODIFIED, FTT_ACCESSED };
109 class FilesystemInterface {
111 virtual ~FilesystemInterface() {}
113 // Returns a DirectoryIterator for a given pathname.
114 // TODO: Do fancy abstracted stuff
115 virtual DirectoryIterator *IterateDirectory() {
116 return new DirectoryIterator();
119 // Opens a file. Returns an open StreamInterface if function succeeds.
120 // Otherwise, returns NULL.
121 // TODO: Add an error param to indicate failure reason, similar to
123 virtual FileStream *OpenFile(const Pathname &filename,
124 const std::string &mode) = 0;
126 // Atomically creates an empty file accessible only to the current user if one
127 // does not already exist at the given path, otherwise fails. This is the only
128 // secure way to create a file in a shared temp directory (e.g., C:\Temp on
129 // Windows or /tmp on Linux).
130 // Note that if it is essential that a file be successfully created then the
131 // app must generate random names and retry on failure, or else it will be
132 // vulnerable to a trivial DoS.
133 virtual bool CreatePrivateFile(const Pathname &filename) = 0;
135 // This will attempt to delete the path located at filename.
136 // It ASSERTS and returns false if the path points to a folder or a
137 // non-existent file.
138 virtual bool DeleteFile(const Pathname &filename) = 0;
140 // This will attempt to delete the empty folder located at 'folder'
141 // It ASSERTS and returns false if the path points to a file or a non-existent
142 // folder. It fails normally if the folder is not empty or can otherwise
144 virtual bool DeleteEmptyFolder(const Pathname &folder) = 0;
146 // This will call IterateDirectory, to get a directory iterator, and then
147 // call DeleteFolderAndContents and DeleteFile on every path contained in this
148 // folder. If the folder is empty, this returns true.
149 virtual bool DeleteFolderContents(const Pathname &folder);
151 // This deletes the contents of a folder, recursively, and then deletes
152 // the folder itself.
153 virtual bool DeleteFolderAndContents(const Pathname &folder) {
154 return DeleteFolderContents(folder) && DeleteEmptyFolder(folder);
157 // This will delete whatever is located at path, be it a file or a folder.
158 // If it is a folder, it will delete it recursively by calling
159 // DeleteFolderAndContents
160 bool DeleteFileOrFolder(const Pathname &path) {
162 return DeleteFolderAndContents(path);
164 return DeleteFile(path);
167 // Creates a directory. This will call itself recursively to create /foo/bar
168 // even if /foo does not exist. Returns true if the function succeeds.
169 virtual bool CreateFolder(const Pathname &pathname) = 0;
171 // This moves a file from old_path to new_path, where "old_path" is a
172 // plain file. This ASSERTs and returns false if old_path points to a
173 // directory, and returns true if the function succeeds.
174 // If the new path is on a different volume than the old path, this function
175 // will attempt to copy and, if that succeeds, delete the old path.
176 virtual bool MoveFolder(const Pathname &old_path,
177 const Pathname &new_path) = 0;
179 // This moves a directory from old_path to new_path, where "old_path" is a
180 // directory. This ASSERTs and returns false if old_path points to a plain
181 // file, and returns true if the function succeeds.
182 // If the new path is on a different volume, this function will attempt to
183 // copy and if that succeeds, delete the old path.
184 virtual bool MoveFile(const Pathname &old_path, const Pathname &new_path) = 0;
186 // This attempts to move whatever is located at old_path to new_path,
187 // be it a file or folder.
188 bool MoveFileOrFolder(const Pathname &old_path, const Pathname &new_path) {
189 if (IsFile(old_path)) {
190 return MoveFile(old_path, new_path);
192 return MoveFolder(old_path, new_path);
196 // This copies a file from old_path to new_path. This method ASSERTs and
197 // returns false if old_path is a folder, and returns true if the copy
199 virtual bool CopyFile(const Pathname &old_path, const Pathname &new_path) = 0;
201 // This copies a folder from old_path to new_path.
202 bool CopyFolder(const Pathname &old_path, const Pathname &new_path);
204 bool CopyFileOrFolder(const Pathname &old_path, const Pathname &new_path) {
205 if (IsFile(old_path))
206 return CopyFile(old_path, new_path);
208 return CopyFolder(old_path, new_path);
211 // Returns true if pathname refers to a directory
212 virtual bool IsFolder(const Pathname& pathname) = 0;
214 // Returns true if pathname refers to a file
215 virtual bool IsFile(const Pathname& pathname) = 0;
217 // Returns true if pathname refers to no filesystem object, every parent
218 // directory either exists, or is also absent.
219 virtual bool IsAbsent(const Pathname& pathname) = 0;
221 // Returns true if pathname represents a temporary location on the system.
222 virtual bool IsTemporaryPath(const Pathname& pathname) = 0;
224 // A folder appropriate for storing temporary files (Contents are
225 // automatically deleted when the program exits)
226 virtual bool GetTemporaryFolder(Pathname &path, bool create,
227 const std::string *append) = 0;
229 virtual std::string TempFilename(const Pathname &dir,
230 const std::string &prefix) = 0;
232 // Determines the size of the file indicated by path.
233 virtual bool GetFileSize(const Pathname& path, size_t* size) = 0;
235 // Determines a timestamp associated with the file indicated by path.
236 virtual bool GetFileTime(const Pathname& path, FileTimeType which,
239 // Returns the path to the running application.
240 // Note: This is not guaranteed to work on all platforms. Be aware of the
241 // limitations before using it, and robustly handle failure.
242 virtual bool GetAppPathname(Pathname* path) = 0;
244 // Get a folder that is unique to the current application, which is suitable
245 // for sharing data between executions of the app. If the per_user arg is
246 // true, the folder is also specific to the current user.
247 virtual bool GetAppDataFolder(Pathname* path, bool per_user) = 0;
249 // Get a temporary folder that is unique to the current user and application.
250 // TODO: Re-evaluate the goals of this function. We probably just need any
251 // directory that won't collide with another existing directory, and which
252 // will be cleaned up when the program exits.
253 virtual bool GetAppTempFolder(Pathname* path) = 0;
255 // Delete the contents of the folder returned by GetAppTempFolder
256 bool CleanAppTempFolder();
258 virtual bool GetDiskFreeSpace(const Pathname& path, int64 *freebytes) = 0;
260 // Returns the absolute path of the current directory.
261 virtual Pathname GetCurrentDirectory() = 0;
263 // Note: These might go into some shared config section later, but they're
264 // used by some methods in this interface, so we're leaving them here for now.
265 void SetOrganizationName(const std::string& organization) {
266 organization_name_ = organization;
268 void GetOrganizationName(std::string* organization) {
269 ASSERT(NULL != organization);
270 *organization = organization_name_;
272 void SetApplicationName(const std::string& application) {
273 application_name_ = application;
275 void GetApplicationName(std::string* application) {
276 ASSERT(NULL != application);
277 *application = application_name_;
281 std::string organization_name_;
282 std::string application_name_;
287 static FilesystemInterface *default_filesystem() {
288 ASSERT(default_filesystem_ != NULL);
289 return default_filesystem_;
292 static void set_default_filesystem(FilesystemInterface *filesystem) {
293 default_filesystem_ = filesystem;
296 static FilesystemInterface *swap_default_filesystem(
297 FilesystemInterface *filesystem) {
298 FilesystemInterface *cur = default_filesystem_;
299 default_filesystem_ = filesystem;
303 static DirectoryIterator *IterateDirectory() {
304 return EnsureDefaultFilesystem()->IterateDirectory();
307 static bool CreateFolder(const Pathname &pathname) {
308 return EnsureDefaultFilesystem()->CreateFolder(pathname);
311 static FileStream *OpenFile(const Pathname &filename,
312 const std::string &mode) {
313 return EnsureDefaultFilesystem()->OpenFile(filename, mode);
316 static bool CreatePrivateFile(const Pathname &filename) {
317 return EnsureDefaultFilesystem()->CreatePrivateFile(filename);
320 static bool DeleteFile(const Pathname &filename) {
321 return EnsureDefaultFilesystem()->DeleteFile(filename);
324 static bool DeleteEmptyFolder(const Pathname &folder) {
325 return EnsureDefaultFilesystem()->DeleteEmptyFolder(folder);
328 static bool DeleteFolderContents(const Pathname &folder) {
329 return EnsureDefaultFilesystem()->DeleteFolderContents(folder);
332 static bool DeleteFolderAndContents(const Pathname &folder) {
333 return EnsureDefaultFilesystem()->DeleteFolderAndContents(folder);
336 static bool MoveFolder(const Pathname &old_path, const Pathname &new_path) {
337 return EnsureDefaultFilesystem()->MoveFolder(old_path, new_path);
340 static bool MoveFile(const Pathname &old_path, const Pathname &new_path) {
341 return EnsureDefaultFilesystem()->MoveFile(old_path, new_path);
344 static bool CopyFolder(const Pathname &old_path, const Pathname &new_path) {
345 return EnsureDefaultFilesystem()->CopyFolder(old_path, new_path);
348 static bool CopyFile(const Pathname &old_path, const Pathname &new_path) {
349 return EnsureDefaultFilesystem()->CopyFile(old_path, new_path);
352 static bool IsFolder(const Pathname& pathname) {
353 return EnsureDefaultFilesystem()->IsFolder(pathname);
356 static bool IsFile(const Pathname &pathname) {
357 return EnsureDefaultFilesystem()->IsFile(pathname);
360 static bool IsAbsent(const Pathname &pathname) {
361 return EnsureDefaultFilesystem()->IsAbsent(pathname);
364 static bool IsTemporaryPath(const Pathname& pathname) {
365 return EnsureDefaultFilesystem()->IsTemporaryPath(pathname);
368 static bool GetTemporaryFolder(Pathname &path, bool create,
369 const std::string *append) {
370 return EnsureDefaultFilesystem()->GetTemporaryFolder(path, create, append);
373 static std::string TempFilename(const Pathname &dir,
374 const std::string &prefix) {
375 return EnsureDefaultFilesystem()->TempFilename(dir, prefix);
378 static bool GetFileSize(const Pathname& path, size_t* size) {
379 return EnsureDefaultFilesystem()->GetFileSize(path, size);
382 static bool GetFileTime(const Pathname& path, FileTimeType which,
384 return EnsureDefaultFilesystem()->GetFileTime(path, which, time);
387 static bool GetAppPathname(Pathname* path) {
388 return EnsureDefaultFilesystem()->GetAppPathname(path);
391 static bool GetAppDataFolder(Pathname* path, bool per_user) {
392 return EnsureDefaultFilesystem()->GetAppDataFolder(path, per_user);
395 static bool GetAppTempFolder(Pathname* path) {
396 return EnsureDefaultFilesystem()->GetAppTempFolder(path);
399 static bool CleanAppTempFolder() {
400 return EnsureDefaultFilesystem()->CleanAppTempFolder();
403 static bool GetDiskFreeSpace(const Pathname& path, int64 *freebytes) {
404 return EnsureDefaultFilesystem()->GetDiskFreeSpace(path, freebytes);
407 // Definition has to be in the .cc file due to returning forward-declared
408 // Pathname by value.
409 static Pathname GetCurrentDirectory();
411 static void SetOrganizationName(const std::string& organization) {
412 EnsureDefaultFilesystem()->SetOrganizationName(organization);
415 static void GetOrganizationName(std::string* organization) {
416 EnsureDefaultFilesystem()->GetOrganizationName(organization);
419 static void SetApplicationName(const std::string& application) {
420 EnsureDefaultFilesystem()->SetApplicationName(application);
423 static void GetApplicationName(std::string* application) {
424 EnsureDefaultFilesystem()->GetApplicationName(application);
428 static FilesystemInterface* default_filesystem_;
430 static FilesystemInterface *EnsureDefaultFilesystem();
431 DISALLOW_IMPLICIT_CONSTRUCTORS(Filesystem);
434 class FilesystemScope{
436 explicit FilesystemScope(FilesystemInterface *new_fs) {
437 old_fs_ = Filesystem::swap_default_filesystem(new_fs);
440 Filesystem::set_default_filesystem(old_fs_);
443 FilesystemInterface* old_fs_;
444 DISALLOW_IMPLICIT_CONSTRUCTORS(FilesystemScope);
447 // Generates a unique filename based on the input path. If no path component
448 // is specified, it uses the temporary directory. If a filename is provided,
449 // up to 100 variations of form basename-N.extension are tried. When
450 // create_empty is true, an empty file of this name is created (which
451 // decreases the chance of a temporary filename collision with another
453 bool CreateUniqueFile(Pathname& path, bool create_empty);
455 } // namespace talk_base
457 #endif // TALK_BASE_FILEUTILS_H_