stdlibc/files: Check for valid path string; chdir: check for existing dir
[meinos.git] / apps / lib / stdlibc / files.c
blobc6816af01e2a8fed2d0e1f6e58ae2f21b5c5babc
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 if (path==NULL || path[0]==0) return NULL;
139 struct fslist_item *fs = mp_match(path,parent);
140 if (fs==NULL) {
141 fs = malloc(sizeof(struct fslist_item));
142 char *mountpoint = strdup(path);
143 fs->id = rpc_call("vfs_getfsid",2,path,parent);
144 if (fs->id<0) {
145 free(mountpoint);
146 errno = -fs->id;
147 return NULL;
149 mountpoint[strlen(mountpoint)-strlen(path)] = 0;
150 fs->mountpoint = path_parse(mountpoint);
151 fs->mountpoint_str = path_output(fs->mountpoint,NULL);
152 free(mountpoint);
153 fs->pid = rpc_call("vfs_getpid",0,fs->id);
154 if (fs->pid<0) {
155 errno = -fs->pid;
156 return NULL;
158 llist_push(fslist,fs);
161 return fs;
165 * Gets list index by filehandle
166 * @param fh filehandle
167 * @return List index
169 static int lidxbyfh(int fh) {
170 struct filelist_item *file;
171 int i;
172 for (i=0;(file = llist_get(filelist,i));i++) {
173 if (file->fh==fh) return i;
175 return -1;
179 * Gets absolute path by relative path
180 * @param relative Relative or absolute path
181 * @return Absolute path (Can be passed to free())
183 static char *getabsolutepath(const char *relative) {
184 path_t *path = path_parse(relative);
185 if (!path->root) {
186 path_t *newpath = path_cat(workdir.path,path);
187 path_destroy(path);
188 path = newpath;
190 path_reject_dots(path);
191 return path_output(path,NULL);
195 * Creates an unnamed pipe
196 * @param read Whether creator is reader
197 * @return Filehandle
199 int _create_unnamed_pipe(int read,int *_shmid) {
200 int shmid = shmget(IPC_PRIVATE,SHMMEM_SIZE,0);
201 if (shmid!=-1) {
202 size_t *shmbuf = shmat(shmid,NULL,0);
203 if (shmbuf!=NULL) {
204 struct filelist_item *new = malloc(sizeof(struct filelist_item));
205 memset(new,0,sizeof(struct filelist_item));
206 new->fh = getnew_fh();
207 new->oflag = read?O_RDONLY:O_WRONLY;
208 new->shmid = shmid;
209 new->shmbuf = shmbuf;
210 shmbuf[0] = read; // Direction
211 shmbuf[1] = 0; // Reserved for error
212 shmbuf[2] = 0; // Reading position
213 shmbuf[3] = 0; // Writing position
214 llist_push(filelist,new);
215 if (_shmid!=NULL) *_shmid = shmid;
216 return new->fh;
218 else shmctl(shmid,IPC_RMID,NULL);
220 return -1;
224 * Destroys an unnamed pipe
225 * @param fh Filehandle of unnamed pipe
226 * @return Success?
228 int _destroy_unnamed_pipe(int fh) {
229 struct filelist_item *file = filebyfh(fh);
231 if (file && file->fs==NULL) {
232 shmdt(file->shmbuf);
233 shmctl(file->shmid,IPC_RMID,NULL);
234 llist_remove(filelist,lidxbyfh(fh));
235 free(file);
236 return 0;
238 else errno = EBADF;
239 return -1;
243 * Opens an unnamed pipe
244 * @param fh Use this filehandle (-1 no specified filehandle)
245 * @param shmid SHM object the unnamed pipe uses
246 * @note If you specify the filehandle, be sure that it isn't used already
247 * @return Filehandle
249 static int _open_unnamed_pipe(int fh,int shmid) {
250 size_t *shmbuf = shmat(shmid,NULL,0);
251 if (shmbuf!=NULL) {
252 if (fh==-1) fh = getnew_fh();
253 struct filelist_item *new = malloc(sizeof(struct filelist_item));
254 memset(new,0,sizeof(struct filelist_item));
255 new->fh = fh;
256 new->oflag = shmbuf[0]?O_WRONLY:O_RDONLY;
257 new->shmid = shmid;
258 new->shmbuf = shmbuf;
259 llist_push(filelist,new);
260 return fh;
262 else return -1;
266 * Destroys an unnamed pipe
267 * @param fh Filehandle of unnamed pipe
268 * @return Success?
270 static int _close_unnamed_pipe(int fh) {
271 struct filelist_item *file = filebyfh(fh);
273 if (file && file->fs==NULL) {
274 shmdt(file->shmbuf);
275 llist_remove(filelist,lidxbyfh(fh));
276 free(file);
277 return 0;
279 else errno = EBADF;
280 return -1;
284 * Reads an unnamed pipe
285 * @param fh Filehandle
286 * @param data Data buffer
287 * @param size How many bytes to read
288 * @return How many bytes read
290 static size_t _read_unnamed_pipe(int fh,void *data,size_t size) {
291 struct filelist_item *file = filebyfh(fh);
292 ssize_t size_read = -1;
294 if (file && file->fs==NULL && file->oflag==O_RDONLY) {
295 size_t *pos_read = file->shmbuf+2*sizeof(size_t);
296 size_t *pos_write = file->shmbuf+3*sizeof(size_t);
297 void *buffer = file->shmbuf+4*sizeof(size_t);
298 size_t size_free = *pos_write>=*pos_read?*pos_write-*pos_read:*pos_write+SHMMEM_SIZE-4*sizeof(int)-*pos_read;
300 if (size>size_free) size = size_free;
301 if (*pos_write>=*pos_read) memcpy(data,buffer,size);
302 else {
303 size_t part1 = SHMMEM_SIZE-4*sizeof(int)-*pos_read;
304 size_t part2 = *pos_write;
305 memcpy(data,buffer+*pos_read,part1);
306 memcpy(data+part1,buffer,part2);
308 *pos_read = (*pos_read+size)%(SHMMEM_SIZE-4*sizeof(int));
310 size_read = size;
312 else errno = EBADF;
313 return size_read;
317 * Writes an unnamed pipe
318 * @param fh Filehandle
319 * @param data Data buffer
320 * @param size How many bytes to write
321 * @return How many bytes written
323 static size_t _write_unnamed_pipe(int fh,const void *data,size_t size) {
324 struct filelist_item *file = filebyfh(fh);
325 ssize_t size_written = -1;
327 if (file && file->fs==NULL && file->oflag==O_WRONLY) {
328 size_t *pos_read = file->shmbuf+2*sizeof(size_t);
329 size_t *pos_write = file->shmbuf+3*sizeof(size_t);
330 void *buffer = file->shmbuf+4*sizeof(size_t);
331 size_t size_free = *pos_read>*pos_write?*pos_read-*pos_write:*pos_read+SHMMEM_SIZE-4*sizeof(int)-*pos_write;
333 if (size>size_free) size = size_free;
334 if (*pos_read>=*pos_write) memcpy(buffer,data,size);
335 else {
336 size_t part1 = SHMMEM_SIZE-4*sizeof(int)-*pos_write;
337 size_t part2 = *pos_read;
338 memcpy(buffer+*pos_write,data,part1);
339 memcpy(buffer,data+part1,part2);
341 *pos_write = (*pos_write+size)%(SHMMEM_SIZE-4*sizeof(int));
343 size_written = size;
345 else errno = EBADF;
346 return size_written;
350 * Gets current workdir
351 * @param buf Buffer to store path in
352 * @param size Size of buffer
353 * @return Current workdir
355 char *getcwd(char *buf,size_t size) {
356 if (buf==NULL) {
357 size = workdir.strlen+1;
358 buf = malloc(size);
360 else if (size==0) {
361 errno = EINVAL;
362 return NULL;
364 else if (workdir.strlen+1>size) {
365 errno = ERANGE;
366 return NULL;
368 return strncpy(buf,workdir.str,size);
372 * Change current workdir
373 * @param new New workdir
374 * @return 0=success; -1=failure
376 int chdir(const char *new) {
377 new = getabsolutepath((char*)new);
378 if (new==NULL) new = "/";
380 DIR *dir = opendir(new);
381 if (dir!=NULL) {
382 closedir(dir);
383 free(workdir.str);
384 path_destroy(workdir.path);
385 workdir.path = path_parse(new);
386 path_reject_dots(workdir.path);
387 workdir.str = path_output(workdir.path,NULL);
388 workdir.strlen = strlen(workdir.str);
389 setenv("PATH",workdir.str,1);
390 return 0;
392 else return -1;
396 * Change current workdir
397 * @param new Filedescriptor of new workdir
398 * @return 0=success; -1=failure
400 int fchdir(int fildes) {
401 int res;
402 struct filelist_item *file = filebyfh(fildes);
403 if (file!=NULL) res = chdir(file->path);
404 else res = -EBADF;
405 errno = res<0?-res:0;
406 return res<0?-1:res;
410 * Creates a new node
411 * @param path Path to new node
412 * @param mode Mode of new node
413 * @param dev DeviceID (not used)
414 * @return 0=success; -1=failure
416 int mknod(const char *path,mode_t mode,dev_t dev) {
417 int res;
418 char *cpath = getabsolutepath((char*)path);
419 struct fslist_item *fs = fsbypath(cpath,1);
420 char *func;
422 if (fs!=NULL) {
423 asprintf(&func,"fs_mknod_%x",fs->pid);
424 res = rpc_call(func,0,fs->id,cpath,mode&(~creation_mask),dev);
425 free(func);
427 else res = -EINVAL;
428 free(cpath);
429 errno = res<0?-res:0;
430 return res<0?-1:res;
434 * Checks whether file can be opened with mode
435 * @param path Path to file
436 * @param amode Mode
437 * @return 0=success; -1=failure
439 int access(const char *path,int amode) {
440 int res;
441 char *cpath = getabsolutepath((char*)path);
442 struct fslist_item *fs = fsbypath(cpath,0);
443 char *func;
445 if (fs!=NULL) {
446 asprintf(&func,"fs_access_%x",fs->pid);
447 res = rpc_call(func,0,fs->id,cpath,amode);
448 free(func);
450 else res = -EINVAL;
451 free(cpath);
452 errno = res<0?-res:0;
453 return res<0?-1:res;
457 * Opens a file
458 * @param path Path to file
459 * @param oflag Mode
461 int open(const char *path,int oflag,...) {
462 va_list args;
463 int fh = 0;
464 void *shmbuf;
465 char *func;
466 char *cpath = getabsolutepath(path);
467 struct fslist_item *fs = fsbypath(cpath,0);
468 if (fs==NULL) fh = -errno;
470 va_start(args,oflag);
472 if (fh==0) {
473 if (oflag&O_CREAT) {
474 oflag &= ~O_CREAT;
475 int res = mknod(path,va_arg(args,mode_t)|S_IFREG,0);
476 if (res==-1 && errno!=EEXIST) fh = -errno;
478 int shmid = shmget(IPC_PRIVATE,SHMMEM_SIZE,0);
479 shmbuf = shmat(shmid,NULL,0);
480 if (shmbuf!=NULL) {
481 strncpy(shmbuf,cpath,SHMMEM_SIZE);
482 asprintf(&func,"fs_open_%x",fs->pid);
483 fh = rpc_call(func,0,fs->id,oflag,shmid);
484 free(func);
485 if (fh>=0) {
486 struct filelist_item *new = malloc(sizeof(struct filelist_item));
487 new->fs_fh = fh;
488 new->fs = fs;
489 new->oflag = oflag;
490 new->mode = S_IFREG;
491 new->fh = getnew_fh();
492 new->path = strdup(cpath);
493 new->shmid = shmid;
494 new->shmbuf = shmbuf;
495 fh = new->fh;
496 llist_push(filelist,new);
500 va_end(args);
501 free(cpath);
502 errno = fh<0?-fh:0;
503 return fh<0?-1:fh;
507 * Closes all filehandles
509 void _close_all_filehandles() {
510 struct filelist_item *file;
511 while ((file = llist_pop(filelist))!=NULL) {
512 if (S_ISREG(file->mode)) close(file->fh);
513 else if (S_ISDIR(file->mode)) closedir(file);
516 // close stdin, stdout and stderr
517 _destroy_unnamed_pipe(STDIN_FILENO);
518 _destroy_unnamed_pipe(STDOUT_FILENO);
519 _destroy_unnamed_pipe(STDERR_FILENO);
524 * Closes a file
525 * @param fildes File descriptor
526 * @return 0=success; -1=failure
528 int close(int fildes) {
529 int res;
530 char *func;
531 struct filelist_item *file = filebyfh(fildes);
532 if (file->fs==NULL) return _close_unnamed_pipe(fildes);
533 if (file) {
534 asprintf(&func,"fs_close_%x",file->fs->pid);
535 res = rpc_call(func,0,file->fs->id,file->fs_fh);
536 free(func);
537 if (res==0) {
538 shmdt(file->shmbuf);
539 shmctl(file->shmid,IPC_RMID,NULL);
540 llist_remove(filelist,lidxbyfh(fildes));
541 free(file->path);
542 free(file);
545 else res = -EBADF;
546 errno = res<0?-res:0;
547 return res<0?-1:res;
548 return -1;
552 * Duplicates a file descriptor
553 * @param fildes File descriptor
554 * @param fildes2 New file descriptor
555 * @return New file desciptor
557 int dup2(int fildes,int fildes2) {
558 int res = -1;
559 char *func;
560 struct filelist_item *file = filebyfh(fildes);
561 if (file) {
562 asprintf(&func,"fs_close_%x",file->fs->pid);
563 res = rpc_call(func,0,file->fs->id,file->fs_fh);
564 free(func);
565 if (res>=0) {
566 struct filelist_item *new = malloc(sizeof(struct filelist_item));
567 memcpy(new,file,sizeof(struct filelist_item));
568 if (fildes2==0) new->fh = getnew_fh();
569 else {
570 close(fildes2);
571 new->fh = fildes2;
573 new->fs_fh = res;
574 new->shmid = shmget(IPC_PRIVATE,SHMMEM_SIZE,0);
575 new->shmbuf = shmat(new->shmid,NULL,0);
576 llist_push(filelist,new);
579 else errno = EBADF;
580 return res;
584 * Reads from a file
585 * @param fildes File descriptor
586 * @param buf Buffer to store read data in
587 * @param count How many bytes to read
588 * @return How many bytes read
590 static ssize_t _read(struct filelist_item *file,void *buf,size_t count) {
591 ssize_t res;
592 char *func;
593 asprintf(&func,"fs_read_%x",file->fs->pid);
594 res = rpc_call(func,0,file->fs->id,file->fs_fh,count);
595 free(func);
596 if (res>0) memcpy(buf,file->shmbuf,res);
597 return res;
599 ssize_t read(int fildes,void *buf,size_t count) {
600 struct filelist_item *file = filebyfh(fildes);
601 if (file->fs==NULL) return _read_unnamed_pipe(fildes,buf,count);
602 else if (file!=NULL) {
603 ssize_t count_rem = count;
604 size_t off = 0;
606 while (count_rem>0) {
607 size_t count_cur = count_rem;
608 if (count_cur>SHMMEM_SIZE) count_cur = SHMMEM_SIZE;
609 count_cur = _read(file,buf+off,count_cur);
610 if (count_cur==-1) return -1;
611 count_rem -= count_cur;
612 if (count_cur==0) break;
613 off += count_cur;
616 return count-count_rem;
618 else {
619 errno = EBADF;
620 return -1;
625 * Writes to a file
626 * @param fildes File descriptor
627 * @param buf Data to write to file
628 * @param count How many bytes to write
629 * @return How many bytes written
631 static ssize_t _write(struct filelist_item *file,const void *buf,size_t count) {
632 char *func;
633 ssize_t res;
634 memcpy(file->shmbuf,buf,count);
635 asprintf(&func,"fs_write_%x",file->fs->pid);
636 res = rpc_call(func,0,file->fs->id,file->fs_fh,count);
637 free(func);
638 return res;
640 ssize_t write(int fildes,const void *buf,size_t count) {
641 struct filelist_item *file = filebyfh(fildes);
642 if (file->fs==NULL) return _write_unnamed_pipe(fildes,buf,count);
643 else if (file) {
644 ssize_t count_rem = count;
645 size_t off = 0;
646 while (count_rem>0) {
647 size_t count_cur = count_rem;
648 if (count_cur>SHMMEM_SIZE) count_cur = SHMMEM_SIZE;
649 count_cur = _write(file,buf+off,count_cur);
650 if (count_cur==-1) return -1;
651 count_rem -= count_cur;
652 if (count_cur==0) break;
653 off += count_cur;
655 return count-count_rem;
657 else {
658 errno = EBADF;
659 return -1;
664 * Seeks in a file
665 * @param fildes File descriptor
666 * @param offset Offset
667 * @param whence SEEK_SET, SEEK_CUR, SEEK_END
668 * @return New position
670 off_t lseek(int fildes,off_t offset,int whence) {
671 int res;
672 char *func;
673 struct filelist_item *file = filebyfh(fildes);
674 if (file) {
675 asprintf(&func,"fs_seek_%x",file->fs->pid);
676 res = rpc_call(func,0,file->fs->id,file->fs_fh,offset,whence);
677 free(func);
679 else res = -EBADF;
680 errno = res<0?-res:0;
681 return res<0?-1:res;
685 * Removes a file
686 * @param path Path to file
687 * @return 0=success; -1=failure
689 int unlink(const char *path) {
690 int res;
691 char *cpath = getabsolutepath((char*)path);
692 struct fslist_item *fs = fsbypath(cpath,1);
693 char *func;
695 if (fs!=NULL) {
696 asprintf(&func,"fs_unlink_%x",fs->pid);
697 res = rpc_call(func,0,fs->id,cpath);
698 free(func);
700 else res = -EINVAL;
701 free(cpath);
702 errno = res<0?-res:0;
703 return res<0?-1:res;
707 * Removes a directory
708 * @param path Path to directory
709 * @return 0=success; -1=failure
711 int rmdir(const char *path) {
712 int res;
713 char *cpath = getabsolutepath((char*)path);
714 struct fslist_item *fs = fsbypath(cpath,1);
715 char *func;
717 if (fs!=NULL) {
718 asprintf(&func,"fs_rmdir_%x",fs->pid);
719 res = rpc_call(func,0,fs->id,cpath);
720 free(func);
722 else res = -EINVAL;
723 free(cpath);
724 errno = res<0?-res:0;
725 return res<0?-1:res;
729 * Renames a file
730 * @param path Path to directory
731 * @return 0=success; -1=failure
733 int rename(const char *old, const char *new) {
734 int res;
735 char *cold = getabsolutepath((char*)old);
736 char *cnew = getabsolutepath((char*)new);
737 struct fslist_item *fs = fsbypath(cold,1);
738 struct fslist_item *fsnew = fsbypath(cnew,1);
739 char *func;
741 if (fs!=NULL && fs==fsnew) {
742 asprintf(&func,"fs_rename_%x",fs->pid);
743 res = rpc_call(func,0,fs->id,old,new);
744 free(func);
746 else res = -EINVAL;
747 errno = res<0?-res:0;
748 return res<0?-1:res;
752 * Truncates a file
753 * @param path Path
754 * @param length New length
755 * @return 0=success; -1=failure
757 int truncate(const char *path,off_t length) {
758 int fh;
759 int res = -1;
760 if ((fh = open(path,O_WRONLY))!=-1) {
761 if (ftruncate(fh,length)!=-1) res = 0;
762 close(fh);
764 return res;
768 * Truncates a file
769 * @param fildes File descriptor
770 * @param length New length
771 * @return 0=success; -1=failure
773 int ftruncate(int fildes,off_t length) {
774 int res;
775 char *func;
776 struct filelist_item *file = filebyfh(fildes);
777 if (file) {
778 asprintf(&func,"fs_ftruncate_%x",file->fs->pid);
779 res = rpc_call(func,0,file->fs->id,file->fs_fh,length);
780 free(func);
782 else res = -EBADF;
783 errno = res<0?-res:0;
784 return res<0?-1:res;
785 return -1;
789 * Opens a directory
790 * @param path Path to directory
791 * @return Pointer to dir handle
793 DIR *opendir(const char *path) {
794 int dh,res;
795 void *shmbuf;
796 char *func;
797 char *cpath = getabsolutepath(path);
798 struct fslist_item *fs = fsbypath(cpath,0);
800 struct filelist_item *new;
801 if (fs!=NULL) {
802 int shmid = shmget(IPC_PRIVATE,SHMMEM_SIZE,0);
803 shmbuf = shmat(shmid,NULL,0);
804 if (shmbuf!=NULL) {
805 strncpy(shmbuf,cpath,SHMMEM_SIZE);
806 asprintf(&func,"fs_opendir_%x",fs->pid);
807 dh = rpc_call(func,0,fs->id,shmid);
808 free(func);
809 if (dh>=0) {
810 new = malloc(sizeof(struct filelist_item));
811 new->fs_fh = dh;
812 new->fs = fs;
813 new->oflag = 0;
814 new->mode = S_IFDIR;
815 new->fh = 0; // Dir handles don't need IDs
816 new->path = strdup(cpath);
817 new->shmid = shmid;
818 new->shmbuf = shmbuf;
819 new->dir_cur.d_name = NULL;
820 llist_push(filelist,new);
821 res = 0;
823 else res = dh;
825 else res = -errno;
827 else res = -ENOENT;
828 free(cpath);
829 errno = res<0?-res:0;
830 return res<0?NULL:((DIR*)new);
834 * Closes a directory
835 * @param file Dirhandle
836 * @return Errorcode
838 int closedir(DIR *file) {
839 int res;
840 char *func;
841 if (file) {
842 asprintf(&func,"fs_closedir_%x",file->fs->pid);
843 res = rpc_call(func,0,file->fs->id,file->fs_fh);
844 free(func);
845 if (res==0) {
846 shmdt(file->shmbuf);
847 shmctl(file->shmid,IPC_RMID,NULL);
848 free(file->path);
849 free(file);
850 llist_remove(filelist,llist_find(filelist,file));
853 else res = -EBADF;
854 errno = res<0?-res:0;
855 return res<0?-1:res;
859 * Reads an entry from an opened dir
860 * @param dh Dirhandle
861 * @return Direntry
863 struct dirent *readdir(DIR *file) {
864 int res;
865 char *func;
866 if (file!=NULL) {
867 asprintf(&func,"fs_readdir_%x",file->fs->pid);
868 res = rpc_call(func,0,file->fs->id,file->fs_fh);
869 free(func);
870 if (res>=0) {
871 if (file->dir_cur.d_name!=NULL) free(file->dir_cur.d_name);
872 file->dir_cur.d_name = strdup(file->shmbuf);
875 else res = -EBADF;
876 errno = res<0 && res!=-ENOENT?-res:0;
877 return res<0?NULL:&(file->dir_cur);
881 * Seeks in dir
882 * @param dh Dirhandle
883 * @param loc Location to seek to
885 void seekdir(DIR *file,long loc) {
886 int res;
887 char *func;
888 if (file) {
889 asprintf(&func,"fs_seekdir_%x",file->fs->pid);
890 res = rpc_call(func,0,file->fs->id,file->fs_fh,loc);
891 free(func);
893 else res = -EBADF;
894 errno = res<0?-res:0;
898 * Gets location in dir
899 * @param dh Dirhandle
900 * @return Location in dir
902 long telldir(DIR *file) {
903 int res;
904 char *func;
905 if (file) {
906 asprintf(&func,"fs_seekdir_%x",file->fs->pid);
907 res = rpc_call(func,0,file->fs->id,file->fs_fh,-1);
908 free(func);
910 else res = -EBADF;
911 errno = res<0?-res:0;
912 return res<0?-1:res;
916 * Gets informations about a file
917 * @param path Path to file
918 * @param buf Pointer to stat structure
919 * @return 0=success; -1=failure
921 int stat(const char *path,struct stat *buf) {
922 int fh;
923 int ret = -1;
924 if ((fh = open(path,O_RDONLY))!=-1) {
925 ret = fstat(fh,buf);
926 close(fh);
928 else {
929 struct filelist_item *dir = opendir(path);
930 if (dir!=NULL) {
931 ret = fstat(dir->fh,buf);
932 closedir(dir);
935 return ret;
939 * Gets informations about a filedescriptor
940 * @param fildes Filedescriptor
941 * @param buf Pointer to stat structure
942 * @return 0=success; -1=failure
944 int fstat(int fildes,struct stat *buf) {
945 int res;
946 char *func;
947 struct filelist_item *file = filebyfh(fildes);
948 if (file) {
949 asprintf(&func,"fs_fstat_%x",file->fs->pid);
950 memset(buf,0,sizeof(struct stat));
951 res = rpc_call(func,0,file->fs->id,file->fs_fh);
952 memcpy(buf,file->shmbuf,sizeof(struct stat));
953 free(func);
955 else res = -EBADF;
956 errno = res<0?-res:0;
957 return res<0?-1:res;
961 * Gets informations about a filesystem
962 * @param path File included in FS of that information is wanted
963 * @param buf Pointer to statvfs structure
966 int statvfs(const char *path,struct statvfs *buf) {
967 int res = 0;
968 void *shmbuf;
969 char *func;
970 char *cpath = getabsolutepath(path);
971 struct fslist_item *fs = fsbypath(cpath,0);
973 if (fs!=NULL) {
974 int shmid = shmget(IPC_PRIVATE,SHMMEM_SIZE,0);
975 shmbuf = shmat(shmid,NULL,0);
976 if (shmbuf!=NULL) {
977 asprintf(&func,"fs_statvfs_%x",fs->pid);
978 memset(buf,0,sizeof(struct statvfs));
979 strncpy(shmbuf,cpath,SHMMEM_SIZE);
980 res = rpc_call(func,0,fs->id,shmid);
981 memcpy(buf,shmbuf,sizeof(struct statvfs));
982 free(func);
983 shmdt(shmbuf);
984 shmctl(shmid,IPC_RMID,NULL);
986 else res = -errno;
988 else res = -EBADF;
989 free(cpath);
990 errno = res<0?-res:0;
991 return res<0?-1:res;
995 * Reads link
996 * @param path Path to link
997 * @param buf Buffer for path
998 * @param bufsize Size of buffer
999 * @return Bytes written to buffer
1001 ssize_t readlink(const char *path,char *buf,size_t bufsize) {
1002 int res = 0;
1003 void *shmbuf;
1004 char *func;
1005 char *cpath = getabsolutepath(path);
1006 struct fslist_item *fs = fsbypath(cpath,0);
1008 if (fs!=NULL) {
1009 int shmid = shmget(IPC_PRIVATE,SHMMEM_SIZE,0);
1010 shmbuf = shmat(shmid,NULL,0);
1011 if (shmbuf!=NULL) {
1012 asprintf(&func,"fs_readlink_%x",fs->pid);
1013 strncpy(shmbuf,cpath,SHMMEM_SIZE);
1014 res = rpc_call(func,0,fs->id,shmid,bufsize);
1015 strncpy(buf,shmbuf,bufsize);
1016 free(func);
1017 shmdt(shmbuf);
1018 shmctl(shmid,IPC_RMID,NULL);
1020 else res = -errno;
1022 else res = -EBADF;
1023 free(cpath);
1024 errno = res<0?-res:0;
1025 return res<0?-1:res;
1029 * Creates a symoblic link
1030 * @param src Source file
1031 * @param dest Destination (name of symlink)
1032 * @return 0=success; -1=failure
1034 int symlink(const char *dest,const char *src) {
1035 int res;
1036 char *csrc = getabsolutepath((char*)src);
1037 char *cdest = getabsolutepath((char*)dest);
1038 struct fslist_item *fs = fsbypath(csrc,1);
1039 char *func;
1041 if (fs!=NULL) {
1042 asprintf(&func,"fs_symlink_%x",fs->pid);
1043 res = rpc_call(func,0,fs->id,csrc,cdest);
1044 free(func);
1046 else res = -EINVAL;
1047 errno = res<0?-res:0;
1048 return res<0?-1:res;
1052 * Creates a hardlink
1053 * @param src Source file
1054 * @param dest Destination (name of hardlink)
1055 * @return 0=success; -1=failure
1057 int link(const char *src,const char *dest) {
1058 int res;
1059 char *csrc = getabsolutepath((char*)src);
1060 char *cdest = getabsolutepath((char*)dest);
1061 struct fslist_item *fs = fsbypath(csrc,1);
1062 struct fslist_item *fsdest = fsbypath(cdest,0);
1063 char *func;
1065 if (fs!=NULL && fs==fsdest) {
1066 asprintf(&func,"fs_link_%x",fs->pid);
1067 res = rpc_call(func,0,fs->id,src,dest);
1068 free(func);
1070 else res = -EINVAL;
1071 errno = res<0?-res:0;
1072 return res<0?-1:res;
1075 int chown(const char *path,uid_t uid,gid_t gid) {
1076 int res;
1077 char *cpath = getabsolutepath((char*)path);
1078 struct fslist_item *fs = fsbypath(cpath,0);
1079 char *func;
1081 if (fs!=NULL) {
1082 asprintf(&func,"fs_chown_%x",fs->pid);
1083 res = rpc_call(func,0,fs->id,cpath,uid,gid);
1084 free(func);
1086 else res = -EINVAL;
1087 free(cpath);
1088 errno = res<0?-res:0;
1089 return res<0?-1:res;
1092 int fchown(int fildes,uid_t uid,gid_t gid) {
1093 int res;
1094 struct filelist_item *file = filebyfh(fildes);
1095 if (file) res = chown(file->path,uid,gid);
1096 else res = -EBADF;
1097 errno = res<0?-res:0;
1098 return res<0?-1:res;
1101 int chmod(const char *path,mode_t mode) {
1102 int res;
1103 char *cpath = getabsolutepath((char*)path);
1104 struct fslist_item *fs = fsbypath(cpath,0);
1105 char *func;
1107 if (fs!=NULL) {
1108 asprintf(&func,"fs_chmod_%x",fs->pid);
1109 res = rpc_call(func,0,fs->id,cpath,mode);
1110 free(func);
1112 else res = -EINVAL;
1113 free(cpath);
1114 errno = res<0?-res:0;
1115 return res<0?-1:res;
1118 int fchmod(int fildes,mode_t mode) {
1119 int res;
1120 struct filelist_item *file = filebyfh(fildes);
1121 if (file) {
1122 res = chmod(file->path,mode);
1123 if (res==0) file->mode = mode;
1125 else res = -EBADF;
1126 errno = res<0?-res:0;
1127 return res<0?-1:res;
1130 int utime(const char *path,const struct utimbuf *times) {
1131 int res = 0;
1132 void *shmbuf;
1133 char *func;
1134 char *cpath = getabsolutepath(path);
1135 struct fslist_item *fs = fsbypath(cpath,0);
1137 if (fs!=NULL) {
1138 int shmid = shmget(IPC_PRIVATE,SHMMEM_SIZE,0);
1139 shmbuf = shmat(shmid,NULL,0);
1140 if (shmbuf!=NULL) {
1141 asprintf(&func,"fs_utime_%x",fs->pid);
1142 strncpy(shmbuf,path,SHMMEM_SIZE);
1143 memcpy(shmbuf+strlen(shmbuf)+1,times,sizeof(struct utimbuf));
1144 res = rpc_call(func,0,fs->id,shmid);
1145 free(func);
1146 shmdt(shmbuf);
1147 shmctl(shmid,IPC_RMID,NULL);
1149 else res = -errno;
1151 else res = -EBADF;
1152 free(cpath);
1153 errno = res<0?-res:0;
1154 return res<0?-1:res;
1157 mode_t umask(mode_t cmask) {
1158 mode_t ret = creation_mask;
1159 creation_mask = cmask&0777;
1160 return ret;
1163 ///////// SOCKET STUFF /////////////////////
1165 int socket(int domain,int type, int protocol) {
1166 return -1;