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>
125 andreas 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
141 andreas 37
 
11 andreas 38
#include "tconfig.h"
39
#include "terror.h"
40
#include "tdirectory.h"
65 andreas 41
#include "tresources.h"
11 andreas 42
 
43
using namespace std;
44
using namespace dir;
99 andreas 45
using namespace std::chrono_literals;
11 andreas 46
 
47
int TDirectory::readDir()
48
{
49
	DECL_TRACER("Directory::readDir()");
50
 
51
	if (path.empty())
52
		return 0;
53
 
88 andreas 54
    if (!exists(path) || !isDirectory(path))
55
    {
56
        MSG_WARNING("Ignoring invalid path " << path);
57
        return 0;
58
    }
59
 
11 andreas 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
 
23 andreas 141
            if (TStreamError::checkFilter(HLOG_DEBUG))
11 andreas 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
 
80 andreas 187
int TDirectory::readDir (const string &p)
11 andreas 188
{
80 andreas 189
	DECL_TRACER("Directory::readDir (const string &p)");
11 andreas 190
 
191
	path.assign(p);
192
 
193
	if (done)
194
		entries.clear();
195
 
196
	done = false;
197
	return readDir();
198
}
199
 
80 andreas 200
int TDirectory::scanFiles(const string &filter)
201
{
202
    DECL_TRACER("TDirectory::scanFiles(const string &filter)");
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
            if (!filter.empty() && f.find(filter) == string::npos)
221
                continue;
222
 
223
            count++;
224
            dr.count = count;
225
#if __GNUC__ < 9
226
            time_t ti = fs::last_write_time(p.path()).time_since_epoch().count();
227
#else
228
            time_t ti = p.last_write_time().time_since_epoch().count();
229
#endif
230
            dr.date = (ti / 1000000000) + 6437664000;
231
 
232
#if __GNUC__ < 9
233
            if (fs::is_directory(p.path()))
234
#else
235
            if (p.is_directory())
236
#endif
237
                dr.size = 0;
238
            else
239
#if __GNUC__ < 9
240
                dr.size = fs::file_size(p.path());
241
#else
242
                dr.size = p.file_size();
243
#endif
244
 
245
            if (strip)
246
                dr.name = f;
247
            else
248
                dr.name = p.path();
249
 
250
            dr.attr = 0;
251
 
252
#if __GNUC__ < 9
253
            if (fs::is_directory(p.path()))
254
#else
255
            if (p.is_directory())
256
#endif
257
                dr.attr = dr.attr | ATTR_DIRECTORY;
258
#if __GNUC__ < 9
259
            else if (fs::is_regular_file(p.path()))
260
#else
261
            else if (p.is_regular_file())
262
#endif
263
            {
264
                if (dr.name.find(".png") != string::npos || dr.name.find(".PNG") != string::npos ||
265
                    dr.name.find(".jpg") != string::npos || dr.name.find(".JPG") != string::npos)
266
                    dr.attr = dr.attr | ATTR_GRAPHIC;
267
                else if (dr.name.find(".wav") != string::npos || dr.name.find(".WAV") != string::npos ||
268
                    dr.name.find(".mp3") != string::npos || dr.name.find(".MP3") != string::npos)
269
                    dr.attr = dr.attr | ATTR_SOUND;
270
                else
271
                    dr.attr = dr.attr | ATTR_TEXT;
272
            }
273
 
274
#if __GNUC__ < 9
275
            if (fs::is_symlink(p.path()))
276
#else
277
            if (p.is_symlink())
278
#endif
279
                dr.attr |= ATTR_LINK;
280
 
281
            entries.push_back(dr);
282
        }
283
 
284
        done = true;
326 andreas 285
        MSG_DEBUG("Read " << count << " entries.");
80 andreas 286
 
326 andreas 287
        if (TStreamError::checkFilter(HLOG_DEBUG))
288
        {
289
            vector<DFILES_T>::iterator iter;
290
 
291
            for (iter = entries.begin(); iter != entries.end(); ++iter)
292
                MSG_DEBUG("Entry: " << iter->name);
293
        }
80 andreas 294
    }
295
    catch(exception& e)
296
    {
297
        MSG_ERROR("Error: " << e.what());
298
        entries.clear();
299
        return 0;
300
    }
301
 
302
    return count;
303
}
304
 
11 andreas 305
size_t TDirectory::getNumEntries()
306
{
307
	DECL_TRACER("Directory::getNumEntries()");
308
 
309
	if (done)
310
		return entries.size();
311
 
312
	return 0;
313
}
314
 
315
DFILES_T TDirectory::getEntry (size_t pos)
316
{
317
	DECL_TRACER("Directory::getEntry (size_t pos)");
318
 
319
	if (!done || pos >= entries.size())
320
	{
321
		DFILES_T d;
322
		d.attr = 0;
323
		d.count = 0;
324
		d.date = 0;
325
		d.size = 0;
326
		return d;
327
	}
328
 
329
	return entries.at(pos);
330
}
331
 
332
string TDirectory::stripPath (const string &p, size_t idx)
333
{
334
	DECL_TRACER("Directory::stripPath (const string &p, size_t idx)");
335
 
336
	if (!done || idx > entries.size())
337
		return "";
338
 
339
	size_t pos;
340
	DFILES_T dr = getEntry(idx);
341
 
342
	if ((pos = dr.name.find(p)) == string::npos)
343
		return "";
344
 
345
	return dr.name.substr(pos + p.length());
346
}
347
 
348
string TDirectory::stripPath (const string &p, const string &s)
349
{
350
	DECL_TRACER("Directory::stripPath (const string &p, const string &s)");
351
 
352
	size_t pos;
353
 
354
	if ((pos = s.find(p)) == string::npos)
355
		return "";
356
 
357
	return s.substr(pos + p.length());
358
}
359
 
65 andreas 360
bool TDirectory::createAllPath(string& path, bool cut)
361
{
88 andreas 362
    DECL_TRACER("TDirectory::createAllPath(string& path, bool cut)");
65 andreas 363
 
364
    string pth = path;
365
 
366
    if (cut)
367
    {
368
        size_t pos = path.find_last_of("/");
369
 
370
        if (pos != string::npos)
371
            pth = path.substr(0, pos);
372
        else
373
            return false;
374
    }
375
 
376
    MSG_INFO("Creating path: " << pth);
377
    return fs::create_directories(pth);
378
}
379
 
380
bool TDirectory::drop(const string &path)
381
{
382
    DECL_TRACER("TDirectory::drop(const string &path)");
383
 
384
    try
385
    {
245 andreas 386
        int n = (int)fs::remove_all(path);
65 andreas 387
        MSG_TRACE("Deleted " << n << " objects.");
388
        return true;
389
    }
390
    catch (std::exception& e)
391
    {
392
        MSG_ERROR("Error deleting file/directory: " << path);
393
        MSG_ERROR(e.what());
394
    }
395
 
396
    return false;
397
}
398
 
119 andreas 399
/**
400
 * @brief TDirectory::dropDir deletes all files in a directory
401
 * This methos deletes only the files in a given directory and leaves all
402
 * subdirectories along with the files in them alone.
403
 *
404
 * @param path  A valid path. The files in this path will be deleted.
405
 * @return On success TRUE is returned.
406
 */
407
bool TDirectory::dropDir(const string& path)
408
{
409
    DECL_TRACER("TDirectory::dropDir(const string& path)");
410
 
411
    if (path.empty())
412
        return 0;
413
 
245 andreas 414
    if (!fs::exists(path))
415
    {
416
        MSG_WARNING("Directory \"" << path << "\" does not exist!");
417
        return 0;
418
    }
326 andreas 419
 
245 andreas 420
    MSG_DEBUG("Dropping directory: " << path);
119 andreas 421
    int count = 0;
422
 
423
    try
424
    {
425
        for(auto& p: fs::directory_iterator(path))
426
        {
427
            string f = fs::path(p.path()).filename();
428
 
429
            if (checkDot(f))
430
                continue;
431
#if __GNUC__ < 9
432
            if (fs::is_directory(p.path()))
433
#else
434
            if (p.is_directory())
435
#endif
436
                continue;
437
 
155 andreas 438
            if (!fs::remove(p.path()))
439
            {
440
                MSG_ERROR("Error deleting file:" << p.path());
441
            }
442
 
119 andreas 443
            count++;
444
        }
445
    }
446
    catch (std::exception& e)
447
    {
448
        MSG_ERROR("Error dir drop: " << e.what());
449
        return false;
450
    }
451
 
452
    MSG_DEBUG("Deleted " << count << " files.");
453
    return true;
454
}
455
 
456
bool TDirectory::dropFile(const string& fname)
457
{
458
    DECL_TRACER("TDirectory::dropFile(const string& fname)");
459
 
460
    try
461
    {
462
        fs::remove(fname);
463
    }
464
    catch (std::exception& e)
465
    {
466
        MSG_ERROR("Error removing file " << fname << "!");
467
        return false;
468
    }
469
 
470
    return true;
471
}
472
 
80 andreas 473
string TDirectory::getEntryWithEnd(const string &end)
474
{
475
    DECL_TRACER("TDirectory::getEntryWithEnd(const string &end)");
476
 
88 andreas 477
    if (entries.size() == 0)
478
        return string();
479
 
80 andreas 480
    vector<DFILES_T>::iterator iter;
481
    size_t pos;
482
 
483
    for (iter = entries.begin(); iter != entries.end(); ++iter)
484
    {
485
        if ((pos = iter->name.find_last_of(end)) != string::npos && (pos + end.length()) == iter->name.length())
486
            return iter->name;
487
    }
488
 
489
    return string();
490
}
491
 
101 andreas 492
string TDirectory::getEntryWithPart(const string &part, bool precice)
80 andreas 493
{
101 andreas 494
    DECL_TRACER("TDirectory::getEntryWithPart(const string &part, bool precice)");
80 andreas 495
 
88 andreas 496
    if (entries.size() == 0)
497
        return string();
498
 
80 andreas 499
    vector<DFILES_T>::iterator iter;
500
    size_t pos;
501
 
502
    for (iter = entries.begin(); iter != entries.end(); ++iter)
503
    {
504
        if ((pos = iter->name.find(part)) != string::npos)
505
        {
506
            char next = iter->name.at(pos + part.length());
507
 
100 andreas 508
            if (next == '.')
509
                return iter->name;
510
 
157 andreas 511
            if (precice && next == '_')
80 andreas 512
                continue;
513
 
157 andreas 514
            if ((next >= 'A' && next <= 'Z') || (next >= 'a' && next <= 'z'))
515
                continue;
516
 
80 andreas 517
            return iter->name;
518
        }
519
    }
520
 
521
    return string();
522
}
523
 
11 andreas 524
size_t TDirectory::getFileSize (const string &f)
525
{
526
	DECL_TRACER("Directory::getFileSize (const string &f)");
527
	size_t s = 0;
528
 
529
	try
530
	{
531
		if (!fs::path(f).has_filename())
532
			return s;
533
 
534
		s = fs::file_size(f);
125 andreas 535
    }
11 andreas 536
	catch(exception& e)
537
	{
538
		MSG_ERROR("Error: " << e.what());
539
		s = 0;
540
	}
541
 
542
	return s;
543
}
544
 
545
bool TDirectory::isFile (const string &f)
546
{
547
	DECL_TRACER("Directory::isFile (const string &f)");
548
 
549
	try
550
	{
551
		return fs::is_regular_file(f);
552
	}
553
	catch(exception& e)
554
	{
555
		MSG_ERROR("Error: " << e.what());
556
	}
557
 
558
	return false;
559
}
560
 
561
bool TDirectory::isDirectory (const string &f)
562
{
563
	DECL_TRACER("Directory::isDirectory (const string &f)");
564
 
565
	try
566
	{
567
		return fs::is_directory(f);
568
	}
569
	catch(exception& e)
570
	{
571
		MSG_ERROR("Error: " << e.what());
572
	}
573
 
574
	return false;
575
}
576
 
577
bool TDirectory::exists (const string &f)
578
{
579
	DECL_TRACER("Directory::exists (const string &f)");
580
 
581
	try
582
	{
583
		return fs::exists(f);
584
	}
585
	catch(exception& e)
586
	{
587
		MSG_ERROR("Error: " << e.what());
588
	}
589
 
590
	return false;
591
}
592
 
593
bool TDirectory::checkDot (const string &s)
594
{
80 andreas 595
//	DECL_TRACER("Directory::checkDot (const string &s)");
11 andreas 596
 
597
	size_t pos = s.find_last_of("/");
598
	string f = s;
599
 
600
	if (pos != string::npos)
601
		f = s.substr(pos + 1);
602
 
603
	if (f.at(0) == '.')
604
		return true;
605
 
606
	return false;
607
}