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