1 | //============================================================================ |
2 | // |
3 | // SSSS tt lll lll |
4 | // SS SS tt ll ll |
5 | // SS tttttt eeee ll ll aaaa |
6 | // SSSS tt ee ee ll ll aa |
7 | // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" |
8 | // SS SS tt ee ll ll aa aa |
9 | // SSSS ttt eeeee llll llll aaaaa |
10 | // |
11 | // Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony |
12 | // and the Stella Team |
13 | // |
14 | // See the file "License.txt" for information on usage and redistribution of |
15 | // this file, and for a DISCLAIMER OF ALL WARRANTIES. |
16 | //============================================================================ |
17 | |
18 | #ifndef FS_NODE_POSIX_HXX |
19 | #define FS_NODE_POSIX_HXX |
20 | |
21 | #include "FSNode.hxx" |
22 | |
23 | #ifdef BSPF_MACOS |
24 | #include <sys/types.h> |
25 | #endif |
26 | |
27 | #include <sys/param.h> |
28 | #include <sys/stat.h> |
29 | #include <dirent.h> |
30 | |
31 | #include <cassert> |
32 | #include <cstdio> |
33 | #include <cstring> |
34 | #include <cstdlib> |
35 | #include <unistd.h> |
36 | |
37 | #ifndef MAXPATHLEN // No MAXPATHLEN, as happens on Hurd |
38 | #define MAXPATHLEN 1024 |
39 | #endif |
40 | |
41 | /* |
42 | * Implementation of the Stella file system API based on POSIX (for Linux and macOS) |
43 | * |
44 | * Parts of this class are documented in the base interface class, AbstractFSNode. |
45 | */ |
46 | class FilesystemNodePOSIX : public AbstractFSNode |
47 | { |
48 | public: |
49 | /** |
50 | * Creates a FilesystemNodePOSIX with the root node as path. |
51 | */ |
52 | FilesystemNodePOSIX(); |
53 | |
54 | /** |
55 | * Creates a FilesystemNodePOSIX for a given path. |
56 | * |
57 | * @param path String with the path the new node should point to. |
58 | * @param verify true if the isValid and isDirectory/isFile flags should |
59 | * be verified during the construction. |
60 | */ |
61 | FilesystemNodePOSIX(const string& path, bool verify = true); |
62 | |
63 | bool exists() const override { return access(_path.c_str(), F_OK) == 0; } |
64 | const string& getName() const override { return _displayName; } |
65 | void setName(const string& name) override { _displayName = name; } |
66 | const string& getPath() const override { return _path; } |
67 | string getShortPath() const override; |
68 | bool hasParent() const override; |
69 | bool isDirectory() const override { return _isDirectory; } |
70 | bool isFile() const override { return _isFile; } |
71 | bool isReadable() const override { return access(_path.c_str(), R_OK) == 0; } |
72 | bool isWritable() const override { return access(_path.c_str(), W_OK) == 0; } |
73 | bool makeDir() override; |
74 | bool rename(const string& newfile) override; |
75 | |
76 | bool getChildren(AbstractFSList& list, ListMode mode) const override; |
77 | AbstractFSNodePtr getParent() const override; |
78 | |
79 | protected: |
80 | string _path; |
81 | string _displayName; |
82 | bool _isValid; |
83 | bool _isFile; |
84 | bool _isDirectory; |
85 | |
86 | private: |
87 | /** |
88 | * Tests and sets the _isValid and _isDirectory/_isFile flags, |
89 | * using the stat() function. |
90 | */ |
91 | virtual void setFlags(); |
92 | |
93 | /** |
94 | * Returns the last component of a given path. |
95 | * |
96 | * Examples: |
97 | * /foo/bar.txt would return /bar.txt |
98 | * /foo/bar/ would return /bar/ |
99 | * |
100 | * @param str String containing the path. |
101 | * @return Pointer to the first char of the last component inside str. |
102 | */ |
103 | static const char* lastPathComponent(const string& str) |
104 | { |
105 | if(str.empty()) |
106 | return "" ; |
107 | |
108 | const char* start = str.c_str(); |
109 | const char* cur = start + str.size() - 2; |
110 | |
111 | while (cur >= start && *cur != '/') |
112 | --cur; |
113 | |
114 | return cur + 1; |
115 | } |
116 | }; |
117 | |
118 | #endif |
119 | |