blob: e58f76c7e9a6fe2055141faf516a77fbce43211f [file] [log] [blame]
henrike@webrtc.org0e118e72013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004--2006, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
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.
15 *
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.
26 */
27
28#ifndef TALK_BASE_FILEUTILS_H_
29#define TALK_BASE_FILEUTILS_H_
30
31#include <string>
32
33#ifdef WIN32
34#include "talk/base/win32.h"
35#else
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000036#include <dirent.h>
mallinath@webrtc.orgb881d272014-02-03 16:57:16 +000037#include <stdio.h>
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000038#include <sys/stat.h>
mallinath@webrtc.orgb881d272014-02-03 16:57:16 +000039#include <sys/types.h>
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000040#include <unistd.h>
41#endif
42
43#include "talk/base/basictypes.h"
44#include "talk/base/common.h"
45#include "talk/base/scoped_ptr.h"
46
47namespace talk_base {
48
49class FileStream;
50class Pathname;
51
52//////////////////////////
53// Directory Iterator //
54//////////////////////////
55
56// A DirectoryIterator is created with a given directory. It originally points
57// to the first file in the directory, and can be advanecd with Next(). This
58// allows you to get information about each file.
59
60class DirectoryIterator {
61 friend class Filesystem;
62 public:
63 // Constructor
64 DirectoryIterator();
65 // Destructor
66 virtual ~DirectoryIterator();
67
68 // Starts traversing a directory
69 // dir is the directory to traverse
70 // returns true if the directory exists and is valid
71 // The iterator will point to the first entry in the directory
72 virtual bool Iterate(const Pathname &path);
73
74 // Advances to the next file
75 // returns true if there were more files in the directory.
76 virtual bool Next();
77
78 // returns true if the file currently pointed to is a directory
79 virtual bool IsDirectory() const;
80
81 // returns the name of the file currently pointed to
82 virtual std::string Name() const;
83
84 // returns the size of the file currently pointed to
85 virtual size_t FileSize() const;
86
87 // returns the last modified time of the file currently pointed to
88 virtual time_t FileModifyTime() const;
89
90 // checks whether current file is a special directory file "." or ".."
91 bool IsDots() const {
92 std::string filename(Name());
93 return (filename.compare(".") == 0) || (filename.compare("..") == 0);
94 }
95
96 private:
97 std::string directory_;
98#ifdef WIN32
99 WIN32_FIND_DATA data_;
100 HANDLE handle_;
101#else
102 DIR *dir_;
103 struct dirent *dirent_;
104 struct stat stat_;
105#endif
106};
107
108enum FileTimeType { FTT_CREATED, FTT_MODIFIED, FTT_ACCESSED };
109
110class FilesystemInterface {
111 public:
112 virtual ~FilesystemInterface() {}
113
114 // Returns a DirectoryIterator for a given pathname.
115 // TODO: Do fancy abstracted stuff
116 virtual DirectoryIterator *IterateDirectory() {
117 return new DirectoryIterator();
118 }
119
120 // Opens a file. Returns an open StreamInterface if function succeeds.
121 // Otherwise, returns NULL.
122 // TODO: Add an error param to indicate failure reason, similar to
123 // FileStream::Open
124 virtual FileStream *OpenFile(const Pathname &filename,
125 const std::string &mode) = 0;
126
127 // Atomically creates an empty file accessible only to the current user if one
128 // does not already exist at the given path, otherwise fails. This is the only
129 // secure way to create a file in a shared temp directory (e.g., C:\Temp on
130 // Windows or /tmp on Linux).
131 // Note that if it is essential that a file be successfully created then the
132 // app must generate random names and retry on failure, or else it will be
133 // vulnerable to a trivial DoS.
134 virtual bool CreatePrivateFile(const Pathname &filename) = 0;
135
136 // This will attempt to delete the path located at filename.
137 // It ASSERTS and returns false if the path points to a folder or a
138 // non-existent file.
139 virtual bool DeleteFile(const Pathname &filename) = 0;
140
141 // This will attempt to delete the empty folder located at 'folder'
142 // It ASSERTS and returns false if the path points to a file or a non-existent
143 // folder. It fails normally if the folder is not empty or can otherwise
144 // not be deleted.
145 virtual bool DeleteEmptyFolder(const Pathname &folder) = 0;
146
147 // This will call IterateDirectory, to get a directory iterator, and then
148 // call DeleteFolderAndContents and DeleteFile on every path contained in this
149 // folder. If the folder is empty, this returns true.
150 virtual bool DeleteFolderContents(const Pathname &folder);
151
152 // This deletes the contents of a folder, recursively, and then deletes
153 // the folder itself.
154 virtual bool DeleteFolderAndContents(const Pathname &folder) {
155 return DeleteFolderContents(folder) && DeleteEmptyFolder(folder);
156 }
157
158 // This will delete whatever is located at path, be it a file or a folder.
159 // If it is a folder, it will delete it recursively by calling
160 // DeleteFolderAndContents
161 bool DeleteFileOrFolder(const Pathname &path) {
162 if (IsFolder(path))
163 return DeleteFolderAndContents(path);
164 else
165 return DeleteFile(path);
166 }
167
168 // Creates a directory. This will call itself recursively to create /foo/bar
169 // even if /foo does not exist. Returns true if the function succeeds.
170 virtual bool CreateFolder(const Pathname &pathname) = 0;
171
172 // This moves a file from old_path to new_path, where "old_path" is a
173 // plain file. This ASSERTs and returns false if old_path points to a
174 // directory, and returns true if the function succeeds.
175 // If the new path is on a different volume than the old path, this function
176 // will attempt to copy and, if that succeeds, delete the old path.
177 virtual bool MoveFolder(const Pathname &old_path,
178 const Pathname &new_path) = 0;
179
180 // This moves a directory from old_path to new_path, where "old_path" is a
181 // directory. This ASSERTs and returns false if old_path points to a plain
182 // file, and returns true if the function succeeds.
183 // If the new path is on a different volume, this function will attempt to
184 // copy and if that succeeds, delete the old path.
185 virtual bool MoveFile(const Pathname &old_path, const Pathname &new_path) = 0;
186
187 // This attempts to move whatever is located at old_path to new_path,
188 // be it a file or folder.
189 bool MoveFileOrFolder(const Pathname &old_path, const Pathname &new_path) {
190 if (IsFile(old_path)) {
191 return MoveFile(old_path, new_path);
192 } else {
193 return MoveFolder(old_path, new_path);
194 }
195 }
196
197 // This copies a file from old_path to new_path. This method ASSERTs and
198 // returns false if old_path is a folder, and returns true if the copy
199 // succeeds.
200 virtual bool CopyFile(const Pathname &old_path, const Pathname &new_path) = 0;
201
202 // This copies a folder from old_path to new_path.
203 bool CopyFolder(const Pathname &old_path, const Pathname &new_path);
204
205 bool CopyFileOrFolder(const Pathname &old_path, const Pathname &new_path) {
206 if (IsFile(old_path))
207 return CopyFile(old_path, new_path);
208 else
209 return CopyFolder(old_path, new_path);
210 }
211
212 // Returns true if pathname refers to a directory
213 virtual bool IsFolder(const Pathname& pathname) = 0;
214
215 // Returns true if pathname refers to a file
216 virtual bool IsFile(const Pathname& pathname) = 0;
217
218 // Returns true if pathname refers to no filesystem object, every parent
219 // directory either exists, or is also absent.
220 virtual bool IsAbsent(const Pathname& pathname) = 0;
221
222 // Returns true if pathname represents a temporary location on the system.
223 virtual bool IsTemporaryPath(const Pathname& pathname) = 0;
224
225 // A folder appropriate for storing temporary files (Contents are
226 // automatically deleted when the program exits)
227 virtual bool GetTemporaryFolder(Pathname &path, bool create,
228 const std::string *append) = 0;
229
230 virtual std::string TempFilename(const Pathname &dir,
231 const std::string &prefix) = 0;
232
233 // Determines the size of the file indicated by path.
234 virtual bool GetFileSize(const Pathname& path, size_t* size) = 0;
235
236 // Determines a timestamp associated with the file indicated by path.
237 virtual bool GetFileTime(const Pathname& path, FileTimeType which,
238 time_t* time) = 0;
239
240 // Returns the path to the running application.
241 // Note: This is not guaranteed to work on all platforms. Be aware of the
242 // limitations before using it, and robustly handle failure.
243 virtual bool GetAppPathname(Pathname* path) = 0;
244
245 // Get a folder that is unique to the current application, which is suitable
246 // for sharing data between executions of the app. If the per_user arg is
247 // true, the folder is also specific to the current user.
248 virtual bool GetAppDataFolder(Pathname* path, bool per_user) = 0;
249
250 // Get a temporary folder that is unique to the current user and application.
251 // TODO: Re-evaluate the goals of this function. We probably just need any
252 // directory that won't collide with another existing directory, and which
253 // will be cleaned up when the program exits.
254 virtual bool GetAppTempFolder(Pathname* path) = 0;
255
256 // Delete the contents of the folder returned by GetAppTempFolder
257 bool CleanAppTempFolder();
258
259 virtual bool GetDiskFreeSpace(const Pathname& path, int64 *freebytes) = 0;
260
261 // Returns the absolute path of the current directory.
262 virtual Pathname GetCurrentDirectory() = 0;
263
264 // Note: These might go into some shared config section later, but they're
265 // used by some methods in this interface, so we're leaving them here for now.
266 void SetOrganizationName(const std::string& organization) {
267 organization_name_ = organization;
268 }
269 void GetOrganizationName(std::string* organization) {
270 ASSERT(NULL != organization);
271 *organization = organization_name_;
272 }
273 void SetApplicationName(const std::string& application) {
274 application_name_ = application;
275 }
276 void GetApplicationName(std::string* application) {
277 ASSERT(NULL != application);
278 *application = application_name_;
279 }
280
281 protected:
282 std::string organization_name_;
283 std::string application_name_;
284};
285
286class Filesystem {
287 public:
288 static FilesystemInterface *default_filesystem() {
289 ASSERT(default_filesystem_ != NULL);
290 return default_filesystem_;
291 }
292
293 static void set_default_filesystem(FilesystemInterface *filesystem) {
294 default_filesystem_ = filesystem;
295 }
296
297 static FilesystemInterface *swap_default_filesystem(
298 FilesystemInterface *filesystem) {
299 FilesystemInterface *cur = default_filesystem_;
300 default_filesystem_ = filesystem;
301 return cur;
302 }
303
304 static DirectoryIterator *IterateDirectory() {
305 return EnsureDefaultFilesystem()->IterateDirectory();
306 }
307
308 static bool CreateFolder(const Pathname &pathname) {
309 return EnsureDefaultFilesystem()->CreateFolder(pathname);
310 }
311
312 static FileStream *OpenFile(const Pathname &filename,
313 const std::string &mode) {
314 return EnsureDefaultFilesystem()->OpenFile(filename, mode);
315 }
316
317 static bool CreatePrivateFile(const Pathname &filename) {
318 return EnsureDefaultFilesystem()->CreatePrivateFile(filename);
319 }
320
321 static bool DeleteFile(const Pathname &filename) {
322 return EnsureDefaultFilesystem()->DeleteFile(filename);
323 }
324
325 static bool DeleteEmptyFolder(const Pathname &folder) {
326 return EnsureDefaultFilesystem()->DeleteEmptyFolder(folder);
327 }
328
329 static bool DeleteFolderContents(const Pathname &folder) {
330 return EnsureDefaultFilesystem()->DeleteFolderContents(folder);
331 }
332
333 static bool DeleteFolderAndContents(const Pathname &folder) {
334 return EnsureDefaultFilesystem()->DeleteFolderAndContents(folder);
335 }
336
337 static bool MoveFolder(const Pathname &old_path, const Pathname &new_path) {
338 return EnsureDefaultFilesystem()->MoveFolder(old_path, new_path);
339 }
340
341 static bool MoveFile(const Pathname &old_path, const Pathname &new_path) {
342 return EnsureDefaultFilesystem()->MoveFile(old_path, new_path);
343 }
344
345 static bool CopyFolder(const Pathname &old_path, const Pathname &new_path) {
346 return EnsureDefaultFilesystem()->CopyFolder(old_path, new_path);
347 }
348
349 static bool CopyFile(const Pathname &old_path, const Pathname &new_path) {
350 return EnsureDefaultFilesystem()->CopyFile(old_path, new_path);
351 }
352
353 static bool IsFolder(const Pathname& pathname) {
354 return EnsureDefaultFilesystem()->IsFolder(pathname);
355 }
356
357 static bool IsFile(const Pathname &pathname) {
358 return EnsureDefaultFilesystem()->IsFile(pathname);
359 }
360
361 static bool IsAbsent(const Pathname &pathname) {
362 return EnsureDefaultFilesystem()->IsAbsent(pathname);
363 }
364
365 static bool IsTemporaryPath(const Pathname& pathname) {
366 return EnsureDefaultFilesystem()->IsTemporaryPath(pathname);
367 }
368
369 static bool GetTemporaryFolder(Pathname &path, bool create,
370 const std::string *append) {
371 return EnsureDefaultFilesystem()->GetTemporaryFolder(path, create, append);
372 }
373
374 static std::string TempFilename(const Pathname &dir,
375 const std::string &prefix) {
376 return EnsureDefaultFilesystem()->TempFilename(dir, prefix);
377 }
378
379 static bool GetFileSize(const Pathname& path, size_t* size) {
380 return EnsureDefaultFilesystem()->GetFileSize(path, size);
381 }
382
383 static bool GetFileTime(const Pathname& path, FileTimeType which,
384 time_t* time) {
385 return EnsureDefaultFilesystem()->GetFileTime(path, which, time);
386 }
387
388 static bool GetAppPathname(Pathname* path) {
389 return EnsureDefaultFilesystem()->GetAppPathname(path);
390 }
391
392 static bool GetAppDataFolder(Pathname* path, bool per_user) {
393 return EnsureDefaultFilesystem()->GetAppDataFolder(path, per_user);
394 }
395
396 static bool GetAppTempFolder(Pathname* path) {
397 return EnsureDefaultFilesystem()->GetAppTempFolder(path);
398 }
399
400 static bool CleanAppTempFolder() {
401 return EnsureDefaultFilesystem()->CleanAppTempFolder();
402 }
403
404 static bool GetDiskFreeSpace(const Pathname& path, int64 *freebytes) {
405 return EnsureDefaultFilesystem()->GetDiskFreeSpace(path, freebytes);
406 }
407
408 // Definition has to be in the .cc file due to returning forward-declared
409 // Pathname by value.
410 static Pathname GetCurrentDirectory();
411
412 static void SetOrganizationName(const std::string& organization) {
413 EnsureDefaultFilesystem()->SetOrganizationName(organization);
414 }
415
416 static void GetOrganizationName(std::string* organization) {
417 EnsureDefaultFilesystem()->GetOrganizationName(organization);
418 }
419
420 static void SetApplicationName(const std::string& application) {
421 EnsureDefaultFilesystem()->SetApplicationName(application);
422 }
423
424 static void GetApplicationName(std::string* application) {
425 EnsureDefaultFilesystem()->GetApplicationName(application);
426 }
427
428 private:
429 static FilesystemInterface* default_filesystem_;
430
431 static FilesystemInterface *EnsureDefaultFilesystem();
432 DISALLOW_IMPLICIT_CONSTRUCTORS(Filesystem);
433};
434
435class FilesystemScope{
436 public:
437 explicit FilesystemScope(FilesystemInterface *new_fs) {
438 old_fs_ = Filesystem::swap_default_filesystem(new_fs);
439 }
440 ~FilesystemScope() {
441 Filesystem::set_default_filesystem(old_fs_);
442 }
443 private:
444 FilesystemInterface* old_fs_;
445 DISALLOW_IMPLICIT_CONSTRUCTORS(FilesystemScope);
446};
447
448// Generates a unique filename based on the input path. If no path component
449// is specified, it uses the temporary directory. If a filename is provided,
450// up to 100 variations of form basename-N.extension are tried. When
451// create_empty is true, an empty file of this name is created (which
452// decreases the chance of a temporary filename collision with another
453// process).
454bool CreateUniqueFile(Pathname& path, bool create_empty);
455
wu@webrtc.org1b571312014-01-23 22:12:45 +0000456// Taken from Chromium's base/platform_file.h.
457// Don't use ClosePlatformFile to close a file opened with FdopenPlatformFile.
458// Use fclose instead.
459// TODO(grunell): Remove when Chromium has started to use AEC in each source.
460// http://crbug.com/264611.
461#if defined(WIN32)
462typedef HANDLE PlatformFile;
463const PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE;
mallinath@webrtc.org62373d62014-01-28 06:58:42 +0000464#elif defined(POSIX)
wu@webrtc.org1b571312014-01-23 22:12:45 +0000465typedef int PlatformFile;
466const PlatformFile kInvalidPlatformFileValue = -1;
mallinath@webrtc.orgb881d272014-02-03 16:57:16 +0000467#else
468#error Unsupported platform
wu@webrtc.org1b571312014-01-23 22:12:45 +0000469#endif
mallinath@webrtc.orgb881d272014-02-03 16:57:16 +0000470
wu@webrtc.org1b571312014-01-23 22:12:45 +0000471FILE* FdopenPlatformFileForWriting(PlatformFile file);
472bool ClosePlatformFile(PlatformFile file);
473
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000474} // namespace talk_base
475
476#endif // TALK_BASE_FILEUTILS_H_