Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
11 andreas 1
/*
88 andreas 2
 * Copyright (C) 2019 to 2022 by Andreas Theofilu <andreas@theosys.at>
11 andreas 3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
 
19
#include <chrono>
21 andreas 20
#if __GNUC__ < 9 && !defined(__ANDROID__)
11 andreas 21
   #if __cplusplus < 201703L
22
      #warning "Your C++ compiler seems to have no support for C++17 standard!"
23
   #endif
24
   #include <experimental/filesystem>
25
   namespace fs = std::experimental::filesystem;
26
#else
21 andreas 27
#  ifdef __ANDROID__
82 andreas 28
#   if _LIBCPP_STD_VER >= 17
29
#       include <filesystem>
30
        namespace fs = std::__fs::filesystem;
31
#   else
32
#       include <experimental/filesystem>
33
        namespace fs = std::__fs::filesystem;
34
#   endif
21 andreas 35
#  else
82 andreas 36
#   include <filesystem>
37
    namespace fs = std::filesystem;
21 andreas 38
#  endif
11 andreas 39
#endif
40
#include "tconfig.h"
41
#include "terror.h"
42
#include "tdirectory.h"
65 andreas 43
#include "tresources.h"
11 andreas 44
 
45
using namespace std;
46
using namespace dir;
99 andreas 47
using namespace std::chrono_literals;
11 andreas 48
 
49
int TDirectory::readDir()
50
{
51
	DECL_TRACER("Directory::readDir()");
52
 
53
	if (path.empty())
54
		return 0;
55
 
88 andreas 56
    if (!exists(path) || !isDirectory(path))
57
    {
58
        MSG_WARNING("Ignoring invalid path " << path);
59
        return 0;
60
    }
61
 
11 andreas 62
	int count = 0;
63
 
64
	try
65
	{
66
		for(auto& p: fs::directory_iterator(path))
67
		{
68
			DFILES_T dr;
69
			string f = fs::path(p.path()).filename();
70
 
71
			if (f.at(0) == '.')
72
				continue;
73
 
74
			if (path.find("__system/") == string::npos && f.find("__system") != string::npos)
75
				continue;
76
#if __GNUC__ < 9
77
			if (path.find("scripts") != string::npos && fs::is_directory(p.path()))
78
#else
79
			if (path.find("scripts") != string::npos && p.is_directory())
80
#endif
81
				continue;
82
 
83
			count++;
84
			dr.count = count;
85
#if __GNUC__ < 9
86
			time_t ti = fs::last_write_time(p.path()).time_since_epoch().count();
87
#else
88
			time_t ti = p.last_write_time().time_since_epoch().count();
89
#endif
90
			dr.date = (ti / 1000000000) + 6437664000;
91
 
92
#if __GNUC__ < 9
93
			if (fs::is_directory(p.path()))
94
#else
95
			if (p.is_directory())
96
#endif
97
				dr.size = 0;
98
			else
99
#if __GNUC__ < 9
100
				dr.size = fs::file_size(p.path());
101
#else
102
				dr.size = p.file_size();
103
#endif
104
 
105
			if (strip)
106
				dr.name = f;
107
			else
108
				dr.name = p.path();
109
 
110
			dr.attr = 0;
111
 
112
#if __GNUC__ < 9
113
			if (fs::is_directory(p.path()))
114
#else
115
			if (p.is_directory())
116
#endif
117
				dr.attr = dr.attr | ATTR_DIRECTORY;
118
#if __GNUC__ < 9
119
			else if (fs::is_regular_file(p.path()))
120
#else
121
			else if (p.is_regular_file())
122
#endif
123
			{
124
				if (dr.name.find(".png") != string::npos || dr.name.find(".PNG") != string::npos ||
125
						dr.name.find(".jpg") != string::npos || dr.name.find(".JPG") != string::npos)
126
					dr.attr = dr.attr | ATTR_GRAPHIC;
127
				else if (dr.name.find(".wav") != string::npos || dr.name.find(".WAV") != string::npos ||
128
						dr.name.find(".mp3") != string::npos || dr.name.find(".MP3") != string::npos)
129
					dr.attr = dr.attr | ATTR_SOUND;
130
				else
131
					dr.attr = dr.attr | ATTR_TEXT;
132
			}
133
 
134
#if __GNUC__ < 9
135
			if (fs::is_symlink(p.path()))
136
#else
137
			if (p.is_symlink())
138
#endif
139
				dr.attr |= ATTR_LINK;
140
 
141
			entries.push_back(dr);
142
 
23 andreas 143
            if (TStreamError::checkFilter(HLOG_DEBUG))
11 andreas 144
			{
145
				char buf[4096];
146
				char d, g, l;
147
 
148
				d = l = '_';
149
				g = ' ';
150
 
151
				if (dr.attr & ATTR_DIRECTORY)
152
					d = 'D';
153
 
154
				if (dr.attr & ATTR_GRAPHIC)
155
					g = 'g';
156
				else if (dr.attr & ATTR_SOUND)
157
					g = 's';
158
				else if (dr.attr & ATTR_TEXT)
159
					g = 't';
160
 
161
				if (dr.attr & ATTR_LINK)
162
					l = 'L';
163
 
164
				struct tm *t = localtime(&dr.date);
165
 
166
				if (t == nullptr)
167
					snprintf(buf, sizeof(buf), "%c%c%c %8zu 0000-00-00 00:00:00 %s", d, g, l, dr.size, dr.name.c_str());
168
				else
169
					snprintf(buf, sizeof(buf), "%c%c%c %8zu %4d-%02d-%02d %02d:%02d:%02d %s", d, g, l, dr.size, t->tm_year + 1900, t->tm_mon+1, t->tm_mday,
170
                         t->tm_hour, t->tm_min, t->tm_sec, dr.name.c_str());
171
 
172
				MSG_TRACE("Buffer: " << buf);
173
			}
174
		}
175
 
176
		done = true;
177
		MSG_TRACE("Read " << count << " entries.");
178
	}
179
	catch(exception& e)
180
	{
181
		MSG_ERROR("Error: " << e.what());
182
		entries.clear();
183
		return 0;
184
	}
185
 
186
	return count;
187
}
188
 
80 andreas 189
int TDirectory::readDir (const string &p)
11 andreas 190
{
80 andreas 191
	DECL_TRACER("Directory::readDir (const string &p)");
11 andreas 192
 
193
	path.assign(p);
194
 
195
	if (done)
196
		entries.clear();
197
 
198
	done = false;
199
	return readDir();
200
}
201
 
80 andreas 202
int TDirectory::scanFiles(const string &filter)
203
{
204
    DECL_TRACER("TDirectory::scanFiles(const string &filter)");
205
 
206
    if (path.empty())
207
        return 0;
208
 
209
    int count = 0;
210
    entries.clear();
211
 
212
    try
213
    {
214
        for(auto& p: fs::directory_iterator(path))
215
        {
216
            DFILES_T dr;
217
            string f = fs::path(p.path()).filename();
218
 
219
            if (checkDot(f))
220
                continue;
221
 
222
            if (!filter.empty() && f.find(filter) == string::npos)
223
                continue;
224
 
225
            count++;
226
            dr.count = count;
227
#if __GNUC__ < 9
228
            time_t ti = fs::last_write_time(p.path()).time_since_epoch().count();
229
#else
230
            time_t ti = p.last_write_time().time_since_epoch().count();
231
#endif
232
            dr.date = (ti / 1000000000) + 6437664000;
233
 
234
#if __GNUC__ < 9
235
            if (fs::is_directory(p.path()))
236
#else
237
            if (p.is_directory())
238
#endif
239
                dr.size = 0;
240
            else
241
#if __GNUC__ < 9
242
                dr.size = fs::file_size(p.path());
243
#else
244
                dr.size = p.file_size();
245
#endif
246
 
247
            if (strip)
248
                dr.name = f;
249
            else
250
                dr.name = p.path();
251
 
252
            dr.attr = 0;
253
 
254
#if __GNUC__ < 9
255
            if (fs::is_directory(p.path()))
256
#else
257
            if (p.is_directory())
258
#endif
259
                dr.attr = dr.attr | ATTR_DIRECTORY;
260
#if __GNUC__ < 9
261
            else if (fs::is_regular_file(p.path()))
262
#else
263
            else if (p.is_regular_file())
264
#endif
265
            {
266
                if (dr.name.find(".png") != string::npos || dr.name.find(".PNG") != string::npos ||
267
                    dr.name.find(".jpg") != string::npos || dr.name.find(".JPG") != string::npos)
268
                    dr.attr = dr.attr | ATTR_GRAPHIC;
269
                else if (dr.name.find(".wav") != string::npos || dr.name.find(".WAV") != string::npos ||
270
                    dr.name.find(".mp3") != string::npos || dr.name.find(".MP3") != string::npos)
271
                    dr.attr = dr.attr | ATTR_SOUND;
272
                else
273
                    dr.attr = dr.attr | ATTR_TEXT;
274
            }
275
 
276
#if __GNUC__ < 9
277
            if (fs::is_symlink(p.path()))
278
#else
279
            if (p.is_symlink())
280
#endif
281
                dr.attr |= ATTR_LINK;
282
 
283
            entries.push_back(dr);
284
        }
285
 
286
        done = true;
287
        MSG_TRACE("Read " << count << " entries.");
288
        vector<DFILES_T>::iterator iter;
289
 
290
        for (iter = entries.begin(); iter != entries.end(); ++iter)
291
            MSG_DEBUG("Entry: " << iter->name);
292
    }
293
    catch(exception& e)
294
    {
295
        MSG_ERROR("Error: " << e.what());
296
        entries.clear();
297
        return 0;
298
    }
299
 
300
    return count;
301
}
302
 
11 andreas 303
size_t TDirectory::getNumEntries()
304
{
305
	DECL_TRACER("Directory::getNumEntries()");
306
 
307
	if (done)
308
		return entries.size();
309
 
310
	return 0;
311
}
312
 
313
DFILES_T TDirectory::getEntry (size_t pos)
314
{
315
	DECL_TRACER("Directory::getEntry (size_t pos)");
316
 
317
	if (!done || pos >= entries.size())
318
	{
319
		DFILES_T d;
320
		d.attr = 0;
321
		d.count = 0;
322
		d.date = 0;
323
		d.size = 0;
324
		return d;
325
	}
326
 
327
	return entries.at(pos);
328
}
329
 
330
string TDirectory::stripPath (const string &p, size_t idx)
331
{
332
	DECL_TRACER("Directory::stripPath (const string &p, size_t idx)");
333
 
334
	if (!done || idx > entries.size())
335
		return "";
336
 
337
	size_t pos;
338
	DFILES_T dr = getEntry(idx);
339
 
340
	if ((pos = dr.name.find(p)) == string::npos)
341
		return "";
342
 
343
	return dr.name.substr(pos + p.length());
344
}
345
 
346
string TDirectory::stripPath (const string &p, const string &s)
347
{
348
	DECL_TRACER("Directory::stripPath (const string &p, const string &s)");
349
 
350
	size_t pos;
351
 
352
	if ((pos = s.find(p)) == string::npos)
353
		return "";
354
 
355
	return s.substr(pos + p.length());
356
}
357
 
65 andreas 358
bool TDirectory::createAllPath(string& path, bool cut)
359
{
88 andreas 360
    DECL_TRACER("TDirectory::createAllPath(string& path, bool cut)");
65 andreas 361
 
362
    string pth = path;
363
 
364
    if (cut)
365
    {
366
        size_t pos = path.find_last_of("/");
367
 
368
        if (pos != string::npos)
369
            pth = path.substr(0, pos);
370
        else
371
            return false;
372
    }
373
 
374
    MSG_INFO("Creating path: " << pth);
375
    return fs::create_directories(pth);
376
}
377
 
378
bool TDirectory::drop(const string &path)
379
{
380
    DECL_TRACER("TDirectory::drop(const string &path)");
381
 
382
    try
383
    {
384
        int n = fs::remove_all(path);
385
        MSG_TRACE("Deleted " << n << " objects.");
386
        return true;
387
    }
388
    catch (std::exception& e)
389
    {
390
        MSG_ERROR("Error deleting file/directory: " << path);
391
        MSG_ERROR(e.what());
392
    }
393
 
394
    return false;
395
}
396
 
119 andreas 397
/**
398
 * @brief TDirectory::dropDir deletes all files in a directory
399
 * This methos deletes only the files in a given directory and leaves all
400
 * subdirectories along with the files in them alone.
401
 *
402
 * @param path  A valid path. The files in this path will be deleted.
403
 * @return On success TRUE is returned.
404
 */
405
bool TDirectory::dropDir(const string& path)
406
{
407
    DECL_TRACER("TDirectory::dropDir(const string& path)");
408
 
409
    if (path.empty())
410
        return 0;
411
 
412
    int count = 0;
413
 
414
    try
415
    {
416
        for(auto& p: fs::directory_iterator(path))
417
        {
418
            string f = fs::path(p.path()).filename();
419
 
420
            if (checkDot(f))
421
                continue;
422
#if __GNUC__ < 9
423
            if (fs::is_directory(p.path()))
424
#else
425
            if (p.is_directory())
426
#endif
427
                continue;
428
 
429
            fs::remove(p.path());
430
            count++;
431
        }
432
    }
433
    catch (std::exception& e)
434
    {
435
        MSG_ERROR("Error dir drop: " << e.what());
436
        return false;
437
    }
438
 
439
    MSG_DEBUG("Deleted " << count << " files.");
440
    return true;
441
}
442
 
443
bool TDirectory::dropFile(const string& fname)
444
{
445
    DECL_TRACER("TDirectory::dropFile(const string& fname)");
446
 
447
    try
448
    {
449
        fs::remove(fname);
450
    }
451
    catch (std::exception& e)
452
    {
453
        MSG_ERROR("Error removing file " << fname << "!");
454
        return false;
455
    }
456
 
457
    return true;
458
}
459
 
80 andreas 460
string TDirectory::getEntryWithEnd(const string &end)
461
{
462
    DECL_TRACER("TDirectory::getEntryWithEnd(const string &end)");
463
 
88 andreas 464
    if (entries.size() == 0)
465
        return string();
466
 
80 andreas 467
    vector<DFILES_T>::iterator iter;
468
    size_t pos;
469
 
470
    for (iter = entries.begin(); iter != entries.end(); ++iter)
471
    {
472
        if ((pos = iter->name.find_last_of(end)) != string::npos && (pos + end.length()) == iter->name.length())
473
            return iter->name;
474
    }
475
 
476
    return string();
477
}
478
 
101 andreas 479
string TDirectory::getEntryWithPart(const string &part, bool precice)
80 andreas 480
{
101 andreas 481
    DECL_TRACER("TDirectory::getEntryWithPart(const string &part, bool precice)");
80 andreas 482
 
88 andreas 483
    if (entries.size() == 0)
484
        return string();
485
 
80 andreas 486
    vector<DFILES_T>::iterator iter;
487
    size_t pos;
488
 
489
    for (iter = entries.begin(); iter != entries.end(); ++iter)
490
    {
491
        if ((pos = iter->name.find(part)) != string::npos)
492
        {
493
            char next = iter->name.at(pos + part.length());
494
 
100 andreas 495
            if (next == '.')
496
                return iter->name;
497
 
101 andreas 498
            if ((next >= 'A' && next <= 'Z') || (next >= 'a' && next <= 'z') || (precice && next == '_'))
80 andreas 499
                continue;
500
 
501
            return iter->name;
502
        }
503
    }
504
 
505
    return string();
506
}
507
 
11 andreas 508
size_t TDirectory::getFileSize (const string &f)
509
{
510
	DECL_TRACER("Directory::getFileSize (const string &f)");
511
	size_t s = 0;
512
 
513
	try
514
	{
515
		if (!fs::path(f).has_filename())
516
			return s;
517
 
518
		s = fs::file_size(f);
519
	}
520
	catch(exception& e)
521
	{
522
		MSG_ERROR("Error: " << e.what());
523
		s = 0;
524
	}
525
 
526
	return s;
527
}
528
 
529
bool TDirectory::isFile (const string &f)
530
{
531
	DECL_TRACER("Directory::isFile (const string &f)");
532
 
533
	try
534
	{
535
		return fs::is_regular_file(f);
536
	}
537
	catch(exception& e)
538
	{
539
		MSG_ERROR("Error: " << e.what());
540
	}
541
 
542
	return false;
543
}
544
 
545
bool TDirectory::isDirectory (const string &f)
546
{
547
	DECL_TRACER("Directory::isDirectory (const string &f)");
548
 
549
	try
550
	{
551
		return fs::is_directory(f);
552
	}
553
	catch(exception& e)
554
	{
555
		MSG_ERROR("Error: " << e.what());
556
	}
557
 
558
	return false;
559
}
560
 
561
bool TDirectory::exists (const string &f)
562
{
563
	DECL_TRACER("Directory::exists (const string &f)");
564
 
565
	try
566
	{
567
		return fs::exists(f);
568
	}
569
	catch(exception& e)
570
	{
571
		MSG_ERROR("Error: " << e.what());
572
	}
573
 
574
	return false;
575
}
576
 
577
bool TDirectory::checkDot (const string &s)
578
{
80 andreas 579
//	DECL_TRACER("Directory::checkDot (const string &s)");
11 andreas 580
 
581
	size_t pos = s.find_last_of("/");
582
	string f = s;
583
 
584
	if (pos != string::npos)
585
		f = s.substr(pos + 1);
586
 
587
	if (f.at(0) == '.')
588
		return true;
589
 
590
	return false;
591
}