GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/fs/virtfs/fs.cpp Lines: 308 377 81.7 %
Date: 2018-11-12 Branches: 232 450 51.6 %

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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


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

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

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

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

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