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