2 meinOS - A unix-like x86 microkernel operating system
3 Copyright (C) 2008 Janosch Gräf <janosch.graef@gmx.net>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <cdi/lists.h>
21 #include <llist.h> // for llist_find()
28 #include <sys/cdefs.h>
30 #include <sys/statvfs.h>
35 #define cdi_list_find(list,element) llist_find((llist_t)(list),(element))
37 #define CDI_FS_STREAM(filesystem,resource) { .fs = (filesystem), .res = (resource), .error = 0 }
39 #define CDI_FS_FIFOBUF_SIZE 4096
42 #define fs_is_reg(res) (res->file!=NULL)
43 #define fs_is_dir(res) (res->dir!=NULL)
44 #define fs_is_link(res) (res->link!=NULL)
45 #define fs_is_block(res) (res->special!=NULL && res->type==CDI_FS_BLOCK)
46 #define fs_is_char(res) (res->special!=NULL && res->type==CDI_FS_CHAR)
47 #define fs_is_fifo(res) (res->special!=NULL && res->type==CDI_FS_FIFO)
48 #define fs_is_sock(res) (res->special!=NULL && res->type==CDI_FS_SOCK)
51 struct cdi_fs_res
*res
;
54 FILE_REG
, // is also for devices
72 * @param driver FS driver
73 * @param fs_name Filesystem name
74 * @param mountpoint Mountpoint
75 * @param readonly If FS should be mounted readonly
78 static int cdi_fs_mount(struct cdi_fs_driver
*driver
,const char *fs_name
,const char *mountpoint
,const char *dev
,int readonly
) {
79 CDI_DEBUG("fs_mount(0x%x,%s,%s,%s,%d)\n",driver
,fs_name
,mountpoint
,dev
,readonly
);
80 int fsid
= rpc_call("vfs_regfs",0,fs_name
,mountpoint
);
82 struct cdi_fs_filesystem
*filesystem
= malloc(sizeof(struct cdi_fs_filesystem
));
83 filesystem
->driver
= driver
;
84 filesystem
->error
= 0;
85 filesystem
->read_only
= readonly
/*||(access(dev,W_OK)==-1)*/;
86 filesystem
->fsid
= fsid
;
87 filesystem
->last_fh
= 0;
88 filesystem
->files
= cdi_list_create();
89 filesystem
->mountpoint
= strdup(mountpoint
);
90 if (dev
!=NULL
) filesystem
->data_fh
= open(dev
,O_RDWR
);
91 else filesystem
->data_fh
= 0;
93 if (filesystem
->data_fh
!=-1) {
94 filesystem
->data_dev
= dev
;
95 if (driver
->fs_init(filesystem
)) {
96 cdi_list_push(driver
->filesystems
,filesystem
);
97 cdi_list_push(cdi_filesystems
,filesystem
);
102 cdi_list_destroy(filesystem
->files
);
103 close(filesystem
->data_fh
);
104 free((void*)(filesystem
->mountpoint
));
111 static int cdi_fs_mount_rpc(char *fs_name
,const char *mountpoint
,const char *dev
,int readonly
) {
112 CDI_DEBUG("fs_mount_rpc(%s,%s,%s,%d)\n",fs_name
,mountpoint
,dev
,readonly
);
114 struct cdi_fs_driver
*driver
;
115 if (!*dev
) dev
= NULL
;
116 for (i
=0;(driver
= cdi_list_get(cdi_drivers
,i
));i
++) {
117 if (strcmp(driver
->drv
.name
,fs_name
)==0) return cdi_fs_mount(driver
,fs_name
,mountpoint
,dev
,readonly
);
122 static int cdi_fs_unmount(struct cdi_fs_filesystem
*filesystem
) {
123 CDI_DEBUG("fs_unmount(0x%x)\n",filesystem
);
124 rpc_call("vfs_unregfs",0,filesystem
->fsid
);
125 return filesystem
->driver
->fs_destroy(filesystem
)?0:-1;
128 static int cdi_fs_unmount_rpc(char *fs_name
,char *mountpoint
) {
129 CDI_DEBUG("fs_unmount_rpc(%s)\n",fs_name
);
131 struct cdi_fs_driver
*driver
;
132 struct cdi_fs_filesystem
*filesystem
;
133 for (i
=0;(driver
= cdi_list_get(cdi_drivers
,i
));i
++) {
134 if (strcmp(driver
->drv
.name
,fs_name
)==0) {
135 for (j
=0;(filesystem
= cdi_list_get(driver
->filesystems
,j
));j
++) {
136 if (strcmp(filesystem
->mountpoint
,mountpoint
)==0) return cdi_fs_unmount(filesystem
);
148 static struct cdi_fs_filesystem
*cdi_fs_find(int fsid
) {
149 CDI_DEBUG("fs_find(%d)\n",fsid
);
151 struct cdi_fs_filesystem
*filesystem
;
152 for (i
=0;(filesystem
= cdi_list_get(cdi_filesystems
,i
));i
++) {
153 if (filesystem
->fsid
==fsid
) return filesystem
;
158 static struct cdi_fs_file
*cdi_fs_file_find(struct cdi_fs_filesystem
*filesystem
,int fh
) {
159 CDI_DEBUG("fs_file_find(0x%x,%d)\n",filesystem
,fh
);
161 struct cdi_fs_file
*file
;
162 for (i
=0;(file
= cdi_list_get(filesystem
->files
,i
));i
++) {
163 if (file
->fh
==fh
) return file
;
169 * Converts a CDI FS error number into a Clib errno
170 * @param error CDI FS error number
173 static int cdi_fs_error2errno(cdi_fs_error_t error
) {
174 if (error
==CDI_FS_ERROR_NONE
) return 0;
175 if (error
==CDI_FS_ERROR_IO
) return EIO
;
176 if (error
==CDI_FS_ERROR_ONS
) return ENOSYS
;
177 if (error
==CDI_FS_ERROR_RNF
) return ENOENT
;
178 if (error
==CDI_FS_ERROR_EOF
) return EOF
;
179 if (error
==CDI_FS_ERROR_RO
) return EROFS
;
180 if (error
==CDI_FS_ERROR_INTERNAL
) return -1;
181 if (error
==CDI_FS_ERROR_NOT_IMPLEMENTED
) return ENOTSUP
;
187 * @param res Resource
188 * @param stream Stream
190 static inline int cdi_fs_loadres(struct cdi_fs_stream
*stream
) {
191 CDI_DEBUG("fs_loadres(0x%x)\n",stream
);
192 return stream
->res
->loaded
?0:(stream
->res
->res
->load(stream
)?0:-1);
197 * @param res Resource
198 * @param stream Stream
200 static inline int cdi_fs_unloadres(struct cdi_fs_stream
*stream
) {
201 CDI_DEBUG("fs_unloadres(0x%x)\n",stream
);
202 /// @todo Zum Verringern von IO, aber wieder normal machen!
203 return stream
->res
->loaded
?(stream
->res
->res
->load(stream
)?0:-1):0;
207 * Gets parent CDI FS resource by path
208 * @param filesystem CDI filesystem
209 * @param path Path to resource
210 * @param filename Reference for filename (will point into path)
211 * @return Resource or NULL
213 static struct cdi_fs_res
*cdi_fs_parentres(struct cdi_fs_filesystem
*filesystem
,char *path_str
,char **filename
) {
214 CDI_DEBUG("fs_parentres(0x%x,%s)\n",filesystem
,path_str
);
215 struct cdi_fs_res
*res
= filesystem
->root_res
;
216 struct cdi_fs_res
*child
= res
;
219 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,res
);
221 path_t
*path
= path_parse(path_str
);
222 for (j
=path
->num_parts
-1;j
>=0 && path
->parts
[j
][0]==0;j
--);
224 if (path
->parts
[i
][0]==0) continue;
225 cdi_fs_loadres(&stream
);
226 for (k
=0;(child
= cdi_list_get(res
->children
,k
));k
++) {
227 if (strcmp(child
->name
,path
->parts
[i
])==0) {
233 if (child
==NULL
) break;
236 *filename
= path_str
;
237 if (j
<0) strcpy(*filename
,"/");
238 else strcpy(path_str
,path
->parts
[j
]);
244 * Gets CDI FS resource by path
245 * @param filesystem CDI filesystem
246 * @param path Path to resource
247 * @return Resource or NULL
249 static struct cdi_fs_res
*cdi_fs_path2res(struct cdi_fs_filesystem
*filesystem
,char *path_str
) {
250 CDI_DEBUG("fs_path2res(0x%x,%s)\n",filesystem
,path_str
);
251 struct cdi_fs_res
*res
= filesystem
->root_res
;
252 struct cdi_fs_res
*child
= res
;
254 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,res
);
256 path_t
*path
= path_parse(path_str
);
257 for (i
=0;i
<path
->num_parts
;i
++) {
258 if (path
->parts
[i
][0]==0) continue;
259 cdi_fs_loadres(&stream
);
260 for (k
=0;(child
= cdi_list_get(res
->children
,k
));k
++) {
261 if (strcmp(child
->name
,path
->parts
[i
])==0) {
267 if (child
==NULL
) break;
274 * Converts POSIX mode to class (and special file type)
275 * @param mode POSIX mode
276 * @param special Reference for special file type
277 * @return Resource class
279 static cdi_fs_res_class_t
cdi_fs_mode2class(mode_t mode
,cdi_fs_res_type_t
*special
) {
280 if (S_ISREG(mode
)) return CDI_FS_CLASS_FILE
;
281 if (S_ISDIR(mode
)) return CDI_FS_CLASS_DIR
;
282 if (S_ISLNK(mode
)) return CDI_FS_CLASS_LINK
;
284 *special
= CDI_FS_CHAR
;
285 return CDI_FS_CLASS_SPECIAL
;
288 *special
= CDI_FS_BLOCK
;
289 return CDI_FS_CLASS_SPECIAL
;
291 if (S_ISFIFO(mode
)) {
292 *special
= CDI_FS_FIFO
;
293 return CDI_FS_CLASS_SPECIAL
;
295 if (S_ISSOCK(mode
)) {
296 *special
= CDI_FS_SOCKET
;
297 return CDI_FS_CLASS_SPECIAL
;
299 return CDI_FS_CLASS_FILE
;
303 * Converts resource class (and special file type) to POSIX mode
304 * @param res Resource
307 static mode_t
cdi_fs_class2mode(struct cdi_fs_res
*res
) {
309 if (res
->file
!=NULL
) mode
|= S_IFREG
;
310 if (res
->dir
!=NULL
) mode
|= S_IFDIR
;
311 if (res
->link
!=NULL
) mode
|= S_IFLNK
;
312 if (res
->special
!=NULL
) {
313 if (res
->type
==CDI_FS_CHAR
) mode
|= S_IFCHR
;
314 else if (res
->type
==CDI_FS_BLOCK
) mode
|= S_IFBLK
;
315 else if (res
->type
==CDI_FS_FIFO
) mode
|= S_IFIFO
;
316 else if (res
->type
==CDI_FS_SOCKET
) mode
|= S_IFSOCK
;
322 * Gets filesize from a resource
323 * @param filesystem CDI Filesystem
324 * @param res Resource
327 static size_t cdi_fs_filesize(struct cdi_fs_filesystem
*filesystem
,struct cdi_fs_res
*res
) {
328 if (res
->res
->meta_read
!=NULL
) {
329 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,res
);
330 return res
->res
->meta_read(&stream
,CDI_FS_META_SIZE
);
335 // FIFO functions ///////
342 static void fs_fifo_open(struct cdi_fs_filesystem
*fs
,struct cdi_fs_file
*fifo
) {
345 fifo
->fifo
.buffer
= malloc(CDI_FS_FIFOBUF_SIZE
);
348 fifo
->type
= FILE_FIFO
;
349 fifo
->fifo
.list
= NULL
;
351 // find other filehandles of this FIFO
352 struct cdi_fs_file
*file
;
353 for (i
=0;(file
= cdi_list_get(fs
->files
,i
));i
++) {
354 if (file
->res
==fifo
->res
) {
355 fifo
->fifo
.list
= file
->fifo
.list
; // same FIFO, get FIFO list
360 if (fifo
->fifo
.list
==NULL
) fifo
->fifo
.list
= cdi_list_create(); // first opener of FIFO, create FIFO list
362 // add yourself to list
363 cdi_list_push(fifo
->fifo
.list
,fifo
);
371 static void fs_fifo_close(struct cdi_fs_filesystem
*fs
,struct cdi_fs_file
*fifo
) {
372 free(fifo
->fifo
.buffer
);
374 if (llist_size(fifo
->fifo
.list
)==1) cdi_list_destroy(fifo
->fifo
.list
); // I am the one and only, destroy list
375 else cdi_list_remove(fifo
->fifo
.list
,cdi_list_find(fifo
->fifo
.list
,fifo
)); // Else just remove yourself from list
382 * @param size How many bytes to read
383 * @return How many bytes read
385 static ssize_t
fs_fifo_read(struct cdi_fs_filesystem
*fs
,struct cdi_fs_file
*fifo
,size_t size
) {
386 if (size
==0) return 0;
388 // calculate free space in buffer
389 size_t size_free
= fifo
->fifo
.posw
>=fifo
->fifo
.posr
?fifo
->fifo
.posw
-fifo
->fifo
.posr
:fifo
->fifo
.posw
+CDI_FS_FIFOBUF_SIZE
-fifo
->fifo
.posr
;
391 // check if buffer is big enough
392 if (size
>size_free
) size
= size_free
;
393 if (size
==0) return 0;
395 // if isn't be wrapped around at end just copy
396 if (fifo
->fifo
.posr
<(fifo
->fifo
.posr
+size
)%CDI_FS_FIFOBUF_SIZE
) memcpy(fifo
->shmbuf
,fifo
->fifo
.buffer
+fifo
->fifo
.posr
,size
);
397 // else you have to do 2 copies
399 size_t part1
= CDI_FS_FIFOBUF_SIZE
-fifo
->fifo
.posr
;
400 size_t part2
= fifo
->fifo
.posw
;
401 memcpy(fifo
->shmbuf
,fifo
->fifo
.buffer
+fifo
->fifo
.posr
,part1
);
402 memcpy(fifo
->shmbuf
+part1
,fifo
->fifo
.buffer
,part2
);
404 fifo
->fifo
.posr
= (fifo
->fifo
.posr
+size
)%CDI_FS_FIFOBUF_SIZE
;
413 * @param size How many bytes to write
414 * @return How many bytes written
416 static ssize_t
fs_fifo_write(struct cdi_fs_filesystem
*fs
,struct cdi_fs_file
*fifo
,size_t size
) {
417 struct cdi_fs_file
*dstfifo
;
419 if (size
==0 || cdi_list_size(fifo
->fifo
.list
)==1) return 0;
421 // calculate minimum free space in buffers
423 size_t size_free
= ~0;
424 for (i
=0;(dstfifo
= cdi_list_get(fifo
->fifo
.list
,i
));i
++) {
426 size_t free
= fifo
->fifo
.posr
>fifo
->fifo
.posw
?fifo
->fifo
.posr
-fifo
->fifo
.posw
:fifo
->fifo
.posr
+CDI_FS_FIFOBUF_SIZE
-fifo
->fifo
.posw
;
427 if (free
<size_free
) size_free
= free
;
431 // check if buffer is big enough
432 if (size
>size_free
) size
= size_free
;
433 if (size
==0) return 0;
435 for (i
=0;(dstfifo
= cdi_list_get(fifo
->fifo
.list
,i
));i
++) {
437 // if isn't wrapped around at end just copy
438 if (dstfifo
->fifo
.posw
<(dstfifo
->fifo
.posr
+size
)%CDI_FS_FIFOBUF_SIZE
) memcpy(dstfifo
->fifo
.buffer
+dstfifo
->fifo
.posw
,fifo
->shmbuf
,size
);
439 // else you have to do 2 copies
441 size_t part1
= CDI_FS_FIFOBUF_SIZE
-dstfifo
->fifo
.posw
;
442 size_t part2
= dstfifo
->fifo
.posr
;
443 memcpy(dstfifo
->fifo
.buffer
+dstfifo
->fifo
.posw
,fifo
->shmbuf
,part1
);
444 memcpy(dstfifo
->fifo
.buffer
,fifo
->shmbuf
+part1
,part2
);
446 dstfifo
->fifo
.posw
= (dstfifo
->fifo
.posw
+size
)%CDI_FS_FIFOBUF_SIZE
;
453 // Wrapper functions ////
455 /// @todo add other filetypes?
456 static int fs_open(int fsid
,int oflag
,int shmid
) {
457 CDI_DEBUG("fs_open(%d,%d,%d)\n",fsid
,oflag
,shmid
);
458 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
459 if (filesystem
!=NULL
) {
460 void *shmbuf
= shmat(shmid
,NULL
,0);
462 struct cdi_fs_res
*res
= cdi_fs_path2res(filesystem
,shmbuf
);
464 if (fs_is_reg(res
) || fs_is_char(res
) || fs_is_block(res
) || fs_is_fifo(res
) || fs_is_link(res
)) {
465 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,res
);
466 if (cdi_fs_loadres(&stream
)==0) {
467 struct cdi_fs_file
*file
= malloc(sizeof(struct cdi_fs_file
));
469 file
->fh
= filesystem
->last_fh
++;
470 file
->shmbuf
= shmbuf
;
471 if (fs_is_reg(res
) || fs_is_char(res
) || fs_is_block(res
)) {
472 file
->type
= FILE_REG
;
473 file
->pos
= (oflag
&O_APPEND
)?cdi_fs_filesize(filesystem
,res
):0;
475 else if (fs_is_link(res
)) file
->type
= FILE_LINK
;
476 else if (fs_is_fifo(res
)) fs_fifo_open(filesystem
,file
);
477 cdi_list_push(filesystem
->files
,file
);
482 return -cdi_fs_error2errno(stream
.error
);
500 static int fs_close(int fsid
,int fh
) {
501 CDI_DEBUG("fs_close(%d,%d)\n",fsid
,fh
);
502 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
503 if (filesystem
!=NULL
) {
504 struct cdi_fs_file
*file
= cdi_fs_file_find(filesystem
,fh
);
506 if (file
->type
==FILE_REG
|| file
->type
==FILE_FIFO
) {
507 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,file
->res
);
508 if (file
->res
->res
->unload(&stream
)) {
509 if (file
->type
==FILE_FIFO
) fs_fifo_close(filesystem
,file
);
511 cdi_list_remove(filesystem
->files
,cdi_list_find(filesystem
->files
,file
));
524 static ssize_t
fs_read(int fsid
,int fh
,size_t count
) {
525 CDI_DEBUG("fs_read(%d,%d,%d)\n",fsid
,fh
,count
);
526 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
527 if (filesystem
!=NULL
) {
528 struct cdi_fs_file
*file
= cdi_fs_file_find(filesystem
,fh
);
530 if (file
->type
==FILE_REG
) {
531 if (file
->res
->file
->read
!=NULL
) {
532 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,file
->res
);
533 ssize_t ret
= file
->res
->file
->read(&stream
,file
->pos
,count
,file
->shmbuf
);
534 if (ret
>0) file
->pos
+= ret
;
535 return ret
>=0?ret
:-cdi_fs_error2errno(stream
.error
);
539 else if (file
->type
==FILE_FIFO
) return fs_fifo_read(filesystem
,file
,count
);
547 static ssize_t
fs_write(int fsid
,int fh
,size_t count
) {
548 CDI_DEBUG("fs_write(%d,%d,%d)\n",fsid
,fh
,count
);
550 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
551 if (filesystem
!=NULL
) {
552 struct cdi_fs_file
*file
= cdi_fs_file_find(filesystem
,fh
);
554 if (file
->type
==FILE_REG
) {
555 if (file
->res
->file
->write
!=NULL
) {
556 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,file
->res
);
557 ssize_t ret
= file
->res
->file
->write(&stream
,file
->pos
,count
,file
->shmbuf
);
558 if (ret
>0) file
->pos
+= ret
;
559 return ret
>=0?ret
:-cdi_fs_error2errno(stream
.error
);
563 else if (file
->type
==FILE_FIFO
) return fs_fifo_write(filesystem
,file
,count
);
571 static off_t
fs_seek(int fsid
,int fh
,off_t off
,int whence
) {
572 CDI_DEBUG("fs_seek(%d,%d,%d,%d)\n",fsid
,fh
,off
,whence
);
573 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
574 if (filesystem
!=NULL
) {
575 struct cdi_fs_file
*file
= cdi_fs_file_find(filesystem
,fh
);
577 if (file
->type
==FILE_REG
) {
578 if (whence
==SEEK_SET
) file
->pos
= off
;
579 else if (whence
==SEEK_CUR
) file
->pos
+= off
;
580 else if (whence
==SEEK_END
) file
->pos
= cdi_fs_filesize(filesystem
,file
->res
)+off
;
582 return (off_t
)file
->pos
;
591 static int fs_fstat(int fsid
,int fh
) {
592 CDI_DEBUG("fs_fstat(%d,%d)\n",fsid
,fh
);
593 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
594 if (filesystem
!=NULL
) {
595 struct cdi_fs_file
*file
= cdi_fs_file_find(filesystem
,fh
);
597 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,file
->res
);
598 struct stat
*stbuf
= file
->shmbuf
;
599 memset(stbuf
,0,sizeof(struct stat
));
600 //if (file->res->special!=NULL && file->res->special->dev_read!=NULL) file->res->special->dev_read(&stream,&(stbuf->st_rdev));
601 stbuf
->st_size
= file
->res
->res
->meta_read(&stream
,CDI_FS_META_SIZE
);
602 stbuf
->st_atime
= file
->res
->res
->meta_read(&stream
,CDI_FS_META_ACCESSTIME
);
603 stbuf
->st_mtime
= file
->res
->res
->meta_read(&stream
,CDI_FS_META_CHANGETIME
);
604 stbuf
->st_ctime
= file
->res
->res
->meta_read(&stream
,CDI_FS_META_CREATETIME
);
605 stbuf
->st_blksize
= file
->res
->res
->meta_read(&stream
,CDI_FS_META_BLOCKSZ
);
606 stbuf
->st_blocks
= file
->res
->res
->meta_read(&stream
,CDI_FS_META_USEDBLOCKS
);
608 stbuf
->st_mode
= cdi_fs_class2mode(file
->res
)|0755;
616 static int fs_unlink(int fsid
,char *path
) {
617 CDI_DEBUG("fs_unlink(%d,%s)\n",fsid
,path
);
618 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
619 if (filesystem
!=NULL
) {
620 struct cdi_fs_res
*res
= cdi_fs_path2res(filesystem
,path
);
622 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,res
);
623 //if (!cdi_list_empty(res->children)) return -ENOTEMPTY;
624 if (!(res
->file
!=NULL
?res
->res
->remove_class(&stream
,CDI_FS_CLASS_FILE
):1)) return -cdi_fs_error2errno(stream
.error
);
625 if (!(res
->dir
!=NULL
?res
->res
->remove_class(&stream
,CDI_FS_CLASS_DIR
):1)) return -cdi_fs_error2errno(stream
.error
);
626 if (!(res
->link
!=NULL
?res
->res
->remove_class(&stream
,CDI_FS_CLASS_LINK
):1)) return -cdi_fs_error2errno(stream
.error
);
627 if (!(res
->special
!=NULL
?res
->res
->remove_class(&stream
,CDI_FS_CLASS_SPECIAL
):1)) return -cdi_fs_error2errno(stream
.error
);
628 return res
->res
->remove(&stream
)?0:-cdi_fs_error2errno(stream
.error
);
635 static int fs_rmdir(int fsid
,char *path
) {
636 CDI_DEBUG("fs_rmdir(%d,%s)\n",fsid
,path
);
637 return fs_unlink(fsid
,path
);
640 static int fs_ftruncate(int fsid
,int fh
,off_t newsize
) {
641 CDI_DEBUG("fs_ftruncate(%d,%d,%d)\n",fsid
,fh
,newsize
);
642 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
643 if (filesystem
!=NULL
) {
644 struct cdi_fs_file
*file
= cdi_fs_file_find(filesystem
,fh
);
646 if (file
->res
->file
!=NULL
&& file
->type
==FILE_REG
) {
647 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,file
->res
);
648 return file
->res
->file
->truncate(&stream
,newsize
)?0:-cdi_fs_error2errno(stream
.error
);
657 static int fs_opendir(int fsid
,int shmid
) {
658 CDI_DEBUG("fs_opendir(%d,%d)\n",fsid
,shmid
);
659 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
660 if (filesystem
!=NULL
) {
661 void *shmbuf
= shmat(shmid
,NULL
,0);
663 struct cdi_fs_res
*res
= cdi_fs_path2res(filesystem
,shmbuf
);
665 if (fs_is_dir(res
)) {
666 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,res
);
667 if (cdi_fs_loadres(&stream
)==0) {
668 struct cdi_fs_file
*file
= malloc(sizeof(struct cdi_fs_file
));
670 file
->fh
= filesystem
->last_fh
++;
671 file
->type
= FILE_DIR
;
673 file
->shmbuf
= shmbuf
;
674 file
->dirlist
= NULL
;
675 cdi_list_push(filesystem
->files
,file
);
680 return -cdi_fs_error2errno(stream
.error
);
698 static int fs_readdir(int fsid
,int dh
) {
699 CDI_DEBUG("fs_readdir(%d,%d)\n",fsid
,dh
);
700 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
701 if (filesystem
!=NULL
) {
702 struct cdi_fs_file
*file
= cdi_fs_file_find(filesystem
,dh
);
704 if (file
->type
==FILE_DIR
) {
706 strcpy(file
->shmbuf
,file
->pos
++==0?".":"..");
710 if (file
->dirlist
==NULL
) {
711 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,file
->res
);
712 cdi_fs_loadres(&stream
);
713 if (file
->res
->dir
!=NULL
) file
->dirlist
= file
->res
->dir
->list(&stream
);
714 else return -ENOTDIR
;
716 struct cdi_fs_res
*child
= cdi_list_get(file
->dirlist
,(file
->pos
++)-2);
718 strcpy(file
->shmbuf
,child
->name
);
724 else return -ENOTDIR
;
731 static int fs_closedir(int fsid
,int dh
) {
732 CDI_DEBUG("fs_closedir(%d,%d)\n",fsid
,dh
);
733 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
734 if (filesystem
!=NULL
) {
735 struct cdi_fs_file
*file
= cdi_fs_file_find(filesystem
,dh
);
737 if (file
->type
==FILE_DIR
) {
739 cdi_list_remove(filesystem
->files
,cdi_list_find(filesystem
->files
,file
));
743 else return -ENOTDIR
;
750 static off_t
fs_seekdir(int fsid
,int dh
,off_t off
) {
751 CDI_DEBUG("fs_seekdir(%d,%d,%d)\n",fsid
,dh
,off
);
752 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
753 if (filesystem
!=NULL
) {
754 struct cdi_fs_file
*file
= cdi_fs_file_find(filesystem
,dh
);
756 if (file
->type
==FILE_DIR
) {
757 if (off
!=-1) file
->pos
= off
;
760 else return -ENOTDIR
;
767 static int fs_statvfs(int fsid
,int shmid
) {
768 CDI_DEBUG("fs_statvfs(%d,%d)\n",fsid
,shmid
);
769 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
770 if (filesystem
!=NULL
) {
771 struct statvfs
*stbuf
= shmat(shmid
,NULL
,0);
773 memset(stbuf
,0,sizeof(struct statvfs
));
783 static int fs_mknod(int fsid
,char *path
,mode_t mode
,dev_t dev
) {
784 CDI_DEBUG("fs_mknod(%d,%s,%d,%d)\n",fsid
,path
,mode
,dev
);
785 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
786 if (filesystem
!=NULL
) {
787 if (cdi_fs_path2res(filesystem
,path
)==NULL
) {
789 struct cdi_fs_res
*res
= cdi_fs_parentres(filesystem
,path
,&filename
);
791 if (res
->dir
!=NULL
) {
792 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,NULL
);
793 if (!res
->dir
->create_child(&stream
,filename
,res
)) return -cdi_fs_error2errno(stream
.error
);
794 if (cdi_fs_loadres(&stream
)==-1) return -cdi_fs_error2errno(stream
.error
);
795 stream
.res
->type
= 0;
796 if (!stream
.res
->res
->assign_class(&stream
,cdi_fs_mode2class(mode
,&(stream
.res
->type
)))) return -cdi_fs_error2errno(stream
.error
);
798 return cdi_fs_unloadres(&stream
)==0?0:-cdi_fs_error2errno(stream
.error
);
800 else return -ENOTDIR
;
809 static ssize_t
fs_readlink(int fsid
,int shmid
,size_t bufsize
) {
810 CDI_DEBUG("fs_readlink(%d,%d,%d)\n",fsid
,shmid
,bufsize
);
811 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
812 if (filesystem
!=NULL
) {
813 void *shmbuf
= shmat(shmid
,NULL
,0);
815 struct cdi_fs_res
*res
= cdi_fs_path2res(filesystem
,shmbuf
);
817 if (res
->link
!=NULL
) {
818 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,res
);
819 const char *link
= res
->link
->read_link(&stream
);
843 static ssize_t
fs_symlink(int fsid
,char *src
,char *dest
) {
844 CDI_DEBUG("fs_symlink(%d,%s,%s)\n",fsid
,src
,dest
);
845 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
846 if (filesystem
!=NULL
) {
848 struct cdi_fs_res
*res
= cdi_fs_parentres(filesystem
,src
,&filename
);
850 if (res
->dir
!=NULL
) {
851 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,NULL
);
852 if (!res
->dir
->create_child(&stream
,filename
,res
)) return -cdi_fs_error2errno(stream
.error
);
853 if (cdi_fs_loadres(&stream
)==-1) return -cdi_fs_error2errno(stream
.error
);
854 stream
.res
->type
= 0;
855 if (!stream
.res
->res
->assign_class(&stream
,CDI_FS_CLASS_LINK
)) return -cdi_fs_error2errno(stream
.error
);
857 if (!stream
.res
->link
->write_link(&stream
,dest
)) return -cdi_fs_error2errno(stream
.error
);
858 return cdi_fs_unloadres(&stream
)==0?0:-cdi_fs_error2errno(stream
.error
);
860 else return -ENOTDIR
;
867 static int fs_dup(int fsid
,int fh
,int shmid
) {
868 CDI_DEBUG("fs_dup(%d,%d,%d)\n",fsid
,fh
,shmid
);
869 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
870 if (filesystem
!=NULL
) {
871 struct cdi_fs_file
*file
= cdi_fs_file_find(filesystem
,fh
);
873 void *shmbuf
= shmat(shmid
,NULL
,0);
875 struct cdi_fs_file
*new = malloc(sizeof(struct cdi_fs_file
));
876 new->fh
= filesystem
->last_fh
++;
877 new->shmbuf
= shmbuf
;
887 static int fs_utime(int fsid
,int shmid
) {
888 CDI_DEBUG("fs_utime(%d,%d)\n",fsid
,shmid
);
889 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
890 if (filesystem
!=NULL
) {
891 void *shmbuf
= shmat(shmid
,NULL
,0);
893 struct cdi_fs_res
*res
= cdi_fs_path2res(filesystem
,shmbuf
);
895 struct utimbuf
*times
= shmbuf
+strlen(shmbuf
)+1;
896 struct cdi_fs_stream stream
= CDI_FS_STREAM(filesystem
,res
);
897 res
->res
->meta_write(&stream
,CDI_FS_META_ACCESSTIME
,times
->actime
);
898 res
->res
->meta_write(&stream
,CDI_FS_META_CHANGETIME
,times
->modtime
);
912 static int fs_sync(int fsid
) {
913 CDI_DEBUG("fs_sync(%d,%d)\n",fsid
,shmid
);
914 struct cdi_fs_filesystem
*filesystem
= cdi_fs_find(fsid
);
915 if (filesystem
!=NULL
) {
916 if (filesystem
->driver
->fs_sync
!=NULL
) {
917 return filesystem
->driver
->fs_sync(filesystem
)?0:-cdi_fs_error2errno(filesystem
->error
);
929 rpc_func(fs_open
,"iii",sizeof(int)*3);
930 rpc_func(fs_close
,"ii",sizeof(int)*2);
931 rpc_func(fs_read
,"iii",sizeof(int)*3);
932 rpc_func(fs_write
,"iii",sizeof(int)*3);
933 rpc_func(fs_seek
,"iiii",sizeof(int)*4);
934 rpc_func(fs_fstat
,"ii",sizeof(int)*2);
935 rpc_func(fs_unlink
,"i$",sizeof(int)+PATH_MAX
);
936 rpc_func(fs_rmdir
,"i$",sizeof(int)+PATH_MAX
);
937 //rpc_func(fs_rename,"i$$",sizeof(int)+PATH_MAX*2);
938 rpc_func(fs_ftruncate
,"iii",sizeof(int)*3);
939 rpc_func(fs_opendir
,"ii",sizeof(int)*2);
940 rpc_func(fs_readdir
,"ii",sizeof(int)*2);
941 rpc_func(fs_closedir
,"ii",sizeof(int)*2);
942 rpc_func(fs_seekdir
,"iii",sizeof(int)*3);
943 rpc_func(fs_statvfs
,"ii",sizeof(int));
944 rpc_func(fs_readlink
,"iii",sizeof(int)*3);
945 rpc_func(fs_symlink
,"i$$",sizeof(int)+PATH_MAX
*2);
946 //rpc_func(fs_link,"i$$",sizeof(int)+PATH_MAX*2);
947 rpc_func(fs_mknod
,"i$ii",sizeof(int)*3+PATH_MAX
);
948 rpc_func(fs_dup
,"iii",sizeof(int)*3);
949 /*rpc_func(fs_chown,"i$ii",sizeof(int)*3+PATH_MAX);
950 rpc_func(fs_chmod,"i$i",sizeof(int)*2+PATH_MAX);
951 rpc_func(fs_access,"i$i",sizeof(int)*2+PATH_MAX);*/
952 rpc_func(fs_utime
,"ii",sizeof(int)*2);
953 rpc_func(fs_sync
,"i",sizeof(int));
958 * Initializes FS driver
959 * @param driver FS driver
961 void cdi_fs_driver_init(struct cdi_fs_driver
* driver
) {
962 CDI_DEBUG("fs_driver_init(0x%x)\n",driver
);
963 cdi_driver_init((struct cdi_driver
*)driver
);
964 driver
->filesystems
= cdi_list_create();
969 * @param driver FS driver
971 void cdi_fs_driver_destroy(struct cdi_fs_driver
* driver
) {
972 CDI_DEBUG("fs_driver_destroy(0x%x)\n",driver
);
973 struct cdi_fs_filesystem
*filesystem
;
974 while ((filesystem
= cdi_list_pop(driver
->filesystems
))) driver
->fs_destroy(filesystem
);
975 cdi_list_destroy(driver
->filesystems
);
976 cdi_driver_destroy((struct cdi_driver
*)driver
);
980 * Registers FS driver
981 * @param driver FS driver
983 void cdi_fs_driver_register(struct cdi_fs_driver
* driver
) {
984 CDI_DEBUG("fs_driver_register(0x%x)\n",driver
);
985 cdi_driver_register((struct cdi_driver
*)driver
);
987 asprintf(&name
,"%s_mount",driver
->drv
.name
);
988 rpc_func_create(name
,cdi_fs_mount_rpc
,"$$$i",NAME_MAX
+PATH_MAX
+sizeof(int));
990 asprintf(&name
,"%s_unmount",driver
->drv
.name
);
991 rpc_func_create(name
,cdi_fs_unmount_rpc
,"$$",NAME_MAX
);
995 size_t cdi_fs_data_read(struct cdi_fs_filesystem
* fs
,uint64_t start
,size_t size
,void* buffer
) {
996 CDI_DEBUG("fs_data_read(0x%x,0x%x,0x%x,0x%x)\n",fs
,start
,size
,buffer
);
997 if (fs
->data_dev
!=NULL
) {
998 if (lseek(fs
->data_fh
,(off_t
)start
,SEEK_SET
)!=-1) return read(fs
->data_fh
,buffer
,size
);
1003 size_t cdi_fs_data_write(struct cdi_fs_filesystem
* fs
,uint64_t start
,size_t size
,const void* buffer
) {
1004 CDI_DEBUG("fs_data_write(0x%x,0x%x,0x%x,0x%x)\n",fs
,start
,size
,buffer
);
1005 if (fs
->data_dev
!=NULL
) {
1006 if (lseek(fs
->data_fh
,(off_t
)start
,SEEK_SET
)!=-1) return write(fs
->data_fh
,buffer
,size
);