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