IBNOS
filesystem.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, Michael Müller
3  * Copyright (c) 2014, Sebastian Lackner
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  */
27 
28 #include <process/filesystem.h>
29 #include <process/object.h>
30 #include <memory/allocator.h>
31 #include <console/console.h>
32 #include <util/list.h>
33 #include <util/util.h>
34 
42 
43 static void __directoryDestroy(struct object *obj);
44 static void __directoryShutdown(struct object *obj, UNUSED uint32_t mode);
45 static int32_t __directoryWrite(struct object *obj, uint8_t *buf, uint32_t length);
46 static int32_t __directoryRead(struct object *obj, uint8_t *buf, uint32_t length);
47 
48 static const struct objectFunctions directoryFunctions =
49 {
50  __directoryDestroy,
51  NULL, /* getMinHandle */
52  __directoryShutdown,
53  NULL, /* getStatus */
54  NULL, /* wait */
55  NULL, /* signal */
56  __directoryWrite,
57  __directoryRead,
58  NULL, /* insert */
59  NULL, /* remove */
60 };
61 
62 static void __fileDestroy(struct object *obj);
63 static void __fileShutdown(struct object *obj, UNUSED uint32_t mode);
64 static int32_t __fileGetStatus(struct object *obj, UNUSED uint32_t mode);
65 static int32_t __fileWrite(struct object *obj, uint8_t *buf, uint32_t length);
66 static int32_t __fileRead(struct object *obj, uint8_t *buf, uint32_t length);
67 
68 static const struct objectFunctions fileFunctions =
69 {
70  __fileDestroy,
71  NULL, /* getMinHandle */
72  __fileShutdown,
73  __fileGetStatus,
74  NULL, /* wait */
75  NULL, /* signal */
76  __fileWrite,
77  __fileRead,
78  NULL, /* insert */
79  NULL, /* remove */
80 };
81 
82 static void __openedDirectoryDestroy(struct object *obj);
83 static int32_t __openedDirectoryRead(struct object *obj, uint8_t *buf, uint32_t length);
84 
85 static const struct objectFunctions openedDirectoryFunctions =
86 {
87  __openedDirectoryDestroy,
88  NULL, /* getMinHandle */
89  NULL, /* shutdown */
90  NULL, /* getStatus */
91  NULL, /* wait */
92  NULL, /* signal */
93  NULL, /* write */
94  __openedDirectoryRead,
95  NULL, /* insert */
96  NULL, /* remove */
97 };
98 
99 static void __openedFileDestroy(struct object *obj);
100 static void __openedFileShutdown(struct object *obj, UNUSED uint32_t mode);
101 static int32_t __openedFileGetStatus(struct object *obj, uint32_t mode);
102 static void __openedFileSignal(struct object *obj, uint32_t result);
103 static int32_t __openedFileWrite(struct object *obj, uint8_t *buf, uint32_t length);
104 static int32_t __openedFileRead(struct object *obj, uint8_t *buf, uint32_t length);
105 
106 static const struct objectFunctions openedFileFunctions =
107 {
108  __openedFileDestroy,
109  NULL, /* getMinHandle */
110  __openedFileShutdown,
111  __openedFileGetStatus,
112  NULL, /* wait */
113  __openedFileSignal,
114  __openedFileWrite,
115  __openedFileRead,
116  NULL, /* insert */
117  NULL, /* remove */
118 };
119 
120 static inline void __directoryShutdownChilds(struct directory *directory)
121 {
122  struct file *f, *__f;
123  struct directory *d, *__d;
124 
125  LL_FOR_EACH_SAFE(f, __f, &directory->files, struct file, obj.entry)
126  {
127  objectShutdown(f, 0);
128  }
129 
130  LL_FOR_EACH_SAFE(d, __d, &directory->directories, struct directory, obj.entry)
131  {
132  objectShutdown(d, 0);
133  }
134 }
135 
136 static inline bool __isValidFilename(struct object *current, struct directory *parent, const char *buf, uint32_t length)
137 {
138  struct file *cur_f;
139  struct directory *cur_d;
140 
141  /* reserved names cannot be a filename */
142  if (stringIsEqual(".", (char *)buf, length) || stringIsEqual("..", (char *)buf, length))
143  return false;
144 
145  if (!parent)
146  return true;
147 
148  /* check collision with other filenames */
149  LL_FOR_EACH(cur_f, &parent->files, struct file, obj.entry)
150  {
151  if (&cur_f->obj != current && stringIsEqual(cur_f->name, (char *)buf, length))
152  return false;
153  }
154 
155  /* check collision with directory names */
156  LL_FOR_EACH(cur_d, &parent->directories, struct directory, obj.entry)
157  {
158  if (&cur_d->obj != current && stringIsEqual(cur_d->name, (char *)buf, length))
159  return false;
160  }
161 
162  return true;
163 }
164 
174 struct directory *directoryCreate(struct directory *parent, char *name, uint32_t nameLength)
175 {
176  struct directory *d;
177  char *buffer = NULL;
178 
179  /* allocate some new memory */
180  if (!(d = heapAlloc(sizeof(*d))))
181  return NULL;
182 
183  /* copy the name */
184  if (name)
185  {
186  if (!(buffer = heapAlloc(nameLength + 1)))
187  {
188  heapFree(d);
189  return NULL;
190  }
191  memcpy(buffer, name, nameLength);
192  buffer[nameLength] = 0;
193  }
194 
195  /* initialize general object info */
196  __objectInit(&d->obj, &directoryFunctions);
197  d->parent = parent;
198  d->name = buffer;
199  ll_init(&d->openedDirectories);
200 
201  ll_init(&d->files);
202  ll_init(&d->directories);
203 
204  if (parent)
205  {
206  ll_add_tail(&parent->directories, &d->obj.entry);
207  objectAddRef(d);
208  }
209 
210  return d;
211 }
212 
218 static void __directoryDestroy(struct object *obj)
219 {
220  struct directory *d = objectContainer(obj, struct directory, &directoryFunctions);
221 
222  /* at this point there shouldn't be any parent directory anymore */
223  assert(!d->parent);
224 
225  /* delete child elements (if any) */
226  __directoryShutdownChilds(d);
227  assert(ll_empty(&d->files) && ll_empty(&d->directories));
228 
229  /* free the memory containing the name */
230  if (d->name) heapFree(d->name);
231 
232  /* release directory memory */
233  d->obj.functions = NULL;
234  heapFree(d);
235 }
236 
243 static void __directoryShutdown(struct object *obj, UNUSED uint32_t mode)
244 {
245  struct directory *d = objectContainer(obj, struct directory, &directoryFunctions);
246 
247  if (d->parent)
248  {
249  /* unlink from the parent directory */
250  ll_remove(&d->obj.entry);
251  d->parent = NULL;
252 
253  /* release object */
254  objectRelease(d);
255  }
256 }
257 
266 static int32_t __directoryWrite(struct object *obj, uint8_t *buf, uint32_t length)
267 {
268  struct directory *d = objectContainer(obj, struct directory, &directoryFunctions);
269 
270  /* get rid of nullterminating character at the end of the filename */
271  while (length > 0 && !buf[length - 1]) length--;
272 
273  if (length && !__isValidFilename(&d->obj, d->parent, (char *)buf, length))
274  return -1;
275 
276  /* deallocate the old name */
277  if (d->name)
278  heapFree(d->name);
279 
280  /* if there is no new name */
281  if (!length)
282  {
283  d->name = NULL;
284  return 0;
285  }
286 
287  /* allocate new memory for the name */
288  d->name = heapAlloc(length + 1);
289  if (!d->name) return 0;
290 
291  memcpy(d->name, buf, length);
292  d->name[length] = 0;
293  return length;
294 }
295 
306 static int32_t __directoryRead(struct object *obj, uint8_t *buf, uint32_t length)
307 {
308  struct directory *d = objectContainer(obj, struct directory, &directoryFunctions);
309  uint32_t file_length;
310  if (!d->name) return -1;
311 
312  file_length = stringLength(d->name) + 1;
313 
314  /* limit the number of characters to the string length + 1 */
315  if (length > file_length)
316  length = file_length;
317 
318  memcpy(buf, d->name, length);
319  return length;
320 }
321 
333 struct file *fileCreate(struct directory *parent, char *name, uint32_t nameLength, uint8_t *staticBuffer, uint32_t staticSize)
334 {
335  struct file *f;
336  char *buffer = NULL;
337 
338  /* allocate some new memory */
339  if (!(f = heapAlloc(sizeof(*f))))
340  return NULL;
341 
342  /* copy the name */
343  if (name)
344  {
345  if (!(buffer = heapAlloc(nameLength + 1)))
346  {
347  heapFree(f);
348  return NULL;
349  }
350  memcpy(buffer, name, nameLength);
351  buffer[nameLength] = 0;
352  }
353 
354  /* initialize general object info */
355  __objectInit(&f->obj, &fileFunctions);
356  f->parent = parent;
357  f->name = buffer;
358  ll_init(&f->openedFiles);
359 
360  if (staticBuffer)
361  {
362  f->isHeap = false;
363  f->buffer = staticBuffer;
364  f->size = staticSize;
365  }
366  else
367  {
368  f->isHeap = true;
369  f->buffer = NULL;
370  f->size = 0;
371  }
372 
373  /* add this element to the directory */
374  if (parent)
375  {
376  ll_add_tail(&parent->files, &f->obj.entry);
377  objectAddRef(f);
378  }
379 
380  return f;
381 }
382 
388 static void __fileDestroy(struct object *obj)
389 {
390  struct file *f = objectContainer(obj, struct file, &fileFunctions);
391 
392  /* at this point there shouldn't be any parent directory anymore */
393  assert(!f->parent);
394 
395  /* free the memory containing the name */
396  if (f->name) heapFree(f->name);
397 
398  /* release heap memory */
399  if (f->isHeap && f->buffer)
400  heapFree(f->buffer);
401 
402  /* release file memory */
403  f->obj.functions = NULL;
404  heapFree(f);
405 }
406 
413 static void __fileShutdown(struct object *obj, UNUSED uint32_t mode)
414 {
415  struct file *f = objectContainer(obj, struct file, &fileFunctions);
416 
417  if (f->parent)
418  {
419  /* unlink from the parent directory */
420  ll_remove(&f->obj.entry);
421  f->parent = NULL;
422 
423  /* release object */
424  objectRelease(f);
425  }
426 }
427 
436 static int32_t __fileGetStatus(struct object *obj, UNUSED uint32_t mode)
437 {
438  struct file *f = objectContainer(obj, struct file, &fileFunctions);
439  return f->size;
440 }
441 
450 static int32_t __fileWrite(struct object *obj, uint8_t *buf, uint32_t length)
451 {
452  struct file *f = objectContainer(obj, struct file, &fileFunctions);
453 
454  /* get rid of nullterminating character at the end of the filename */
455  while (length > 0 && !buf[length - 1]) length--;
456 
457  if (length && !__isValidFilename(&f->obj, f->parent, (char *)buf, length))
458  return -1;
459 
460  /* deallocate the old name */
461  if (f->name)
462  heapFree(f->name);
463 
464  /* if there is no new name */
465  if (!length)
466  {
467  f->name = NULL;
468  return 0;
469  }
470 
471  /* allocate new memory for the name */
472  f->name = heapAlloc(length + 1);
473  if (!f->name) return 0;
474 
475  memcpy(f->name, buf, length);
476  f->name[length] = 0;
477  return length;
478 }
479 
490 static int32_t __fileRead(struct object *obj, uint8_t *buf, uint32_t length)
491 {
492  struct file *f = objectContainer(obj, struct file, &fileFunctions);
493  uint32_t file_length;
494  if (!f->name) return -1;
495 
496  file_length = stringLength(f->name) + 1;
497 
498  /* limit the number of characters to the string length + 1 */
499  if (length > file_length)
500  length = file_length;
501 
502  memcpy(buf, f->name, length);
503  return length;
504 }
505 
513 struct openedFile *fileOpen(struct file *file)
514 {
515  struct openedFile *h;
516  assert(file);
517 
518  /* allocate some new memory */
519  if (!(h = heapAlloc(sizeof(*h))))
520  return NULL;
521 
522  /* initialize general object info */
523  __objectInit(&h->obj, &openedFileFunctions);
524  h->file = file;
525  h->pos = 0;
526 
527  /* add this element to the file */
528  ll_add_tail(&file->openedFiles, &h->obj.entry);
529  objectAddRef(file);
530 
531  return h;
532 }
533 
539 static void __openedFileDestroy(struct object *obj)
540 {
541  struct openedFile *h = objectContainer(obj, struct openedFile, &openedFileFunctions);
542  struct file *file = h->file;
543  assert(file);
544 
545  /* unlink from the file */
546  ll_remove(&h->obj.entry);
547 
548  /* release file memory */
549  h->obj.functions = NULL;
550  heapFree(h);
551 
552  /* decrement the refcount of the parent object */
553  objectRelease(file);
554 }
555 
562 static void __openedFileShutdown(struct object *obj, UNUSED uint32_t mode)
563 {
564  struct openedFile *h = objectContainer(obj, struct openedFile, &openedFileFunctions);
565  struct file *f = h->file;
566 
567  /* only truncating supported so far */
568  if (h->pos < f->size)
569  {
570  /* realloc buffer */
571  if (f->isHeap && f->buffer)
572  {
573  uint8_t *new_buffer = heapReAlloc(f->buffer, h->pos);
574  if (new_buffer || !h->pos) f->buffer = new_buffer;
575  }
576 
577  /* define new size */
578  f->size = h->pos;
579  }
580 }
581 
591 static int32_t __openedFileGetStatus(struct object *obj, uint32_t mode)
592 {
593  struct openedFile *h = objectContainer(obj, struct openedFile, &openedFileFunctions);
594  return mode ? h->pos : h->file->size;
595 }
596 
603 static void __openedFileSignal(struct object *obj, uint32_t result)
604 {
605  struct openedFile *h = objectContainer(obj, struct openedFile, &openedFileFunctions);
606  h->pos = result;
607 }
608 
618 static int32_t __openedFileWrite(struct object *obj, uint8_t *buf, uint32_t length)
619 {
620  struct openedFile *h = objectContainer(obj, struct openedFile, &openedFileFunctions);
621  struct file *f = h->file;
622  if (length == 0) return 0;
623 
624  /* reallocate file memory */
625  if (h->pos + length > f->size)
626  {
627  uint8_t *new_buffer;
628 
629  if (!f->isHeap || !f->buffer)
630  new_buffer = heapAlloc(h->pos + length);
631  else
632  new_buffer = heapReAlloc(f->buffer, h->pos + length);
633 
634  if (new_buffer)
635  {
636  /* copy buffer */
637  if (!f->isHeap && f->buffer)
638  memcpy(new_buffer, f->buffer, f->size);
639 
640  /* clear unused buffer space */
641  if (h->pos > f->size)
642  memset(new_buffer + f->size, 0, h->pos - f->size);
643 
644  f->isHeap = true;
645  f->buffer = new_buffer;
646  f->size = h->pos + length;
647  }
648  else if (f->isHeap && h->pos < f->size)
649  {
650  assert(f->size - h->pos < length);
651  length = f->size - h->pos;
652  }
653  else return 0; /* no bytes left */
654  }
655 
656  /* copy bytes to the buffer */
657  memcpy(f->buffer + h->pos, buf, length);
658  h->pos += length;
659 
660  return length;
661 }
662 
672 static int32_t __openedFileRead(struct object *obj, uint8_t *buf, uint32_t length)
673 {
674  struct openedFile *h = objectContainer(obj, struct openedFile, &openedFileFunctions);
675  struct file *f = h->file;
676  if (h->pos >= f->size) return -1;
677 
678  /* don't read beyond the end of the file */
679  if (length > f->size - h->pos)
680  length = f->size - h->pos;
681 
682  /* copy bytes to the output */
683  if (length > 0)
684  {
685  memcpy(buf, f->buffer + h->pos, length);
686  h->pos += length;
687  }
688 
689  return length;
690 }
691 
700 {
701  struct openedDirectory *h;
702  assert(directory);
703 
704  /* allocate some new memory */
705  if (!(h = heapAlloc(sizeof(*h))))
706  return NULL;
707 
708  /* initialize general object info */
709  __objectInit(&h->obj, &openedDirectoryFunctions);
710  h->directory = directory;
711  h->pos = NULL;
712 
713  /* add this element to the directory */
714  ll_add_tail(&directory->openedDirectories, &h->obj.entry);
715  objectAddRef(directory);
716 
717  return h;
718 }
719 
725 static void __openedDirectoryDestroy(struct object *obj)
726 {
727  struct openedDirectory *h = objectContainer(obj, struct openedDirectory, &openedDirectoryFunctions);
728  struct directory *directory = h->directory;
729  assert(directory);
730 
731  /* unlink from the directory */
732  ll_remove(&h->obj.entry);
733 
734  /* release current object pointer */
735  if (h->pos)
736  __objectRelease(h->pos);
737 
738  /* release directory memory */
739  h->obj.functions = NULL;
740  heapFree(h);
741 
742  /* decrement the refcount of the parent object */
743  objectRelease(directory);
744 }
745 
754 static int32_t __openedDirectoryRead(struct object *obj, uint8_t *buf, uint32_t length)
755 {
756  struct openedDirectory *h = objectContainer(obj, struct openedDirectory, &openedDirectoryFunctions);
757  struct directory *directory = h->directory;
758 
759  struct file *f;
760  struct directory *d;
761 
762  const char *name;
763  uint32_t name_length;
764 
765  if (!h->pos || h->pos->functions == &fileFunctions)
766  {
767  if (!h->pos)
768  f = LL_ENTRY(directory->files.next, struct file, obj.entry);
769  else
770  {
771  f = objectContainer(h->pos, struct file, &fileFunctions);
772  f = LL_ENTRY(f->obj.entry.next, struct file, obj.entry);
773  }
774 
775  while (&f->obj.entry != &directory->files && !f->name)
776  f = LL_ENTRY(f->obj.entry.next, struct file, obj.entry);
777 
778  if (&f->obj.entry == &directory->files)
779  {
780  d = LL_ENTRY(directory->directories.next, struct directory, obj.entry);
781  goto enumdir;
782  }
783 
784  h->pos = &f->obj;
785  name = f->name;
786  }
787  else if (h->pos->functions == &directoryFunctions)
788  {
789  d = objectContainer(h->pos, struct directory, &directoryFunctions);
790  d = LL_ENTRY(d->obj.entry.next, struct directory, obj.entry);
791 enumdir:
792  while (&d->obj.entry != &directory->directories && !d->name)
793  d = LL_ENTRY(d->obj.entry.next, struct directory, obj.entry);
794 
795  if (&d->obj.entry == &directory->directories)
796  {
797  h->pos = NULL;
798  return -1;
799  }
800 
801  h->pos = &d->obj;
802  name = d->name;
803  }
804  else assert(0); /* should never happen */
805 
806  /* output name */
807  name_length = stringLength(name) + 1;
808 
809  /* limit the number of characters to the string length + 1 */
810  if (length > name_length)
811  length = name_length;
812 
813  memcpy(buf, name, length);
814  return length;
815 }
816 
817 static inline bool __tarVerifyChecksum(struct tarHeader *tar)
818 {
819  int8_t *buf = (int8_t *)tar;
820  uint32_t i, cksum = 0;
821 
822  for (i = 0; i < 148; i++)
823  cksum += buf[i];
824 
825  /* checksum filled with spaces */
826  for (i = 0; i < 8; i++)
827  cksum += ' ';
828 
829  for (i = 156; i < 512; i++)
830  cksum += buf[i];
831 
832  return (cksum == stringParseOctal(tar->checksum, sizeof(tar->checksum)));
833 }
834 
835 static inline bool __tarIsEOF(struct tarHeader *tar, uint32_t length)
836 {
837  uint8_t *buf = (uint8_t *)tar;
838 
839  if (length < sizeof(struct tarHeader)*2)
840  return false;
841 
842  length = sizeof(struct tarHeader)*2;
843 
844  while (length)
845  {
846  if (*buf)
847  return false;
848  buf++;
849  length--;
850  }
851 
852  return true;
853 }
854 
858 void fileSystemInit(void *addr, uint32_t length)
859 {
860  struct tarHeader *tar;
861 
862  assert(!fileSystemRoot);
863 
864  fileSystemRoot = directoryCreate(NULL, NULL, 0);
865  assert(fileSystemRoot);
866 
867  /* tar header should fit exactly in one block */
868  assert(sizeof(struct tarHeader) == 512);
869 
870  /* initialize default layout */
871  tar = (struct tarHeader *)addr;
872  while (length >= sizeof(struct tarHeader))
873  {
874  uint32_t size;
875  struct file *f;
876  char *name, namebuf[100+1+155+1];
877 
878  /* detect eof */
879  if (__tarIsEOF(tar, length))
880  break;
881 
882  /* ensure tar header is valid */
883  assert(__tarVerifyChecksum(tar));
884  size = stringParseOctal(tar->size, sizeof(tar->size));
885  assert(size != (uint32_t)-1);
886  assert(sizeof(struct tarHeader) + size <= length);
887  name = namebuf;
888 
889  /* prepend with prefix */
890  if (stringIsEqual("ustar", tar->magic, sizeof(tar->magic)) && tar->prefix[0])
891  {
892  uint32_t prefixlen;
893  tar->prefix[sizeof(tar->prefix) - 1] = 0;
894  prefixlen = stringLength(tar->prefix);
895  memcpy(name, tar->prefix, prefixlen);
896  name += prefixlen;
897  *name++ = '/';
898  }
899 
900  /* afterwards add the name and a null to terminate the string */
901  memcpy(name, tar->name, sizeof(tar->name));
902  name += sizeof(tar->name);
903  *name = 0;
904 
905  if (!tar->typeflag || tar->typeflag == TAR_TYPE_FILE)
906  {
907  f = fileSystemSearchFile(0, namebuf, stringLength(namebuf), true);
908  assert(f);
909 
910  f->isHeap = false;
911  f->buffer = (uint8_t *)(tar + 1);;
912  f->size = size;
913  objectRelease(f);
914  }
915 
916  /* round up to next 512 byte boundary */
917  size = sizeof(struct tarHeader) + ((size + 511) & ~511);
918  if (size > length)
919  break;
920  tar = (struct tarHeader *)((uint8_t *)tar + size);
921  length -= size;
922  }
923 }
924 
934 struct directory *fileSystemIsValidDirectory(struct object *obj)
935 {
936  if (!obj) return NULL;
937 
938  if (obj->functions == &openedDirectoryFunctions)
939  {
940  struct openedDirectory *h = objectContainer(obj, struct openedDirectory, &openedDirectoryFunctions);
941  if (!h->pos || h->pos->functions != &directoryFunctions) return NULL;
942  return objectContainer(h->pos, struct directory, &directoryFunctions);
943  }
944 
945  if (obj->functions == &directoryFunctions)
946  return objectContainer(obj, struct directory, &directoryFunctions);
947 
948  return NULL;
949 }
950 
960 struct file *fileSystemIsValidFile(struct object *obj)
961 {
962  if (!obj) return NULL;
963 
964  if (obj->functions == &openedDirectoryFunctions)
965  {
966  struct openedDirectory *h = objectContainer(obj, struct openedDirectory, &openedDirectoryFunctions);
967  if (!h->pos || h->pos->functions != &fileFunctions) return NULL;
968  return objectContainer(h->pos, struct file, &fileFunctions);
969  }
970 
971  if (obj->functions == &fileFunctions)
972  return objectContainer(obj, struct file, &fileFunctions);
973 
974  return NULL;
975 }
976 
986 {
987  /* return reference to the root file system */
988  objectAddRef(fileSystemRoot);
989  return fileSystemRoot;
990 }
991 
1004 struct directory *fileSystemSearchDirectory(struct directory *directory, char *path, uint32_t pathLength, bool create)
1005 {
1006  struct file *f;
1007  struct directory *d;
1008  uint32_t componentLength;
1009 
1010  if (!directory)
1011  directory = fileSystemRoot;
1012 
1013 subdir:
1014  assert(directory);
1015 
1016  /* skip over leading slashes */
1017  while (pathLength > 0 && path[0] == '/')
1018  {
1019  pathLength--;
1020  path++;
1021  }
1022 
1023  /* search for the path delimiter */
1024  componentLength = 0;
1025  while (componentLength < pathLength && path[componentLength] != '/') componentLength++;
1026 
1027  /* if the path is empty then return the current directory */
1028  if (!componentLength)
1029  {
1030  objectAddRef(directory);
1031  return directory;
1032  }
1033 
1034  /* handle special cases */
1035  if (stringIsEqual(".", path, componentLength) || stringIsEqual("..", path, componentLength))
1036  {
1037  path += componentLength;
1038  pathLength -= componentLength;
1039 
1040  /* go to the parent directory (if any) */
1041  if (stringIsEqual("..", path, componentLength) && directory->parent)
1042  directory = directory->parent;
1043 
1044  goto subdir;
1045  }
1046 
1047  /* search for subdirectory */
1048  LL_FOR_EACH(d, &directory->directories, struct directory, obj.entry)
1049  {
1050  if (stringIsEqual(d->name, path, componentLength))
1051  {
1052  path += componentLength;
1053  pathLength -= componentLength;
1054  directory = d;
1055  goto subdir;
1056  }
1057  }
1058 
1059  /* if we don't want to create it we can return immediately */
1060  if (!create) return NULL;
1061 
1062  /* ensure name is not used by a file */
1063  LL_FOR_EACH(f, &directory->files, struct file, obj.entry)
1064  {
1065  if (stringIsEqual(f->name, path, componentLength))
1066  return NULL;
1067  }
1068 
1069  /* create a new directory (empty) */
1070  d = directoryCreate(directory, path, componentLength);
1071  if (!d) return NULL;
1072 
1073  path += componentLength;
1074  pathLength -= componentLength;
1075  directory = d;
1076  goto subdir;
1077 }
1078 
1079 
1092 struct file *fileSystemSearchFile(struct directory *directory, char *path, uint32_t pathLength, bool create)
1093 {
1094  struct file *f;
1095  struct directory *d;
1096  uint32_t componentLength;
1097 
1098  componentLength = pathLength;
1099  while (componentLength > 0 && path[componentLength-1] != '/') componentLength--;
1100 
1101  /* no filename specified */
1102  if (componentLength >= pathLength)
1103  return NULL;
1104 
1105  d = fileSystemSearchDirectory(directory, path, componentLength, create);
1106  if (!d) return NULL;
1107 
1108  path += componentLength;
1109  pathLength -= componentLength;
1110  directory = d;
1111 
1112  /* reserved names cannot be a filename */
1113  if (stringIsEqual(".", path, pathLength) || stringIsEqual("..", path, pathLength))
1114  goto err;
1115 
1116  /* search for the file */
1117  LL_FOR_EACH(f, &directory->files, struct file, obj.entry)
1118  {
1119  if (stringIsEqual(f->name, path, pathLength))
1120  {
1121  objectAddRef(f);
1122  objectRelease(directory);
1123  return f;
1124  }
1125  }
1126 
1127  /* if we don't want to create it we can return immediately */
1128  if (!create) goto err;
1129 
1130  /* ensure the name is not used by a directory */
1131  LL_FOR_EACH(d, &directory->directories, struct directory, obj.entry)
1132  {
1133  if (stringIsEqual(d->name, path, pathLength))
1134  goto err;
1135  }
1136 
1137  /* create a new file and return the reference */
1138  f = fileCreate(directory, path, pathLength, NULL, 0);
1139  objectRelease(directory);
1140  return f;
1141 
1142 err:
1143  objectRelease(directory);
1144  return NULL;
1145 }
1146 
uint32_t size
Definition: filesystem.h:65
struct file * fileCreate(struct directory *parent, char *name, uint32_t nameLength, uint8_t *staticBuffer, uint32_t staticSize)
Creates a new kernel file object.
Definition: filesystem.c:333
#define TAR_TYPE_FILE
Definition: filesystem.h:105
struct object * pos
Definition: filesystem.h:73
uint8_t * buffer
Definition: filesystem.h:64
struct directory * fileSystemIsValidDirectory(struct object *obj)
Checks if a given object is of the type directory and casts it if possible.
Definition: filesystem.c:934
struct openedDirectory * directoryOpen(struct directory *directory)
Creates a new kernel openedDirectory object.
Definition: filesystem.c:699
void * heapReAlloc(void *addr, uint32_t length)
Resizes a block of kernel memory.
Definition: allocator.c:439
const struct objectFunctions * functions
Definition: object.h:72
void * heapAlloc(uint32_t length)
Allocates a block of kernel memory.
Definition: allocator.c:363
struct openedFile * fileOpen(struct file *file)
Creates a new kernel openedFile object.
Definition: filesystem.c:513
#define assert(ex)
Definition: util.h:61
struct file * fileSystemIsValidFile(struct object *obj)
Checks if a given object is of the type file and casts it if possible.
Definition: filesystem.c:960
uint32_t pos
Definition: filesystem.h:81
#define UNUSED
Definition: util.h:39
void * memset(void *ptr, int value, size_t num)
Fills a memory region with some specific byte value.
Definition: util.c:123
#define objectShutdown(p, a)
Definition: object.h:111
uint32_t stringLength(const char *str)
Returns the length of a nullterminated string.
Definition: util.c:37
void heapFree(void *addr)
Deallocates a block of kernel memory.
Definition: allocator.c:385
char size[12]
Definition: filesystem.h:68
struct directory * parent
Definition: filesystem.h:46
#define LL_ENTRY(element, type, field)
Definition: list.h:127
char * name
Definition: filesystem.h:59
struct object obj
Definition: filesystem.h:70
char prefix[155]
Definition: filesystem.h:101
struct linkedList directories
Definition: filesystem.h:52
char name[100]
Definition: filesystem.h:86
char magic[6]
Definition: filesystem.h:95
struct linkedList openedFiles
Definition: filesystem.h:61
char * name
Definition: filesystem.h:47
void fileSystemInit(void *addr, uint32_t length)
Initializes the root file system.
Definition: filesystem.c:858
struct directory * fileSystemSearchDirectory(struct directory *directory, char *path, uint32_t pathLength, bool create)
Opens or creates a directory.
Definition: filesystem.c:1004
struct object obj
Definition: filesystem.h:78
struct file * file
Definition: filesystem.h:79
struct linkedList * next
Definition: list.h:36
#define objectAddRef(p)
Definition: object.h:89
#define objectContainer(p, type, functions)
Definition: object.h:66
struct object obj
Definition: filesystem.h:57
struct linkedList entry
Definition: object.h:73
#define ll_add_tail
Definition: list.h:100
void * memcpy(void *destination, const void *source, size_t num)
Copies a block of memory from source to destination.
Definition: util.c:141
char checksum[8]
Definition: filesystem.h:92
struct linkedList openedDirectories
Definition: filesystem.h:49
struct directory * directory
Definition: filesystem.h:71
struct directory * directoryCreate(struct directory *parent, char *name, uint32_t nameLength)
Creates a new kernel directory object.
Definition: filesystem.c:174
uint32_t stringParseOctal(const char *str, uint32_t len)
Converts an octal string to a integer number.
Definition: util.c:84
char size[12]
Definition: filesystem.h:90
struct linkedList files
Definition: filesystem.h:51
char name[100]
Definition: filesystem.h:64
struct directory * parent
Definition: filesystem.h:58
#define objectRelease(p)
Definition: object.h:97
struct directory * fileSystemGetRoot()
Returns a reference to the root node of the file system.
Definition: filesystem.c:985
struct directory * fileSystemRoot
Definition: filesystem.c:41
bool stringIsEqual(const char *str, const char *buf, uint32_t len)
Checks if the string is equal to the memory region.
Definition: util.c:57
#define LL_FOR_EACH_SAFE(element, next_element, list, type, field)
Allows to iterate a linkedList similar to a for-loop (safe when deleting elements).
Definition: list.h:148
bool isHeap
Definition: filesystem.h:63
struct object obj
Definition: filesystem.h:45
struct file * fileSystemSearchFile(struct directory *directory, char *path, uint32_t pathLength, bool create)
Opens or creates a file.
Definition: filesystem.c:1092
char mode[8]
Definition: filesystem.h:65
#define LL_FOR_EACH(element, list, type, field)
Allows to iterate a linkedList similar to a for-loop.
Definition: list.h:138
char typeflag
Definition: filesystem.h:93