Blame view

RIOT/sys/fs/constfs/constfs.c 9.61 KB
a752c7ab   elopes   add first test an...
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
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  /*
   * Copyright (C) 2016 Eistec AB
   *
   * This file is subject to the terms and conditions of the GNU Lesser
   * General Public License v2.1. See the file LICENSE in the top level
   * directory for more details.
   */
  
  /**
   * @ingroup     sys_fs_constfs
   * @{
   *
   * @file
   * @brief       ConstFS implementation
   *
   * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
   *
   * @}
   */
  
  /* Required for strnlen in string.h, when building with -std=c99 */
  #define _DEFAULT_SOURCE 1
  #include <stddef.h>
  #include <string.h>
  #include <unistd.h>
  #include <fcntl.h>
  #include <errno.h>
  
  #include "fs/constfs.h"
  #include "vfs.h"
  
  #define ENABLE_DEBUG (0)
  #include "debug.h"
  
  /* File system operations */
  static int constfs_mount(vfs_mount_t *mountp);
  static int constfs_umount(vfs_mount_t *mountp);
  static int constfs_unlink(vfs_mount_t *mountp, const char *name);
  static int constfs_stat(vfs_mount_t *mountp, const char *restrict name, struct stat *restrict buf);
  static int constfs_statvfs(vfs_mount_t *mountp, const char *restrict path, struct statvfs *restrict buf);
  
  /* File operations */
  static int constfs_close(vfs_file_t *filp);
  static int constfs_fstat(vfs_file_t *filp, struct stat *buf);
  static off_t constfs_lseek(vfs_file_t *filp, off_t off, int whence);
  static int constfs_open(vfs_file_t *filp, const char *name, int flags, mode_t mode, const char *abs_path);
  static ssize_t constfs_read(vfs_file_t *filp, void *dest, size_t nbytes);
  static ssize_t constfs_write(vfs_file_t *filp, const void *src, size_t nbytes);
  
  /* Directory operations */
  static int constfs_opendir(vfs_DIR *dirp, const char *dirname, const char *abs_path);
  static int constfs_readdir(vfs_DIR *dirp, vfs_dirent_t *entry);
  static int constfs_closedir(vfs_DIR *dirp);
  
  static const vfs_file_system_ops_t constfs_fs_ops = {
      .mount = constfs_mount,
      .umount = constfs_umount,
      .unlink = constfs_unlink,
      .statvfs = constfs_statvfs,
      .stat = constfs_stat,
  };
  
  static const vfs_file_ops_t constfs_file_ops = {
      .close = constfs_close,
      .fstat = constfs_fstat,
      .lseek = constfs_lseek,
      .open  = constfs_open,
      .read  = constfs_read,
      .write = constfs_write,
  };
  
  static const vfs_dir_ops_t constfs_dir_ops = {
      .opendir = constfs_opendir,
      .readdir = constfs_readdir,
      .closedir = constfs_closedir,
  };
  
  
  const vfs_file_system_t constfs_file_system = {
      .f_op = &constfs_file_ops,
      .fs_op = &constfs_fs_ops,
      .d_op = &constfs_dir_ops,
  };
  
  /**
   * @internal
   * @brief Fill a file information struct with information about the file
   * pointed to by @p fp
   *
   * @param[in]  fp     file to query
   * @param[out] buf    output buffer
   */
  static void _constfs_write_stat(const constfs_file_t *fp, struct stat *restrict buf);
  
  static int constfs_mount(vfs_mount_t *mountp)
  {
      /* perform any extra initialization here */
      (void) mountp; /* prevent warning: unused parameter */
      return 0;
  }
  
  static int constfs_umount(vfs_mount_t *mountp)
  {
      /* free resources and perform any clean up here */
      (void) mountp; /* prevent warning: unused parameter */
      return 0;
  }
  
  static int constfs_unlink(vfs_mount_t *mountp, const char *name)
  {
      /* Removing files is prohibited */
      (void) mountp; /* prevent warning: unused parameter */
      (void) name; /* prevent warning: unused parameter */
      return -EROFS;
  }
  
  static int constfs_stat(vfs_mount_t *mountp, const char *restrict name, struct stat *restrict buf)
  {
      (void) name;
      /* Fill out some information about this file */
      if (buf == NULL) {
          return -EFAULT;
      }
      constfs_t *fs = mountp->private_data;
      /* linear search through the files array */
      for (size_t i = 0; i < fs->nfiles; ++i) {
          DEBUG("constfs_stat ? \"%s\"\n", fs->files[i].path);
          if (strcmp(fs->files[i].path, name) == 0) {
              DEBUG("constfs_stat: Found :)\n");
              _constfs_write_stat(&fs->files[i], buf);
              buf->st_ino = i;
              return 0;
          }
      }
      DEBUG("constfs_stat: Not found :(\n");
      return -ENOENT;
  }
  
  static int constfs_statvfs(vfs_mount_t *mountp, const char *restrict path, struct statvfs *restrict buf)
  {
      (void) path;
      /* Fill out some information about this file system */
      if (buf == NULL) {
          return -EFAULT;
      }
      constfs_t *fs = mountp->private_data;
      /* clear out the stat buffer first */
      memset(buf, 0, sizeof(*buf));
      buf->f_bsize = sizeof(uint8_t); /* block size */
      buf->f_frsize = sizeof(uint8_t); /* fundamental block size */
      fsblkcnt_t f_blocks = 0;
      for (size_t i = 0; i < fs->nfiles; ++i) {
          f_blocks += fs->files[i].size;
      }
      buf->f_blocks = f_blocks;  /* Blocks total */
      buf->f_bfree = 0;          /* Blocks free */
      buf->f_bavail = 0;         /* Blocks available to non-privileged processes */
      buf->f_files = fs->nfiles; /* Total number of file serial numbers */
      buf->f_ffree = 0;          /* Total number of free file serial numbers */
      buf->f_favail = 0;         /* Number of file serial numbers available to non-privileged process */
      buf->f_fsid = 0;           /* File system id */
      buf->f_flag = (ST_RDONLY | ST_NOSUID); /* File system flags */
      buf->f_namemax = UINT8_MAX; /* Maximum file name length */
      return 0;
  }
  
  static int constfs_close(vfs_file_t *filp)
  {
      /* perform any necessary clean ups */
      (void) filp; /* prevent warning: unused parameter */
      return 0;
  }
  
  static int constfs_fstat(vfs_file_t *filp, struct stat *buf)
  {
      constfs_file_t *fp = filp->private_data.ptr;
      if (buf == NULL) {
          return -EFAULT;
      }
      _constfs_write_stat(fp, buf);
      return 0;
  }
  
  static off_t constfs_lseek(vfs_file_t *filp, off_t off, int whence)
  {
      constfs_file_t *fp = filp->private_data.ptr;
      switch (whence) {
          case SEEK_SET:
              break;
          case SEEK_CUR:
              off += filp->pos;
              break;
          case SEEK_END:
              off += fp->size;
              break;
          default:
              return -EINVAL;
      }
      if (off < 0) {
          /* the resulting file offset would be negative */
          return -EINVAL;
      }
      /* POSIX allows seeking past the end of the file, even with O_RDONLY */
      filp->pos = off;
      return off;
  }
  
  static int constfs_open(vfs_file_t *filp, const char *name, int flags, mode_t mode, const char *abs_path)
  {
      (void) mode;
      (void) abs_path;
      constfs_t *fs = filp->mp->private_data;
      DEBUG("constfs_open: %p, \"%s\", 0x%x, 0%03lo, \"%s\"\n", (void *)filp, name, flags, (unsigned long)mode, abs_path);
      /* We only support read access */
      if ((flags & O_ACCMODE) != O_RDONLY) {
          return -EROFS;
      }
      /* linear search through the files array */
      for (size_t i = 0; i < fs->nfiles; ++i) {
          DEBUG("constfs_open ? \"%s\"\n", fs->files[i].path);
          if (strcmp(fs->files[i].path, name) == 0) {
              DEBUG("constfs_open: Found :)\n");
              filp->private_data.ptr = (void *)&fs->files[i];
              return 0;
          }
      }
      DEBUG("constfs_open: Not found :(\n");
      return -ENOENT;
  }
  
  static ssize_t constfs_read(vfs_file_t *filp, void *dest, size_t nbytes)
  {
      constfs_file_t *fp = filp->private_data.ptr;
      DEBUG("constfs_read: %p, %p, %lu\n", (void *)filp, dest, (unsigned long)nbytes);
      if ((size_t)filp->pos >= fp->size) {
          /* Current offset is at or beyond end of file */
          return 0;
      }
  
      if (nbytes > (fp->size - filp->pos)) {
          nbytes = fp->size - filp->pos;
      }
      memcpy(dest, fp->data + filp->pos, nbytes);
      DEBUG("constfs_read: read %d bytes\n", nbytes);
      filp->pos += nbytes;
      return nbytes;
  }
  
  static ssize_t constfs_write(vfs_file_t *filp, const void *src, size_t nbytes)
  {
      DEBUG("constfs_write: %p, %p, %lu\n", (void *)filp, src, (unsigned long)nbytes);
      /* Read only file system */
      DEBUG("constfs_write: read only FS\n");
      /* prevent warning: unused parameter */
      (void) filp;
      (void) src;
      (void) nbytes;
      return -EBADF;
  }
  
  static int constfs_opendir(vfs_DIR *dirp, const char *dirname, const char *abs_path)
  {
      (void) abs_path;
      DEBUG("constfs_opendir: %p, \"%s\", \"%s\"\n", (void *)dirp, dirname, abs_path);
      if (strncmp(dirname, "/", 2) != 0) {
          /* We keep it simple and only support a flat file system, only a root directory */
          return -ENOENT;
      }
      dirp->private_data.value = 0;
      return 0;
  }
  
  static int constfs_readdir(vfs_DIR *dirp, vfs_dirent_t *entry)
  {
      DEBUG("constfs_readdir: %p, %p\n", (void *)dirp, (void *)entry);
      constfs_t *fs = dirp->mp->private_data;
      int filenum = dirp->private_data.value;
      if ((size_t)filenum >= fs->nfiles) {
          /* End of stream */
          return 0;
      }
      const constfs_file_t *fp = &fs->files[filenum];
      if (fp->path == NULL) {
          return -EIO;
      }
      size_t len = strnlen(fp->path, VFS_NAME_MAX + 1);
      if (len > VFS_NAME_MAX) {
          /* name does not fit in vfs_dirent_t buffer */
          /* skipping past the broken entry */
          ++filenum;
          dirp->private_data.value = filenum;
          return -EAGAIN;
      }
      /* copy the string, including terminating null */
      memcpy(&entry->d_name[0], fp->path, len + 1);
      entry->d_ino = filenum;
      ++filenum;
      dirp->private_data.value = filenum;
      return 1;
  }
  
  static int constfs_closedir(vfs_DIR *dirp)
  {
      /* Just an example, it's not necessary to define closedir if there is
       * nothing to clean up */
      (void) dirp;
      return 0;
  }
  
  static void _constfs_write_stat(const constfs_file_t *fp, struct stat *restrict buf)
  {
      /* clear out the stat buffer first */
      memset(buf, 0, sizeof(*buf));
      buf->st_nlink = 1;
      buf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
      buf->st_size = fp->size;
      buf->st_blocks = fp->size;
      buf->st_blksize = sizeof(uint8_t);
  }