2 Copyright (C) 2008 Mathias Gottschlag
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in the
6 Software without restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
8 Software, and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #include <ke/errors.h>
25 #include <ke/spinlock.h>
26 #include <fs/request.h>
31 struct file_system_driver
33 FsFileSystemDriver driver
;
34 struct cdi_fs_driver
*cdidriver
;
35 cdi_list_t filesystems
;
37 static cdi_list_t fsdrivers
= 0;
42 struct cdi_fs_filesystem cdifs
;
48 struct cdi_fs_res
*res
;
54 #define FILE_TYPE_FILE 0
55 #define FILE_TYPE_DIR 1
57 KeSpinlock request_lock
;
59 /*static void cdi_fs_check_filesystem_part(struct cdi_fs_filesystem *fs, struct cdi_fs_res *top, char *msg)
61 struct cdi_fs_res *res = top;
62 struct cdi_fs_stream stream;
66 // Loop through children
67 if (!stream.res->loaded) stream.res->res->load(&stream);
69 for (i = 0; i < cdi_list_size(res->children); i++)
71 struct cdi_fs_res *child = cdi_list_get(res->children, i);
72 if (child->name < 0xC0000000)
74 kePrint("%s Child of %s invalid: %x\n", msg, res->name, child->name);
77 cdi_fs_check_filesystem_part(fs, child, msg);
80 static void cdi_fs_check_filesystem(struct cdi_fs_filesystem *fs, char *msg)
82 cdi_fs_check_filesystem_part(fs, fs->root_res, msg);
85 static struct cdi_fs_res
*cdi_fs_get_file(struct cdi_fs_filesystem
*fs
, char *path
)
87 char *tmppath
= strdup(path
);
88 char *currentpath
= tmppath
;
89 struct cdi_fs_res
*res
= fs
->root_res
;
90 struct cdi_fs_stream stream
;
94 // Loop through parts of the path
97 char *nextpath
= strchr(currentpath
, '/');
103 if (!stream
.res
->loaded
) stream
.res
->res
->load(&stream
);
106 for (i
= 0; i
< cdi_list_size(res
->children
); i
++)
108 struct cdi_fs_res
*child
= cdi_list_get(res
->children
, i
);
109 if (!strcmp(currentpath
, child
->name
))
113 currentpath
= nextpath
;
118 if (!found
) return 0;
124 static int cdi_fs_open(struct FsFileSystem
*fs
, struct FsRequest
*request
)
126 struct cdi_fs_filesystem
*cdifs
= &((struct file_system
*)fs
)->cdifs
;
127 char *path
= strdup(request
->buffer
);
129 struct cdi_fs_res
*res
= 0;
130 struct cdi_fs_stream stream
;
135 // Get parent directory
136 if (strrchr(path
, '/'))
138 filename
= strrchr(path
, '/') + 1;
139 *strrchr(path
, '/') = 0;
140 res
= cdi_fs_get_file(cdifs
, path
);
151 res
= cdifs
->root_res
;
155 if (!stream
.res
->loaded
) stream
.res
->res
->load(&stream
);
156 if (strcmp(filename
, ""))
158 // Look for file in directory
161 for (i
= 0; i
< cdi_list_size(res
->children
); i
++)
163 struct cdi_fs_res
*child
= cdi_list_get(res
->children
, i
);
164 if (!strcmp(filename
, child
->name
))
168 if (!res
->loaded
) res
->res
->load(&stream
);
174 if (request
->flags
& FS_OPEN_CREATE
)
176 kePrint("Creating file %s.\n", filename
);
179 res
->dir
->create_child(&stream
, filename
, res
);
180 if (!stream
.res
->loaded
) stream
.res
->res
->load(&stream
);
181 stream
.res
->res
->assign_class(&stream
, CDI_FS_CLASS_FILE
);
186 kePrint("cdi_fs: File not found.\n");
192 // Fill file structure
193 struct file
*file
= malloc(sizeof(struct file
));
194 memset(file
, 0, sizeof(struct file
));
197 file
->type
= FILE_TYPE_DIR
;
199 file
->type
= FILE_TYPE_FILE
;
201 file
->mode
= request
->flags
;
202 cdifs
->files
= cdi_list_push(cdifs
->files
, file
);
204 request
->file
= &file
->file
;
207 static int cdi_fs_close(struct FsFileSystem
*fs
, struct FsRequest
*request
)
209 struct cdi_fs_filesystem
*cdifs
= &((struct file_system
*)fs
)->cdifs
;
212 for (i
= 0; i
< cdi_list_size(cdifs
->files
); i
++)
214 struct file
*file
= cdi_list_get(cdifs
->files
, i
);
215 if (&file
->file
== request
->file
)
217 // Close resource and delete file
218 struct cdi_fs_stream stream
;
219 stream
.res
= file
->res
;
222 // FIXME: The file might be opened twice, or there are children opened
223 //file->res->res->unload(&stream);
224 //if (file->dirlist) cdi_list_destroy(file->dirlist);
226 cdi_list_remove(cdifs
->files
, i
);
232 static int cdi_fs_mknod(struct FsFileSystem
*fs
, struct FsRequest
*request
)
234 struct cdi_fs_filesystem
*cdifs
= &((struct file_system
*)fs
)->cdifs
;
235 char *path
= strdup(request
->buffer
);
237 struct cdi_fs_res
*res
= 0;
238 struct cdi_fs_stream stream
;
243 // Get parent directory
244 if (strrchr(path
, '/'))
246 filename
= strrchr(path
, '/') + 1;
247 *strrchr(path
, '/') = 0;
248 res
= cdi_fs_get_file(cdifs
, path
);
259 res
= cdifs
->root_res
;
263 if (!stream
.res
->loaded
) stream
.res
->res
->load(&stream
);
264 if (strcmp(filename
, ""))
266 // Look for file in directory
269 for (i
= 0; i
< cdi_list_size(res
->children
); i
++)
271 struct cdi_fs_res
*child
= cdi_list_get(res
->children
, i
);
272 if (!strcmp(filename
, child
->name
))
279 kePrint("Creating file %s.\n", filename
);
282 res
->dir
->create_child(&stream
, filename
, res
);
283 if (!stream
.res
->loaded
) stream
.res
->res
->load(&stream
);
284 if (request
->flags
== FS_MKNOD_FILE
)
285 stream
.res
->res
->assign_class(&stream
, CDI_FS_CLASS_FILE
);
286 else if (request
->flags
== FS_MKNOD_DIR
)
287 stream
.res
->res
->assign_class(&stream
, CDI_FS_CLASS_DIR
);
296 static int cdi_fs_read(struct FsFileSystem
*fs
, struct FsRequest
*request
)
298 struct cdi_fs_filesystem
*cdifs
= &((struct file_system
*)fs
)->cdifs
;
299 struct file
*file
= (struct file
*)request
->file
;
300 if (file
->type
== FILE_TYPE_FILE
)
302 if (!(file
->mode
& FS_OPEN_READ
)) return -1;
303 // Read data from file
304 struct cdi_fs_stream stream
;
305 stream
.res
= file
->res
;
308 if (!file
->res
->file
->read
) return -1;
309 ssize_t ret
= file
->res
->file
->read(&stream
, request
->offset
,
310 request
->bufferlength
, request
->buffer
);
313 if ((stream
.error
== CDI_FS_ERROR_EOF
) || (stream
.error
== 0))
322 struct cdi_fs_stream stream
;
323 stream
.res
= file
->res
;
326 if (request
->bufferlength
< 1) return -1;
329 if (file
->res
->dir
== 0) return -1;
330 file
->dirlist
= file
->res
->dir
->list(&stream
);
332 if (request
->offset
< 2)
334 strncpy(request
->buffer
, request
->offset
?"..":".", request
->bufferlength
);
337 struct cdi_fs_res
*child
= cdi_list_get(file
->dirlist
, request
->offset
- 2);
340 strncpy(request
->buffer
, child
->name
, request
->bufferlength
);
346 static int cdi_fs_write(struct FsFileSystem
*fs
, struct FsRequest
*request
)
348 struct cdi_fs_filesystem
*cdifs
= &((struct file_system
*)fs
)->cdifs
;
349 struct file
*file
= (struct file
*)request
->file
;
350 if (file
->type
!= FILE_TYPE_FILE
) return -1;
351 if (!(file
->mode
& FS_OPEN_WRITE
)) return -1;
352 // Write data to file
353 struct cdi_fs_stream stream
;
354 stream
.res
= file
->res
;
357 if (!file
->res
->file
->write
) return -1;
358 ssize_t ret
= file
->res
->file
->write(&stream
, request
->offset
,
359 request
->bufferlength
, request
->buffer
);
366 static int cdi_fs_seek(struct FsFileSystem
*fs
, struct FsRequest
*request
)
368 struct cdi_fs_filesystem
*cdifs
= &((struct file_system
*)fs
)->cdifs
;
369 struct file
*file
= (struct file
*)request
->file
;
371 struct cdi_fs_stream stream
;
372 stream
.res
= file
->res
;
375 if (file
->type
== FILE_TYPE_FILE
)
377 int64_t size
= file
->res
->res
->meta_read(&stream
, CDI_FS_META_SIZE
);
378 // TODO: These casts to int are broken
379 switch (request
->whence
)
382 if ((int)request
->offset
> size
)
383 request
->offset
= size
;
384 if ((int)request
->offset
< 0)
388 if ((int)request
->offset
> size
)
389 request
->offset
= size
;
390 if ((int)request
->offset
< 0)
394 if ((int)request
->offset
> 0)
396 if ((int)request
->offset
< -size
)
397 request
->offset
= -size
;
398 request
->offset
= (int)request
->offset
+ size
;
407 int64_t size
= cdi_list_size(file
->dirlist
) + 2;
408 // TODO: These casts to int are broken
409 switch (request
->whence
)
412 if ((int)request
->offset
> size
)
413 request
->offset
= size
;
414 if ((int)request
->offset
< 0)
418 if ((int)request
->offset
> size
)
419 request
->offset
= size
;
420 if ((int)request
->offset
< 0)
424 if ((int)request
->offset
> 0)
426 if ((int)request
->offset
< -size
)
427 request
->offset
= -size
;
428 request
->offset
= (int)request
->offset
+ size
;
437 static int cdi_fs_unmount(struct FsFileSystem
*fs
)
440 return KE_ERROR_UNKNOWN
;
442 static int cdi_fs_request(struct FsFileSystem
*fs
, struct FsRequest
*request
)
444 if (!request
) return -1;
445 keLockSpinlock(&request_lock
);
446 switch (request
->type
)
448 case FS_REQUEST_OPEN
:
449 request
->return_value
= cdi_fs_open(fs
, request
);
450 keUnlockSpinlock(&request_lock
);
451 fsFinishRequest(request
);
453 case FS_REQUEST_CLOSE
:
454 request
->return_value
= cdi_fs_close(fs
, request
);
455 keUnlockSpinlock(&request_lock
);
456 fsFinishRequest(request
);
458 case FS_REQUEST_MKNOD
:
459 request
->return_value
= cdi_fs_mknod(fs
, request
);
460 keUnlockSpinlock(&request_lock
);
461 fsFinishRequest(request
);
463 case FS_REQUEST_READ
:
464 request
->return_value
= cdi_fs_read(fs
, request
);
465 keUnlockSpinlock(&request_lock
);
466 fsFinishRequest(request
);
468 case FS_REQUEST_WRITE
:
469 request
->return_value
= cdi_fs_write(fs
, request
);
470 keUnlockSpinlock(&request_lock
);
471 fsFinishRequest(request
);
473 case FS_REQUEST_SEEK
:
474 request
->return_value
= cdi_fs_seek(fs
, request
);
475 keUnlockSpinlock(&request_lock
);
476 fsFinishRequest(request
);
479 keUnlockSpinlock(&request_lock
);
480 return KE_ERROR_UNKNOWN
;
484 static FsFileSystem
*cdi_fs_mount(FsFileSystemDriver
*driver
, const char *path
,
485 const char *device
, uint32_t flags
)
487 struct file_system_driver
*fsdrv
= (struct file_system_driver
*)driver
;
488 // Create file system
489 struct file_system
*fs
= malloc(sizeof(struct file_system
));
490 memset(fs
, 0, sizeof(struct file_system
));
491 fs
->cdifs
.driver
= fsdrv
->cdidriver
;
492 fs
->cdifs
.files
= cdi_list_create();
493 fs
->fs
.path
= strdup(path
);
494 fs
->fs
.unmount
= cdi_fs_unmount
;
495 fs
->fs
.query_request
= cdi_fs_request
;
496 if (device
&& strcmp(device
, ""))
498 // Open source device
499 fs
->fs
.device
= fsOpen(device
, 0);
506 fs
->cdifs
.data
= fs
->fs
.device
;
508 // Initialize file system
509 if (fsdrv
->cdidriver
->fs_init(&fs
->cdifs
))
511 fsdrv
->filesystems
= cdi_list_push(fsdrv
->filesystems
, fs
);
522 void cdi_fs_driver_init(struct cdi_fs_driver
*driver
)
524 cdi_driver_init(&driver
->drv
);
526 void cdi_fs_driver_destroy(struct cdi_fs_driver
*driver
)
528 cdi_driver_destroy(&driver
->drv
);
530 void cdi_fs_driver_register(struct cdi_fs_driver
*driver
)
532 cdi_driver_register(&driver
->drv
);
533 kePrint("File system: %s\n", driver
->drv
.name
);
534 struct file_system_driver
*fsdrv
= malloc(sizeof(struct file_system_driver
));
535 memset(fsdrv
, 0, sizeof(struct file_system_driver
));
536 fsdrv
->cdidriver
= driver
;
537 fsdrv
->driver
.mount
= cdi_fs_mount
;
538 fsdrv
->filesystems
= cdi_list_create();
539 if (!fsdrivers
) fsdrivers
= cdi_list_create();
540 fsdrivers
= cdi_list_push(fsdrivers
, driver
);
541 fsRegisterDriver(&fsdrv
->driver
, driver
->drv
.name
);
545 size_t cdi_fs_data_read(struct cdi_fs_filesystem
*fs
, uint64_t start
,
546 size_t size
, void *buffer
)
548 if (!fs
->data
) return 0;
549 fsSeek(fs
->data
, start
, 0);
550 int read
= fsRead(fs
->data
, buffer
, size
, 1);
554 size_t cdi_fs_data_write(struct cdi_fs_filesystem
* fs
, uint64_t start
,
555 size_t size
, const void* buffer
)
557 if (!fs
->data
) return 0;
558 fsSeek(fs
->data
, start
, 0);
559 int written
= fsWrite(fs
->data
, (void*)buffer
, size
);