summaryrefslogtreecommitdiff
path: root/ACE/ace/MQX_Filesystem.h
blob: 2bc32cb24a44da47a6fdf7f84c72fcf1786b4a73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
/**
 * @file MQX_Filesystem.h
 *
 * @author Frederick Hornsey <hornseyf@objectcomputing.com>
 */

#ifndef MQX_FILESYSTEM_HEADER
#define MQX_FILESYSTEM_HEADER

#include "ace/config-all.h"

#ifdef ACE_MQX

#include <mqx.h>
#include <fio.h>

#if !defined (FOPEN_MAX)
# define FOPEN_MAX 20
#endif

#if !defined (ACE_MQX_DLIB_FULL)
# undef read
# undef write
#endif

struct stat;
typedef struct stat ACE_stat;

#define ACE_MQX_ABS_PATH_SIZE (IOCFG_FS_MAX_DEVLEN + FS_FILENAME_SIZE - 1)

/**
 * Since MQX has an unusual filesystem API, this class is provided to try to
 * normalize it by managing the current working directory on a global context
 * instead of a device by device context provided by MQX. It also tries to make
 * these functions act more like their UNIX counterparts to some extent.
 *
 * This class is also the interface between the DLib IO functions and MQX file
 * IO. It does this by implementing the classic UNIX IO functions below.
 *
 * WARNING: This is already being done in the ACE_TMAIN macro, but
 * complete_initialization() should be called before using DLib or ACE file IO
 * functions, but after MQX has been initialized. Either way, standard streams
 * will not work properly, or some other behavior depending on the what
 * functions are called in what order.
 */
class MQX_Filesystem {
public:
  /// Get the singleton instance of the class
  inline static MQX_Filesystem &inst() {
    return instance_;
  }

  /**
   * Initialize the Standard Streams and the Current Filesystem
   *
   * This must be done after MQX has been initialized. See warning in class
   * documenting comment.
   */
  void complete_initialization ();

  /**
   * Attempt to reset the cwd state by asking MQX for the first valid filesystem
   * and "cd-ing" into the root of it.
   */
  bool reset_state ();

  /**
   * @name Unix-like File Functions
   *
   * Classic UNIX-like Operations Implemented for for DLib
   */
  ///@{
  /**
   * Open a file and return the file descriptor.
   *
   * Returns the file descriptor if successful, -1 otherwise.
   *
   * Known Limitations:
   *  - Mode is being converted from DLib Unix-like mode to MQX cstdlib mode.
   *    This is not perfected yet and is limited by the common denominator of
   *    what is supported by both systems.
   */
  int open (const char *path, int mode);
  int close (int fd);
  size_t read (int fd, unsigned char *buffer, size_t size);
  size_t write (int fd, const unsigned char *buffer, size_t size);
  long lseek (int fd, long offset, int whence);
  ///@}

  /**
   * @name Unix-like Filesystem Functions
   */
  ///@{
  /**
   * Put the current directory path in buf of size.
   *
   * Returns NULL if an error occurred, otherwise buf.
   */
  char *getcwd (char *buf, size_t size);

  /**
   * Create a directory at path.
   *
   * Returns -1 if an error occurred, otherwise 0.
   */
  int mkdir (const char *path);

  /**
   * Change to the directory at path.
   *
   * Returns -1 if an error occurred, otherwise 0.
   */
  int chdir (const char *path);

  /**
   * Remove the empty directory at path.
   *
   * Returns -1 if an error occurred, otherwise 0.
   */
  int rmdir (const char *path);

  /**
   * Unlink the file at path.
   *
   * Returns -1 if an error occurred, otherwise 0.
   */
  int unlink (const char *path);

  /**
   * Rename or move the file or rename the directory from newpath to oldpath.
   *
   * Returns -1 if an error occurred, otherwise 0.
   *
   * As standard rename does, this sets errno to EXDEV if you try to move a
   * file across filesystems. It also overwrites regular files that occupy the
   * new path.
   *
   * Known Limitations:
   *   - Can only rename directories, will refuse to move them. This is MFS's
   *     IO_IOCTL_RENAME_FILE refusing to do this. This could be implemented by
   *     the function, but would involve either manually copying the file tree
   *     or refusing to move nonempty directories.
   */
  int rename (const char *oldpath, const char *newpath);

  /**
   * Get status of file given by path.
   *
   * Returns -1 if an error occurred, otherwise 0.
   *
   * Known Limitations:
   *   - st_mtime is currently not implemented and is set to 0.
   *   - st_mode is limited to
   *     - S_IFDIR: file is a directory
   *     - S_IFREG: file is a regular file
   */
  int stat (const char * path, ACE_stat *statbuf);

  /**
   * Get status of file given by file descriptor.
   *
   * Returns -1 if an error occurred, otherwise 0.
   *
   * Known Limitations:
   *   - st_mtime is currently not implemented and returns 0
   *   - In MFS there seems to be no direct way to get st_msize from a MQX file
   *     alone. The only way to get a file size using the documented API seems
   *     to be IO_IOCTL_FIND_FIRST_FILE, which requires the path. For now this
   *     will be set to 0.
   *   - st_mode is limited to
   *     - S_IFDIR: file is a directory
   *     - S_IFREG: file is a regular file
   *     - S_IFCHR: file is a special character device file, (e.g. ACE_STDOUT)
   */
  int fstat (int fd, ACE_stat *statbuf);
  ///@}

private:
  /// The singleton instance of the class
  static MQX_Filesystem instance_;

  MQX_Filesystem();

  /**
   * @name Current Filesystem for resolving relative paths.
   */
  ///@{
  MQX_FILE_PTR current_fs_;
  char current_fs_name_[IOCFG_FS_MAX_DEVLEN];
  unsigned current_fs_name_len_;
  ///@}

  /**
   * @name Manage open files using file descriptors.
   */
  ///@{
  struct File {
    /// DLib File Descriptor. Invalid if -1.
    int fd;
    /// MQX File
    MQX_FILE_PTR mqx_file;
    /// Mark this as special character device file (Standard Streams)
    bool chardev_file;
  };
  File files_[FOPEN_MAX];

  /**
   * Last file descriptor created.
   */
  int last_fd_;

  /**
   * Max VALUE for File Descriptors.
   *
   * NOTE: Max open file count is FOPEN_MAX, defined by DLib. This creates a
   * limit on the number of unique file descriptor values.
   */
  int max_fd_;

  /**
   * Get a File struct for the file descriptor.
   *
   * Returns NULL and sets EBADF if no such file exists
   */
  File *get_file (int fd);

  /**
   * Get a File struct pointer to use for a new file.
   *
   * Returns NULL and sets ENFILE if exceeded max number of open files.
   */
  File *get_new_file ();
  ///@}

  /**
   * Check to see if the current filesystem is valid, if not reset it.
   *
   * Returns true if reseting failed, otherwise false. Failure would probably
   * mean no filesystems are mounted.
   */
  bool check_state ();

  /**
   * Set the supplied pointer as the filesystem of the current working
   * directory.
   */
  void update_fs (MQX_FILE_PTR fs);

  /**
   * Resolve the filesystem of the supplied path and return it.
   *
   * This will be the filesystem of the current working directory if the path
   * is relative. Sets the fs_name_len to the length of the device name in the
   * path. This would be 0 if the path is relative.
   */
  MQX_FILE_PTR resolve_fs (const char *path, int *fs_name_len);
};

#endif // ACE_MQX
#endif // MQX_FILESYSTEM_HEADER