GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/fs/virtfs/fs.cpp Lines: 300 367 81.7 %
Date: 2017-11-29 Branches: 210 408 51.5 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2013-2017  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
2
        STD_VECTOR<FsEntry*> mEntries;
55
    }  // namespace
56
57
240
    void init(const std::string &restrict name)
58
    {
59
        updateDirSeparator();
60
240
        FsDir::init(name);
61
240
        FsZip::init();
62
240
    }
63
64
2
    void updateDirSeparator()
65
    {
66
#ifdef WIN32
67
        dirSeparator = "\\";
68
#else  // WIN32
69
242
        dirSeparator = "/";
70
#endif  // WIN32
71
2
    }
72
73
4
    const char *getDirSeparator()
74
    {
75
4
        return dirSeparator;
76
    }
77
78
562
    const char *getBaseDir()
79
    {
80
562
        return FsDir::getBaseDir();
81
    }
82
83
1118
    const char *getUserDir()
84
    {
85
1118
        return FsDir::getUserDir();
86
    }
87
88
706
    STD_VECTOR<FsEntry*> &getEntries()
89
    {
90
706
        return mEntries;
91
    }
92
93
1346
    FsEntry *searchByRootInternal(const std::string &restrict root,
94
                                  const std::string &restrict subDir)
95
    {
96
7332
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
97
        {
98
740
            const FsEntry *const entry = *it;
99
902
            if (entry->root == root &&
100
162
                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
8952
    bool exists(std::string name)
124
    {
125
8952
        prepareFsPath(name);
126
8952
        if (checkPath(name) == false)
127
        {
128
12
            reportAlways("FsDir::exists invalid path: %s",
129
                name.c_str());
130
            return false;
131
        }
132
133
17896
        std::string rootDir = name;
134

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

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

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

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

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

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

5096
        if (findLast(dirName, std::string(dirSeparator)) == false)
249
342
            dirName += dirSeparator;
250
251
7310
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
252
        {
253
1870
            FsEntry *const entry = *it;
254
1870
            bool isDirFlag(false);
255
3740
            if (entry->funcs->isDirectory(entry, dirName, isDirFlag) == true)
256
            {
257
930
                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
54
    void freeList(List *restrict const handle)
269
    {
270
54
        delete handle;
271
54
    }
272
273
3218
    File *openRead(std::string filename)
274
    {
275
3218
        prepareFsPath(filename);
276
3218
        if (checkPath(filename) == false)
277
        {
278
            reportAlways("VirtFs::openRead invalid path: %s",
279
                filename.c_str());
280
            return nullptr;
281
        }
282
18004
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
283
        {
284
4992
            FsEntry *const entry = *it;
285
14976
            File *const file = entry->funcs->openRead(entry, filename);
286
4992
            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
1144
    void addEntry(FsEntry *const entry,
336
                  const Append append)
337
    {
338
1144
        if (append == Append_true)
339
116
            mEntries.push_back(entry);
340
        else
341
2056
            mEntries.insert(mEntries.begin(), entry);
342
1144
    }
343
344
954
    bool mountDirInternal(const std::string &restrict newDir,
345
                          std::string subDir,
346
                          const Append append)
347
    {
348
954
        if (newDir.find(".zip") != std::string::npos)
349
        {
350
            reportAlways("Called FsDir::mount with zip archive");
351
            return false;
352
        }
353
1908
        std::string rootDir = newDir;
354

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

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

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

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

954
            FsDir::getFuncs()),
388
            append);
389
954
        return true;
390
    }
391
392
64
    bool mountDir(std::string newDir,
393
                  const Append append)
394
    {
395
64
        prepareFsPath(newDir);
396
64
        if (Files::existsLocal(newDir) == false)
397
        {
398
            reportNonTests("VirtFs::mount directory not exists: %s",
399
                newDir.c_str());
400
            return false;
401
        }
402

256
        return mountDirInternal(newDir, dirSeparator, append);
403
    }
404
405
22
    bool mountDir2(std::string newDir,
406
                   std::string subDir,
407
                   const Append append)
408
    {
409
22
        prepareFsPath(newDir);
410
22
        prepareFsPath(subDir);
411
22
        if (Files::existsLocal(newDir) == false)
412
        {
413
            reportNonTests("VirtFs::mount directory not exists: %s",
414
                newDir.c_str());
415
            return false;
416
        }
417
44
        return mountDirInternal(newDir, subDir, append);
418
    }
419
420
1474
    bool mountDirSilent(std::string newDir,
421
                        const Append append)
422
    {
423
1474
        prepareFsPath(newDir);
424
1474
        if (Files::existsLocal(newDir) == false)
425
        {
426
1460
            logger->log("VirtFs::mount directory not exists: %s",
427
                newDir.c_str());
428
730
            return false;
429
        }
430
1488
        return mountDirInternal(newDir, std::string(), append);
431
    }
432
433
29
    bool mountDirSilent2(std::string newDir,
434
                         std::string subDir,
435
                         const Append append)
436
    {
437
29
        prepareFsPath(newDir);
438
29
        prepareFsPath(subDir);
439
29
        if (Files::existsLocal(newDir) == false)
440
        {
441
26
            logger->log("VirtFs::mount directory not exists: %s",
442
                newDir.c_str());
443
13
            return false;
444
        }
445
32
        return mountDirInternal(newDir, subDir, append);
446
    }
447
448
#ifdef UNITTESTS
449
56
    bool mountDirSilentTest(std::string newDir,
450
                            const Append append)
451
    {
452
56
        prepareFsPath(newDir);
453
56
        if (Files::existsLocal(newDir) == false)
454
        {
455
112
            logger->log("VirtFs::mount directory not exists: %s",
456
                newDir.c_str());
457
        }
458
112
        return mountDirInternal(newDir, std::string(), append);
459
    }
460
461
52
    bool mountDirSilentTest2(std::string newDir,
462
                             std::string subDir,
463
                             const Append append)
464
    {
465
52
        prepareFsPath(newDir);
466
52
        prepareFsPath(subDir);
467
52
        if (Files::existsLocal(newDir) == false)
468
        {
469
104
            logger->log("VirtFs::mount directory not exists: %s",
470
                newDir.c_str());
471
        }
472
104
        return mountDirInternal(newDir, subDir, append);
473
    }
474
#endif  // UNITTESTS
475
476
1606
    bool unmountDirInternal(std::string oldDir,
477
                            std::string subDir)
478
    {
479

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

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

3296
                 findLast(subDir, std::string(dirSeparator)) == false)
487
        {
488
40
            subDir += dirSeparator;
489
        }
490
5700
        FOR_EACH (STD_VECTOR<FsEntry*>::iterator, it, mEntries)
491
        {
492
1730
            FsEntry *const entry = *it;
493
3442
            if (entry->root == oldDir &&
494
856
                entry->type == FsEntryType::Dir &&
495
1704
                entry->subDir == subDir)
496
            {
497
848
                DirEntry *const dirEntry = static_cast<DirEntry*>(
498
                    entry);
499
848
                if (subDir.empty())
500
                {
501
1628
                    logger->log("Remove virtual directory: " + oldDir);
502
                }
503
                else
504
                {
505
102
                    logger->log("Remove virtual directory: %s with dir %s",
506
                        oldDir.c_str(),
507
                        subDir.c_str());
508
                }
509
1696
                mEntries.erase(it);
510
848
                delete dirEntry;
511
848
                return true;
512
            }
513
        }
514
        return false;
515
    }
516
517
104
    bool unmountDir(std::string oldDir)
518
    {
519
104
        prepareFsPath(oldDir);
520
104
        if (oldDir.find(".zip") != std::string::npos)
521
        {
522
            reportAlways("Called unmount with zip archive");
523
            return false;
524
        }
525

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

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

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

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

552
        if (findLast(newDir, ".zip") == false)
600
        {
601
            reportAlways("Called VirtFs::mount without "
602
                "zip archive");
603
            return false;
604
        }
605
276
        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
276
            std::string(),
613

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

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

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

200
                 findLast(subDir, std::string(dirSeparator)) == false)
649
        {
650
50
            subDir += dirSeparator;
651
        }
652
52
        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
52
            FsZip::getFuncs());
661
52
        if (ZipReader::readArchiveInfo(entry) == false)
662
        {
663
            delete entry;
664
            return false;
665
        }
666
667
156
        logger->log("Add virtual zip: %s with dir %s",
668
            newDir.c_str(),
669
            subDir.c_str());
670
52
        addEntry(entry, append);
671
52
        return true;
672
    }
673
674
116
    bool unmountZip(std::string oldDir)
675
    {
676
116
        prepareFsPath(oldDir);
677

464
        if (findLast(oldDir, ".zip") == false)
678
        {
679
            reportAlways("Called unmount without zip archive");
680
            return false;
681
        }
682
374
        FOR_EACH (STD_VECTOR<FsEntry*>::iterator, it, mEntries)
683
        {
684
142
            FsEntry *const entry = *it;
685
374
            if (entry->root == oldDir &&
686
232
                entry->type == FsEntryType::Zip &&
687
232
                entry->subDir.empty())
688
            {
689
116
                ZipEntry *const zipEntry = static_cast<ZipEntry*>(
690
                    entry);
691
232
                logger->log("Remove virtual zip: " + oldDir);
692
232
                mEntries.erase(it);
693
116
                delete zipEntry;
694
116
                return true;
695
            }
696
        }
697
698
        reportAlways("VirtFs::unmountZip not exists: %s",
699
            oldDir.c_str());
700
        return false;
701
    }
702
703
28
    bool unmountZip2(std::string oldDir,
704
                     std::string subDir)
705
    {
706
28
        prepareFsPath(oldDir);
707

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

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

112
                 findLast(subDir, std::string(dirSeparator)) == false)
719
        {
720
28
            subDir += dirSeparator;
721
        }
722
90
        FOR_EACH (STD_VECTOR<FsEntry*>::iterator, it, mEntries)
723
        {
724
34
            FsEntry *const entry = *it;
725
90
            if (entry->root == oldDir &&
726
28
                entry->type == FsEntryType::Zip &&
727
56
                entry->subDir == subDir)
728
            {
729
28
                ZipEntry *const zipEntry = static_cast<ZipEntry*>(
730
                    entry);
731
84
                logger->log("Remove virtual zip: %s with dir %s",
732
                    oldDir.c_str(),
733
                    subDir.c_str());
734
56
                mEntries.erase(it);
735
28
                delete zipEntry;
736
28
                return true;
737
            }
738
        }
739
740
        reportAlways("VirtFs::unmountZip not exists: %s",
741
            oldDir.c_str());
742
        return false;
743
    }
744
745
1638
    std::string getRealDir(std::string fileName)
746
    {
747
1638
        prepareFsPath(fileName);
748
1638
        if (checkPath(fileName) == false)
749
        {
750
            reportAlways("FsDir::getRealDir invalid path: %s",
751
                fileName.c_str());
752
            return std::string();
753
        }
754
755
3276
        std::string rootDir = fileName;
756

6552
        if (findLast(rootDir, std::string(dirSeparator)) == false)
757
1638
            rootDir += dirSeparator;
758
759
9488
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
760
        {
761
2882
            FsEntry *const entry = *it;
762
4180
            std::string realDir;
763
14410
            if (entry->funcs->getRealDir(entry,
764
                fileName,
765
                rootDir,
766
2882
                realDir) == true)
767
            {
768
3168
                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
238
    bool deinit()
785
    {
786
238
        FsDir::deinit();
787
238
        FsZip::deinit();
788
866
        FOR_EACH (STD_VECTOR<FsEntry*>::iterator, it, mEntries)
789
        {
790
152
            FsEntry *const entry = *it;
791
152
            if (entry->type == FsEntryType::Dir)
792
106
                delete static_cast<DirEntry*>(entry);
793
46
            else if (entry->type == FsEntryType::Zip)
794
46
                delete static_cast<ZipEntry*>(entry);
795
            else
796
                delete entry;
797
        }
798
238
        mEntries.clear();
799
238
        return true;
800
    }
801
802
40
    void permitLinks(const bool val)
803
    {
804
40
        FsDir::permitLinks(val);
805
40
    }
806
807
94
    int close(File *restrict const file)
808
    {
809
94
        if (file == nullptr)
810
            return 0;
811
94
        return file->funcs->close(file);
812
    }
813
814
122
    int64_t read(File *restrict const file,
815
                 void *restrict const buffer,
816
                 const uint32_t objSize,
817
                 const uint32_t objCount)
818
    {
819
122
        return file->funcs->read(file,
820
            buffer,
821
            objSize,
822
122
            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
40
    int64_t fileLength(File *restrict const file)
837
    {
838
40
        return file->funcs->fileLength(file);
839
    }
840
841
168
    int64_t tell(File *restrict const file)
842
    {
843
168
        return file->funcs->tell(file);
844
    }
845
846
60
    int seek(File *restrict const file,
847
             const uint64_t pos)
848
    {
849
60
        return file->funcs->seek(file,
850
60
            pos);
851
    }
852
853
186
    int eof(File *restrict const file)
854
    {
855
186
        return file->funcs->eof(file);
856
    }
857
858
4778
    const char *loadFile(std::string filename,
859
                         int &restrict fileSize)
860
    {
861
4778
        prepareFsPath(filename);
862
4778
        if (checkPath(filename) == false)
863
        {
864
            reportAlways("VirtFs::loadFile invalid path: %s",
865
                filename.c_str());
866
            return nullptr;
867
        }
868
27312
        FOR_EACH (STD_VECTOR<FsEntry*>::const_iterator, it, mEntries)
869
        {
870
8034
            FsEntry *const entry = *it;
871
24102
            const char *const buf = entry->funcs->loadFile(entry,
872
                filename,
873
8034
                fileSize);
874
8034
            if (buf != nullptr)
875
                return buf;
876
        }
877
        return nullptr;
878
    }
879
880
4
}  // namespace VirtFs