Made file data buffer larger (2*PAGE_SIZE); stdlibc: fixed getcwd()
[meinos.git] / apps / lib / stdlibc / files.c
blobc622c87b38281d97cc626855375934bc07af560e
1 /*
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/>.
19 #include <sys/types.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <llist.h>
23 #include <errno.h>
24 #include <stdarg.h>
25 #include <rpc.h>
26 #include <sys/ipc.h>
27 #include <sys/shm.h>
28 #include <limits.h>
29 #include <stdio.h>
30 #include <path.h>
31 #include <misc.h>
33 #include <fcntl.h> // open,close
34 #include <unistd.h> // read,write,seek,truncate
35 #include <dirent.h> // *dir
36 #include <sys/stat.h> // stat
37 #include <sys/statvfs.h> // statvfs
38 #include <utime.h> // utime
40 #include <sys/socket.h> // Socket stuff
42 #define getnew_fh() (lastfh++)
43 #define filebyfh(fh) llist_get(filelist,lidxbyfh(fh))
45 #define SHMMEM_SIZE (2*PAGE_SIZE)
47 struct fslist_item {
48 pid_t pid;
49 id_t id;
50 path_t *mountpoint;
51 char *mountpoint_str;
54 struct filelist_item {
55 struct fslist_item *fs;
56 int fs_fh;
57 struct dirent dir_cur;
58 mode_t mode;
59 int oflag;
60 int fh;
61 char *path;
62 int shmid;
63 void *shmbuf;
64 enum { FL_FILE,FL_DIR,FL_PIPE,FL_SOCK } type;
65 /// @todo Check for right file types (e.g. in read()/write()) and set them in open()/opendir()/socket()
68 static llist_t filelist;
69 static llist_t fslist;
70 static int lastfh;
71 static struct {
72 char *str;
73 size_t strlen;
74 path_t *path;
75 } workdir;
76 static mode_t creation_mask;
77 struct process_data *_process_data;
79 static int _open_unnamed_pipe(int fh,int shmid);
81 /**
82 * Initializes File I/O
84 void _fs_init() {
85 filelist = llist_create();
86 fslist = llist_create();
87 lastfh = 3;
88 creation_mask = 0777;
90 // Init current workdir
91 char *path = getenv("PATH");
92 if (path==NULL) path = "/";
93 memset(&workdir,0,sizeof(workdir));
94 chdir(path);
96 // Create stdin, stdout, stderr
97 _open_unnamed_pipe(STDIN_FILENO,_process_data->shmid_stdin);
98 _open_unnamed_pipe(STDOUT_FILENO,_process_data->shmid_stdout);
99 _open_unnamed_pipe(STDERR_FILENO,_process_data->shmid_stderr);
103 * Match mountpoint
104 * @param file Path to file
105 * @param parent If FS of parent directory of file is needed
106 * @return FS List item
108 static struct fslist_item *mp_match(char *file,int parent) {
109 size_t i,curcmp;
110 size_t maxcmp = 0;
111 struct fslist_item *fs;
112 struct fslist_item *maxfs = NULL;
113 path_t *path = path_parse(file);
115 if (parent) path_parent(path);
117 for (i=0;(fs = llist_get(fslist,i));i++) {
118 curcmp = path_compare(path,fs->mountpoint);
119 if (curcmp>maxcmp) {
120 maxcmp = curcmp;
121 maxfs = fs;
125 if (maxfs!=NULL) memmove(file,file+strlen(maxfs->mountpoint_str),strlen(file)-strlen(maxfs->mountpoint_str)+1);
126 if (file[0]==0) strcpy(file,"/");
128 return maxfs;
132 * Gets FSID and PID by path and cuts path to relative path for FS
133 * @param path Path to file
134 * @param parent If FS of parent directory of file is needed
135 * @return FSID
137 static struct fslist_item *fsbypath(char *path,int parent) {
138 struct fslist_item *fs = mp_match(path,parent);
139 if (fs==NULL) {
140 fs = malloc(sizeof(struct fslist_item));
141 char *mountpoint = strdup(path);
142 fs->id = rpc_call("vfs_getfsid",2,path,parent);
143 if (fs->id<0) {
144 free(mountpoint);
145 errno = -fs->id;
146 return NULL;
148 mountpoint[strlen(mountpoint)-strlen(path)] = 0;
149 fs->mountpoint = path_parse(mountpoint);
150 fs->mountpoint_str = path_output(fs->mountpoint,NULL);
151 free(mountpoint);
152 fs->pid = rpc_call("vfs_getpid",0,fs->id);
153 if (fs->pid<0) {
154 errno = -fs->pid;
155 return NULL;
157 llist_push(fslist,fs);
160 return fs;
164 * Gets list index by filehandle
165 * @param fh filehandle
166 * @return List index
168 static int lidxbyfh(int fh) {
169 struct filelist_item *file;
170 int i;
171 for (i=0;(file = llist_get(filelist,i));i++) {
172 if (file->fh==fh) return i;
174 return -1;
178 * Gets absolute path by relative path
179 * @param relative Relative or absolute path
180 * @return Absolute path (Can be passed to free())
182 static char *getabsolutepath(const char *relative) {
183 path_t *path = path_parse(relative);
184 if (!path->root) {
185 path_t *newpath = path_cat(workdir.path,path);
186 path_destroy(path);
187 path = newpath;
189 path_reject_dots(path);
190 return path_output(path,NULL);
194 * Creates an unnamed pipe
195 * @param read Whether creator is reader
196 * @return Filehandle
198 int _create_unnamed_pipe(int read,int *_shmid) {
199 int shmid = shmget(IPC_PRIVATE,SHMMEM_SIZE,0);
200 if (shmid!=-1) {
201 size_t *shmbuf = shmat(shmid,NULL,0);
202 if (shmbuf!=NULL) {
203 struct filelist_item *new = malloc(sizeof(struct filelist_item));
204 memset(new,0,sizeof(struct filelist_item));
205 new->fh = getnew_fh();
206 new->oflag = read?O_RDONLY:O_WRONLY;
207 new->shmid = shmid;
208 new->shmbuf = shmbuf;
209 shmbuf[0] = read; // Direction
210 shmbuf[1] = 0; // Reserved for error
211 shmbuf[2] = 0; // Reading position
212 shmbuf[3] = 0; // Writing position
213 llist_push(filelist,new);
214 if (_shmid!=NULL) *_shmid = shmid;
215 return new->fh;
217 else shmctl(shmid,IPC_RMID,NULL);
219 return -1;
223 * Destroys an unnamed pipe
224 * @param fh Filehandle of unnamed pipe
225 * @return Success?
227 int _destroy_unnamed_pipe(int fh) {
228 struct filelist_item *file = filebyfh(fh);
230 if (file && file->fs==NULL) {
231 shmdt(file->shmbuf);
232 shmctl(file->shmid,IPC_RMID,NULL);
233 llist_remove(filelist,lidxbyfh(fh));
234 free(file);
235 return 0;
237 else errno = EBADF;
238 return -1;
242 * Opens an unnamed pipe
243 * @param fh Use this filehandle (-1 no specified filehandle)
244 * @param shmid SHM object the unnamed pipe uses
245 * @note If you specify the filehandle, be sure that it isn't used already
246 * @return Filehandle
248 static int _open_unnamed_pipe(int fh,int shmid) {
249 size_t *shmbuf = shmat(shmid,NULL,0);
250 if (shmbuf!=NULL) {
251 if (fh==-1) fh = getnew_fh();
252 struct filelist_item *new = malloc(sizeof(struct filelist_item));
253 memset(new,0,sizeof(struct filelist_item));
254 new->fh = fh;
255 new->oflag = shmbuf[0]?O_WRONLY:O_RDONLY;
256 new->shmid = shmid;
257 new->shmbuf = shmbuf;
258 llist_push(filelist,new);
259 return fh;
261 else return -1;
265 * Destroys an unnamed pipe
266 * @param fh Filehandle of unnamed pipe
267 * @return Success?
269 static int _close_unnamed_pipe(int fh) {
270 struct filelist_item *file = filebyfh(fh);
272 if (file && file->fs==NULL) {
273 shmdt(file->shmbuf);
274 llist_remove(filelist,lidxbyfh(fh));
275 free(file);
276 return 0;
278 else errno = EBADF;
279 return -1;
283 * Reads an unnamed pipe
284 * @param fh Filehandle
285 * @param data Data buffer
286 * @param size How many bytes to read
287 * @return How many bytes read
289 static size_t _read_unnamed_pipe(int fh,void *data,size_t size) {
290 struct filelist_item *file = filebyfh(fh);
291 ssize_t size_read = -1;
293 if (file && file->fs==NULL && file->oflag==O_RDONLY) {
294 size_t *pos_read = file->shmbuf+2*sizeof(size_t);
295 size_t *pos_write = file->shmbuf+3*sizeof(size_t);
296 void *buffer = file->shmbuf+4*sizeof(size_t);
297 size_t size_free = *pos_write>=*pos_read?*pos_write-*pos_read:*pos_write+SHMMEM_SIZE-4*sizeof(int)-*pos_read;
299 if (size>size_free) size = size_free;
300 if (*pos_write>=*pos_read) memcpy(data,buffer,size);
301 else {
302 size_t part1 = SHMMEM_SIZE-4*sizeof(int)-*pos_read;
303 size_t part2 = *pos_write;
304 memcpy(data,buffer+*pos_read,part1);
305 memcpy(data+part1,buffer,part2);
307 *pos_read = (*pos_read+size)%(SHMMEM_SIZE-4*sizeof(int));
309 size_read = size;
311 else errno = EBADF;
312 return size_read;
316 * Writes an unnamed pipe
317 * @param fh Filehandle
318 * @param data Data buffer
319 * @param size How many bytes to write
320 * @return How many bytes written
322 static size_t _write_unnamed_pipe(int fh,const void *data,size_t size) {
323 struct filelist_item *file = filebyfh(fh);
324 ssize_t size_written = -1;
326 if (file && file->fs==NULL && file->oflag==O_WRONLY) {
327 size_t *pos_read = file->shmbuf+2*sizeof(size_t);
328 size_t *pos_write = file->shmbuf+3*sizeof(size_t);
329 void *buffer = file->shmbuf+4*sizeof(size_t);
330 size_t size_free = *pos_read>*pos_write?*pos_read-*pos_write:*pos_read+SHMMEM_SIZE-4*sizeof(int)-*pos_write;
332 if (size>size_free) size = size_free;
333 if (*pos_read>=*pos_write) memcpy(buffer,data,size);
334 else {
335 size_t part1 = SHMMEM_SIZE-4*sizeof(int)-*pos_write;
336 size_t part2 = *pos_read;
337 memcpy(buffer+*pos_write,data,part1);
338 memcpy(buffer,data+part1,part2);
340 *pos_write = (*pos_write+size)%(SHMMEM_SIZE-4*sizeof(int));
342 size_written = size;
344 else errno = EBADF;
345 return size_written;
349 * Gets current workdir
350 * @param buf Buffer to store path in
351 * @param size Size of buffer
352 * @return Current workdir
354 char *getcwd(char *buf,size_t size) {
355 if (buf==NULL) {
356 size = workdir.strlen+1;
357 buf = malloc(size);
359 else if (size==0) {
360 errno = EINVAL;
361 return NULL;
363 else if (workdir.strlen+1>size) {
364 errno = ERANGE;
365 return NULL;
367 return strncpy(buf,workdir.str,size);
371 * Change current workdir
372 * @param new New workdir
373 * @return 0=success; -1=failure
375 int chdir(const char *new) {
376 new = getabsolutepath((char*)new);
377 if (new==NULL) new = "/";
379 /*DIR *dir = opendir(new);
380 if (dir!=NULL) {
381 closedir(dir);*/
382 free(workdir.str);
383 path_destroy(workdir.path);
384 workdir.path = path_parse(new);
385 path_reject_dots(workdir.path);
386 workdir.str = path_output(workdir.path,NULL);
387 workdir.strlen = strlen(workdir.str);
388 setenv("PATH",workdir.str,1);
389 return 0;
391 //else return -1;
395 * Change current workdir
396 * @param new Filedescriptor of new workdir
397 * @return 0=success; -1=failure
399 int fchdir(int fildes) {
400 int res;
401 struct filelist_item *file = filebyfh(fildes);
402 if (file!=NULL) res = chdir(file->path);
403 else res = -EBADF;
404 errno = res<0?-res:0;
405 return res<0?-1:res;
409 * Creates a new node
410 * @param path Path to new node
411 * @param mode Mode of new node
412 * @param dev DeviceID (not used)
413 * @return 0=success; -1=failure
415 int mknod(const char *path,mode_t mode,dev_t dev) {
416 int res;
417 char *cpath = getabsolutepath((char*)path);
418 struct fslist_item *fs = fsbypath(cpath,1);
419 char *func;
421 if (fs!=NULL) {
422 asprintf(&func,"fs_mknod_%x",fs->pid);
423 res = rpc_call(func,0,fs->id,cpath,mode&(~creation_mask),dev);
424 free(func);
426 else res = -EINVAL;
427 free(cpath);
428 errno = res<0?-res:0;
429 return res<0?-1:res;
433 * Checks whether file can be opened with mode
434 * @param path Path to file
435 * @param amode Mode
436 * @return 0=success; -1=failure
438 int access(const char *path,int amode) {
439 int res;
440 char *cpath = getabsolutepath((char*)path);
441 struct fslist_item *fs = fsbypath(cpath,0);
442 char *func;
444 if (fs!=NULL) {
445 asprintf(&func,"fs_access_%x",fs->pid);
446 res = rpc_call(func,0,fs->id,cpath,amode);
447 free(func);
449 else res = -EINVAL;
450 free(cpath);
451 errno = res<0?-res:0;
452 return res<0?-1:res;
456 * Opens a file
457 * @param path Path to file
458 * @param oflag Mode
460 int open(const char *path,int oflag,...) {
461 va_list args;
462 int fh = 0;
463 void *shmbuf;
464 char *func;
465 char *cpath = getabsolutepath(path);
466 struct fslist_item *fs = fsbypath(cpath,0);
467 if (fs==NULL) fh = -errno;
469 va_start(args,oflag);
471 if (fh==0) {
472 if (oflag&O_CREAT) {
473 oflag &= ~O_CREAT;
474 int res = mknod(path,va_arg(args,mode_t)|S_IFREG,0);
475 if (res==-1 && errno!=EEXIST) fh = -errno;
477 int shmid = shmget(IPC_PRIVATE,SHMMEM_SIZE,0);
478 shmbuf = shmat(shmid,NULL,0);
479 if (shmbuf!=NULL) {
480 strncpy(shmbuf,cpath,SHMMEM_SIZE);
481 asprintf(&func,"fs_open_%x",fs->pid);
482 fh = rpc_call(func,0,fs->id,oflag,shmid);
483 free(func);
484 if (fh>=0) {
485 struct filelist_item *new = malloc(sizeof(struct filelist_item));
486 new->fs_fh = fh;
487 new->fs = fs;
488 new->oflag = oflag;
489 new->mode = S_IFREG;
490 new->fh = getnew_fh();
491 new->path = strdup(cpath);
492 new->shmid = shmid;
493 new->shmbuf = shmbuf;
494 fh = new->fh;
495 llist_push(filelist,new);
499 va_end(args);
500 free(cpath);
501 errno = fh<0?-fh:0;
502 return fh<0?-1:fh;
506 * Closes all filehandles
508 void _close_all_filehandles() {
509 struct filelist_item *file;
510 while ((file = llist_pop(filelist))!=NULL) {
511 if (S_ISREG(file->mode)) close(file->fh);
512 else if (S_ISDIR(file->mode)) closedir(file);
515 // close stdin, stdout and stderr
516 _destroy_unnamed_pipe(STDIN_FILENO);
517 _destroy_unnamed_pipe(STDOUT_FILENO);
518 _destroy_unnamed_pipe(STDERR_FILENO);
523 * Closes a file
524 * @param fildes File descriptor
525 * @return 0=success; -1=failure
527 int close(int fildes) {
528 int res;
529 char *func;
530 struct filelist_item *file = filebyfh(fildes);
531 if (file->fs==NULL) return _close_unnamed_pipe(fildes);
532 if (file) {
533 asprintf(&func,"fs_close_%x",file->fs->pid);
534 res = rpc_call(func,0,file->fs->id,file->fs_fh);
535 free(func);
536 if (res==0) {
537 shmdt(file->shmbuf);
538 shmctl(file->shmid,IPC_RMID,NULL);
539 llist_remove(filelist,lidxbyfh(fildes));
540 free(file->path);
541 free(file);
544 else res = -EBADF;
545 errno = res<0?-res:0;
546 return res<0?-1:res;
547 return -1;
551 * Duplicates a file descriptor
552 * @param fildes File descriptor
553 * @param fildes2 New file descriptor
554 * @return New file desciptor
556 int dup2(int fildes,int fildes2) {
557 int res = -1;
558 char *func;
559 struct filelist_item *file = filebyfh(fildes);
560 if (file) {
561 asprintf(&func,"fs_close_%x",file->fs->pid);
562 res = rpc_call(func,0,file->fs->id,file->fs_fh);
563 free(func);
564 if (res>=0) {
565 struct filelist_item *new = malloc(sizeof(struct filelist_item));
566 memcpy(new,file,sizeof(struct filelist_item));
567 if (fildes2==0) new->fh = getnew_fh();
568 else {
569 close(fildes2);
570 new->fh = fildes2;
572 new->fs_fh = res;
573 new->shmid = shmget(IPC_PRIVATE,SHMMEM_SIZE,0);
574 new->shmbuf = shmat(new->shmid,NULL,0);
575 llist_push(filelist,new);
578 else errno = EBADF;
579 return res;
583 * Reads from a file
584 * @param fildes File descriptor
585 * @param buf Buffer to store read data in
586 * @param count How many bytes to read
587 * @return How many bytes read
589 static ssize_t _read(struct filelist_item *file,void *buf,size_t count) {
590 ssize_t res;
591 char *func;
592 asprintf(&func,"fs_read_%x",file->fs->pid);
593 res = rpc_call(func,0,file->fs->id,file->fs_fh,count);
594 free(func);
595 if (res>0) memcpy(buf,file->shmbuf,res);
596 return res;
598 ssize_t read(int fildes,void *buf,size_t count) {
599 struct filelist_item *file = filebyfh(fildes);
600 if (file->fs==NULL) return _read_unnamed_pipe(fildes,buf,count);
601 else if (file!=NULL) {
602 ssize_t count_rem = count;
603 size_t off = 0;
605 while (count_rem>0) {
606 size_t count_cur = count_rem;
607 if (count_cur>SHMMEM_SIZE) count_cur = SHMMEM_SIZE;
608 count_cur = _read(file,buf+off,count_cur);
609 if (count_cur==-1) return -1;
610 count_rem -= count_cur;
611 if (count_cur==0) break;
612 off += count_cur;
615 return count-count_rem;
617 else {
618 errno = EBADF;
619 return -1;
624 * Writes to a file
625 * @param fildes File descriptor
626 * @param buf Data to write to file
627 * @param count How many bytes to write
628 * @return How many bytes written
630 static ssize_t _write(struct filelist_item *file,const void *buf,size_t count) {
631 char *func;
632 ssize_t res;
633 memcpy(file->shmbuf,buf,count);
634 asprintf(&func,"fs_write_%x",file->fs->pid);
635 res = rpc_call(func,0,file->fs->id,file->fs_fh,count);
636 free(func);
637 return res;
639 ssize_t write(int fildes,const void *buf,size_t count) {
640 struct filelist_item *file = filebyfh(fildes);
641 if (file->fs==NULL) return _write_unnamed_pipe(fildes,buf,count);
642 else if (file) {
643 ssize_t count_rem = count;
644 size_t off = 0;
645 while (count_rem>0) {
646 size_t count_cur = count_rem;
647 if (count_cur>SHMMEM_SIZE) count_cur = SHMMEM_SIZE;
648 count_cur = _write(file,buf+off,count_cur);
649 if (count_cur==-1) return -1;
650 count_rem -= count_cur;
651 if (count_cur==0) break;
652 off += count_cur;
654 return count-count_rem;
656 else {
657 errno = EBADF;
658 return -1;
663 * Seeks in a file
664 * @param fildes File descriptor
665 * @param offset Offset
666 * @param whence SEEK_SET, SEEK_CUR, SEEK_END
667 * @return New position
669 off_t lseek(int fildes,off_t offset,int whence) {
670 int res;
671 char *func;
672 struct filelist_item *file = filebyfh(fildes);
673 if (file) {
674 asprintf(&func,"fs_seek_%x",file->fs->pid);
675 res = rpc_call(func,0,file->fs->id,file->fs_fh,offset,whence);
676 free(func);
678 else res = -EBADF;
679 errno = res<0?-res:0;
680 return res<0?-1:res;
684 * Removes a file
685 * @param path Path to file
686 * @return 0=success; -1=failure
688 int unlink(const char *path) {
689 int res;
690 char *cpath = getabsolutepath((char*)path);
691 struct fslist_item *fs = fsbypath(cpath,1);
692 char *func;
694 if (fs!=NULL) {
695 asprintf(&func,"fs_unlink_%x",fs->pid);
696 res = rpc_call(func,0,fs->id,cpath);
697 free(func);
699 else res = -EINVAL;
700 free(cpath);
701 errno = res<0?-res:0;
702 return res<0?-1:res;
706 * Removes a directory
707 * @param path Path to directory
708 * @return 0=success; -1=failure
710 int rmdir(const char *path) {
711 int res;
712 char *cpath = getabsolutepath((char*)path);
713 struct fslist_item *fs = fsbypath(cpath,1);
714 char *func;
716 if (fs!=NULL) {
717 asprintf(&func,"fs_rmdir_%x",fs->pid);
718 res = rpc_call(func,0,fs->id,cpath);
719 free(func);
721 else res = -EINVAL;
722 free(cpath);
723 errno = res<0?-res:0;
724 return res<0?-1:res;
728 * Renames a file
729 * @param path Path to directory
730 * @return 0=success; -1=failure
732 int rename(const char *old, const char *new) {
733 int res;
734 char *cold = getabsolutepath((char*)old);
735 char *cnew = getabsolutepath((char*)new);
736 struct fslist_item *fs = fsbypath(cold,1);
737 struct fslist_item *fsnew = fsbypath(cnew,1);
738 char *func;
740 if (fs!=NULL && fs==fsnew) {
741 asprintf(&func,"fs_rename_%x",fs->pid);
742 res = rpc_call(func,0,fs->id,old,new);
743 free(func);
745 else res = -EINVAL;
746 errno = res<0?-res:0;
747 return res<0?-1:res;
751 * Truncates a file
752 * @param path Path
753 * @param length New length
754 * @return 0=success; -1=failure
756 int truncate(const char *path,off_t length) {
757 int fh;
758 int res = -1;
759 if ((fh = open(path,O_WRONLY))!=-1) {
760 if (ftruncate(fh,length)!=-1) res = 0;
761 close(fh);
763 return res;
767 * Truncates a file
768 * @param fildes File descriptor
769 * @param length New length
770 * @return 0=success; -1=failure
772 int ftruncate(int fildes,off_t length) {
773 int res;
774 char *func;
775 struct filelist_item *file = filebyfh(fildes);
776 if (file) {
777 asprintf(&func,"fs_ftruncate_%x",file->fs->pid);
778 res = rpc_call(func,0,file->fs->id,file->fs_fh,length);
779 free(func);
781 else res = -EBADF;
782 errno = res<0?-res:0;
783 return res<0?-1:res;
784 return -1;
788 * Opens a directory
789 * @param path Path to directory
790 * @return Pointer to dir handle
792 DIR *opendir(const char *path) {
793 int dh,res;
794 void *shmbuf;
795 char *func;
796 char *cpath = getabsolutepath(path);
797 struct fslist_item *fs = fsbypath(cpath,0);
799 struct filelist_item *new;
800 if (fs!=NULL) {
801 int shmid = shmget(IPC_PRIVATE,SHMMEM_SIZE,0);
802 shmbuf = shmat(shmid,NULL,0);
803 if (shmbuf!=NULL) {
804 strncpy(shmbuf,cpath,SHMMEM_SIZE);
805 asprintf(&func,"fs_opendir_%x",fs->pid);
806 dh = rpc_call(func,0,fs->id,shmid);
807 free(func);
808 if (dh>=0) {
809 new = malloc(sizeof(struct filelist_item));
810 new->fs_fh = dh;
811 new->fs = fs;
812 new->oflag = 0;
813 new->mode = S_IFDIR;
814 new->fh = 0; // Dir handles don't need IDs
815 new->path = strdup(cpath);
816 new->shmid = shmid;
817 new->shmbuf = shmbuf;
818 new->dir_cur.d_name = NULL;
819 llist_push(filelist,new);
820 res = 0;
822 else res = dh;
824 else res = -errno;
826 else res = -ENOENT;
827 free(cpath);
828 errno = res<0?-res:0;
829 return res<0?NULL:((DIR*)new);
833 * Closes a directory
834 * @param file Dirhandle
835 * @return Errorcode
837 int closedir(DIR *file) {
838 int res;
839 char *func;
840 if (file) {
841 asprintf(&func,"fs_closedir_%x",file->fs->pid);
842 res = rpc_call(func,0,file->fs->id,file->fs_fh);
843 free(func);
844 if (res==0) {
845 shmdt(file->shmbuf);
846 shmctl(file->shmid,IPC_RMID,NULL);
847 free(file->path);
848 free(file);
849 llist_remove(filelist,llist_find(filelist,file));
852 else res = -EBADF;
853 errno = res<0?-res:0;
854 return res<0?-1:res;
858 * Reads an entry from an opened dir
859 * @param dh Dirhandle
860 * @return Direntry
862 struct dirent *readdir(DIR *file) {
863 int res;
864 char *func;
865 if (file!=NULL) {
866 asprintf(&func,"fs_readdir_%x",file->fs->pid);
867 res = rpc_call(func,0,file->fs->id,file->fs_fh);
868 free(func);
869 if (res>=0) {
870 if (file->dir_cur.d_name!=NULL) free(file->dir_cur.d_name);
871 file->dir_cur.d_name = strdup(file->shmbuf);
874 else res = -EBADF;
875 errno = res<0 && res!=-ENOENT?-res:0;
876 return res<0?NULL:&(file->dir_cur);
880 * Seeks in dir
881 * @param dh Dirhandle
882 * @param loc Location to seek to
884 void seekdir(DIR *file,long loc) {
885 int res;
886 char *func;
887 if (file) {
888 asprintf(&func,"fs_seekdir_%x",file->fs->pid);
889 res = rpc_call(func,0,file->fs->id,file->fs_fh,loc);
890 free(func);
892 else res = -EBADF;
893 errno = res<0?-res:0;
897 * Gets location in dir
898 * @param dh Dirhandle
899 * @return Location in dir
901 long telldir(DIR *file) {
902 int res;
903 char *func;
904 if (file) {
905 asprintf(&func,"fs_seekdir_%x",file->fs->pid);
906 res = rpc_call(func,0,file->fs->id,file->fs_fh,-1);
907 free(func);
909 else res = -EBADF;
910 errno = res<0?-res:0;
911 return res<0?-1:res;
915 * Gets informations about a file
916 * @param path Path to file
917 * @param buf Pointer to stat structure
918 * @return 0=success; -1=failure
920 int stat(const char *path,struct stat *buf) {
921 int fh;
922 int ret = -1;
923 if ((fh = open(path,O_RDONLY))!=-1) {
924 ret = fstat(fh,buf);
925 close(fh);
927 else {
928 struct filelist_item *dir = opendir(path);
929 if (dir!=NULL) {
930 ret = fstat(dir->fh,buf);
931 closedir(dir);
934 return ret;
938 * Gets informations about a filedescriptor
939 * @param fildes Filedescriptor
940 * @param buf Pointer to stat structure
941 * @return 0=success; -1=failure
943 int fstat(int fildes,struct stat *buf) {
944 int res;
945 char *func;
946 struct filelist_item *file = filebyfh(fildes);
947 if (file) {
948 asprintf(&func,"fs_fstat_%x",file->fs->pid);
949 memset(buf,0,sizeof(struct stat));
950 res = rpc_call(func,0,file->fs->id,file->fs_fh);
951 memcpy(buf,file->shmbuf,sizeof(struct stat));
952 free(func);
954 else res = -EBADF;
955 errno = res<0?-res:0;
956 return res<0?-1:res;
960 * Gets informations about a filesystem
961 * @param path File included in FS of that information is wanted
962 * @param buf Pointer to statvfs structure
965 int statvfs(const char *path,struct statvfs *buf) {
966 int res = 0;
967 void *shmbuf;
968 char *func;
969 char *cpath = getabsolutepath(path);
970 struct fslist_item *fs = fsbypath(cpath,0);
972 if (fs!=NULL) {
973 int shmid = shmget(IPC_PRIVATE,SHMMEM_SIZE,0);
974 shmbuf = shmat(shmid,NULL,0);
975 if (shmbuf!=NULL) {
976 asprintf(&func,"fs_statvfs_%x",fs->pid);
977 memset(buf,0,sizeof(struct statvfs));
978 strncpy(shmbuf,cpath,SHMMEM_SIZE);
979 res = rpc_call(func,0,fs->id,shmid);
980 memcpy(buf,shmbuf,sizeof(struct statvfs));
981 free(func);
982 shmdt(shmbuf);
983 shmctl(shmid,IPC_RMID,NULL);
985 else res = -errno;
987 else res = -EBADF;
988 free(cpath);
989 errno = res<0?-res:0;
990 return res<0?-1:res;
994 * Reads link
995 * @param path Path to link
996 * @param buf Buffer for path
997 * @param bufsize Size of buffer
998 * @return Bytes written to buffer
1000 ssize_t readlink(const char *path,char *buf,size_t bufsize) {
1001 int res = 0;
1002 void *shmbuf;
1003 char *func;
1004 char *cpath = getabsolutepath(path);
1005 struct fslist_item *fs = fsbypath(cpath,0);
1007 if (fs!=NULL) {
1008 int shmid = shmget(IPC_PRIVATE,SHMMEM_SIZE,0);
1009 shmbuf = shmat(shmid,NULL,0);
1010 if (shmbuf!=NULL) {
1011 asprintf(&func,"fs_readlink_%x",fs->pid);
1012 strncpy(shmbuf,cpath,SHMMEM_SIZE);
1013 res = rpc_call(func,0,fs->id,shmid,bufsize);
1014 strncpy(buf,shmbuf,bufsize);
1015 free(func);
1016 shmdt(shmbuf);
1017 shmctl(shmid,IPC_RMID,NULL);
1019 else res = -errno;
1021 else res = -EBADF;
1022 free(cpath);
1023 errno = res<0?-res:0;
1024 return res<0?-1:res;
1028 * Creates a symoblic link
1029 * @param src Source file
1030 * @param dest Destination (name of symlink)
1031 * @return 0=success; -1=failure
1033 int symlink(const char *dest,const char *src) {
1034 int res;
1035 char *csrc = getabsolutepath((char*)src);
1036 char *cdest = getabsolutepath((char*)dest);
1037 struct fslist_item *fs = fsbypath(csrc,1);
1038 char *func;
1040 if (fs!=NULL) {
1041 asprintf(&func,"fs_symlink_%x",fs->pid);
1042 res = rpc_call(func,0,fs->id,csrc,cdest);
1043 free(func);
1045 else res = -EINVAL;
1046 errno = res<0?-res:0;
1047 return res<0?-1:res;
1051 * Creates a hardlink
1052 * @param src Source file
1053 * @param dest Destination (name of hardlink)
1054 * @return 0=success; -1=failure
1056 int link(const char *src,const char *dest) {
1057 int res;
1058 char *csrc = getabsolutepath((char*)src);
1059 char *cdest = getabsolutepath((char*)dest);
1060 struct fslist_item *fs = fsbypath(csrc,1);
1061 struct fslist_item *fsdest = fsbypath(cdest,0);
1062 char *func;
1064 if (fs!=NULL && fs==fsdest) {
1065 asprintf(&func,"fs_link_%x",fs->pid);
1066 res = rpc_call(func,0,fs->id,src,dest);
1067 free(func);
1069 else res = -EINVAL;
1070 errno = res<0?-res:0;
1071 return res<0?-1:res;
1074 int chown(const char *path,uid_t uid,gid_t gid) {
1075 int res;
1076 char *cpath = getabsolutepath((char*)path);
1077 struct fslist_item *fs = fsbypath(cpath,0);
1078 char *func;
1080 if (fs!=NULL) {
1081 asprintf(&func,"fs_chown_%x",fs->pid);
1082 res = rpc_call(func,0,fs->id,cpath,uid,gid);
1083 free(func);
1085 else res = -EINVAL;
1086 free(cpath);
1087 errno = res<0?-res:0;
1088 return res<0?-1:res;
1091 int fchown(int fildes,uid_t uid,gid_t gid) {
1092 int res;
1093 struct filelist_item *file = filebyfh(fildes);
1094 if (file) res = chown(file->path,uid,gid);
1095 else res = -EBADF;
1096 errno = res<0?-res:0;
1097 return res<0?-1:res;
1100 int chmod(const char *path,mode_t mode) {
1101 int res;
1102 char *cpath = getabsolutepath((char*)path);
1103 struct fslist_item *fs = fsbypath(cpath,0);
1104 char *func;
1106 if (fs!=NULL) {
1107 asprintf(&func,"fs_chmod_%x",fs->pid);
1108 res = rpc_call(func,0,fs->id,cpath,mode);
1109 free(func);
1111 else res = -EINVAL;
1112 free(cpath);
1113 errno = res<0?-res:0;
1114 return res<0?-1:res;
1117 int fchmod(int fildes,mode_t mode) {
1118 int res;
1119 struct filelist_item *file = filebyfh(fildes);
1120 if (file) {
1121 res = chmod(file->path,mode);
1122 if (res==0) file->mode = mode;
1124 else res = -EBADF;
1125 errno = res<0?-res:0;
1126 return res<0?-1:res;
1129 int utime(const char *path,const struct utimbuf *times) {
1130 int res = 0;
1131 void *shmbuf;
1132 char *func;
1133 char *cpath = getabsolutepath(path);
1134 struct fslist_item *fs = fsbypath(cpath,0);
1136 if (fs!=NULL) {
1137 int shmid = shmget(IPC_PRIVATE,SHMMEM_SIZE,0);
1138 shmbuf = shmat(shmid,NULL,0);
1139 if (shmbuf!=NULL) {
1140 asprintf(&func,"fs_utime_%x",fs->pid);
1141 strncpy(shmbuf,path,SHMMEM_SIZE);
1142 memcpy(shmbuf+strlen(shmbuf)+1,times,sizeof(struct utimbuf));
1143 res = rpc_call(func,0,fs->id,shmid);
1144 free(func);
1145 shmdt(shmbuf);
1146 shmctl(shmid,IPC_RMID,NULL);
1148 else res = -errno;
1150 else res = -EBADF;
1151 free(cpath);
1152 errno = res<0?-res:0;
1153 return res<0?-1:res;
1156 mode_t umask(mode_t cmask) {
1157 mode_t ret = creation_mask;
1158 creation_mask = cmask&0777;
1159 return ret;
1162 ///////// SOCKET STUFF /////////////////////
1164 int socket(int domain,int type, int protocol) {
1165 return -1;