IBR-DTNSuite  0.10
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 <sstream>
25 #include <errno.h>
26 #include <sys/stat.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <cstring>
33 #include <cerrno>
34 
35 #if !defined(HAVE_FEATURES_H) || defined(ANDROID)
36 #include <libgen.h>
37 #endif
38 
39 namespace ibrcommon
40 {
42  : _path(), _type(DT_UNKNOWN)
43  {
44  }
45 
46  File::File(const std::string &path, const unsigned char t)
47  : _path(path), _type(t)
48  {
49  resolveAbsolutePath();
50  removeSlash();
51  }
52 
53  File::File(const std::string &path)
54  : _path(path), _type(DT_UNKNOWN)
55  {
56  resolveAbsolutePath();
57  removeSlash();
58  update();
59  }
60 
61  void File::removeSlash()
62  {
63  std::string::iterator iter = _path.end(); --iter;
64 
65  if ((*iter) == '/')
66  {
67  _path.erase(iter);
68  }
69  }
70 
71  void File::resolveAbsolutePath()
72  {
73  std::string::iterator iter = _path.begin();
74 
75  if ((*iter) != '/')
76  {
77  _path = "./" + _path;
78  }
79  }
80 
81  bool File::exists() const
82  {
83  struct stat st;
84  if( stat(_path.c_str(), &st ) == 0)
85  return true;
86 
87  return false;
88  }
89 
90  void File::update()
91  {
92  struct stat s;
93 
94  if ( stat(_path.c_str(), &s) == 0 )
95  {
96  int type = s.st_mode & S_IFMT;
97 
98  switch (type)
99  {
100  case S_IFREG:
101  _type = DT_REG;
102  break;
103 
104  case S_IFLNK:
105  _type = DT_LNK;
106  break;
107 
108  case S_IFDIR:
109  _type = DT_DIR;
110  break;
111 
112  default:
113  _type = DT_UNKNOWN;
114  break;
115  }
116  }
117  }
118 
120  {}
121 
122  unsigned char File::getType() const
123  {
124  return _type;
125  }
126 
127  int File::getFiles(std::list<File> &files) const
128  {
129  if (!isDirectory()) return -1;
130 
131  DIR *dp;
132  struct dirent dirp_data;
133  struct dirent *dirp;
134  if((dp = opendir(_path.c_str())) == NULL) {
135  return errno;
136  }
137 
138  while (::readdir_r(dp, &dirp_data, &dirp) == 0)
139  {
140  if (dirp == NULL) break;
141 
142  // TODO: check if the name is always limited by a zero
143  // std::string name = std::string(dirp->d_name, dirp->d_reclen);
144 
145  std::string name = std::string(dirp->d_name);
146  std::stringstream ss; ss << getPath() << "/" << name;
147  File file(ss.str(), dirp->d_type);
148  files.push_back(file);
149  }
150  closedir(dp);
151 
152  return 0;
153  }
154 
155  bool File::isSystem() const
156  {
157  return ((getBasename() == "..") || (getBasename() == "."));
158  }
159 
160  bool File::isDirectory() const
161  {
162  if (_type == DT_DIR) return true;
163  return false;
164  }
165 
166  string File::getPath() const
167  {
168  return _path;
169  }
170 
171  std::string File::getBasename() const
172  {
173 #if !defined(ANDROID) && defined(HAVE_FEATURES_H)
174  return std::string(basename(_path.c_str()));
175 #else
176  char path[_path.length()+1];
177  ::memcpy(&path, _path.c_str(), _path.length()+1);
178 
179  return std::string(basename(path));
180 #endif
181  }
182 
183  File File::get(string filename) const
184  {
185  stringstream ss; ss << getPath() << "/" << filename;
186  File file(ss.str());
187 
188  return file;
189  }
190 
191  int File::remove(bool recursive)
192  {
193  if (isSystem()) return -1;
194  if (_type == DT_UNKNOWN) return -1;
195 
196  if (isDirectory())
197  {
198  if (recursive)
199  {
200  int ret = 0;
201 
202  // container for all files
203  list<File> files;
204 
205  // get all files in this directory
206  if ((ret = getFiles(files)) < 0)
207  return ret;
208 
209  for (list<File>::iterator iter = files.begin(); iter != files.end(); ++iter)
210  {
211  ibrcommon::File &file = (*iter);
212  if (!file.isSystem())
213  {
214  if ((ret = file.remove(recursive)) < 0)
215  return ret;
216  }
217  }
218  }
219 
220  ::rmdir(getPath().c_str());
221  }
222  else
223  {
224  ::remove(getPath().c_str());
225  }
226 
227  return 0;
228  }
229 
231  {
232  size_t pos = _path.find_last_of('/');
233  return File(_path.substr(0, pos));
234  }
235 
237  {
238  if (!path.exists())
239  {
240  File parent = path.getParent();
241  File::createDirectory(parent);
242 
243  // create path
244  ::mkdir(path.getPath().c_str(), 0700);
245 
246  // update file information
247  path.update();
248  }
249  }
250 
251  size_t File::size() const
252  {
253  struct stat filestatus;
254  stat( getPath().c_str(), &filestatus );
255  return static_cast<size_t>(filestatus.st_size);
256  }
257 
258  time_t File::lastaccess() const
259  {
260  struct stat filestatus;
261  stat( getPath().c_str(), &filestatus );
262  return filestatus.st_atime;
263  }
264 
265  time_t File::lastmodify() const
266  {
267  struct stat filestatus;
268  stat( getPath().c_str(), &filestatus );
269  return filestatus.st_mtime;
270  }
271 
272  time_t File::laststatchange() const
273  {
274  struct stat filestatus;
275  stat( getPath().c_str(), &filestatus );
276  return filestatus.st_ctime;
277  }
278 
279  bool File::operator==(const ibrcommon::File &other) const
280  {
281  return (other._path == _path);
282  }
283 
284  bool File::operator<(const ibrcommon::File &other) const
285  {
286  return (_path < other._path);
287  }
288 
289  TemporaryFile::TemporaryFile(const File &path, const std::string prefix)
290  : File(tmpname(path, prefix))
291  {
292  }
293 
295  {
296  }
297 
298  std::string TemporaryFile::tmpname(const File &path, const std::string prefix)
299  {
300  // check if path is a directory
301  if (!path.isDirectory())
302  {
303  throw ibrcommon::IOException("given path is not a directory.");
304  }
305 
306  std::string pattern = path.getPath() + "/" + prefix + "XXXXXX";
307 
308  std::vector<char> name(pattern.length() + 1);
309  ::strcpy(&name[0], pattern.c_str());
310 
311  int fd = mkstemp(&name[0]);
312  if (fd == -1) throw ibrcommon::IOException("Could not create a temporary name.");
313  ::close(fd);
314 
315  return std::string(name.begin(), name.end());
316  }
317 }