1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) 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, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #if defined(__MORPHOS__)
24
25 #include "backends/fs/morphos/morphos-fs.h"
26 #include "backends/fs/stdiostream.h"
27 #include "common/debug.h"
28 #include "common/util.h"
29
30 /**
31 * Returns the last component of a given path.
32 *
33 * @param str Common::String containing the path.
34 * @return Pointer to the first char of the last component inside str.
35 */
lastPathComponent(const Common::String & str)36 const char *lastPathComponent(const Common::String &str) {
37
38 int offset = str.size();
39
40 if (offset <= 0) {
41 debug(6, "Bad offset");
42 return 0;
43 }
44
45 const char *p = str.c_str();
46
47 while (offset > 0 && (p[offset-1] == '/' || p[offset-1] == ':'))
48 offset--;
49
50 while (offset > 0 && (p[offset-1] != '/' && p[offset-1] != ':'))
51 offset--;
52
53 return p + offset;
54 }
55
MorphOSFilesystemNode()56 MorphOSFilesystemNode::MorphOSFilesystemNode() {
57
58 _sDisplayName = "Available HDDs/Partitions";
59 _bIsValid = true;
60 _bIsDirectory = true;
61 _sPath = "";
62 _pFileLock = 0;
63 _nProt = 0; // Protection is ignored for the root volume
64 }
65
MorphOSFilesystemNode(const Common::String & p)66 MorphOSFilesystemNode::MorphOSFilesystemNode(const Common::String &p) {
67
68 int offset = p.size();
69 if (offset <= 0) {
70 debug(6, "Bad offset");
71 return;
72 }
73
74 _sPath = p;
75 _sDisplayName = ::lastPathComponent(_sPath);
76 _pFileLock = 0;
77 _bIsDirectory = false;
78 _bIsValid = false;
79
80 struct FileInfoBlock *fib = (struct FileInfoBlock*) AllocDosObject(DOS_FIB, NULL);
81
82 if (fib == NULL) {
83 debug(6,"Failed...");
84 return;
85 }
86
87 BPTR pLock = Lock((CONST_STRPTR)_sPath.c_str(), SHARED_LOCK);
88 if (pLock) {
89 if (Examine(pLock, fib) != DOSFALSE) {
90 if (fib->fib_EntryType > 0) {
91 _bIsDirectory = true;
92 _pFileLock = DupLock(pLock);
93 _bIsValid = (_pFileLock != 0);
94 const char c = _sPath.lastChar();
95 if (c != '/' && c != ':')
96 _sPath += '/';
97 } else {
98 _bIsDirectory = false;
99 _bIsValid = false;
100 }
101 }
102 UnLock(pLock);
103 }
104 FreeDosObject(DOS_FIB, fib);
105 }
106
MorphOSFilesystemNode(BPTR pLock,const char * pDisplayName)107 MorphOSFilesystemNode::MorphOSFilesystemNode(BPTR pLock, const char *pDisplayName) {
108
109 int bufSize = MAXPATHLEN;
110 _pFileLock = 0;
111
112 while (true) {
113 char *n = new char[bufSize];
114 if (NameFromLock(pLock, (STRPTR)n, bufSize) != DOSFALSE) {
115 _sPath = n;
116 _sDisplayName = pDisplayName ? pDisplayName : FilePart((STRPTR)n);
117 delete[] n;
118 break;
119 }
120
121 if (IoErr() != ERROR_LINE_TOO_LONG) {
122 _bIsValid = false;
123 debug(6, "IoErr() != ERROR_LINE_TOO_LONG");
124 delete[] n;
125 return;
126 }
127
128 bufSize *= 2;
129 delete[] n;
130 }
131
132 _bIsValid = false;
133 _bIsDirectory = false;
134
135 FileInfoBlock *fib = (FileInfoBlock*) AllocDosObject(DOS_FIB, NULL);
136
137 if (fib == NULL) {
138 debug(6,"Failed...");
139 return;
140 }
141
142 if (Examine(pLock, fib) != DOSFALSE) {
143 _bIsDirectory = fib->fib_EntryType >0;
144 if (_bIsDirectory) {
145 if (fib->fib_EntryType != ST_ROOT)
146 _sPath += '/';
147 _pFileLock = DupLock(pLock);
148 if (_pFileLock) _bIsValid = true;
149 } else {
150 _bIsValid = true;
151 }
152 }
153 FreeDosObject(DOS_FIB, fib);
154 }
155
156 // We need the custom copy constructor because of DupLock()
MorphOSFilesystemNode(const MorphOSFilesystemNode & node)157 MorphOSFilesystemNode::MorphOSFilesystemNode(const MorphOSFilesystemNode& node)
158 : AbstractFSNode() {
159
160 _sDisplayName = node._sDisplayName;
161 _bIsValid = node._bIsValid;
162 _bIsDirectory = node._bIsDirectory;
163 _sPath = node._sPath;
164 _pFileLock = DupLock(node._pFileLock);
165 _nProt = node._nProt;
166 }
167
~MorphOSFilesystemNode()168 MorphOSFilesystemNode::~MorphOSFilesystemNode() {
169
170 if (_pFileLock)
171 UnLock(_pFileLock);
172 }
173
exists() const174 bool MorphOSFilesystemNode::exists() const {
175
176 if (_sPath.empty())
177 return false;
178
179 bool nodeExists = false;
180
181 BPTR pLock = Lock(_sPath.c_str(), SHARED_LOCK);
182 if (pLock) {
183 nodeExists = true;
184 UnLock(pLock);
185 }
186
187 return nodeExists;
188 }
189
getChild(const Common::String & n) const190 AbstractFSNode *MorphOSFilesystemNode::getChild(const Common::String &n) const {
191
192 if (!_bIsDirectory) {
193 debug(6, "Not a directory");
194 return 0;
195 }
196
197 Common::String newPath(_sPath);
198
199 if (_sPath.lastChar() != '/')
200 newPath += '/';
201
202 newPath += n;
203
204 return new MorphOSFilesystemNode(newPath);
205 }
206
getChildren(AbstractFSList & myList,ListMode mode,bool hidden) const207 bool MorphOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
208
209 if (!_bIsValid) {
210 debug(6, "Invalid node");
211 return false; // Empty list
212 }
213
214 if (!_bIsDirectory) {
215 debug(6, "Not a directory");
216 return false; // Empty list
217 }
218
219 if (isRootNode()) {
220 debug(6, "Root node");
221 myList = listVolumes();
222 return true;
223 }
224
225 FileInfoBlock *fib = (FileInfoBlock*) AllocDosObject(DOS_FIB, NULL);
226
227 if (fib == NULL) {
228 debug(6, "Failed to allocate memory for FileInfoBLock");
229 return false;
230 }
231
232 if (Examine(_pFileLock, fib) != DOSFALSE) {
233
234 MorphOSFilesystemNode *entry;
235
236 while (ExNext(_pFileLock, fib) != DOSFALSE) {
237 Common::String full_path = NULL;
238 BPTR pLock;
239 if ((mode == Common::FSNode::kListAll) || (fib->fib_EntryType > 0 && (Common::FSNode::kListDirectoriesOnly == mode)) || (fib->fib_EntryType < 0 && (Common::FSNode::kListFilesOnly == mode ))) {
240 full_path = _sPath;
241 full_path += fib->fib_FileName;
242 pLock = Lock(full_path.c_str(), SHARED_LOCK);
243 if (pLock) {
244 entry = new MorphOSFilesystemNode( pLock, fib->fib_FileName );
245 if (entry) {
246 myList.push_back(entry);
247 }
248 UnLock(pLock);
249 }
250 }
251 }
252 if (ERROR_NO_MORE_ENTRIES != IoErr() ) {
253 debug(6, "An error occurred during ExamineDir");
254 return false;
255 }
256 }
257
258 FreeDosObject(DOS_FIB, fib);
259 return true;
260 }
261
getParent() const262 AbstractFSNode *MorphOSFilesystemNode::getParent() const {
263
264 if (isRootNode()) {
265 debug(6, "Root node");
266 return new MorphOSFilesystemNode(*this);
267 }
268
269 BPTR pLock = _pFileLock;
270
271 if (!_bIsDirectory) {
272 assert(!pLock);
273 pLock = Lock((CONST_STRPTR)_sPath.c_str(), SHARED_LOCK);
274 assert(pLock);
275 }
276
277 MorphOSFilesystemNode *node;
278
279 BPTR parentDir = ParentDir( pLock );
280 if (parentDir) {
281 node = new MorphOSFilesystemNode(parentDir);
282 UnLock(parentDir);
283 } else
284 node = new MorphOSFilesystemNode();
285
286 if (!_bIsDirectory) {
287 UnLock(pLock);
288 }
289
290 return node;
291 }
292
293
listVolumes() const294 AbstractFSList MorphOSFilesystemNode::listVolumes() const {
295
296 AbstractFSList myList;
297 DosList *dosList;
298 const ULONG kLockFlags = LDF_READ | LDF_VOLUMES;
299 char buffer[MAXPATHLEN];
300
301 dosList = LockDosList(kLockFlags);
302
303 if (dosList == NULL) {
304 debug(6, "Cannot lock the DOS list");
305 return myList;
306 }
307
308 dosList = NextDosEntry(dosList, LDF_VOLUMES);
309
310 MorphOSFilesystemNode *entry;
311
312 while (dosList) {
313
314 if (dosList->dol_Type == DLT_VOLUME &&
315 dosList->dol_Name &&
316 dosList->dol_Task) {
317
318 CONST_STRPTR volName = (CONST_STRPTR)BADDR(dosList->dol_Name)+1;
319 CONST_STRPTR devName = (CONST_STRPTR)((struct Task *)dosList->dol_Task->mp_SigTask)->tc_Node.ln_Name;
320 BPTR volumeLock;
321
322 strcpy(buffer, volName);
323 strcat(buffer, ":");
324
325 volumeLock = Lock(buffer, SHARED_LOCK);
326 if (volumeLock) {
327
328 sprintf(buffer, "%s (%s)", volName, devName);
329
330 entry = new MorphOSFilesystemNode(volumeLock, buffer);
331 if (entry) {
332 myList.push_back(entry);
333 }
334
335 UnLock(volumeLock);
336 }
337 }
338 dosList = NextDosEntry(dosList, LDF_VOLUMES);
339 }
340
341 UnLockDosList(kLockFlags);
342
343 return myList;
344 }
345
createReadStream()346 Common::SeekableReadStream *MorphOSFilesystemNode::createReadStream() {
347 StdioStream *readStream = StdioStream::makeFromPath(getPath(), false);
348
349 if (readStream) {
350 readStream->setBufferSize(8192);
351 }
352
353 return readStream;
354 }
355
createWriteStream()356 Common::SeekableWriteStream *MorphOSFilesystemNode::createWriteStream() {
357 return StdioStream::makeFromPath(getPath(), true);
358 }
359
createDirectory()360 bool MorphOSFilesystemNode::createDirectory() {
361 warning("MorphOSFilesystemNode::createDirectory(): Not supported");
362 return _bIsValid && _bIsDirectory;
363 }
364
365 #endif //defined(__MORPHOS__)
366