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  int64_t freespace = -1;
45  QByteArray cstr = file_on_disk.toLocal8Bit();
46 
47  total = used = -1;
48 
49  // there are cases where statfs will return 0 (good), but f_blocks and
50  // others are invalid and set to 0 (such as when an automounted directory
51  // is not mounted but still visible because --ghost was used),
52  // so check to make sure we can have a total size > 0
53  if ((statfs(cstr.constData(), &statbuf) == 0) &&
54  (statbuf.f_blocks > 0) &&
55  (statbuf.f_bsize > 0))
56  {
57  total = statbuf.f_blocks;
58  total *= statbuf.f_bsize;
59  total = total >> 10;
60 
61  freespace = statbuf.f_bavail;
62  freespace *= statbuf.f_bsize;
63  freespace = freespace >> 10;
64 
65  used = total - freespace;
66  }
67 
68  return freespace;
69 }
70 
71 bool extractZIP(const QString &zipFile, const QString &outDir)
72 {
73  UnZip uz;
74  UnZip::ErrorCode ec = uz.openArchive(zipFile);
75 
76  if (ec != UnZip::Ok)
77  {
78  LOG(VB_GENERAL, LOG_ERR,
79  QString("extractZIP(): Unable to open ZIP file %1")
80  .arg(zipFile));
81  return false;
82  }
83 
84  ec = uz.extractAll(outDir);
85 
86  if (ec != UnZip::Ok)
87  {
88  LOG(VB_GENERAL, LOG_ERR,
89  QString("extractZIP(): Error extracting ZIP file %1")
90  .arg(zipFile));
91  return false;
92  }
93 
94  uz.closeArchive();
95 
96  return true;
97 }
98 
99 bool gzipFile(const QString &inFilename, const QString &gzipFilename)
100 {
101  QFile infile(inFilename);
102  QFile outfile(gzipFilename);
103 
104  if (!infile.open(QIODevice::ReadOnly))
105  {
106  LOG(VB_GENERAL, LOG_ERR, QString("gzipFile(): Error opening file for reading '%1'").arg(inFilename));
107  return false;
108  }
109 
110  if (!outfile.open(QIODevice::WriteOnly))
111  {
112  LOG(VB_GENERAL, LOG_ERR, QString("gzipFile(): Error opening file for writing '%1'").arg(gzipFilename));
113  infile.close();
114  return false;
115  }
116 
117  QByteArray uncompressedData = infile.readAll();
118  QByteArray compressedData = gzipCompress(uncompressedData);
119 
120  if (!outfile.write(compressedData))
121  {
122  LOG(VB_GENERAL, LOG_ERR, QString("gzipFile(): Error while writing to '%1'").arg(gzipFilename));
123  infile.close();
124  outfile.close();
125  return false;
126  }
127 
128  infile.close();
129  outfile.close();
130 
131  return true;
132 }
133 
134 bool gunzipFile(const QString &gzipFilename, const QString &outFilename)
135 {
136  QFile infile(gzipFilename);
137  QFile outfile(outFilename);
138 
139  if (!infile.open(QIODevice::ReadOnly))
140  {
141  LOG(VB_GENERAL, LOG_ERR, QString("gunzipFile(): Error opening file for reading '%1'").arg(gzipFilename));
142  return false;
143  }
144 
145  if (!outfile.open(QIODevice::WriteOnly))
146  {
147  LOG(VB_GENERAL, LOG_ERR, QString("gunzipFile(): Error opening file for writing '%1'").arg(outFilename));
148  infile.close();
149  return false;
150  }
151 
152  QByteArray compressedData = infile.readAll();
153  QByteArray uncompressedData = gzipUncompress(compressedData);
154 
155  if (outfile.write(uncompressedData) < uncompressedData.size())
156  {
157  LOG(VB_GENERAL, LOG_ERR, QString("gunzipFile(): Error while writing to '%1'").arg(outFilename));
158  infile.close();
159  outfile.close();
160  return false;
161  }
162 
163  infile.close();
164  outfile.close();
165 
166  return true;
167 }
168 
169 QByteArray gzipCompress(const QByteArray& data)
170 {
171  if (data.length() == 0)
172  return QByteArray();
173 
174  static constexpr int kChunkSize = 1024;
175  char out[kChunkSize];
176 
177  // allocate inflate state
178  z_stream strm;
179 
180  strm.zalloc = Z_NULL;
181  strm.zfree = Z_NULL;
182  strm.opaque = Z_NULL;
183  strm.avail_in = data.length();
184  strm.next_in = (Bytef*)(data.data());
185 
186  int ret = deflateInit2(&strm,
187  Z_DEFAULT_COMPRESSION,
188  Z_DEFLATED,
189  15 + 16,
190  8,
191  Z_DEFAULT_STRATEGY ); // gzip encoding
192  if (ret != Z_OK)
193  return QByteArray();
194 
195  QByteArray result;
196 
197  // run deflate()
198  do
199  {
200  strm.avail_out = kChunkSize;
201  strm.next_out = (Bytef*)(out);
202 
203  ret = deflate(&strm, Z_FINISH);
204 
205  Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered
206 
207  switch (ret)
208  {
209  case Z_NEED_DICT:
210  case Z_DATA_ERROR:
211  case Z_MEM_ERROR:
212  (void)deflateEnd(&strm);
213  return QByteArray();
214  }
215 
216  result.append(out, kChunkSize - strm.avail_out);
217  }
218  while (strm.avail_out == 0);
219 
220  // clean up and return
221 
222  deflateEnd(&strm);
223 
224  return result;
225 }
226 
227 QByteArray gzipUncompress(const QByteArray &data)
228 {
229  if (data.length() == 0)
230  return QByteArray();
231 
232  static constexpr int kChunkSize = 1024;
233  char out[kChunkSize];
234 
235  // allocate inflate state
236  z_stream strm;
237 
238  strm.zalloc = Z_NULL;
239  strm.zfree = Z_NULL;
240  strm.opaque = Z_NULL;
241  strm.avail_in = data.length();
242  strm.next_in = (Bytef*)(data.data());
243 
244  int ret = inflateInit2(&strm, 15 + 16);
245 
246  if (ret != Z_OK)
247  return QByteArray();
248 
249  QByteArray result;
250 
251  do
252  {
253  strm.avail_out = kChunkSize;
254  strm.next_out = (Bytef*)out;
255  ret = inflate(&strm, Z_NO_FLUSH);
256 
257  Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered
258 
259  switch (ret)
260  {
261  case Z_NEED_DICT:
262  case Z_DATA_ERROR:
263  case Z_MEM_ERROR:
264  (void) deflateEnd(&strm);
265  return QByteArray();
266  }
267 
268  result.append(out, kChunkSize - strm.avail_out);
269  }
270  while (strm.avail_out == 0);
271 
272  (void) inflateEnd(& strm);
273 
274  return result;
275 }
276 
277 static QString downloadRemoteFile(const QString &cmd, const QString &url,
278  const QString &storageGroup,
279  const QString &filename)
280 {
281  QStringList strlist(cmd);
282  strlist << url;
283  strlist << storageGroup;
284  strlist << filename;
285 
286  bool ok = gCoreContext->SendReceiveStringList(strlist);
287 
288  if (!ok || strlist.size() < 2 || strlist[0] != "OK")
289  {
290  LOG(VB_GENERAL, LOG_ERR,
291  "downloadRemoteFile(): " + cmd + " returned ERROR!");
292  return QString();
293  }
294 
295  return strlist[1];
296 }
297 
298 QString RemoteDownloadFile(const QString &url,
299  const QString &storageGroup,
300  const QString &filename)
301 {
302  return downloadRemoteFile("DOWNLOAD_FILE", url, storageGroup, filename);
303 }
304 
305 QString RemoteDownloadFileNow(const QString &url,
306  const QString &storageGroup,
307  const QString &filename)
308 {
309  return downloadRemoteFile("DOWNLOAD_FILE_NOW", url, storageGroup, filename);
310 }
311 
312 /* 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