GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/fs/virtfs/fs.cpp Lines: 308 373 82.6 %
Date: 2021-03-17 Branches: 232 450 51.6 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2013-2019  The ManaPlus Developers
4
 *  Copyright (C) 2019-2021  Andrei Karas
5
 *
6
 *  This file is part of The ManaPlus Client.
7
 *
8
 *  This program is free software; you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation; either version 2 of the License, or
11
 *  any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
#include "fs/virtfs/fs.h"
23
24
#include "fs/files.h"
25
#include "fs/paths.h"
26
27
#include "fs/virtfs/direntry.h"
28
#include "fs/virtfs/file.h"
29
#include "fs/virtfs/fsdir.h"
30
#include "fs/virtfs/fsfuncs.h"
31
#include "fs/virtfs/fszip.h"
32
#include "fs/virtfs/list.h"
33
#include "fs/virtfs/zipentry.h"
34
#include "fs/virtfs/zipreader.h"
35
36
#include "utils/checkutils.h"
37
#include "utils/foreach.h"
38
#include "utils/stdmove.h"
39
#include "utils/stringutils.h"
40
41
#include "debug.h"
42
43
const char *dirSeparator = nullptr;
44
45
#ifdef UNITTESTS
46
#define reportNonTests(a, b) logger->log(a, b);
47
#else  // UNITTESTS
48
#define reportNonTests(a, b) reportAlways(a, b)
49
#endif  // UNITTESTS
50
51
namespace VirtFs
52
{
53
    namespace
54
    {
55
1
        STD_VECTOR<FsEntry*> mEntries;
56
    }  // namespace
57
58
120
    void init(const std::string &restrict name)
59
    {
60
        updateDirSeparator();
61
120
        FsDir::init(name);
62
120
        FsZip::init();
63
120
    }
64
65
1
    void updateDirSeparator()
66
    {
67
#ifdef WIN32
68
        dirSeparator = "\\";
69
#else  // WIN32
70
121
        dirSeparator = "/";
71
#endif  // WIN32
72
1
    }
73
74
2
    const char *getDirSeparator()
75
    {
76
2
        return dirSeparator;
77
    }
78
79
293
    const char *getBaseDir()
80
    {
81
293
        return FsDir::getBaseDir();
82
    }
83
84
583
    const char *getUserDir()
85
    {
86
583
        return FsDir::getUserDir();
87
    }
88
89
353
    STD_VECTOR<FsEntry*> &getEntries()
90
    {
91
353
        return mEntries;
92
    }
93
94
706
    FsEntry *searchByRootInternal(const std::string &restrict root,
95
                                  const std::string &restrict subDir)
96
    {
97
3852
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
98
        {
99
391
            const FsEntry *const entry = *it;
100

472
            if (entry->root == root &&
101
81
                entry->subDir == subDir)
102
            {
103
                return *it;
104
            }
105
        }
106
        return nullptr;
107
    }
108
109
    FsEntry *searchByTypeInternal(const std::string &restrict root,
110
                                  const FsEntryTypeT type)
111
    {
112
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
113
        {
114
            const FsEntry *const entry = *it;
115
            if (entry->root == root &&
116
                entry->type == type)
117
            {
118
                return *it;
119
            }
120
        }
121
        return nullptr;
122
    }
123
124
4634
    bool exists(std::string name)
125
    {
126
4634
        prepareFsPath(name);
127
4634
        if (checkPath(name) == false)
128
        {
129
6
            reportAlways("FsDir::exists invalid path: %s",
130
                name.c_str())
131
            return false;
132
        }
133
134
9264
        std::string rootDir = name;
135

18528
        if (findLast(rootDir, std::string(dirSeparator)) == false)
136
4621
            rootDir += dirSeparator;
137
138
28552
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
139
        {
140
8463
            FsEntry *const entry = *it;
141

42315
            if (entry->funcs->exists(entry, name, rootDir) == true)
142
                return true;
143
        }
144
        return false;
145
    }
146
147
27
    List *enumerateFiles(std::string dirName)
148
    {
149
27
        List *const list = new List;
150
27
        prepareFsPath(dirName);
151
27
        if (checkPath(dirName) == false)
152
        {
153
            reportAlways("VirtFs::enumerateFiles invalid path: %s",
154
                dirName.c_str())
155
            return list;
156
        }
157
158
81
        std::string rootDir = STD_MOVE(dirName);
159

108
        if (findLast(rootDir, std::string(dirSeparator)) == false)
160
13
            rootDir += dirSeparator;
161
27
        StringVect &names = list->names;
162
163
170
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
164
        {
165
35
            FsEntry *const entry = *it;
166
105
            entry->funcs->enumerate(entry, rootDir, names);
167
        }
168
169
27
        return list;
170
    }
171
172
15
    void getFiles(std::string dirName,
173
                  StringVect &list)
174
    {
175
15
        prepareFsPath(dirName);
176
15
        if (checkPath(dirName) == false)
177
        {
178
            reportAlways("VirtFs::enumerateFiles invalid path: %s",
179
                dirName.c_str())
180
            return;
181
        }
182
183
45
        std::string rootDir = STD_MOVE(dirName);
184

60
        if (findLast(rootDir, std::string(dirSeparator)) == false)
185
9
            rootDir += dirSeparator;
186
187
92
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
188
        {
189
17
            FsEntry *const entry = *it;
190
51
            entry->funcs->getFiles(entry, rootDir, list);
191
        }
192
15
    }
193
194
95
    void getFilesWithDir(std::string dirName,
195
                         StringVect &list)
196
    {
197
95
        prepareFsPath(dirName);
198
95
        if (checkPath(dirName) == false)
199
        {
200
            reportAlways("VirtFs::enumerateFiles invalid path: %s",
201
                dirName.c_str())
202
            return;
203
        }
204
205
285
        std::string rootDir = STD_MOVE(dirName);
206

380
        if (findLast(rootDir, std::string(dirSeparator)) == false)
207
89
            rootDir += dirSeparator;
208
209
653
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
210
        {
211
178
            FsEntry *const entry = *it;
212
178
            entry->funcs->getFilesWithDir(entry, rootDir, list);
213
        }
214
95
    }
215
216
217
12
    void getDirs(std::string dirName,
218
                 StringVect &list)
219
    {
220
12
        prepareFsPath(dirName);
221
12
        if (checkPath(dirName) == false)
222
        {
223
            reportAlways("VirtFs::enumerateFiles invalid path: %s",
224
                dirName.c_str())
225
            return;
226
        }
227
228
36
        std::string rootDir = STD_MOVE(dirName);
229

48
        if (findLast(rootDir, std::string(dirSeparator)) == false)
230
7
            rootDir += dirSeparator;
231
232
74
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
233
        {
234
14
            FsEntry *const entry = *it;
235
42
            entry->funcs->getDirs(entry, rootDir, list);
236
        }
237
12
    }
238
239
661
    bool isDirectory(std::string name)
240
    {
241
661
        prepareFsPath(name);
242
661
        if (checkPath(name) == false)
243
        {
244
            reportAlways("VirtFs::isDirectory invalid path: %s",
245
                name.c_str())
246
            return false;
247
        }
248
1983
        std::string dirName = STD_MOVE(name);
249

2644
        if (findLast(dirName, std::string(dirSeparator)) == false)
250
171
            dirName += dirSeparator;
251
252
3817
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
253
        {
254
1001
            FsEntry *const entry = *it;
255
1001
            bool isDirFlag(false);
256

3003
            if (entry->funcs->isDirectory(entry, dirName, isDirFlag) == true)
257
            {
258
489
                return isDirFlag;
259
            }
260
        }
261
        return false;
262
    }
263
264
    bool isSymbolicLink(const std::string &restrict name)
265
    {
266
        return FsDir::isSymbolicLink(name);
267
    }
268
269
27
    void freeList(List *restrict const handle)
270
    {
271
27
        delete handle;
272
27
    }
273
274
2451
    File *openRead(std::string filename)
275
    {
276
2451
        prepareFsPath(filename);
277
2451
        if (checkPath(filename) == false)
278
        {
279
            reportAlways("VirtFs::openRead invalid path: %s",
280
                filename.c_str())
281
            return nullptr;
282
        }
283
13946
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
284
        {
285
4072
            FsEntry *const entry = *it;
286
12216
            File *const file = entry->funcs->openRead(entry, filename);
287
4072
            if (file != nullptr)
288
                return file;
289
        }
290
        return nullptr;
291
    }
292
293
    File *openWrite(std::string filename)
294
    {
295
        prepareFsPath(filename);
296
        if (checkPath(filename) == false)
297
        {
298
            reportAlways("VirtFs::openWrite invalid path: %s",
299
                filename.c_str())
300
            return nullptr;
301
        }
302
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
303
        {
304
            FsEntry *const entry = *it;
305
            File *const file = entry->funcs->openWrite(entry, filename);
306
            if (file != nullptr)
307
                return file;
308
        }
309
        return nullptr;
310
    }
311
312
    File *openAppend(std::string filename)
313
    {
314
        prepareFsPath(filename);
315
        if (checkPath(filename) == false)
316
        {
317
            reportAlways("VirtFs::openAppend invalid path: %s",
318
                filename.c_str())
319
            return nullptr;
320
        }
321
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
322
        {
323
            FsEntry *const entry = *it;
324
            File *const file = entry->funcs->openAppend(entry, filename);
325
            if (file != nullptr)
326
                return file;
327
        }
328
        return nullptr;
329
    }
330
331
    bool setWriteDir(const std::string &restrict newDir)
332
    {
333
        return FsDir::setWriteDir(newDir);
334
    }
335
336
605
    void addEntry(FsEntry *const entry,
337
                  const Append append)
338
    {
339
605
        if (append == Append_true)
340
58
            mEntries.push_back(entry);
341
        else
342
1094
            mEntries.insert(mEntries.begin(), entry);
343
605
    }
344
345
510
    bool mountDirInternal(const std::string &restrict newDir,
346
                          std::string subDir,
347
                          const Append append)
348
    {
349
510
        if (newDir.find(".zip") != std::string::npos)
350
        {
351
            reportAlways("Called FsDir::mount with zip archive")
352
            return false;
353
        }
354
1020
        std::string rootDir = newDir;
355

2040
        if (findLast(rootDir, std::string(dirSeparator)) == false)
356
506
            rootDir += dirSeparator;
357
1020
        if (subDir == dirSeparator)
358
        {
359
            subDir.clear();
360
        }
361

1474
        else if (!subDir.empty() &&
362


606
                 findLast(subDir, std::string(dirSeparator)) == false)
363
        {
364
43
            subDir += dirSeparator;
365
        }
366
510
        const FsEntry *const entry = searchByRootInternal(rootDir, subDir);
367
510
        if (entry != nullptr)
368
        {
369
            reportAlways("VirtFs::mount already exists: %s",
370
                newDir.c_str())
371
            return false;
372
        }
373
510
        if (subDir.empty())
374
        {
375

934
            logger->log("Add virtual directory: " + newDir);
376
        }
377
        else
378
        {
379
86
            logger->log("Add virtual directory: %s with dir %s",
380
                newDir.c_str(),
381
43
                subDir.c_str());
382
        }
383
384
        addEntry(new DirEntry(newDir,
385
            rootDir,
386
            subDir,
387
1020
            rootDir + subDir,
388

510
            FsDir::getFuncs()),
389
510
            append);
390
510
        return true;
391
    }
392
393
31
    bool mountDir(std::string newDir,
394
                  const Append append)
395
    {
396
31
        prepareFsPath(newDir);
397
31
        if (Files::existsLocal(newDir) == false)
398
        {
399
            reportNonTests("VirtFs::mount directory not exists: %s",
400
                newDir.c_str())
401
            return false;
402
        }
403
124
        return mountDirInternal(newDir, dirSeparator, append);
404
    }
405
406
10
    bool mountDir2(std::string newDir,
407
                   std::string subDir,
408
                   const Append append)
409
    {
410
10
        prepareFsPath(newDir);
411
10
        prepareFsPath(subDir);
412
10
        if (Files::existsLocal(newDir) == false)
413
        {
414
            reportNonTests("VirtFs::mount directory not exists: %s",
415
                newDir.c_str())
416
            return false;
417
        }
418
20
        return mountDirInternal(newDir, subDir, append);
419
    }
420
421
805
    bool mountDirSilent(std::string newDir,
422
                        const Append append)
423
    {
424
805
        prepareFsPath(newDir);
425
805
        if (Files::existsLocal(newDir) == false)
426
        {
427
399
            logger->log("VirtFs::mount directory not exists: %s",
428
399
                newDir.c_str());
429
399
            return false;
430
        }
431
812
        return mountDirInternal(newDir, std::string(), append);
432
    }
433
434
16
    bool mountDirSilent2(std::string newDir,
435
                         std::string subDir,
436
                         const Append append)
437
    {
438
16
        prepareFsPath(newDir);
439
16
        prepareFsPath(subDir);
440
16
        if (Files::existsLocal(newDir) == false)
441
        {
442
7
            logger->log("VirtFs::mount directory not exists: %s",
443
7
                newDir.c_str());
444
7
            return false;
445
        }
446
18
        return mountDirInternal(newDir, subDir, append);
447
    }
448
449
#ifdef UNITTESTS
450
28
    bool mountDirSilentTest(std::string newDir,
451
                            const Append append)
452
    {
453
28
        prepareFsPath(newDir);
454
28
        if (Files::existsLocal(newDir) == false)
455
        {
456
28
            logger->log("VirtFs::mount directory not exists: %s",
457
28
                newDir.c_str());
458
        }
459
56
        return mountDirInternal(newDir, std::string(), append);
460
    }
461
462
26
    bool mountDirSilentTest2(std::string newDir,
463
                             std::string subDir,
464
                             const Append append)
465
    {
466
26
        prepareFsPath(newDir);
467
26
        prepareFsPath(subDir);
468
26
        if (Files::existsLocal(newDir) == false)
469
        {
470
26
            logger->log("VirtFs::mount directory not exists: %s",
471
26
                newDir.c_str());
472
        }
473
52
        return mountDirInternal(newDir, subDir, append);
474
    }
475
#endif  // UNITTESTS
476
477
869
    bool unmountDirInternal(std::string oldDir,
478
                            std::string subDir)
479
    {
480

3476
        if (findLast(oldDir, std::string(dirSeparator)) == false)
481
865
            oldDir += dirSeparator;
482
1738
        if (subDir == dirSeparator)
483
        {
484
            subDir.clear();
485
        }
486

2628
        else if (!subDir.empty() &&
487


932
                 findLast(subDir, std::string(dirSeparator)) == false)
488
        {
489
20
            subDir += dirSeparator;
490
        }
491
3284
        FOR_EACH (STD_VECTOR<FsEntry*>::iterator, it, mEntries)
492
        {
493
1134
            FsEntry *const entry = *it;
494

2729
            if (entry->root == oldDir &&
495

1595
                entry->type == FsEntryType::Dir &&
496
461
                entry->subDir == subDir)
497
            {
498
                DirEntry *const dirEntry = static_cast<DirEntry*>(
499
457
                    entry);
500
457
                if (subDir.empty())
501
                {
502
880
                    logger->log("Remove virtual directory: " + oldDir);
503
                }
504
                else
505
                {
506
34
                    logger->log("Remove virtual directory: %s with dir %s",
507
                        oldDir.c_str(),
508
17
                        subDir.c_str());
509
                }
510
914
                mEntries.erase(it);
511
457
                delete dirEntry;
512
                return true;
513
            }
514
        }
515
        return false;
516
    }
517
518
52
    bool unmountDir(std::string oldDir)
519
    {
520
52
        prepareFsPath(oldDir);
521
52
        if (oldDir.find(".zip") != std::string::npos)
522
        {
523
            reportAlways("Called unmount with zip archive")
524
            return false;
525
        }
526

208
        if (unmountDirInternal(oldDir, std::string()) == false)
527
        {
528
42
            reportAlways("VirtFs::unmountDir not exists: %s",
529
                oldDir.c_str())
530
            return false;
531
        }
532
        return true;
533
    }
534
535
15
    bool unmountDir2(std::string oldDir,
536
                     std::string subDir)
537
    {
538
15
        prepareFsPath(oldDir);
539
15
        if (oldDir.find(".zip") != std::string::npos)
540
        {
541
            reportAlways("Called unmount with zip archive")
542
            return false;
543
        }
544
15
        prepareFsPath(subDir);
545

60
        if (unmountDirInternal(oldDir, subDir) == false)
546
        {
547
9
            reportAlways("VirtFs::unmountDir not exists: %s",
548
                oldDir.c_str())
549
            return false;
550
        }
551
        return true;
552
    }
553
554
796
    bool unmountDirSilent(std::string oldDir)
555
    {
556
796
        prepareFsPath(oldDir);
557
796
        if (oldDir.find(".zip") != std::string::npos)
558
        {
559
            reportAlways("Called unmount with zip archive")
560
            return false;
561
        }
562

3184
        if (unmountDirInternal(oldDir, std::string()) == false)
563
        {
564
394
            logger->log("VirtFs::unmountDir not exists: %s",
565
394
                oldDir.c_str());
566
394
            return false;
567
        }
568
        return true;
569
    }
570
571
6
    bool unmountDirSilent2(std::string oldDir,
572
                           std::string subDir)
573
    {
574
6
        prepareFsPath(oldDir);
575
6
        if (oldDir.find(".zip") != std::string::npos)
576
        {
577
            reportAlways("Called unmount with zip archive")
578
            return false;
579
        }
580
6
        prepareFsPath(subDir);
581

24
        if (unmountDirInternal(oldDir, subDir) == false)
582
        {
583
1
            logger->log("VirtFs::unmountDir not exists: %s",
584
1
                oldDir.c_str());
585
1
            return false;
586
        }
587
        return true;
588
    }
589
590
69
    bool mountZip(std::string newDir,
591
                  const Append append)
592
    {
593
69
        prepareFsPath(newDir);
594
69
        if (Files::existsLocal(newDir) == false)
595
        {
596
            reportNonTests("FsZip::mount file not exists: %s",
597
                newDir.c_str())
598
            return false;
599
        }
600

276
        if (findLast(newDir, ".zip") == false)
601
        {
602
            reportAlways("Called VirtFs::mount without "
603
                "zip archive")
604
            return false;
605
        }
606
138
        if (searchByRootInternal(newDir, std::string()) != nullptr)
607
        {
608
            reportAlways("FsZip::mount already exists: %s",
609
                newDir.c_str())
610
            return false;
611
        }
612
        ZipEntry *const entry = new ZipEntry(newDir,
613
138
            std::string(),
614

69
            FsZip::getFuncs());
615
69
        if (ZipReader::readArchiveInfo(entry) == false)
616
        {
617
            delete entry;
618
            return false;
619
        }
620
621
138
        logger->log("Add virtual zip: " + newDir);
622
69
        addEntry(entry, append);
623
69
        return true;
624
    }
625
626
26
    bool mountZip2(std::string newDir,
627
                   std::string subDir,
628
                   const Append append)
629
    {
630
26
        prepareFsPath(newDir);
631
26
        if (Files::existsLocal(newDir) == false)
632
        {
633
            reportNonTests("FsZip::mount file not exists: %s",
634
                newDir.c_str())
635
            return false;
636
        }
637

104
        if (findLast(newDir, ".zip") == false)
638
        {
639
            reportAlways("Called VirtFs::mount without "
640
                "zip archive")
641
            return false;
642
        }
643
26
        prepareFsPath(subDir);
644
52
        if (subDir == dirSeparator)
645
        {
646
            subDir.clear();
647
        }
648

100
        else if (!subDir.empty() &&
649


100
                 findLast(subDir, std::string(dirSeparator)) == false)
650
        {
651
25
            subDir += dirSeparator;
652
        }
653
26
        if (searchByRootInternal(newDir, subDir) != nullptr)
654
        {
655
            reportAlways("FsZip::mount already exists: %s",
656
                newDir.c_str())
657
            return false;
658
        }
659
        ZipEntry *const entry = new ZipEntry(newDir,
660
            subDir,
661
26
            FsZip::getFuncs());
662
26
        if (ZipReader::readArchiveInfo(entry) == false)
663
        {
664
            delete entry;
665
            return false;
666
        }
667
668
52
        logger->log("Add virtual zip: %s with dir %s",
669
            newDir.c_str(),
670
26
            subDir.c_str());
671
26
        addEntry(entry, append);
672
26
        return true;
673
    }
674
675
58
    bool unmountZip(std::string oldDir)
676
    {
677
58
        prepareFsPath(oldDir);
678

232
        if (findLast(oldDir, ".zip") == false)
679
        {
680
            reportAlways("Called unmount without zip archive")
681
            return false;
682
        }
683
187
        FOR_EACH (STD_VECTOR<FsEntry*>::iterator, it, mEntries)
684
        {
685
71
            FsEntry *const entry = *it;
686

200
            if (entry->root == oldDir &&
687

129
                entry->type == FsEntryType::Zip &&
688
116
                entry->subDir.empty())
689
            {
690
                ZipEntry *const zipEntry = static_cast<ZipEntry*>(
691
58
                    entry);
692
116
                logger->log("Remove virtual zip: " + oldDir);
693
116
                mEntries.erase(it);
694
58
                delete zipEntry;
695
58
                return true;
696
            }
697
        }
698
699
        reportAlways("VirtFs::unmountZip not exists: %s",
700
            oldDir.c_str())
701
        return false;
702
    }
703
704
14
    bool unmountZip2(std::string oldDir,
705
                     std::string subDir)
706
    {
707
14
        prepareFsPath(oldDir);
708

56
        if (findLast(oldDir, ".zip") == false)
709
        {
710
            reportAlways("Called unmount without zip archive")
711
            return false;
712
        }
713
14
        prepareFsPath(subDir);
714
28
        if (subDir == dirSeparator)
715
        {
716
            subDir.clear();
717
        }
718

56
        else if (!subDir.empty() &&
719


56
                 findLast(subDir, std::string(dirSeparator)) == false)
720
        {
721
14
            subDir += dirSeparator;
722
        }
723
45
        FOR_EACH (STD_VECTOR<FsEntry*>::iterator, it, mEntries)
724
        {
725
17
            FsEntry *const entry = *it;
726

48
            if (entry->root == oldDir &&
727

31
                entry->type == FsEntryType::Zip &&
728
14
                entry->subDir == subDir)
729
            {
730
                ZipEntry *const zipEntry = static_cast<ZipEntry*>(
731
14
                    entry);
732
28
                logger->log("Remove virtual zip: %s with dir %s",
733
                    oldDir.c_str(),
734
14
                    subDir.c_str());
735
28
                mEntries.erase(it);
736
14
                delete zipEntry;
737
14
                return true;
738
            }
739
        }
740
741
        reportAlways("VirtFs::unmountZip not exists: %s",
742
            oldDir.c_str())
743
        return false;
744
    }
745
746
74
    std::string getRealDir(std::string fileName)
747
    {
748
74
        prepareFsPath(fileName);
749
74
        if (checkPath(fileName) == false)
750
        {
751
            reportAlways("FsDir::getRealDir invalid path: %s",
752
                fileName.c_str())
753
            return std::string();
754
        }
755
756
148
        std::string rootDir = fileName;
757

296
        if (findLast(rootDir, std::string(dirSeparator)) == false)
758
74
            rootDir += dirSeparator;
759
760
418
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
761
        {
762
96
            FsEntry *const entry = *it;
763
144
            std::string realDir;
764

480
            if (entry->funcs->getRealDir(entry,
765
                fileName,
766
                rootDir,
767
                realDir) == true)
768
            {
769
96
                return realDir;
770
            }
771
        }
772
        return std::string();
773
    }
774
775
    bool mkdir(const std::string &restrict dirname)
776
    {
777
        return FsDir::mkdir(dirname);
778
    }
779
780
    bool remove(const std::string &restrict filename)
781
    {
782
        return FsDir::remove(filename);
783
    }
784
785
119
    bool deinit()
786
    {
787
119
        FsDir::deinit();
788
119
        FsZip::deinit();
789
433
        FOR_EACH (STD_VECTOR<FsEntry*>::iterator, it, mEntries)
790
        {
791
76
            FsEntry *const entry = *it;
792
76
            if (entry->type == FsEntryType::Dir)
793
53
                delete static_cast<DirEntry*>(entry);
794
23
            else if (entry->type == FsEntryType::Zip)
795
23
                delete static_cast<ZipEntry*>(entry);
796
            else
797
                delete entry;
798
        }
799
119
        mEntries.clear();
800
119
        return true;
801
    }
802
803
20
    void permitLinks(const bool val)
804
    {
805
20
        FsDir::permitLinks(val);
806
20
    }
807
808
47
    int close(File *restrict const file)
809
    {
810
47
        if (file == nullptr)
811
            return 0;
812
47
        return file->funcs->close(file);
813
    }
814
815
61
    int64_t read(File *restrict const file,
816
                 void *restrict const buffer,
817
                 const uint32_t objSize,
818
                 const uint32_t objCount)
819
    {
820
61
        return file->funcs->read(file,
821
            buffer,
822
            objSize,
823
61
            objCount);
824
    }
825
826
    int64_t write(File *restrict const file,
827
                  const void *restrict const buffer,
828
                  const uint32_t objSize,
829
                  const uint32_t objCount)
830
    {
831
        return file->funcs->write(file,
832
            buffer,
833
            objSize,
834
            objCount);
835
    }
836
837
20
    int64_t fileLength(File *restrict const file)
838
    {
839
20
        return file->funcs->fileLength(file);
840
    }
841
842
84
    int64_t tell(File *restrict const file)
843
    {
844
84
        return file->funcs->tell(file);
845
    }
846
847
30
    int seek(File *restrict const file,
848
             const uint64_t pos)
849
    {
850
30
        return file->funcs->seek(file,
851
30
            pos);
852
    }
853
854
93
    int eof(File *restrict const file)
855
    {
856
93
        return file->funcs->eof(file);
857
    }
858
859
2510
    const char *loadFile(std::string filename,
860
                         int &restrict fileSize)
861
    {
862
2510
        prepareFsPath(filename);
863
2510
        if (checkPath(filename) == false)
864
        {
865
            reportAlways("VirtFs::loadFile invalid path: %s",
866
                filename.c_str())
867
            return nullptr;
868
        }
869
14424
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
870
        {
871
4300
            FsEntry *const entry = *it;
872
12900
            const char *const buf = entry->funcs->loadFile(entry,
873
                filename,
874
4300
                fileSize);
875
4300
            if (buf != nullptr)
876
                return buf;
877
        }
878
        return nullptr;
879
    }
880
881
2
}  // namespace VirtFs