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;
285
        MSG_TRACE("Read " << count << " entries.");
286
        vector<DFILES_T>::iterator iter;
287
 
288
        for (iter = entries.begin(); iter != entries.end(); ++iter)
289
            MSG_DEBUG("Entry: " << iter->name);
290
    }
291
    catch(exception& e)
292
    {
293
        MSG_ERROR("Error: " << e.what());
294
        entries.clear();
295
        return 0;
296
    }
297
 
298
    return count;
299
}
300
 
11 andreas 301
size_t TDirectory::getNumEntries()
302
{
303
	DECL_TRACER("Directory::getNumEntries()");
304
 
305
	if (done)
306
		return entries.size();
307
 
308
	return 0;
309
}
310
 
311
DFILES_T TDirectory::getEntry (size_t pos)
312
{
313
	DECL_TRACER("Directory::getEntry (size_t pos)");
314
 
315
	if (!done || pos >= entries.size())
316
	{
317
		DFILES_T d;
318
		d.attr = 0;
319
		d.count = 0;
320
		d.date = 0;
321
		d.size = 0;
322
		return d;
323
	}
324
 
325
	return entries.at(pos);
326
}
327
 
328
string TDirectory::stripPath (const string &p, size_t idx)
329
{
330
	DECL_TRACER("Directory::stripPath (const string &p, size_t idx)");
331
 
332
	if (!done || idx > entries.size())
333
		return "";
334
 
335
	size_t pos;
336
	DFILES_T dr = getEntry(idx);
337
 
338
	if ((pos = dr.name.find(p)) == string::npos)
339
		return "";
340
 
341
	return dr.name.substr(pos + p.length());
342
}
343
 
344
string TDirectory::stripPath (const string &p, const string &s)
345
{
346
	DECL_TRACER("Directory::stripPath (const string &p, const string &s)");
347
 
348
	size_t pos;
349
 
350
	if ((pos = s.find(p)) == string::npos)
351
		return "";
352
 
353
	return s.substr(pos + p.length());
354
}
355
 
65 andreas 356
bool TDirectory::createAllPath(string& path, bool cut)
357
{
88 andreas 358
    DECL_TRACER("TDirectory::createAllPath(string& path, bool cut)");
65 andreas 359
 
360
    string pth = path;
361
 
362
    if (cut)
363
    {
364
        size_t pos = path.find_last_of("/");
365
 
366
        if (pos != string::npos)
367
            pth = path.substr(0, pos);
368
        else
369
            return false;
370
    }
371
 
372
    MSG_INFO("Creating path: " << pth);
373
    return fs::create_directories(pth);
374
}
375
 
376
bool TDirectory::drop(const string &path)
377
{
378
    DECL_TRACER("TDirectory::drop(const string &path)");
379
 
380
    try
381
    {
382
        int n = fs::remove_all(path);
383
        MSG_TRACE("Deleted " << n << " objects.");
384
        return true;
385
    }
386
    catch (std::exception& e)
387
    {
388
        MSG_ERROR("Error deleting file/directory: " << path);
389
        MSG_ERROR(e.what());
390
    }
391
 
392
    return false;
393
}
394
 
119 andreas 395
/**
396
 * @brief TDirectory::dropDir deletes all files in a directory
397
 * This methos deletes only the files in a given directory and leaves all
398
 * subdirectories along with the files in them alone.
399
 *
400
 * @param path  A valid path. The files in this path will be deleted.
401
 * @return On success TRUE is returned.
402
 */
403
bool TDirectory::dropDir(const string& path)
404
{
405
    DECL_TRACER("TDirectory::dropDir(const string& path)");
406
 
407
    if (path.empty())
408
        return 0;
409
 
410
    int count = 0;
411
 
412
    try
413
    {
414
        for(auto& p: fs::directory_iterator(path))
415
        {
416
            string f = fs::path(p.path()).filename();
417
 
418
            if (checkDot(f))
419
                continue;
420
#if __GNUC__ < 9
421
            if (fs::is_directory(p.path()))
422
#else
423
            if (p.is_directory())
424
#endif
425
                continue;
426
 
155 andreas 427
            if (!fs::remove(p.path()))
428
            {
429
                MSG_ERROR("Error deleting file:" << p.path());
430
            }
431
 
119 andreas 432
            count++;
433
        }
434
    }
435
    catch (std::exception& e)
436
    {
437
        MSG_ERROR("Error dir drop: " << e.what());
438
        return false;
439
    }
440
 
441
    MSG_DEBUG("Deleted " << count << " files.");
442
    return true;
443
}
444
 
445
bool TDirectory::dropFile(const string& fname)
446
{
447
    DECL_TRACER("TDirectory::dropFile(const string& fname)");
448
 
449
    try
450
    {
451
        fs::remove(fname);
452
    }
453
    catch (std::exception& e)
454
    {
455
        MSG_ERROR("Error removing file " << fname << "!");
456
        return false;
457
    }
458
 
459
    return true;
460
}
461
 
80 andreas 462
string TDirectory::getEntryWithEnd(const string &end)
463
{
464
    DECL_TRACER("TDirectory::getEntryWithEnd(const string &end)");
465
 
88 andreas 466
    if (entries.size() == 0)
467
        return string();
468
 
80 andreas 469
    vector<DFILES_T>::iterator iter;
470
    size_t pos;
471
 
472
    for (iter = entries.begin(); iter != entries.end(); ++iter)
473
    {
474
        if ((pos = iter->name.find_last_of(end)) != string::npos && (pos + end.length()) == iter->name.length())
475
            return iter->name;
476
    }
477
 
478
    return string();
479
}
480
 
101 andreas 481
string TDirectory::getEntryWithPart(const string &part, bool precice)
80 andreas 482
{
101 andreas 483
    DECL_TRACER("TDirectory::getEntryWithPart(const string &part, bool precice)");
80 andreas 484
 
88 andreas 485
    if (entries.size() == 0)
486
        return string();
487
 
80 andreas 488
    vector<DFILES_T>::iterator iter;
489
    size_t pos;
490
 
491
    for (iter = entries.begin(); iter != entries.end(); ++iter)
492
    {
493
        if ((pos = iter->name.find(part)) != string::npos)
494
        {
495
            char next = iter->name.at(pos + part.length());
496
 
100 andreas 497
            if (next == '.')
498
                return iter->name;
499
 
157 andreas 500
            if (precice && next == '_')
80 andreas 501
                continue;
502
 
157 andreas 503
            if ((next >= 'A' && next <= 'Z') || (next >= 'a' && next <= 'z'))
504
                continue;
505
 
80 andreas 506
            return iter->name;
507
        }
508
    }
509
 
510
    return string();
511
}
512
 
11 andreas 513
size_t TDirectory::getFileSize (const string &f)
514
{
515
	DECL_TRACER("Directory::getFileSize (const string &f)");
516
	size_t s = 0;
517
 
518
	try
519
	{
520
		if (!fs::path(f).has_filename())
521
			return s;
522
 
523
		s = fs::file_size(f);
125 andreas 524
    }
11 andreas 525
	catch(exception& e)
526
	{
527
		MSG_ERROR("Error: " << e.what());
528
		s = 0;
529
	}
530
 
531
	return s;
532
}
533
 
534
bool TDirectory::isFile (const string &f)
535
{
536
	DECL_TRACER("Directory::isFile (const string &f)");
537
 
538
	try
539
	{
540
		return fs::is_regular_file(f);
541
	}
542
	catch(exception& e)
543
	{
544
		MSG_ERROR("Error: " << e.what());
545
	}
546
 
547
	return false;
548
}
549
 
550
bool TDirectory::isDirectory (const string &f)
551
{
552
	DECL_TRACER("Directory::isDirectory (const string &f)");
553
 
554
	try
555
	{
556
		return fs::is_directory(f);
557
	}
558
	catch(exception& e)
559
	{
560
		MSG_ERROR("Error: " << e.what());
561
	}
562
 
563
	return false;
564
}
565
 
566
bool TDirectory::exists (const string &f)
567
{
568
	DECL_TRACER("Directory::exists (const string &f)");
569
 
570
	try
571
	{
572
		return fs::exists(f);
573
	}
574
	catch(exception& e)
575
	{
576
		MSG_ERROR("Error: " << e.what());
577
	}
578
 
579
	return false;
580
}
581
 
582
bool TDirectory::checkDot (const string &s)
583
{
80 andreas 584
//	DECL_TRACER("Directory::checkDot (const string &s)");
11 andreas 585
 
586
	size_t pos = s.find_last_of("/");
587
	string f = s;
588
 
589
	if (pos != string::npos)
590
		f = s.substr(pos + 1);
591
 
592
	if (f.at(0) == '.')
593
		return true;
594
 
595
	return false;
596
}