NCBI C++ ToolKit
download_job.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: download_job.cpp 39418 2017-09-21 20:24:21Z katargir $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Anatoliy Kuznetsov
27  *
28  */
29 
30 #include <ncbi_pch.hpp>
31 #include <math.h>
32 
33 #include <corelib/ncbifile.hpp>
34 #include <corelib/ncbi_system.hpp>
37 #include <util/compress/tar.hpp>
38 
40 
41 
43 
44 extern "C" {
46 {
47  if (type != eCONN_OnClose/* && !s_Signaled*/) {
48  // Reinstate the callback right away
51  }
52 
54  = reinterpret_cast<const CDownloadJob::CDownloadCallbackData*>(data);
55  size_t pos = CONN_GetPosition(conn, eIO_Read);
56  //size_t size = dlcbdata->GetSize();
57 
58  dlcbdata->SetPos(pos);
59 
60 #if 0
61  //double time = dlcbdata->GetElapsed();
62  if (!size) {
63  /*
64  cerr << "Downloaded " << pos << "/unknown"
65  " in " << fixed << setprecision(2) << time
66  << left << setw(16) << 's' << '\r' << flush;
67  */
68  } else {
69 
70  /*
71  double percent = (pos * 100.0) / size;
72  if (percent > 100.00)
73  percent = 100.00;
74  */
75  /*
76  cerr << "Downloaded " << pos << '/' << size
77  << " (" << fixed << setprecision(2) << percent << "%)"
78  " in " << fixed << setprecision(2) << time;
79  if (time) {
80  double kbps = pos / time / 1024.0;
81  cerr << "s (" << fixed << setprecision(2) << kbps
82  << left << setw(16) << "KB/s)" << '\r' << flush;
83 
84  } else {
85  cerr << left << setw(16) << 's' << '\r' << flush;
86  }
87  */
88  }
89 #endif
90 
91  if (type == eCONN_OnClose) {
92  if (dlcbdata->CB().func)
93  dlcbdata->CB().func(conn, type, dlcbdata->CB().data);
94  cerr << endl;
95 
96  } else if (dlcbdata->GetCancel()) {
97  return eIO_Interrupt;
98  }
99 
100  return eIO_Success;
101 }
102 }
103 
104 class CTarCheckpointed : public CTar
105 {
106 public:
108  : CTar(is), m_DlCbData(dlcbdata) { }
109 
110 protected:
111  virtual bool Checkpoint(const CTarEntryInfo& current, bool /**/)
112  {
113  m_DlCbData->AddTotalSize(current.GetSize());
114  //cerr.flush();
115  //cout << current << endl;
116  return true;
117  }
118 
119 private:
121 };
122 
123 
124 static size_t s_GetFtpFilesize(iostream& ios, const char* filename)
125 {
126  size_t retval;
127  ios << "SIZE " << filename << endl;
128  if (!(ios >> retval)) {
129  retval = 0;
130  }
131  ios.clear();
132  return retval;
133 }
134 
135 static void s_InitiateFtpFileDownload(iostream& ios, const char* filename)
136 {
137  ios << "RETR " << filename << endl;
138 }
139 
140 
141 
142 ///////////////////////////////////////////////////////////////////////////////
143 /// CNetBlastLoadingJob
144 
145 CDownloadJob::CDownloadJob(const string& desc,
146  const string& base_dir,
147  const string& download_url,
148  bool extract_archive)
149 : m_TaskName(desc),
150  m_BaseDir(base_dir),
151  m_URL(download_url),
152  m_ExtractArchives(extract_archive),
153  m_DlcbData(0)
154 {
155 }
156 
157 CDownloadJob::CDownloadJob(const string& desc,
158  const string& base_dir,
159  const string& download_url,
160  const vector<string>& files_to_load,
161  bool extract_archive)
162 : m_TaskName(desc),
163  m_BaseDir(base_dir),
164  m_URL(download_url),
165  m_FilesToLoad(files_to_load),
166  m_ExtractArchives(extract_archive),
167  m_DlcbData(0)
168 {
169 }
170 
171 
173 {
174  delete m_DlcbData;
175 }
176 
178 {
179  return m_TaskName;
180 }
181 
183 {
184  CFastMutexGuard lock(m_Mutex);
185  if (m_DlcbData) {
186  m_DlcbData->Cancel();
187  }
188 }
189 
191 {
192  CFastMutexGuard lock(m_Mutex);
193  if (m_DlcbData) {
194  return m_DlcbData->GetCancel() != 0;
195  }
196  return false;
197 }
198 
199 string CDownloadJob::x_FormatSize(size_t bytes)
200 {
201  if (0 == bytes)
202  return "0 Bytes";
203  static const string sizes[] = { "Bytes", "KB", "MB", "GB", "TB", "PB" };
204 
205  unsigned i = (unsigned)floor(log10((double)bytes) / 3);
206 
207  string result = NStr::DoubleToString(bytes / pow(1000,i),2);
208  result += ' ';
209  result += sizes[i];
210  return result;
211 }
212 
214 {
215  CFastMutexGuard lock(m_Mutex);
216 
217  float progress = 0.0;
218  if (!m_DlcbData) {
219  return CConstIRef<IAppJobProgress>(new CAppJobProgress(progress, "unknown"));
220  }
221 
222  size_t size = m_DlcbData->GetSize();
223  size_t pos = m_DlcbData->GetPos();
224  if (size) {
225  progress = float(pos * 100.0) / (float)size;
226  if (progress > 100.00)
227  progress = 100.00;
228  }
229 
230  string status;
231  status = m_TaskName + " (" + x_FormatSize(pos) + "/" + x_FormatSize(size) + ")";
232 
233  return CConstIRef<IAppJobProgress>(new CAppJobProgress(progress, status));
234 }
235 
237 {
238  return m_Result;
239 }
240 
242 {
244 }
245 
247 {
248  // check the base directory
249  //
250 
251  try {
252  CDirEntry de(m_BaseDir);
253  if (!de.Exists()) {
255  }
256  } catch (CException& ex) {
257  ERR_POST(ex.ReportAll());
258  m_Error = new CAppJobError("Target path create error: '" + m_BaseDir + "'");
259  return IAppJob::eFailed;
260  }
261 
262  if (m_FilesToLoad.empty()) {
263  if (m_ExtractArchives)
264  return x_DownloadAndExtract(m_URL);
265  else {
266  size_t pos = m_URL.rfind('/');
267  if ((string::npos == pos) || (pos == (m_URL.length() - 1))) {
268  m_Error = new CAppJobError("Invalid URL specified: '" + m_URL + "'");
269  return IAppJob::eFailed;
270  }
271  string file_name = m_URL.substr(pos + 1);
272  return x_Download(m_URL, file_name);
273  }
274  }
275  else {
276  ITERATE(vector<string>, it, m_FilesToLoad) {
277  string fname = m_URL;
278  if ('/' != m_URL[m_URL.length()-1])
279  fname.append("/");
280  fname.append(*it);
282  if (m_ExtractArchives)
283  js = x_DownloadAndExtract(fname);
284  else
285  js = x_Download(fname,*it);
286  if (js != IAppJob::eCompleted)
287  return js;
288  }
289  }
290  return IAppJob::eCompleted;
291 }
292 
293 IAppJob::EJobState CDownloadJob::x_Download(const string& file_url, const string& file_name)
294 {
295  SConnNetInfo* net_info = ConnNetInfo_Create(0);
296 
297  const char* url = file_url.c_str();
298 
299  if (!ConnNetInfo_ParseURL(net_info, url)) {
300  string err = "Cannot parse URL \"";
301  err.append(m_URL);
302  err.append("\"");
303  ERR_POST(Fatal << err);
304  m_Error = new CAppJobError(err);
305  return IAppJob::eFailed;
306  }
307 
308  if (net_info->scheme != eURL_Ftp) {
309  string err = "URL scheme must be FTP";
310  err.append(m_URL);
311  err.append("\"");
312  ERR_POST(Fatal << err);
313  m_Error = new CAppJobError(err);
314  return IAppJob::eFailed;
315  }
316 
317  if (!*net_info->user) {
318  strcpy(net_info->user, "ftp");
319  }
320 
321  CConn_FtpStream ftp(net_info->host,
322  net_info->user,
323  net_info->pass);
324 
325 
326  size_t size = s_GetFtpFilesize(ftp, net_info->path);
327  if (size) {
328  ERR_POST(Info << "Downloading " << net_info->path
329  << " from " << net_info->host << ", "
330  << size << " byte" << &"s"[size == 1]);
331  }
332  else {
333  ERR_POST(Info << "Downloading " << net_info->path
334  << " from " << net_info->host);
335  }
336  s_InitiateFtpFileDownload(ftp, net_info->path);
337 
338  ConnNetInfo_Destroy(net_info);
339  // Reset I/O positions
341 
342  // Set both read and close callbacks
343  CDownloadCallbackData* dblcdata;
344  if (m_DlcbData)
345  dblcdata = m_DlcbData;
346  else
347  dblcdata = new CDownloadCallbackData(size);
348 
349  {{
350  CFastMutexGuard lock(m_Mutex);
351 
352  SCONN_Callback cb = { s_FtpCallback, dblcdata };
353  CONN_SetCallback(ftp.GetCONN(), eCONN_OnRead, &cb, 0);
354  CONN_SetCallback(ftp.GetCONN(), eCONN_OnClose, &cb, dblcdata->CB());
355  // Build on-the-fly ungzip stream on top of ftp
356 
357  m_DlcbData = dblcdata;
358  }}
359 
360 
361  bool download_ok = false;
362 
363  // make temp directory for download
364  //
365  static unsigned s_cnt = 0;
366  ++s_cnt;
367  string filePath(m_BaseDir);
368  if (CDirEntry::GetPathSeparator() != m_BaseDir[m_BaseDir.length() - 1])
369  filePath += CDirEntry::GetPathSeparator();
370  filePath += file_name;
371 
372  const size_t buff_size = 1;// 65536;
373  char* buffer = new char[buff_size];
374 
375  try {
376  CNcbiFstream os(filePath.c_str(), IOS_BASE::out | IOS_BASE::binary | IOS_BASE::trunc);
377 
378  while (!ftp.eof() && !m_DlcbData->GetCancel()) {
379  ftp.read(buffer, buff_size);
380  if (ftp.gcount())
381  os.write(buffer, ftp.gcount());
382  }
383 
384  os.close();
385  ftp.Close();
386 
387  download_ok = true;
388 
389  }
390  catch (CException& ex) {
391  if (!m_DlcbData->GetCancel()) {
392  m_Error = new CAppJobError(ex.ReportAll());
393  }
394  }
395  catch (std::exception& e) {
396  if (!m_DlcbData->GetCancel()) {
397  m_Error = new CAppJobError(e.what());
398  }
399  }
400  delete[] buffer;
401 
402  if (!download_ok || m_DlcbData->GetCancel()) {
403  CDirEntry de(filePath);
404  de.Remove();
405  if (m_DlcbData->GetCancel()) {
406  return IAppJob::eCanceled;
407  }
408  return IAppJob::eFailed;
409  }
410 
411  ERR_POST(Info << "Download OK");
412 
413  return IAppJob::eCompleted;
414 }
415 
417 {
418  SConnNetInfo* net_info = ConnNetInfo_Create(0);
419 
420  const char* url = file_url.c_str();
421 
422  if (!ConnNetInfo_ParseURL(net_info, url)) {
423  string err = "Cannot parse URL \"";
424  err.append(m_URL);
425  err.append("\"");
426  ERR_POST(Fatal << err);
427  m_Error = new CAppJobError(err);
428  return IAppJob::eFailed;
429  }
430 
431  if (net_info->scheme != eURL_Ftp) {
432  string err = "URL scheme must be FTP";
433  err.append(m_URL);
434  err.append("\"");
435  ERR_POST(Fatal << err);
436  m_Error = new CAppJobError(err);
437  return IAppJob::eFailed;
438  }
439 
440  if (!*net_info->user) {
441  strcpy(net_info->user, "ftp");
442  }
443 
444  CConn_FtpStream ftp(net_info->host,
445  net_info->user,
446  net_info->pass);
447 
448 
449  size_t size = s_GetFtpFilesize(ftp, net_info->path);
450  if (size) {
451  ERR_POST(Info << "Downloading " << net_info->path
452  << " from " << net_info->host << ", "
453  << size << " byte" << &"s"[size == 1]);
454  } else {
455  ERR_POST(Info << "Downloading " << net_info->path
456  << " from " << net_info->host);
457  }
458  s_InitiateFtpFileDownload(ftp, net_info->path);
459 
460  ConnNetInfo_Destroy(net_info);
461  // Reset I/O positions
463 
464  // Set both read and close callbacks
465  CDownloadCallbackData* dblcdata;
466  if (m_DlcbData)
467  dblcdata = m_DlcbData;
468  else
469  dblcdata = new CDownloadCallbackData(size);
470 
471  {{
472  CFastMutexGuard lock(m_Mutex);
473 
474  SCONN_Callback cb = { s_FtpCallback, dblcdata };
475  CONN_SetCallback(ftp.GetCONN(), eCONN_OnRead, &cb, 0);
476  CONN_SetCallback(ftp.GetCONN(), eCONN_OnClose, &cb, dblcdata->CB());
477  // Build on-the-fly ungzip stream on top of ftp
478 
479  m_DlcbData = dblcdata;
480  }}
481 
483 
484  bool download_ok = false;
485 
486  // make temp directory for download
487  //
488  static unsigned s_cnt = 0;
489  ++s_cnt;
490  string base_temp_dir = m_BaseDir;
491  string temp_dir = string("tmp") + NStr::IntToString(s_cnt);
492  base_temp_dir = CDirEntry::ConcatPath(base_temp_dir, temp_dir);
493 
494  try {
495  CDirEntry::CreateAbsolutePath(base_temp_dir);
496 
497  // Build streaming [un]tar on top of uncompressed data
498  CTarCheckpointed tar(is, m_DlcbData);
499 
500  tar.SetBaseDir(base_temp_dir);
502 
503  tar.Extract();
504 
505  tar.Close();
506 
507  ftp.Close();
508 
509  download_ok = true;
510 
511  } catch (CException& ex) {
512  if (!m_DlcbData->GetCancel()) {
513  m_Error = new CAppJobError(ex.ReportAll());
514  }
515  } catch (std::exception& e) {
516  if (!m_DlcbData->GetCancel()) {
517  m_Error = new CAppJobError(e.what());
518  }
519  }
520 
521  if (!download_ok || m_DlcbData->GetCancel()) {
522  CDirEntry de(base_temp_dir);
523  de.Remove();
524  if (m_DlcbData->GetCancel()) {
525  // return IAppJob::eCompleted;
526  return IAppJob::eCanceled;
527  }
528  return IAppJob::eFailed;
529  }
530 
531  // download ok, need to move temp directory content one level up
532  try {
533  {{
534  CDir dir(base_temp_dir);
535  CDir::TEntries contents = dir.GetEntries("*", CDir::fIgnoreRecursive);
536  ITERATE(CDir::TEntries, i, contents) {
537  string entry = (*i)->GetPath();
538  string new_name = CDirEntry::MakePath(m_BaseDir, (*i)->GetName());
539  CDirEntry(entry).Rename(new_name, CDirEntry::fRF_Overwrite);
540  }
541  }}
542  CDirEntry de(base_temp_dir);
543  de.Remove();
544  } catch (CException& ex) {
545  if (!m_DlcbData->GetCancel()) {
546  m_Error = new CAppJobError(ex.ReportAll());
547  return IAppJob::eFailed;
548  }
549  return IAppJob::eCanceled;
550  } catch (std::exception& e) {
551  if (!m_DlcbData->GetCancel()) {
552  m_Error = new CAppJobError(e.what());
553  return IAppJob::eFailed;
554  }
555  return IAppJob::eCanceled;
556  }
557  ERR_POST(Info << "Download OK");
558 
559  return IAppJob::eCompleted;
560 }
561 
562 
CAppJobError Default implementation for IAppJobError - encapsulates a text error message.
CAppJobProgress Default implementation for IAppJobProgress - the class encapsulates a text message an...
CConn_FtpStream is an elaborate FTP client, can be used for data downloading and/or uploading to and ...
CDecompressIStream –.
CDirEntry –.
Definition: ncbifile.hpp:262
CDir –.
Definition: ncbifile.hpp:1696
CAtomicCounter::TValue GetCancel() const
string m_TaskName
Name of the task.
string m_URL
URL to download.
EJobState x_DownloadAndExtract(const string &url)
virtual bool IsCanceled() const
CRef< CObject > m_Result
bool m_ExtractArchives
Flag, indicating whether to extract archives on download.
CFastMutex m_Mutex
Mutex for guarding state access.
virtual CRef< CObject > GetResult()
Returns the Job Result.
string m_BaseDir
Base directory to download and optionally unpack.
CRef< CAppJobError > m_Error
CDownloadJob(const string &desc, const string &base_dir, const string &download_url, bool extract_archive=true)
CNetBlastLoadingJob.
virtual string GetDescr() const
Returns a human readable description of the Job (optional)
virtual void RequestCancel()
RequestCancel() is called to notify the Job that it shall exit Run() function ASAP.
EJobState x_Download(const string &url, const string &file_name)
CDownloadCallbackData * m_DlcbData
string x_FormatSize(size_t bytes)
vector< string > m_FilesToLoad
List of files to load.
virtual CConstIRef< IAppJobProgress > GetProgress()
return progress object, the function shall be synchronized internally.
virtual CConstIRef< IAppJobError > GetError()
Returns IAppJobError object describing internal error that caused the Job to fail.
virtual EJobState Run()
Function that does all the useful work, called by the Engine.
CDownloadJob::CDownloadCallbackData * m_DlCbData
CTarCheckpointed(istream &is, CDownloadJob::CDownloadCallbackData *dlcbdata)
virtual bool Checkpoint(const CTarEntryInfo &current, bool)
Return false to skip the current entry when reading; the return code gets ignored when writing.
CTarEntryInfo class.
Definition: tar.hpp:159
CTar class.
Definition: tar.hpp:301
const char * file_name[]
static size_t s_GetFtpFilesize(iostream &ios, const char *filename)
static EIO_Status s_FtpCallback(CONN conn, TCONN_Callback type, void *data)
static void s_InitiateFtpFileDownload(iostream &ios, const char *filename)
std::ofstream out("events_result.xml")
main entry point for tests
static CS_CONNECTION * conn
Definition: ct_dynamic.c:25
static int trunc
Definition: array_out.c:8
char data[12]
Definition: iconv.c:80
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
string
Definition: cgiapp.hpp:687
@ eGZipFile
.gz file (including concatenated files)
void SetBaseDir(const string &dirname)
Set base directory to use for files while extracting from/adding to the archive, and in the latter ca...
Definition: tar.cpp:4603
Uint8 GetSize(void) const
Definition: tar.hpp:211
void SetFlags(TFlags flags)
Set processing flags.
Definition: tar.hpp:862
void Close(void)
Close the archive making sure all pending output is flushed.
Definition: tar.hpp:814
unique_ptr< TEntries > Extract(void)
Extract the entire archive (into either current directory or a directory otherwise specified by SetBa...
Definition: tar.cpp:1632
@ fOverwrite
Allow to overwrite destinations with entries from the archive.
Definition: tar.hpp:316
virtual EIO_Status Close(void)
Close CONNection, free all internal buffers and underlying structures, and render the stream unusable...
CONN GetCONN(void) const
ECONN_Callback
Set user callback function to be invoked upon an event specified by the callback type.
EIO_Status CONN_SetCallback(CONN conn, ECONN_Callback type, const SCONN_Callback *new_cb, SCONN_Callback *old_cb)
unsigned int TCONN_Callback
TNCBI_BigCount CONN_GetPosition(CONN conn, EIO_Event event)
Get read ("event" == eIO_Read) or write ("event" == eIO_Write) position within the connection.
void * data
data to pass to the callback as its last arg
FCONN_Callback func
function address to call on the event
@ eCONN_OnClose
NB: CONN has been flushed prior to the call.
@ eCONN_OnRead
Read from CONNECTOR is about to occur.
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
Definition: ncbidiag.hpp:186
string ReportAll(TDiagPostFlags flags=eDPF_Exception) const
Report all exceptions.
Definition: ncbiexpt.cpp:370
void Fatal(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1209
void Info(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1185
TEntries GetEntries(const string &mask=kEmptyStr, TGetEntriesFlags flags=0) const
Get directory entries based on the specified "mask".
Definition: ncbifile.cpp:3846
static string CreateAbsolutePath(const string &path, ERelativeToWhat rtw=eRelativeToCwd)
Get an absolute path from some, possibly relative, path.
Definition: ncbifile.cpp:665
virtual bool Exists(void) const
Check the entry existence.
Definition: ncbifile.cpp:2325
bool Rename(const string &new_path, TRenameFlags flags=fRF_Default)
Rename entry.
Definition: ncbifile.cpp:2456
virtual bool Remove(TRemoveFlags flags=eRecursive) const
Remove a directory entry.
Definition: ncbifile.cpp:2595
static string MakePath(const string &dir=kEmptyStr, const string &base=kEmptyStr, const string &ext=kEmptyStr)
Assemble a path from basic components.
Definition: ncbifile.cpp:413
static char GetPathSeparator(void)
Get path separator symbol specific for the current platform.
Definition: ncbifile.cpp:433
static string ConcatPath(const string &first, const string &second)
Concatenate two parts of the path for the current OS.
Definition: ncbifile.cpp:776
list< TEntry > TEntries
Definition: ncbifile.hpp:1751
@ fRF_Overwrite
Remove destination if it exists.
Definition: ncbifile.hpp:612
@ fIgnoreRecursive
Suppress "self recursive" elements (the directories "." and "..").
Definition: ncbifile.hpp:1756
EJobState
Job states (describe FSM)
Definition: app_job.hpp:86
@ eCanceled
Definition: app_job.hpp:91
@ eCompleted
Definition: app_job.hpp:89
@ eFailed
Definition: app_job.hpp:90
TObjectType * GetPointer(void) THROWS_NONE
Get pointer,.
Definition: ncbiobj.hpp:998
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
IO_PREFIX::fstream CNcbiFstream
Portable alias for fstream.
Definition: ncbistre.hpp:538
static string DoubleToString(double value, int precision=-1, TNumToStringFlags flags=0)
Convert double to string.
Definition: ncbistr.hpp:5189
static string IntToString(int value, TNumToStringFlags flags=0, int base=10)
Convert int to string.
Definition: ncbistr.hpp:5086
int ConnNetInfo_ParseURL(SConnNetInfo *net_info, const char *url)
char user[63+1]
EIO_Status
I/O status.
Definition: ncbi_core.h:132
EBURLScheme scheme
char pass[63+1]
SConnNetInfo * ConnNetInfo_Create(const char *service)
char host[255+1]
char path[4095+1]
void ConnNetInfo_Destroy(SConnNetInfo *net_info)
@ eURL_Ftp
@ eIO_Interrupt
signal arrival prevented any I/O to succeed
Definition: ncbi_core.h:136
@ eIO_Success
everything is fine, no error occurred
Definition: ncbi_core.h:133
@ eIO_Open
also serves as no-event indicator in SOCK_Poll
Definition: ncbi_core.h:119
@ eIO_Read
read
Definition: ncbi_core.h:120
int i
const struct ncbi::grid::netcache::search::fields::SIZE size
Defines classes: CDirEntry, CFile, CDir, CSymLink, CMemoryFile, CFileUtil, CFileLock,...
T log10(T x_)
static pcre_uint8 * buffer
Definition: pcretest.c:1051
C++ I/O stream wrappers to compress/decompress data on-the-fly.
Definition: type.c:6
Tar archive API.
else result
Definition: token2.c:20
Modified on Sun Jul 14 04:59:45 2024 by modify_doxy.py rev. 669887