IBR-DTNSuite  0.12
TarUtils.cpp
Go to the documentation of this file.
1 /*
2  * TarUtils.cpp
3  *
4  * Copyright (C) 2013 IBR, TU Braunschweig
5  *
6  * Written-by: David Goltzsche <goltzsch@ibr.cs.tu-bs.de>
7  * Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  * Created on: Sep 16, 2013
22  */
23 
24 #include "io/TarUtils.h"
25 #include "io/ObservedFile.h"
26 #include <ibrcommon/Logger.h>
27 
28 #include <stdlib.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <sstream>
32 #include <typeinfo>
33 #include <fstream>
34 
35 #include <archive.h>
36 #include <archive_entry.h>
37 
38 #ifdef HAVE_LIBTFFS
39 #include "io/FatImageReader.h"
40 #endif
41 
42 #define BUFF_SIZE 8192
43 
44 namespace io
45 {
47  {
48  }
50  {
51  }
52 
53  int __tar_utils_open_callback( struct archive *, void * )
54  {
55  //blob does not need to be opened, do nothing
56  return ARCHIVE_OK;
57  }
58 
59  ssize_t __tar_utils_write_callback( struct archive *, void *ostream_ptr, const void *buffer, size_t length )
60  {
61  ssize_t ret = 0;
62  char* cast_buf = (char*) buffer;
63 
64  std::ostream &os = *(std::ostream*)ostream_ptr;
65  os.write(cast_buf, length);
66  ret += length;
67 
68  return ret;
69  }
70 
71  ssize_t __tar_utils_read_callback( struct archive *, void *istream_ptr, const void **buffer )
72  {
73  char *cbuff = new char[BUFF_SIZE];
74 
75  std::istream &is = *(std::istream*)istream_ptr;
76  is.read(cbuff,BUFF_SIZE);
77 
78  *buffer = cbuff;
79  return BUFF_SIZE;
80  }
81 
82  int __tar_utils_close_callback( struct archive *, void * )
83  {
84  //blob does not need to be closed, do nothing
85  return ARCHIVE_OK;
86  }
87 
88  void TarUtils::read( const ibrcommon::File &extract_folder, std::istream &input )
89  {
90  struct archive *a;
91  struct archive_entry *entry;
92  int ret,fd;
93 
94  a = archive_read_new();
95  archive_read_support_filter_all(a);
96  archive_read_support_compression_all(a);
97  archive_read_support_format_tar(a);
98 
99  archive_read_open(a, (void*) &input, &__tar_utils_open_callback, &__tar_utils_read_callback, &__tar_utils_close_callback);
100 
101  while ((ret = archive_read_next_header(a, &entry)) == ARCHIVE_OK )
102  {
103  ibrcommon::File filename = extract_folder.get(archive_entry_pathname(entry));
104  ibrcommon::File path = filename.getParent();
106  fd = open(filename.getPath().c_str(),O_CREAT|O_WRONLY,0600);
107  if(fd < 0) throw ibrcommon::IOException("cannot open file " + path.getPath());
108  archive_read_data_into_fd(a,fd);
109  close(fd);
110  }
111 
112  archive_read_free(a);
113  }
114 
115  void TarUtils::write(std::ostream &output, const io::ObservedFile &root, const std::set<ObservedFile> &files_to_send)
116  {
117  bool processed = false;
118 
119  //create new archive, set format to tar, use callbacks (above this method)
120  struct archive *a;
121  a = archive_write_new();
122  archive_write_set_format_ustar(a);
124 
125  for(std::set<ObservedFile>::const_iterator of_iter = files_to_send.begin(); of_iter != files_to_send.end(); ++of_iter)
126  {
127  const ObservedFile &of = (*of_iter);
128  const ibrcommon::File &file = of.getFile();
129 
130  struct archive_entry *entry;
131  entry = archive_entry_new();
132  archive_entry_set_size(entry, file.size());
133 
134  if(file.isDirectory())
135  {
136  archive_entry_set_filetype(entry, AE_IFDIR);
137  archive_entry_set_perm(entry, 0755);
138  }
139  else
140  {
141  archive_entry_set_filetype(entry, AE_IFREG);
142  archive_entry_set_perm(entry, 0644);
143  }
144 
145  archive_entry_set_pathname(entry, rel_filename(root, of).c_str());
146 
147  //set timestamps
148  struct timespec ts;
149  clock_gettime(CLOCK_REALTIME, &ts);
150  archive_entry_set_atime(entry, ts.tv_sec, ts.tv_nsec); //accesstime
151  archive_entry_set_birthtime(entry, ts.tv_sec, ts.tv_nsec); //creationtime
152  archive_entry_set_ctime(entry, ts.tv_sec, ts.tv_nsec); //time, inode changed
153  archive_entry_set_mtime(entry, ts.tv_sec, ts.tv_nsec); //modification time
154 
155  archive_write_header(a, entry);
156 
157  try {
158 #ifdef HAVE_LIBTFFS
159  //read file on vfat-image
160  try {
161  const FATFile &ffile = dynamic_cast<const FATFile&>(file);
162  processed = true;
163 
164  // get image reader
165  const FatImageReader &reader = ffile.getReader();
166 
167  // open fat file
168  io::FatImageReader::FileHandle fh = reader.open(ffile);
169 
170  char buff[BUFF_SIZE];
171  ssize_t ret = 0;
172  size_t len = 0;
173 
174  // read file
175  len = fh.read((unsigned char*)&buff, BUFF_SIZE);
176 
177  //write buffer to archive
178  while (len > 0)
179  {
180  if( (ret = archive_write_data(a, buff, len)) < 0)
181  {
182  IBRCOMMON_LOGGER_TAG("TarUtils", error) << "archive_write_data failed" << IBRCOMMON_LOGGER_ENDL;
183  break;
184  }
185 
186  // read next chunk
187  len = fh.read((unsigned char*)&buff, BUFF_SIZE);
188  }
189  } catch (const std::bad_cast&) { };
190 #endif
191 
192  if (!processed)
193  {
194  char buff[BUFF_SIZE];
195  ssize_t ret = 0;
196 
197  // open file for reading
198  std::ifstream fs(file.getPath().c_str());
199 
200  // write buffer to archive
201  while (fs.good())
202  {
203  // read bytes
204  fs.read(buff, BUFF_SIZE);
205 
206  // write bytes to archive
207  if( (ret = archive_write_data(a, buff, fs.gcount())) < 0)
208  {
209  IBRCOMMON_LOGGER_TAG("TarUtils", error) << "archive write failed" << IBRCOMMON_LOGGER_ENDL;
210  break;
211  }
212  }
213  }
214  } catch (const ibrcommon::IOException &e) {
215  // write failed
216  IBRCOMMON_LOGGER_TAG("TarUtils", error) << "archive write failed: " << e.what() << IBRCOMMON_LOGGER_ENDL;
217 
218  archive_entry_free(entry);
219  archive_write_close(a);
220  archive_write_free(a);
221 
222  throw;
223  }
224 
225  archive_entry_free(entry);
226  }
227  archive_write_close(a);
228  archive_write_free(a);
229  }
230 
231  std::string TarUtils::rel_filename(const ObservedFile &parent, const ObservedFile &f)
232  {
233  // get file path
234  const std::string file_path = f.getFile().getPath();
235 
236  // get wrapping path
237  const std::string parent_path = parent.getFile().getPath();
238 
239  // special case: if parent is root return the full path
240  if (parent.getFile().isRoot()) return file_path.substr(parent_path.length(), file_path.length() - parent_path.length());
241 
242  // if path is sub-path
243  return file_path.substr(parent_path.length() + 1, file_path.length() - parent_path.length() - 1);
244  }
245 }