MythTV  master
mythcoreutil.cpp
Go to the documentation of this file.
1 
2 #include "mythcoreutil.h"
3 
4 // POSIX
5 #include <unistd.h>
6 #include <fcntl.h>
7 
8 // System specific C headers
9 #include "compat.h"
10 
11 #ifdef linux
12 #include <sys/vfs.h>
13 #include <sys/sysinfo.h>
14 #endif
15 
16 #if CONFIG_DARWIN
17 #include <mach/mach.h>
18 #endif
19 
20 #ifdef BSD
21 #include <sys/mount.h> // for struct statfs
22 #include <sys/sysctl.h>
23 #endif
24 
25 // Qt headers
26 #include <QByteArray>
27 #include <QStringList>
28 #include <QFile>
29 
30 // libmythbase headers
31 #include "mythcorecontext.h"
32 #include "mythlogging.h"
33 #include "unzip.h"
34 
40 int64_t getDiskSpace(const QString &file_on_disk,
41  int64_t &total, int64_t &used)
42 {
43  struct statfs statbuf;
44  memset(&statbuf, 0, sizeof(statbuf));
45  int64_t freespace = -1;
46  QByteArray cstr = file_on_disk.toLocal8Bit();
47 
48  total = used = -1;
49 
50  // there are cases where statfs will return 0 (good), but f_blocks and
51  // others are invalid and set to 0 (such as when an automounted directory
52  // is not mounted but still visible because --ghost was used),
53  // so check to make sure we can have a total size > 0
54  if ((statfs(cstr.constData(), &statbuf) == 0) &&
55  (statbuf.f_blocks > 0) &&
56  (statbuf.f_bsize > 0))
57  {
58  total = statbuf.f_blocks;
59  total *= statbuf.f_bsize;
60  total = total >> 10;
61 
62  freespace = statbuf.f_bavail;
63  freespace *= statbuf.f_bsize;
64  freespace = freespace >> 10;
65 
66  used = total - freespace;
67  }
68 
69  return freespace;
70 }
71 
72 bool extractZIP(const QString &zipFile, const QString &outDir)
73 {
74  UnZip uz;
75  UnZip::ErrorCode ec = uz.openArchive(zipFile);
76 
77  if (ec != UnZip::Ok)
78  {
79  LOG(VB_GENERAL, LOG_ERR,
80  QString("extractZIP(): Unable to open ZIP file %1")
81  .arg(zipFile));
82  return false;
83  }
84 
85  ec = uz.extractAll(outDir);
86 
87  if (ec != UnZip::Ok)
88  {
89  LOG(VB_GENERAL, LOG_ERR,
90  QString("extractZIP(): Error extracting ZIP file %1")
91  .arg(zipFile));
92  return false;
93  }
94 
95  uz.closeArchive();
96 
97  return true;
98 }
99 
100 bool gzipFile(const QString &inFilename, const QString &gzipFilename)
101 {
102  QFile infile(inFilename);
103  QFile outfile(gzipFilename);
104 
105  if (!infile.open(QIODevice::ReadOnly))
106  {
107  LOG(VB_GENERAL, LOG_ERR, QString("gzipFile(): Error opening file for reading '%1'").arg(inFilename));
108  return false;
109  }
110 
111  if (!outfile.open(QIODevice::WriteOnly))
112  {
113  LOG(VB_GENERAL, LOG_ERR, QString("gzipFile(): Error opening file for writing '%1'").arg(gzipFilename));
114  infile.close();
115  return false;
116  }
117 
118  QByteArray uncompressedData = infile.readAll();
119  QByteArray compressedData = gzipCompress(uncompressedData);
120 
121  if (!outfile.write(compressedData))
122  {
123  LOG(VB_GENERAL, LOG_ERR, QString("gzipFile(): Error while writing to '%1'").arg(gzipFilename));
124  infile.close();
125  outfile.close();
126  return false;
127  }
128 
129  infile.close();
130  outfile.close();
131 
132  return true;
133 }
134 
135 bool gunzipFile(const QString &gzipFilename, const QString &outFilename)
136 {
137  QFile infile(gzipFilename);
138  QFile outfile(outFilename);
139 
140  if (!infile.open(QIODevice::ReadOnly))
141  {
142  LOG(VB_GENERAL, LOG_ERR, QString("gunzipFile(): Error opening file for reading '%1'").arg(gzipFilename));
143  return false;
144  }
145 
146  if (!outfile.open(QIODevice::WriteOnly))
147  {
148  LOG(VB_GENERAL, LOG_ERR, QString("gunzipFile(): Error opening file for writing '%1'").arg(outFilename));
149  infile.close();
150  return false;
151  }
152 
153  QByteArray compressedData = infile.readAll();
154  QByteArray uncompressedData = gzipUncompress(compressedData);
155 
156  if (outfile.write(uncompressedData) < uncompressedData.size())
157  {
158  LOG(VB_GENERAL, LOG_ERR, QString("gunzipFile(): Error while writing to '%1'").arg(outFilename));
159  infile.close();
160  outfile.close();
161  return false;
162  }
163 
164  infile.close();
165  outfile.close();
166 
167  return true;
168 }
169 
170 QByteArray gzipCompress(const QByteArray& data)
171 {
172  if (data.length() == 0)
173  return QByteArray();
174 
175  static const int CHUNK_SIZE = 1024;
176  char out[CHUNK_SIZE];
177 
178  // allocate inflate state
179  z_stream strm;
180 
181  strm.zalloc = Z_NULL;
182  strm.zfree = Z_NULL;
183  strm.opaque = Z_NULL;
184  strm.avail_in = data.length();
185  strm.next_in = (Bytef*)(data.data());
186 
187  int ret = deflateInit2(&strm,
188  Z_DEFAULT_COMPRESSION,
189  Z_DEFLATED,
190  15 + 16,
191  8,
192  Z_DEFAULT_STRATEGY ); // gzip encoding
193  if (ret != Z_OK)
194  return QByteArray();
195 
196  QByteArray result;
197 
198  // run deflate()
199  do
200  {
201  strm.avail_out = CHUNK_SIZE;
202  strm.next_out = (Bytef*)(out);
203 
204  ret = deflate(&strm, Z_FINISH);
205 
206  Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered
207 
208  switch (ret)
209  {
210  case Z_NEED_DICT:
211  case Z_DATA_ERROR:
212  case Z_MEM_ERROR:
213  (void)deflateEnd(&strm);
214  return QByteArray();
215  }
216 
217  result.append(out, CHUNK_SIZE - strm.avail_out);
218  }
219  while (strm.avail_out == 0);
220 
221  // clean up and return
222 
223  deflateEnd(&strm);
224 
225  return result;
226 }
227 
228 QByteArray gzipUncompress(const QByteArray &data)
229 {
230  if (data.length() == 0)
231  return QByteArray();
232 
233  static const int CHUNK_SIZE = 1024;
234  char out[CHUNK_SIZE];
235 
236  // allocate inflate state
237  z_stream strm;
238 
239  strm.zalloc = Z_NULL;
240  strm.zfree = Z_NULL;
241  strm.opaque = Z_NULL;
242  strm.avail_in = data.length();
243  strm.next_in = (Bytef*)(data.data());
244 
245  int ret = inflateInit2(&strm, 15 + 16);
246 
247  if (ret != Z_OK)
248  return QByteArray();
249 
250  QByteArray result;
251 
252  do
253  {
254  strm.avail_out = CHUNK_SIZE;
255  strm.next_out = (Bytef*)out;
256  ret = inflate(&strm, Z_NO_FLUSH);
257 
258  Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered
259 
260  switch (ret)
261  {
262  case Z_NEED_DICT:
263  case Z_DATA_ERROR:
264  case Z_MEM_ERROR:
265  (void) deflateEnd(&strm);
266  return QByteArray();
267  }
268 
269  result.append(out, CHUNK_SIZE - strm.avail_out);
270  }
271  while (strm.avail_out == 0);
272 
273  (void) inflateEnd(& strm);
274 
275  return result;
276 }
277 
278 static QString downloadRemoteFile(const QString &cmd, const QString &url,
279  const QString &storageGroup,
280  const QString &filename)
281 {
282  QStringList strlist(cmd);
283  strlist << url;
284  strlist << storageGroup;
285  strlist << filename;
286 
287  bool ok = gCoreContext->SendReceiveStringList(strlist);
288 
289  if (!ok || strlist.size() < 2 || strlist[0] != "OK")
290  {
291  LOG(VB_GENERAL, LOG_ERR,
292  "downloadRemoteFile(): " + cmd + " returned ERROR!");
293  return QString();
294  }
295 
296  return strlist[1];
297 }
298 
299 QString RemoteDownloadFile(const QString &url,
300  const QString &storageGroup,
301  const QString &filename)
302 {
303  return downloadRemoteFile("DOWNLOAD_FILE", url, storageGroup, filename);
304 }
305 
306 QString RemoteDownloadFileNow(const QString &url,
307  const QString &storageGroup,
308  const QString &filename)
309 {
310  return downloadRemoteFile("DOWNLOAD_FILE_NOW", url, storageGroup, filename);
311 }
312 
313 /* vim: set expandtab tabstop=4 shiftwidth=4: */
void closeArchive()
Definition: unzip.cpp:264
bool gzipFile(const QString &inFilename, const QString &gzipFilename)
ErrorCode openArchive(const QString &filename)
Definition: unzip.cpp:228
ErrorCode extractAll(const QString &dirname, ExtractionOptions options=ExtractPaths)
Definition: unzip.cpp:363
long f_bavail
Definition: compat.h:170
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
bool extractZIP(const QString &zipFile, const QString &outDir)
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
int statfs(const char *path, struct statfs *buffer)
Definition: compat.h:177
ErrorCode
Definition: unzip.h:52
bool gunzipFile(const QString &gzipFilename, const QString &outFilename)
static QString downloadRemoteFile(const QString &cmd, const QString &url, const QString &storageGroup, const QString &filename)
PKZip 2.0 file decompression. Compatibility with later versions is not ensured as they may use unsupp...
Definition: unzip.h:49
QString RemoteDownloadFileNow(const QString &url, const QString &storageGroup, const QString &filename)
QByteArray gzipUncompress(const QByteArray &data)
QByteArray gzipCompress(const QByteArray &data)
Definition: compat.h:165
int64_t getDiskSpace(const QString &file_on_disk, int64_t &total, int64_t &used)
QString RemoteDownloadFile(const QString &url, const QString &storageGroup, const QString &filename)
long f_blocks
Definition: compat.h:168
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
long f_bsize
Definition: compat.h:167
#define Z_NULL
Definition: unzip.h:37