IBR-DTNSuite  0.12
FatImageReader.cpp
Go to the documentation of this file.
1 /*
2  * FatImageReader.cpp
3  *
4  * Copyright (C) 2014 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  * Created on: Mar 14, 2014
21  */
22 
23 #include "FatImageReader.h"
24 #include <ibrcommon/Logger.h>
25 #include <sstream>
26 
27 namespace io
28 {
29  const std::string FatImageReader::TAG = "FatImageReader";
30 
31  FatImageReader::FatImageException::FatImageException(int errcode, const std::string &operation, const ibrcommon::File &file)
32  : ibrcommon::IOException(create_message(errcode, operation, file)), _errorcode(errcode)
33  {
34  }
35 
37  {
38  }
39 
40  std::string FatImageReader::FatImageException::create_message(int errcode, const std::string &operation, const ibrcommon::File &file)
41  {
42  std::stringstream ss;
43  ss << operation << " failed with " << errcode << " for " << file.getPath();
44  return ss.str();
45  }
46 
48  {
49  return _errorcode;
50  }
51 
53  : _filename(filename)
54  {
55  }
56 
58  {
59  }
60 
61  bool FatImageReader::isDirectory(const FATFile &file) const throw ()
62  {
63  try {
64  if (file.isRoot()) return true;
65 
66  dirent_t d;
67  update(file, d);
68  return d.dir_attr & DIR_ATTR_DIRECTORY;
69  } catch (const ibrcommon::IOException &e) {
70  return false;
71  }
72  }
73 
74  size_t FatImageReader::size(const FATFile &file) const throw ()
75  {
76  try {
77  if (file.isRoot()) return 0;
78 
79  dirent_t d;
80  update(file, d);
81  return d.dir_file_size;
82  } catch (const ibrcommon::IOException &e) {
83  return 0;
84  }
85  }
86 
87  time_t FatImageReader::lastaccess(const FATFile &file) const throw ()
88  {
89  try {
90  if (file.isRoot()) return 0;
91 
92  dirent_t d;
93  update(file, d);
94 
95  struct tm tm;
96  tm.tm_year = d.crttime.year - 1900;
97  tm.tm_mon = d.crttime.month - 1;
98  tm.tm_mday = d.crttime.day;
99  tm.tm_hour = d.crttime.hour;
100  tm.tm_min = d.crttime.min;
101  tm.tm_sec = d.crttime.sec / 2; //somehow, libtffs writes seconds from 0-119;
102  return mktime(&tm);
103  } catch (const ibrcommon::IOException &e) {
104  return 0;
105  }
106  }
107 
108  bool FatImageReader::exists(const FATFile &file) const throw ()
109  {
110  try {
111  dirent_t d;
112  update(file, d);
113  return true;
114  } catch (const ibrcommon::IOException &e) {
115  return false;
116  }
117  }
118 
119  void FatImageReader::update(const FATFile &path, dirent_t &d) const throw (ibrcommon::IOException)
120  {
121  int ret = 0;
122  tdir_handle_t hdir;
123  tffs_handle_t htffs;
124  bool found = false;
125 
126  // root does not have a dirent entry
127  if (path.isRoot()) return;
128 
129  // open fat image
130  byte* image_path = const_cast<char *>(_filename.getPath().c_str());
131  if ((ret = TFFS_mount(image_path, &htffs)) != TFFS_OK) {
132  throw FatImageException(ret, "TFFS_mount", _filename);
133  }
134 
135  // get parent directory
136  FATFile parent = path.getParent();
137 
138  // open directory
139  const std::string dir_path = parent.getPath() + (parent.isRoot() ? "" : "/");
140  if ((ret = TFFS_opendir(htffs, const_cast<char *>(dir_path.c_str()), &hdir)) != TFFS_OK) {
141  IBRCOMMON_LOGGER_TAG(TAG, error) << "TFFS_opendir failed" << IBRCOMMON_LOGGER_ENDL;
142  }
143  else
144  {
145  // list files, searching the selected one
146  while( 1 )
147  {
148  ret = TFFS_readdir(hdir, &d);
149  if (ret == TFFS_OK) {
150  if (d.d_name == path.getBasename()) {
151  found = true;
152  break;
153  }
154  } else {
155  // "ret" might be "ERR_TFFS_LAST_DIRENTRY"
156  break;
157  }
158  }
159 
160  // close directory
161  if ((ret = TFFS_closedir(hdir)) != TFFS_OK) {
162  IBRCOMMON_LOGGER_TAG(TAG, error) << "TFFS_closedir failed" << IBRCOMMON_LOGGER_ENDL;
163  }
164  }
165 
166  // close image file
167  if ((ret = TFFS_umount(htffs)) != TFFS_OK) {
168  throw FatImageException(ret, "TFFS_umount", _filename);
169  }
170 
171  if (!found) {
172  throw ibrcommon::IOException("File not found");
173  }
174  }
175 
177  {
178  FATFile root(*this, "/");
179  list(root, files);
180  }
181 
182  void FatImageReader::list(const FATFile &directory, filelist &files) const throw (FatImageException)
183  {
184  int ret = 0;
185  tdir_handle_t hdir;
186  dirent_t dirent;
187  tffs_handle_t htffs;
188 
189  // open fat image
190  byte* image_path = const_cast<char *>(_filename.getPath().c_str());
191  if ((ret = TFFS_mount(image_path, &htffs)) != TFFS_OK) {
192  throw FatImageException(ret, "TFFS_mount", _filename);
193  }
194 
195  // open directory
196  const std::string dir_path = directory.getPath() + (directory.isRoot() ? "" : "/");
197  if ((ret = TFFS_opendir(htffs, const_cast<char *>(dir_path.c_str()), &hdir)) != TFFS_OK) {
198  IBRCOMMON_LOGGER_TAG(TAG, error) << "TFFS_opendir failed" << IBRCOMMON_LOGGER_ENDL;
199  }
200  else
201  {
202  while( 1 )
203  {
204  if ((ret = TFFS_readdir(hdir, &dirent)) == TFFS_OK)
205  {
206  files.push_back(directory.get(dirent.d_name));
207  }
208  else if (ret == ERR_TFFS_LAST_DIRENTRY) { // end of directory
209  break;
210  }
211  else {
212  break;
213  }
214  }
215 
216  // close directory
217  if ((ret = TFFS_closedir(hdir)) != TFFS_OK) {
218  IBRCOMMON_LOGGER_TAG(TAG, error) << "TFFS_closedir failed" << IBRCOMMON_LOGGER_ENDL;
219  }
220  }
221 
222  // close image file
223  if ((ret = TFFS_umount(htffs)) != TFFS_OK) {
224  throw FatImageException(ret, "TFFS_umount", _filename);
225  }
226  }
227 
229  {
230  return FatImageReader::FileHandle(_filename, file.getPath());
231  }
232 
233  FatImageReader::FileHandle::FileHandle(const ibrcommon::File &image, const std::string &p)
234  : _open(false)
235  {
236  int ret = 0;
237 
238  // mount tffs
239  byte* path = const_cast<char *>(image.getPath().c_str());
240  if ((ret = TFFS_mount(path, &_htffs)) != TFFS_OK)
241  {
242  throw FatImageException(ret, "TFFS_mount", image);
243  }
244 
245  try {
246  // open file
247  byte* file = const_cast<char*>(p.c_str());
248  if ((ret = TFFS_fopen(_htffs, file, "r", &_hfile)) != TFFS_OK)
249  {
250  throw FatImageException(ret, "TFFS_fopen", p);
251  }
252 
253  _open = true;
254  } catch (const FatImageException&) {
255  // unmount
256  TFFS_umount(_htffs);
257  throw;
258  }
259  }
260 
262  {
263  close();
264  }
265 
266  size_t FatImageReader::FileHandle::read(unsigned char *buff, size_t buf_size)
267  {
268  ssize_t ret = 0;
269 
270  // read file
271  if (( ret = TFFS_fread(_hfile, buf_size, (unsigned char*) buff)) < 0)
272  {
273  if( ret == ERR_TFFS_FILE_EOF) return 0;
274  else
275  {
276  std::stringstream ss;
277  ss << "TFFS_fread " << ret;
278  throw ibrcommon::IOException(ss.str());
279  }
280  }
281  else
282  {
283  return (ret >= 0) ? (size_t)ret : 0;
284  }
285  }
286 
288  {
289  if (!_open) return;
290 
291  if (TFFS_fclose(_hfile) != TFFS_OK) {
292  IBRCOMMON_LOGGER_TAG("FatFileHandle", error) << "TFFS_fclose failed" << IBRCOMMON_LOGGER_ENDL;
293  }
294 
295  // close image file
296  if (TFFS_umount(_htffs) != TFFS_OK) {
297  IBRCOMMON_LOGGER_TAG("FatFileHandle", error) << "TFFS_umount failed" << IBRCOMMON_LOGGER_ENDL;
298  }
299  }
300 } /* namespace io */