~ubuntu-branches/debian/experimental/kopete/experimental

« back to all changes in this revision

Viewing changes to protocols/jabber/libjingle/talk/base/fileutils.cc

  • Committer: Package Import Robot
  • Author(s): Maximiliano Curia
  • Date: 2015-02-24 11:32:57 UTC
  • mfrom: (1.1.41 vivid)
  • Revision ID: package-import@ubuntu.com-20150224113257-gnupg4v7lzz18ij0
Tags: 4:14.12.2-1
* New upstream release (14.12.2).
* Bump Standards-Version to 3.9.6, no changes needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include <cassert>
 
29
 
 
30
#ifdef WIN32
 
31
#include "talk/base/win32.h"
 
32
#endif
 
33
 
 
34
#include "talk/base/pathutils.h"
 
35
#include "talk/base/fileutils.h"
 
36
#include "talk/base/stringutils.h"
 
37
#include "talk/base/stream.h"
 
38
 
 
39
#include "talk/base/unixfilesystem.h"
 
40
#include "talk/base/win32filesystem.h"
 
41
 
 
42
#ifndef WIN32
 
43
#define MAX_PATH 260
 
44
#endif
 
45
 
 
46
namespace talk_base {
 
47
 
 
48
//////////////////////////
 
49
// Directory Iterator   //
 
50
//////////////////////////
 
51
 
 
52
// A DirectoryIterator is created with a given directory. It originally points
 
53
// to the first file in the directory, and can be advanecd with Next(). This
 
54
// allows you to get information about each file.
 
55
 
 
56
  // Constructor
 
57
DirectoryIterator::DirectoryIterator()
 
58
#ifdef _WIN32
 
59
    : handle_(INVALID_HANDLE_VALUE) {
 
60
#else
 
61
    : dir_(NULL), dirent_(NULL) {
 
62
#endif
 
63
}
 
64
 
 
65
  // Destructor
 
66
DirectoryIterator::~DirectoryIterator() {
 
67
#ifdef WIN32
 
68
  if (handle_ != INVALID_HANDLE_VALUE)
 
69
    ::FindClose(handle_);
 
70
#else
 
71
  if (dir_)
 
72
    closedir(dir_);
 
73
#endif
 
74
}
 
75
 
 
76
  // Starts traversing a directory.
 
77
  // dir is the directory to traverse
 
78
  // returns true if the directory exists and is valid
 
79
bool DirectoryIterator::Iterate(const Pathname &dir) {
 
80
  directory_ = dir.pathname();
 
81
#ifdef WIN32
 
82
  if (handle_ != INVALID_HANDLE_VALUE)
 
83
    ::FindClose(handle_);
 
84
  std::string d = dir.pathname() + '*';
 
85
  handle_ = ::FindFirstFile(ToUtf16(d).c_str(), &data_);
 
86
  if (handle_ == INVALID_HANDLE_VALUE)
 
87
    return false;
 
88
#else
 
89
  if (dir_ != NULL)
 
90
    closedir(dir_);
 
91
  dir_ = ::opendir(directory_.c_str());
 
92
  if (dir_ == NULL)
 
93
    return false;
 
94
  dirent_ = readdir(dir_);
 
95
  if (dirent_ == NULL)
 
96
    return false;
 
97
 
 
98
  if (::stat(std::string(directory_ + Name()).c_str(), &stat_) != 0)
 
99
    return false;
 
100
#endif
 
101
  return true;
 
102
}
 
103
 
 
104
  // Advances to the next file
 
105
  // returns true if there were more files in the directory.
 
106
bool DirectoryIterator::Next() {
 
107
#ifdef WIN32
 
108
  return ::FindNextFile(handle_, &data_) == TRUE;
 
109
#else
 
110
  dirent_ = ::readdir(dir_);
 
111
  if (dirent_ == NULL)
 
112
    return false;
 
113
 
 
114
  return ::stat(std::string(directory_ + Name()).c_str(), &stat_) == 0;
 
115
#endif
 
116
}
 
117
 
 
118
  // returns true if the file currently pointed to is a directory
 
119
bool DirectoryIterator::IsDirectory() const {
 
120
#ifdef WIN32
 
121
  return (data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FALSE;
 
122
#else
 
123
  return S_ISDIR(stat_.st_mode);
 
124
#endif
 
125
}
 
126
 
 
127
  // returns the name of the file currently pointed to
 
128
std::string DirectoryIterator::Name() const {
 
129
#ifdef WIN32
 
130
  return ToUtf8(data_.cFileName);
 
131
#else
 
132
  assert(dirent_ != NULL);
 
133
  return dirent_->d_name;
 
134
#endif
 
135
}
 
136
 
 
137
  // returns the size of the file currently pointed to
 
138
size_t DirectoryIterator::FileSize() const {
 
139
#ifndef WIN32
 
140
  return stat_.st_size;
 
141
#else
 
142
  return data_.nFileSizeLow;
 
143
#endif
 
144
}
 
145
 
 
146
  // returns the last modified time of this file
 
147
time_t DirectoryIterator::FileModifyTime() const {
 
148
#ifdef WIN32
 
149
  time_t val;
 
150
  FileTimeToUnixTime(data_.ftLastWriteTime, &val);
 
151
  return val;
 
152
#else
 
153
  return stat_.st_mtime;
 
154
#endif
 
155
}
 
156
 
 
157
FilesystemInterface* Filesystem::default_filesystem_ = NULL;
 
158
 
 
159
FilesystemInterface *Filesystem::EnsureDefaultFilesystem() {
 
160
  if (!default_filesystem_) {
 
161
#ifdef WIN32
 
162
    default_filesystem_ = new Win32Filesystem();
 
163
#else
 
164
    default_filesystem_ = new UnixFilesystem();
 
165
#endif
 
166
  }
 
167
  return default_filesystem_;
 
168
}
 
169
 
 
170
bool FilesystemInterface::CopyFolder(const Pathname &old_path,
 
171
                                     const Pathname &new_path) {
 
172
  bool success = true;
 
173
  VERIFY(IsFolder(old_path));
 
174
  Pathname new_dir;
 
175
  new_dir.SetFolder(new_path.pathname());
 
176
  Pathname old_dir;
 
177
  old_dir.SetFolder(old_path.pathname());
 
178
  if (!CreateFolder(new_dir))
 
179
    return false;
 
180
  DirectoryIterator *di = IterateDirectory();
 
181
  if (!di)
 
182
    return false;
 
183
  if (di->Iterate(old_dir.pathname())) {
 
184
    do {
 
185
      if (di->Name() == "." || di->Name() == "..")
 
186
        continue;
 
187
      Pathname source;
 
188
      Pathname dest;
 
189
      source.SetFolder(old_dir.pathname());
 
190
      dest.SetFolder(new_path.pathname());
 
191
      source.SetFilename(di->Name());
 
192
      dest.SetFilename(di->Name());
 
193
      if (!CopyFileOrFolder(source, dest))
 
194
        success = false;
 
195
    } while (di->Next());
 
196
  }
 
197
  delete di;
 
198
  return success;
 
199
}
 
200
 
 
201
bool FilesystemInterface::DeleteFolderContents(const Pathname &folder) {
 
202
  bool success = true;
 
203
  VERIFY(IsFolder(folder));
 
204
  DirectoryIterator *di = IterateDirectory();
 
205
  if (!di)
 
206
    return false;
 
207
  if (di->Iterate(folder)) {
 
208
    do {
 
209
      if (di->Name() == "." || di->Name() == "..")
 
210
        continue;
 
211
      Pathname subdir;
 
212
      subdir.SetFolder(folder.pathname());
 
213
      if (di->IsDirectory()) {
 
214
        subdir.AppendFolder(di->Name());
 
215
        if (!DeleteFolderAndContents(subdir)) {
 
216
          success = false;
 
217
        }
 
218
      } else {
 
219
        subdir.SetFilename(di->Name());
 
220
        if (!DeleteFile(subdir)) {
 
221
          success = false;
 
222
        }
 
223
      }
 
224
    } while (di->Next());
 
225
  }
 
226
  delete di;
 
227
  return success;
 
228
}
 
229
 
 
230
bool FilesystemInterface::CleanAppTempFolder() {
 
231
  Pathname path;
 
232
  if (!GetAppTempFolder(&path))
 
233
    return false;
 
234
  if (IsAbsent(path))
 
235
    return true;
 
236
  if (!IsTemporaryPath(path)) {
 
237
    ASSERT(false);
 
238
    return false;
 
239
  }
 
240
  return DeleteFolderContents(path);
 
241
}
 
242
 
 
243
Pathname Filesystem::GetCurrentDirectory() {
 
244
  return EnsureDefaultFilesystem()->GetCurrentDirectory();
 
245
}
 
246
 
 
247
bool CreateUniqueFile(Pathname& path, bool create_empty) {
 
248
  LOG(LS_INFO) << "Path " << path.pathname() << std::endl;
 
249
  // If no folder is supplied, use the temporary folder
 
250
  if (path.folder().empty()) {
 
251
    Pathname temporary_path;
 
252
    if (!Filesystem::GetTemporaryFolder(temporary_path, true, NULL)) {
 
253
      printf("Get temp failed\n");
 
254
      return false;
 
255
    }
 
256
    path.SetFolder(temporary_path.pathname());
 
257
  }
 
258
 
 
259
  // If no filename is supplied, use a temporary name
 
260
  if (path.filename().empty()) {
 
261
    std::string folder(path.folder());
 
262
    std::string filename = Filesystem::TempFilename(folder, "gt");
 
263
    path.SetPathname(filename);
 
264
    if (!create_empty) {
 
265
      Filesystem::DeleteFile(path.pathname());
 
266
    }
 
267
    return true;
 
268
  }
 
269
 
 
270
  // Otherwise, create a unique name based on the given filename
 
271
  // foo.txt -> foo-N.txt
 
272
  const std::string basename = path.basename();
 
273
  const size_t MAX_VERSION = 100;
 
274
  size_t version = 0;
 
275
  while (version < MAX_VERSION) {
 
276
    std::string pathname = path.pathname();
 
277
 
 
278
    if (!Filesystem::IsFile(pathname)) {
 
279
      if (create_empty) {
 
280
        FileStream* fs = Filesystem::OpenFile(pathname, "w");
 
281
        delete fs;
 
282
      }
 
283
      return true;
 
284
    }
 
285
    version += 1;
 
286
    char version_base[MAX_PATH];
 
287
    sprintfn(version_base, ARRAY_SIZE(version_base), "%s-%u",
 
288
             basename.c_str(), version);
 
289
    path.SetBasename(version_base);
 
290
  }
 
291
  return true;
 
292
}
 
293
 
 
294
}  // namespace talk_base