Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

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