Fixed typos
[ACE_TAO.git] / ACE / ace / MQX_Filesystem.cpp
blobf04303d8675e09ad6249726035ccb20bb15c8b39
1 #include "MQX_Filesystem.h"
3 #ifdef ACE_MQX
5 #include "ace/OS_NS_unistd.h"
6 #include "ace/OS_NS_sys_stat.h"
8 #include <mqx.h>
9 #include <fio.h>
10 #include <mfs.h>
12 #include <string.h>
14 #ifndef FOPEN_MAX
15 # error "FOPEN_MAX, the max number of open files, must be defined"
16 #endif
17 #if FOPEN_MAX < 3
18 # error "FOPEN_MAX is less than 3, no room for standard streams, let alone other files descriptors"
19 #endif
21 #define MQX_FILE_ERROR static_cast<size_t>(-1)
23 MQX_Filesystem MQX_Filesystem::instance_;
25 MQX_Filesystem::MQX_Filesystem ()
26 : current_fs_ (0)
27 , current_fs_name_len_ (0)
28 , max_fd_ (255)
29 , last_fd_ (-1)
31 current_fs_name_[0] = '\0';
33 // Initialize files_
34 for (unsigned i = 0; i < FOPEN_MAX; i++)
36 files_[i].fd = -1;
37 files_[i].mqx_file = 0;
41 void MQX_Filesystem::complete_initialization ()
43 // Set the Standard Streams
44 files_[0] = {ACE_STDIN, (MQX_FILE_PTR) _io_get_handle (IO_STDIN), true};
45 files_[1] = {ACE_STDOUT, (MQX_FILE_PTR) _io_get_handle (IO_STDOUT), true};
46 files_[2] = {ACE_STDERR, (MQX_FILE_PTR) _io_get_handle (IO_STDERR), true};
49 * Try to set the current filesystem. Ignore the error return because if
50 * we're missing a filesystem now, it's okay because a filesystem might be
51 * added later.
53 reset_state ();
56 bool
57 MQX_Filesystem::check_state ()
59 if (!_io_is_fs_valid (current_fs_))
61 if (reset_state ())
63 errno = ENODEV;
64 return true;
67 return false;
70 bool
71 MQX_Filesystem::reset_state ()
73 update_fs (_io_get_first_valid_fs ());
74 if (current_fs_ != 0)
75 chdir ("\\");
76 return current_fs_ == 0;
79 void
80 MQX_Filesystem::update_fs (MQX_FILE_PTR fs)
82 current_fs_ = fs;
83 bool invalid = false;
84 if (fs == 0)
85 invalid = true;
86 else if (_io_get_fs_name (fs, current_fs_name_, IOCFG_FS_MAX_DEVLEN) != MQX_OK)
87 invalid = true;
88 else
89 current_fs_name_len_ = strlen (current_fs_name_);
91 if (invalid)
93 current_fs_ = 0;
94 current_fs_name_[0] = '\0';
95 current_fs_name_len_ = 0;
99 int
100 MQX_Filesystem::open (const char *path, int mode)
102 if (check_state ()) return -1;
104 // Convert open mode to fopen mode
105 bool r = ACE_BIT_DISABLED (mode, O_RDONLY);
106 bool w = ACE_BIT_ENABLED (mode, O_WRONLY);
107 bool rw = ACE_BIT_ENABLED (mode, O_RDWR);
108 bool a = ACE_BIT_ENABLED (mode, O_CREAT | O_APPEND);
109 bool t = ACE_BIT_ENABLED (mode, O_CREAT | O_TRUNC);
110 if (!(r || (w && (a || t)) || rw))
112 errno = EINVAL;
113 return -1;
115 char cstdlib_mode[4] = {0}; // r/w/a, t/b, +?, null terminator
116 cstdlib_mode[0] = r ? 'r' : a ? 'a' : 'w';
117 cstdlib_mode[1] = 'b';
118 cstdlib_mode[2] = rw ? '+' : '\0';
120 /// Get Absolute Path
121 char cwd[FS_FILENAME_SIZE];
122 int mqx_error = _io_ioctl (current_fs_, IO_IOCTL_GET_CURRENT_DIR, (uint32_t*) cwd);
123 if (mqx_error != MQX_OK)
125 errno = ACE_OS::mqx_error_to_errno (mqx_error);
126 return -1;
128 char abspath[ACE_MQX_ABS_PATH_SIZE];
129 mqx_error = _io_rel2abs (abspath, cwd, path, ACE_MQX_ABS_PATH_SIZE, current_fs_name_);
130 if (mqx_error != MQX_OK)
132 errno = ACE_OS::mqx_error_to_errno (mqx_error);
133 return -1;
136 // Set up a new File Entry
137 File *file = get_new_file ();
138 if (file == 0) return -1;
140 // Call into MQX
141 file->mqx_file = _io_fopen (abspath, cstdlib_mode);
142 if (file->mqx_file == 0)
144 file->fd = -1; // Free File in Our Array
145 errno = ACE_OS::mqx_error_to_errno (_task_get_error());
146 if (_task_get_error() == FS_FILE_NOT_FOUND)
147 _task_set_error(MQX_OK);
150 return file->fd;
154 MQX_Filesystem::close (int fd)
156 File *file = get_file (fd);
157 if (file == 0) return -1;
158 int mqx_error = _io_fclose (file->mqx_file);
159 if (mqx_error != MQX_OK)
161 errno = ACE_OS::mqx_error_to_errno (mqx_error);
162 return -1;
164 return 0;
167 size_t
168 MQX_Filesystem::read (int fd, unsigned char *buffer, size_t size)
170 File *file = get_file (fd);
171 if (file == 0) return MQX_FILE_ERROR;
172 int result = _io_read (file->mqx_file, buffer, size);
173 if (result == IO_ERROR)
175 errno = EIO;
176 return MQX_FILE_ERROR;
178 return result;
181 size_t
182 MQX_Filesystem::write (int fd, const unsigned char *buffer, size_t size)
184 File *file = get_file (fd);
185 if (file == 0) return MQX_FILE_ERROR;
186 int result = _io_write (file->mqx_file, const_cast<unsigned char *> (buffer), size);
187 if (result == IO_ERROR)
189 errno = EIO;
190 return MQX_FILE_ERROR;
192 return result;
195 long
196 MQX_Filesystem::lseek (int fd, long offset, int whence)
198 switch (whence)
200 case SEEK_SET:
201 whence = IO_SEEK_SET;
202 break;
203 case SEEK_CUR:
204 whence = IO_SEEK_CUR;
205 break;
206 case SEEK_END:
207 whence = IO_SEEK_END;
208 break;
209 default:
210 errno = EINVAL;
211 return -1;
213 File *file = get_file (fd);
214 if (file == 0) return -1;
215 return _io_fseek (file->mqx_file, offset, whence) == MQX_OK ? 0 : -1;
218 char*
219 MQX_Filesystem::getcwd (char *buf, size_t size)
221 if (check_state ()) return 0;
222 if (buf == 0)
224 errno = EINVAL;
225 return 0;
228 char curdirtmp[FS_FILENAME_SIZE];
229 int mqx_error = _io_ioctl (current_fs_, IO_IOCTL_GET_CURRENT_DIR, (uint32_t*) curdirtmp);
230 if (mqx_error != MFS_NO_ERROR)
232 errno = ACE_OS::mqx_error_to_errno (mqx_error);
233 return 0;
235 if ((current_fs_name_len_ + strlen (curdirtmp) + 1) > size)
237 errno = ERANGE;
238 return 0;
240 strcpy (buf, current_fs_name_);
241 strcat (buf, curdirtmp);
242 return buf;
245 MQX_FILE_PTR
246 MQX_Filesystem::resolve_fs (const char *path, int *fs_name_len)
248 if (check_state ()) return 0;
250 if (fs_name_len == 0 || path == 0 || path[0] == '\0')
252 errno = EINVAL;
253 return 0;
255 MQX_FILE_PTR fs;
256 char fs_name[IOCFG_FS_MAX_DEVLEN];
257 bool fs_in_path;
258 *fs_name_len = _io_get_dev_for_path (
259 fs_name, &fs_in_path, IOCFG_FS_MAX_DEVLEN, path, current_fs_name_);
260 if (fs_in_path)
262 fs = _io_get_fs_by_name (fs_name);
264 else if (*fs_name_len)
266 fs = current_fs_;
267 *fs_name_len = 0;
269 else
271 errno = EINVAL;
272 fs = 0;
274 return fs;
278 MQX_Filesystem::mkdir (const char *path)
280 int fs_name_len;
281 MQX_FILE_PTR fs = resolve_fs (path, &fs_name_len);
282 if (fs == 0) return -1;
283 int mqx_error = _io_ioctl (
284 fs, IO_IOCTL_CREATE_SUBDIR, (uint32_t*) (path + fs_name_len));
285 if (mqx_error != MQX_OK)
287 errno = ACE_OS::mqx_error_to_errno (mqx_error);
288 return -1;
290 return 0;
294 MQX_Filesystem::chdir (const char *path)
296 int fs_name_len;
297 MQX_FILE_PTR fs = resolve_fs (path, &fs_name_len);
298 if (fs == 0) return -1;
299 if (fs != current_fs_) update_fs(fs);
300 int mqx_error = _io_ioctl (fs, IO_IOCTL_CHANGE_CURRENT_DIR,
301 (uint32_t*) (path + fs_name_len));
302 if (mqx_error != MQX_OK)
304 errno = ACE_OS::mqx_error_to_errno (mqx_error);
305 return -1;
307 return 0;
311 MQX_Filesystem::rmdir (const char *path)
313 int fs_name_len;
314 MQX_FILE_PTR fs = resolve_fs (path, &fs_name_len);
315 if (fs == 0) return -1;
316 int mqx_error = _io_ioctl (fs, IO_IOCTL_REMOVE_SUBDIR,
317 (uint32_t*) (path + fs_name_len));
318 if (mqx_error != MQX_OK)
320 errno = ACE_OS::mqx_error_to_errno (mqx_error);
321 return -1;
323 return 0;
327 MQX_Filesystem::unlink (const char *path)
329 int fs_name_len;
330 MQX_FILE_PTR fs = resolve_fs (path, &fs_name_len);
331 if (fs == 0) return -1;
332 int mqx_error = _io_ioctl (fs, IO_IOCTL_DELETE_FILE,
333 (uint32_t*) (path + fs_name_len));
334 if (mqx_error != MQX_OK)
336 errno = ACE_OS::mqx_error_to_errno (mqx_error);
337 return -1;
339 return 0;
343 MQX_Filesystem::rename (const char *oldpath, const char *newpath)
345 // TODO: Handle Moving Directories?
346 int old_fs_name_len;
347 MQX_FILE_PTR fs = resolve_fs (oldpath, &old_fs_name_len);
348 int new_fs_name_len;
349 MQX_FILE_PTR other_fs = resolve_fs (newpath, &new_fs_name_len);
350 if (fs == 0 || other_fs == 0) return -1;
351 if (fs != other_fs)
353 errno = EXDEV;
354 return -1;
357 ACE_stat file_status;
358 if (this->stat (newpath, &file_status) == 0)
360 // New path already exists...
361 if (file_status.st_mode & S_IFREG)
363 // It's a file, we can delete it.
364 if (this->unlink (newpath))
366 return -1;
369 else if (file_status.st_mode & S_IFDIR)
371 // It's a directory, we can't delete that.
372 errno = EEXIST;
373 return -1;
375 else
377 // Unknown type, error
378 errno = EINVAL;
379 return -1;
383 MFS_RENAME_PARAM mfs_rename;
384 char oldtmp[FS_FILENAME_SIZE];
385 strcpy (oldtmp, oldpath + old_fs_name_len);
386 mfs_rename.OLD_PATHNAME = oldtmp;
387 char newtmp[FS_FILENAME_SIZE];
388 strcpy (newtmp, newpath + new_fs_name_len);
389 mfs_rename.NEW_PATHNAME = newtmp;
391 int mqx_error = _io_ioctl (fs, IO_IOCTL_RENAME_FILE, (uint32_t*) &mfs_rename);
392 if (mqx_error != MQX_OK)
394 errno = ACE_OS::mqx_error_to_errno (mqx_error);
395 return -1;
397 return 0;
400 MQX_Filesystem::File *
401 MQX_Filesystem::get_file (int fd)
403 for (int i = 0; i < FOPEN_MAX; i++)
405 if (files_[i].fd == fd) return &files_[i];
407 errno = EBADF;
408 return 0;
411 MQX_Filesystem::File *
412 MQX_Filesystem::get_new_file ()
414 // Get Unused File Struct
415 File *file = get_file (-1);
416 if (file != 0)
418 file->mqx_file = 0;
419 // Get Unused File Descriptor
420 for (int fd = last_fd_ + 1; fd != last_fd_; fd++)
422 if (get_file (fd) == 0)
424 file->fd = fd;
425 last_fd_ = fd;
426 return file;
428 if (fd == max_fd_) fd = 0;
431 errno = ENFILE;
432 return 0;
435 static inline int
436 mfs_file_attrs_to_stat_mode (int attributes)
438 int mode = (attributes & MFS_ATTR_DIR_NAME) ? S_IFDIR : S_IFREG;
439 return mode;
443 MQX_Filesystem::stat (const char * path, ACE_stat *statbuf)
445 if (statbuf == 0)
447 errno = EINVAL;
448 return -1;
451 int fs_name_len;
452 MQX_FILE_PTR fs = resolve_fs (path, &fs_name_len);
453 if (fs == 0) return -1;
455 statbuf->st_size = 0;
456 statbuf->st_mtime = 0;
457 statbuf->st_mode = 0;
458 statbuf->st_nlink = 0;
460 MFS_SEARCH_PARAM search;
461 search.ATTRIBUTE = MFS_SEARCH_ANY;
462 char tmppath[ACE_MQX_ABS_PATH_SIZE];
463 strcpy (&tmppath[0], path);
464 search.WILDCARD = &tmppath[fs_name_len];
465 MFS_SEARCH_DATA search_results;
466 search.SEARCH_DATA_PTR = &search_results;
467 int mqx_error = _io_ioctl (fs, IO_IOCTL_FIND_FIRST_FILE, (uint32_t *) &search);
468 if (mqx_error == MFS_NO_ERROR)
470 statbuf->st_size = search_results.FILE_SIZE;
471 statbuf->st_mode = mfs_file_attrs_to_stat_mode (search_results.ATTRIBUTE);
472 statbuf->st_nlink = 1;
473 // TODO: statbuf->st_mtime
474 return 0;
476 errno = ACE_OS::mqx_error_to_errno (mqx_error);
477 return -1;
481 MQX_Filesystem::fstat (int fd, ACE_stat *statbuf)
483 if (statbuf == 0)
485 errno = EINVAL;
486 return -1;
489 File *file = get_file (fd);
490 if (file == 0) return -1;
492 statbuf->st_size = 0;
493 statbuf->st_mtime = 0;
494 statbuf->st_mode = 0;
495 statbuf->st_nlink = 0;
497 if (file->chardev_file)
499 statbuf->st_mode &= S_IFCHR;
500 return 0;
503 int attributes = 0;
504 int mqx_error = _io_ioctl (file->mqx_file, IO_IOCTL_GET_FILE_ATTR, (uint32_t *) &attributes);
505 if (mqx_error != MQX_OK)
507 errno = ACE_OS::mqx_error_to_errno (mqx_error);
508 return -1;
510 statbuf->st_mode = mfs_file_attrs_to_stat_mode (attributes);
511 statbuf->st_nlink = 1;
513 // TODO: statbuf->st_mtime
515 return 0;
518 /* The following are the function definitions that DLib will use to access MQX
519 * IO through MQX_Filesystem.
522 extern "C" {
524 int __open (const char *filename, int mode)
526 return MQX_Filesystem::inst ().open (filename, mode);
529 size_t __read (int handle, unsigned char *buffer, size_t size)
531 return MQX_Filesystem::inst ().read (handle, buffer, size);
534 size_t __write (int handle, const unsigned char *buffer, size_t size)
536 return MQX_Filesystem::inst ().write (handle, buffer, size);
539 long __lseek (int handle, long offset, int whence)
541 return MQX_Filesystem::inst ().lseek (handle, offset, whence);
544 int __close (int handle)
546 return MQX_Filesystem::inst ().close (handle);
549 } // extern "C"
551 #endif // ACE_MQX