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
    {
245 andreas 382
        int n = (int)fs::remove_all(path);
65 andreas 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
 
245 andreas 410
    if (!fs::exists(path))
411
    {
412
        MSG_WARNING("Directory \"" << path << "\" does not exist!");
413
        return 0;
414
    }
415
 
416
    MSG_DEBUG("Dropping directory: " << path);
119 andreas 417
    int count = 0;
418
 
419
    try
420
    {
421
        for(auto& p: fs::directory_iterator(path))
422
        {
423
            string f = fs::path(p.path()).filename();
424
 
425
            if (checkDot(f))
426
                continue;
427
#if __GNUC__ < 9
428
            if (fs::is_directory(p.path()))
429
#else
430
            if (p.is_directory())
431
#endif
432
                continue;
433
 
155 andreas 434
            if (!fs::remove(p.path()))
435
            {
436
                MSG_ERROR("Error deleting file:" << p.path());
437
            }
438
 
119 andreas 439
            count++;
440
        }
441
    }
442
    catch (std::exception& e)
443
    {
444
        MSG_ERROR("Error dir drop: " << e.what());
445
        return false;
446
    }
447
 
448
    MSG_DEBUG("Deleted " << count << " files.");
449
    return true;
450
}
451
 
452
bool TDirectory::dropFile(const string& fname)
453
{
454
    DECL_TRACER("TDirectory::dropFile(const string& fname)");
455
 
456
    try
457
    {
458
        fs::remove(fname);
459
    }
460
    catch (std::exception& e)
461
    {
462
        MSG_ERROR("Error removing file " << fname << "!");
463
        return false;
464
    }
465
 
466
    return true;
467
}
468
 
80 andreas 469
string TDirectory::getEntryWithEnd(const string &end)
470
{
471
    DECL_TRACER("TDirectory::getEntryWithEnd(const string &end)");
472
 
88 andreas 473
    if (entries.size() == 0)
474
        return string();
475
 
80 andreas 476
    vector<DFILES_T>::iterator iter;
477
    size_t pos;
478
 
479
    for (iter = entries.begin(); iter != entries.end(); ++iter)
480
    {
481
        if ((pos = iter->name.find_last_of(end)) != string::npos && (pos + end.length()) == iter->name.length())
482
            return iter->name;
483
    }
484
 
485
    return string();
486
}
487
 
101 andreas 488
string TDirectory::getEntryWithPart(const string &part, bool precice)
80 andreas 489
{
101 andreas 490
    DECL_TRACER("TDirectory::getEntryWithPart(const string &part, bool precice)");
80 andreas 491
 
88 andreas 492
    if (entries.size() == 0)
493
        return string();
494
 
80 andreas 495
    vector<DFILES_T>::iterator iter;
496
    size_t pos;
497
 
498
    for (iter = entries.begin(); iter != entries.end(); ++iter)
499
    {
500
        if ((pos = iter->name.find(part)) != string::npos)
501
        {
502
            char next = iter->name.at(pos + part.length());
503
 
100 andreas 504
            if (next == '.')
505
                return iter->name;
506
 
157 andreas 507
            if (precice && next == '_')
80 andreas 508
                continue;
509
 
157 andreas 510
            if ((next >= 'A' && next <= 'Z') || (next >= 'a' && next <= 'z'))
511
                continue;
512
 
80 andreas 513
            return iter->name;
514
        }
515
    }
516
 
517
    return string();
518
}
519
 
11 andreas 520
size_t TDirectory::getFileSize (const string &f)
521
{
522
	DECL_TRACER("Directory::getFileSize (const string &f)");
523
	size_t s = 0;
524
 
525
	try
526
	{
527
		if (!fs::path(f).has_filename())
528
			return s;
529
 
530
		s = fs::file_size(f);
125 andreas 531
    }
11 andreas 532
	catch(exception& e)
533
	{
534
		MSG_ERROR("Error: " << e.what());
535
		s = 0;
536
	}
537
 
538
	return s;
539
}
540
 
541
bool TDirectory::isFile (const string &f)
542
{
543
	DECL_TRACER("Directory::isFile (const string &f)");
544
 
545
	try
546
	{
547
		return fs::is_regular_file(f);
548
	}
549
	catch(exception& e)
550
	{
551
		MSG_ERROR("Error: " << e.what());
552
	}
553
 
554
	return false;
555
}
556
 
557
bool TDirectory::isDirectory (const string &f)
558
{
559
	DECL_TRACER("Directory::isDirectory (const string &f)");
560
 
561
	try
562
	{
563
		return fs::is_directory(f);
564
	}
565
	catch(exception& e)
566
	{
567
		MSG_ERROR("Error: " << e.what());
568
	}
569
 
570
	return false;
571
}
572
 
573
bool TDirectory::exists (const string &f)
574
{
575
	DECL_TRACER("Directory::exists (const string &f)");
576
 
577
	try
578
	{
579
		return fs::exists(f);
580
	}
581
	catch(exception& e)
582
	{
583
		MSG_ERROR("Error: " << e.what());
584
	}
585
 
586
	return false;
587
}
588
 
589
bool TDirectory::checkDot (const string &s)
590
{
80 andreas 591
//	DECL_TRACER("Directory::checkDot (const string &s)");
11 andreas 592
 
593
	size_t pos = s.find_last_of("/");
594
	string f = s;
595
 
596
	if (pos != string::npos)
597
		f = s.substr(pos + 1);
598
 
599
	if (f.at(0) == '.')
600
		return true;
601
 
602
	return false;
603
}