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