IBR-DTNSuite  0.12
File.cpp
Go to the documentation of this file.
1 /*
2  * File.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
22 #include "ibrcommon/config.h"
23 #include "ibrcommon/data/File.h"
24 #include "ibrcommon/thread/Mutex.h"
26 #include <sstream>
27 #include <errno.h>
28 #include <sys/stat.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <cstring>
35 #include <cerrno>
36 #include <fstream>
37 
38 #if !defined(HAVE_FEATURES_H) || defined(ANDROID)
39 #include <libgen.h>
40 #endif
41 
42 #ifdef __WIN32__
43 #include <io.h>
44 #define FILE_DELIMITER_CHAR '\\'
45 #define FILE_DELIMITER "\\"
46 #else
47 #define FILE_DELIMITER_CHAR '/'
48 #define FILE_DELIMITER "/"
49 #endif
50 
51 namespace ibrcommon
52 {
54  : _type(DT_UNKNOWN), _path()
55  {
56  }
57 
58  File::File(const std::string &path, const unsigned char t)
59  : _type(t), _path(path)
60  {
61  resolveAbsolutePath();
62  removeSlash();
63  }
64 
65  File::File(const std::string &path)
66  :_type(DT_UNKNOWN), _path(path)
67  {
68  resolveAbsolutePath();
69  removeSlash();
70  update();
71  }
72 
73  void File::removeSlash()
74  {
75  if (_path == FILE_DELIMITER) return;
76 
77  std::string::iterator iter = _path.end(); --iter;
78 
79  if ((*iter) == FILE_DELIMITER_CHAR)
80  {
81  _path.erase(iter);
82  }
83  }
84 
85  void File::resolveAbsolutePath()
86  {
87 #ifndef __WIN32__
88  std::string::iterator iter = _path.begin();
89 
90  if ((*iter) != FILE_DELIMITER_CHAR)
91  {
92  _path = "." + std::string(FILE_DELIMITER) + _path;
93  }
94 #endif
95  }
96 
97  bool File::exists() const
98  {
99 #ifdef __WIN32__
100  DWORD st = GetFileAttributesA(_path.c_str());
101  if (st == INVALID_FILE_ATTRIBUTES)
102  return false;
103 
104  return true;
105 #else
106  struct stat st;
107  if( stat(_path.c_str(), &st ) == 0)
108  return true;
109 
110  return false;
111 #endif
112  }
113 
115  {
116 #ifdef __WIN32__
117  DWORD s = GetFileAttributesA(_path.c_str());
118  if (s == INVALID_FILE_ATTRIBUTES) {
119  _type = DT_UNKNOWN;
120  }
121  else if (s & FILE_ATTRIBUTE_DIRECTORY) {
122  _type = DT_DIR;
123  }
124  else {
125  _type = DT_REG;
126  }
127 #else
128  struct stat s;
129 
130  if ( stat(_path.c_str(), &s) == 0 )
131  {
132  int type = s.st_mode & S_IFMT;
133 
134  switch (type)
135  {
136  case S_IFREG:
137  _type = DT_REG;
138  break;
139 
140  case S_IFLNK:
141  _type = DT_LNK;
142  break;
143 
144  case S_IFDIR:
145  _type = DT_DIR;
146  break;
147 
148  default:
149  _type = DT_UNKNOWN;
150  break;
151  }
152  }
153 #endif
154  }
155 
157  {}
158 
159  unsigned char File::getType() const
160  {
161  return _type;
162  }
163 
164  int File::getFiles(std::list<File> &files) const
165  {
166  if (!isDirectory()) return -1;
167 
168  DIR *dp;
169  struct dirent dirp_data;
170  struct dirent *dirp;
171  if((dp = opendir(_path.c_str())) == NULL) {
172  return errno;
173  }
174 
175 #if __WIN32__
176  while ((dirp = ::readdir(dp)) != NULL)
177 #else
178  while (::readdir_r(dp, &dirp_data, &dirp) == 0)
179 #endif
180  {
181  if (dirp == NULL) break;
182 
183  // TODO: check if the name is always limited by a zero
184  // std::string name = std::string(dirp->d_name, dirp->d_reclen);
185 
186  std::string name = std::string(dirp->d_name);
187  std::stringstream ss; ss << getPath() << FILE_DELIMITER_CHAR << name;
188 #if __WIN32__
189  File file(ss.str());
190 #else
191  File file(ss.str(), dirp->d_type);
192 #endif
193  files.push_back(file);
194  }
195  closedir(dp);
196 
197  return 0;
198  }
199 
200  bool File::isRoot() const
201  {
202  return _path == FILE_DELIMITER;
203  }
204 
205  bool File::isSystem() const
206  {
207  return ((getBasename() == "..") || (getBasename() == "."));
208  }
209 
210  bool File::isDirectory() const
211  {
212  if (_type == DT_DIR) return true;
213  return false;
214  }
215 
216  string File::getPath() const
217  {
218  return _path;
219  }
220 
221  std::string File::getBasename() const
222  {
223 #if !defined(ANDROID) && defined(HAVE_FEATURES_H)
224  return std::string(basename(_path.c_str()));
225 #else
226  char path[_path.length()+1];
227  ::memcpy(&path, _path.c_str(), _path.length()+1);
228 
229  return std::string(basename(path));
230 #endif
231  }
232 
233  File File::get(const std::string &filename) const
234  {
235  stringstream ss;
236  if (!isRoot()) ss << getPath();
237  ss << FILE_DELIMITER_CHAR << filename;
238 
239  File file(ss.str());
240 
241  return file;
242  }
243 
244  int File::remove(bool recursive)
245  {
246  if (isSystem()) return -1;
247  if (_type == DT_UNKNOWN) return -1;
248 
249  if (isDirectory())
250  {
251  if (recursive)
252  {
253  int ret = 0;
254 
255  // container for all files
256  list<File> files;
257 
258  // get all files in this directory
259  if ((ret = getFiles(files)) < 0)
260  return ret;
261 
262  for (list<File>::iterator iter = files.begin(); iter != files.end(); ++iter)
263  {
264  ibrcommon::File &file = (*iter);
265  if (!file.isSystem())
266  {
267  if ((ret = file.remove(recursive)) < 0)
268  return ret;
269  }
270  }
271  }
272 
273  ::rmdir(getPath().c_str());
274  }
275  else
276  {
277  ::remove(getPath().c_str());
278  }
279 
280  return 0;
281  }
282 
284  {
285  if (isRoot()) return (*this);
286 
287  size_t pos = _path.find_last_of(FILE_DELIMITER_CHAR);
288  if (pos == string::npos) return (*this);
289  if (pos == 0) return File(FILE_DELIMITER);
290  return File(_path.substr(0, pos));
291  }
292 
294  {
295  if (!path.exists())
296  {
297  File parent = path.getParent();
298  File::createDirectory(parent);
299 
300  // create path
301 #ifdef __WIN32__
302  ::mkdir(path.getPath().c_str());
303 #else
304  ::mkdir(path.getPath().c_str(), 0700);
305 #endif
306 
307  // update file information
308  path.update();
309  }
310  }
311 
312  size_t File::size() const
313  {
314  struct stat filestatus;
315  stat( getPath().c_str(), &filestatus );
316  return static_cast<size_t>(filestatus.st_size);
317  }
318 
319  time_t File::lastaccess() const
320  {
321  struct stat filestatus;
322  stat( getPath().c_str(), &filestatus );
323  return filestatus.st_atime;
324  }
325 
326  time_t File::lastmodify() const
327  {
328  struct stat filestatus;
329  stat( getPath().c_str(), &filestatus );
330  return filestatus.st_mtime;
331  }
332 
333  time_t File::laststatchange() const
334  {
335  struct stat filestatus;
336  stat( getPath().c_str(), &filestatus );
337  return filestatus.st_ctime;
338  }
339 
340  bool File::operator==(const ibrcommon::File &other) const
341  {
342  return (other._path == _path);
343  }
344 
345  bool File::operator<(const ibrcommon::File &other) const
346  {
347  return (_path < other._path);
348  }
349 
350  TemporaryFile::TemporaryFile(const File &path, const std::string prefix)
351  : File(tmpname(path, prefix))
352  {
353  }
354 
356  {
357  }
358 
359  std::string TemporaryFile::tmpname(const File &path, const std::string prefix)
360  {
361  // check if path is a directory
362  if (!path.isDirectory())
363  {
364  throw ibrcommon::IOException("given path is not a directory.");
365  }
366 
367  std::string pattern = path.getPath() + FILE_DELIMITER_CHAR + prefix + "XXXXXX";
368 
369  std::vector<char> name(pattern.length() + 1);
370  ::strcpy(&name[0], pattern.c_str());
371 
372 #ifdef __WIN32__
373  // create temporary file - win32 style
374  int fd = -1;
375 
376  // since _mktemp is not thread-safe and _mktemp_s not available in mingw
377  // we have to lock this method globally
378  static ibrcommon::Mutex temp_mutex;
379  ibrcommon::MutexLock l(temp_mutex);
380 
381  // create temporary name
382  if (_mktemp(&name[0]) == NULL) {
383  if (errno == EINVAL) {
384  throw ibrcommon::IOException("_mktemp(): Bad parameter.");
385  }
386  else if (errno == EEXIST) {
387  throw ibrcommon::IOException("_mktemp(): Out of unique filenames.");
388  }
389  } else {
390  // create and open the temporary file
391  std::fstream file(&name[0], std::fstream::out | std::fstream::trunc);
392  if (!file.good())
393  throw ibrcommon::IOException("Could not create a temporary file.");
394  }
395 #else
396  int fd = mkstemp(&name[0]);
397  if (fd == -1) throw ibrcommon::IOException("Could not create a temporary file.");
398  ::close(fd);
399 #endif
400 
401  return std::string(name.begin(), name.end());
402  }
403 }