@@ -28,8 +28,14 @@ syscall_(open, char *path0, uint64_t flags, uint64_t mode) {
2828 node = vfs_open (normalized_path );
2929 if (node == NULL )
3030 goto err ;
31- else
31+ else {
32+ if (flags & O_CREAT ) {
33+ uint16_t final_mode = (uint16_t )(mode & 0777 );
34+ final_mode &= (uint16_t )~(get_current_task ()-> process -> umask & 0777 );
35+ vfs_chmod (node , final_mode );
36+ }
3237 goto next ;
38+ }
3339 } else
3440 err :
3541 free (normalized_path );
@@ -159,17 +165,7 @@ syscall_(readv, int fd, struct iovec *iov, int iovcnt0) {
159165 return status ;
160166}
161167
162- syscall_ (stat , char * fn , struct stat * buf ) {
163- if (unlikely (fn == NULL || buf == NULL )) return SYSCALL_FAULT_ (EINVAL );
164- char * path = vfs_cwd_path_build (fn );
165- vfs_node_t node = vfs_open (path );
166-
167- // logkf("sys_stat: stat %s\n", path);
168-
169- if (node == NULL ) {
170- free (path );
171- return SYSCALL_FAULT_ (ENOENT );
172- }
168+ static inline void vfs_fill_stat (vfs_node_t node , struct stat * buf ) {
173169 buf -> st_gid = (int )node -> group ;
174170 buf -> st_uid = (int )node -> owner ;
175171 buf -> st_ino = node -> inode ;
@@ -184,7 +180,30 @@ syscall_(stat, char *fn, struct stat *buf) {
184180 buf -> st_nlink = 1 ;
185181 buf -> st_dev = (long )node -> dev ;
186182 buf -> st_rdev = (long )node -> rdev ;
183+ }
184+
185+ syscall_ (stat , char * fn , struct stat * buf ) {
186+ if (unlikely (fn == NULL || buf == NULL )) return SYSCALL_FAULT_ (EINVAL );
187+ char * path = vfs_cwd_path_build (fn );
188+ vfs_node_t node = vfs_open (path );
189+
190+ if (node == NULL ) {
191+ free (path );
192+ return SYSCALL_FAULT_ (ENOENT );
193+ }
194+ vfs_fill_stat (node , buf );
195+ free (path );
196+ return EOK ;
197+ }
198+
199+ syscall_ (lstat , char * fn , struct stat * buf ) {
200+ if (unlikely (fn == NULL || buf == NULL )) return SYSCALL_FAULT_ (EINVAL );
201+ char * path = vfs_cwd_path_build (fn );
202+ vfs_node_t node = vfs_open_nofollow (path );
187203 free (path );
204+ if (node == NULL ) { return SYSCALL_FAULT_ (ENOENT ); }
205+ vfs_fill_stat (node , buf );
206+ vfs_close (node );
188207 return EOK ;
189208}
190209
@@ -435,7 +454,12 @@ syscall_(lseek, int fd, size_t offset, size_t whence) {
435454 if (real_offset < 0 && handle -> node -> type & file_none && whence != SEEK_CUR )
436455 return SYSCALL_FAULT_ (EBADF );
437456 switch (whence ) {
438- case SEEK_SET : handle -> offset = real_offset ; break ;
457+ case SEEK_SET :
458+ handle -> offset = real_offset ;
459+ if ((handle -> node -> type & file_dir ) && real_offset == 0 ) {
460+ handle -> dir_last = NULL ;
461+ }
462+ break ;
439463 case SEEK_CUR :
440464 handle -> offset += real_offset ;
441465 if ((int64_t )handle -> offset < 0 ) {
@@ -527,16 +551,23 @@ syscall_(rename, char *oldpath, char *newpath) {
527551}
528552
529553syscall_ (symlink , char * name , char * new ) {
554+ if (name == NULL || new == NULL ) return SYSCALL_FAULT_ (EINVAL );
530555 if (check_user_overflow ((uint64_t )name , strlen (name ))) { return SYSCALL_FAULT_ (EFAULT ); }
531- errno_t ret = vfs_symlink (name , new );
532- return ret ;
556+ if (check_user_overflow ((uint64_t )new , strlen (new ))) { return SYSCALL_FAULT_ (EFAULT ); }
557+ char * linkpath = vfs_cwd_path_build (new );
558+ errno_t ret = vfs_symlink (linkpath , name );
559+ free (linkpath );
560+ return ret < 0 ? SYSCALL_FAULT_ (- ret ) : ret ;
533561}
534562
535563syscall_ (link , char * name , char * new ) {
564+ if (name == NULL || new == NULL ) return SYSCALL_FAULT_ (EINVAL );
536565 if (check_user_overflow ((uint64_t )name , strlen (name ))) { return SYSCALL_FAULT_ (EFAULT ); }
537- errno_t ret = vfs_link (name , new );
538-
539- return ret ;
566+ if (check_user_overflow ((uint64_t )new , strlen (new ))) { return SYSCALL_FAULT_ (EFAULT ); }
567+ char * linkpath = vfs_cwd_path_build (new );
568+ errno_t ret = vfs_link (linkpath , name );
569+ free (linkpath );
570+ return ret < 0 ? SYSCALL_FAULT_ (- ret ) : ret ;
540571}
541572
542573syscall_ (select , int nfds , uint8_t * read , uint8_t * write , uint8_t * except ,
@@ -655,15 +686,28 @@ syscall_(getdents, int fd, struct dirent *dents, size_t size) {
655686 fd_t * handle = get_fd (get_current_task ()-> process -> fdts , fd );
656687 if (unlikely (handle == NULL )) { return SYSCALL_FAULT_ (EBADF ); }
657688 if (handle -> node -> type != file_dir ) { return SYSCALL_FAULT_ (ENOTDIR ); }
658- size_t child_count = (uint64_t )list_length (handle -> node -> child );
659689 size_t max_dents_num = size / sizeof (struct dirent );
660690 size_t read_count = 0 ;
661- uint64_t offset = 0 ;
662- list_foreach (handle -> node -> child , i ) {
663- if (offset < handle -> offset ) { goto next ; }
664- if (handle -> offset >= (child_count * sizeof (struct dirent ))) { break ; }
691+ if (max_dents_num == 0 ) { return 0 ; }
692+
693+ list_t start = handle -> node -> child ;
694+ if (handle -> dir_last ) {
695+ list_t cur = handle -> node -> child ;
696+ while (cur && cur -> data != handle -> dir_last ) {
697+ cur = cur -> next ;
698+ }
699+ if (cur ) {
700+ start = cur -> next ;
701+ } else {
702+ handle -> dir_last = NULL ;
703+ }
704+ }
705+
706+ for (list_t it = start ; it ; it = it -> next ) {
665707 if (read_count >= max_dents_num ) { break ; }
666- vfs_node_t child_node = (vfs_node_t )i -> data ;
708+ vfs_node_t child_node = (vfs_node_t )it -> data ;
709+ handle -> dir_last = child_node ;
710+ if (child_node -> type & file_delete ) { continue ; }
667711 dents [read_count ].d_ino = (long )child_node -> inode ;
668712 dents [read_count ].d_off = (long )handle -> offset ;
669713 dents [read_count ].d_reclen = sizeof (struct dirent );
@@ -685,15 +729,19 @@ syscall_(getdents, int fd, struct dirent *dents, size_t size) {
685729 strncpy (dents [read_count ].d_name , child_node -> name , 256 );
686730 handle -> offset += sizeof (struct dirent );
687731 read_count ++ ;
688- next :
689- offset += sizeof (struct dirent );
690732 }
691733 return read_count * sizeof (struct dirent );
692734}
693735
694736syscall_ (newfstatat , int dirfd , char * pathname , struct stat * buf , uint64_t flags ) {
695737 char * resolved = at_resolve_pathname (dirfd , pathname );
696- uint64_t ret = syscall_stat (resolved , buf , 0 , 0 , 0 , 0 , regs );
738+ if (resolved == NULL ) return SYSCALL_FAULT_ (ENOENT );
739+ uint64_t ret ;
740+ if (flags & AT_SYMLINK_NOFOLLOW ) {
741+ ret = syscall_lstat (resolved , buf , 0 , 0 , 0 , 0 , regs );
742+ } else {
743+ ret = syscall_stat (resolved , buf , 0 , 0 , 0 , 0 , regs );
744+ }
697745 free (resolved );
698746 return ret ;
699747}
@@ -810,40 +858,45 @@ syscall_(pipe, int *pipefd) {
810858syscall_ (unlink , char * name ) {
811859 if (name == NULL ) return SYSCALL_FAULT_ (EINVAL );
812860 char * npath = vfs_cwd_path_build (name );
813- vfs_node_t node = vfs_open (npath );
861+ vfs_node_t node = vfs_open_nofollow (npath );
814862 if (node == NULL ) return SYSCALL_FAULT_ (ENOENT );
815863 if (node -> type != file_none && node -> type != file_symlink ) {
816864 vfs_close (node );
817865 return SYSCALL_FAULT_ (ENOTDIR );
818866 }
819867
820- if (node -> refcount > 1 ) {
821- node -> refcount -- ;
822- free (npath );
823- return EOK ;
824- }
825868 size_t ret = vfs_delete (node ) == EOK ? EOK : SYSCALL_FAULT_ (ENOENT );
826- vfs_close (node );
869+ if (ret == EOK ) {
870+ errno_t c = vfs_close (node );
871+ if (c < 0 ) ret = SYSCALL_FAULT_ (- c );
872+ } else {
873+ vfs_close (node );
874+ }
827875 free (npath );
828876 return ret ;
829877}
830878
831879syscall_ (rmdir , char * name ) {
832880 if (name == NULL ) return SYSCALL_FAULT_ (EINVAL );
833881 char * n_name = vfs_cwd_path_build (name );
834- vfs_node_t node = vfs_open (n_name );
882+ vfs_node_t node = vfs_open_nofollow (n_name );
835883 if (node == NULL ) return SYSCALL_FAULT_ (ENOENT );
836884 if (node -> type != file_dir ) {
837885 vfs_close (node );
838886 free (n_name );
839887 return SYSCALL_FAULT_ (ENOTDIR );
840888 }
841- size_t ret ;
842- if (node -> refcount > 0 ) {
843- node -> refcount -- ;
844- ret = EOK ;
889+ if (node -> child != NULL ) {
890+ vfs_close (node );
891+ free (n_name );
892+ return SYSCALL_FAULT_ (ENOTEMPTY );
893+ }
894+ size_t ret = vfs_delete (node ) == EOK ? EOK : SYSCALL_FAULT_ (ENOENT );
895+ if (ret == EOK ) {
896+ errno_t c = vfs_close (node );
897+ if (c < 0 ) ret = SYSCALL_FAULT_ (- c );
845898 } else {
846- ret = vfs_delete (node );
899+ vfs_close (node );
847900 }
848901 free (n_name );
849902 return ret ;
@@ -868,8 +921,17 @@ syscall_(access, char *filename) {
868921
869922syscall_ (mkdir , char * name , uint64_t mode ) {
870923 if (name == NULL ) return SYSCALL_FAULT_ (EINVAL );
871- char * npath = vfs_cwd_path_build (name );
872- size_t ret = vfs_mkdir (npath ) == EOK ? EOK : -1 ;
924+ char * npath = vfs_cwd_path_build (name );
925+ size_t ret = vfs_mkdir (npath ) == EOK ? EOK : -1 ;
926+ if (ret == EOK ) {
927+ vfs_node_t node = vfs_open (npath );
928+ if (node ) {
929+ uint16_t final_mode = (uint16_t )(mode & 0777 );
930+ final_mode &= (uint16_t )~(get_current_task ()-> process -> umask & 0777 );
931+ vfs_chmod (node , final_mode );
932+ vfs_close (node );
933+ }
934+ }
873935 free (npath );
874936 return ret ;
875937}
@@ -878,13 +940,29 @@ syscall_(readlink, char *path, char *buf, uint64_t size) {
878940 if (path == NULL || buf == NULL || size == 0 ) { return SYSCALL_FAULT_ (EINVAL ); }
879941 if (check_user_overflow ((uint64_t )buf , size )) { return SYSCALL_FAULT_ (EFAULT ); }
880942
881- vfs_node_t node = vfs_open (path );
943+ char * npath = vfs_cwd_path_build (path );
944+ vfs_node_t node = vfs_open_nofollow (npath );
945+ free (npath );
882946 if (node == NULL ) { return SYSCALL_FAULT_ (ENOENT ); }
883947 if (!(node -> type & file_symlink )) return SYSCALL_FAULT_ (EINVAL );
884948
885949 return vfs_readlink (node , buf , (size_t )size );
886950}
887951
952+ syscall_ (chmod , char * path , uint64_t mode ) {
953+ if (unlikely (!path || check_user_overflow ((uint64_t )path , strlen (path )))) {
954+ return SYSCALL_FAULT_ (EFAULT );
955+ }
956+ char * npath = vfs_cwd_path_build (path );
957+ vfs_node_t node = vfs_open (npath );
958+ free (npath );
959+ if (node == NULL ) return SYSCALL_FAULT_ (ENOENT );
960+ errno_t ret = vfs_chmod (node , (uint16_t )(mode & 0777 ));
961+ vfs_close (node );
962+ if (ret < 0 ) return SYSCALL_FAULT_ (- ret );
963+ return EOK ;
964+ }
965+
888966syscall_ (sendfile , int out_fd , int in_fd , uint64_t * offset_ptr , size_t count ) {
889967 pcb_t process = get_current_task ()-> process ;
890968 fd_t * out_handle = get_fd (process -> fdts , out_fd );
@@ -934,6 +1012,13 @@ syscall_(sendfile, int out_fd, int in_fd, uint64_t *offset_ptr, size_t count) {
9341012 return total_sent ;
9351013}
9361014
1015+ syscall_ (umask , uint64_t mask ) {
1016+ pcb_t process = get_current_task ()-> process ;
1017+ uint16_t old = process -> umask ;
1018+ process -> umask = (uint16_t )(mask & 0777 );
1019+ return old ;
1020+ }
1021+
9371022syscall_ (openat , int dirfd , char * name , uint64_t flags , uint64_t mode ) {
9381023 if (unlikely (!name || check_user_overflow ((uint64_t )name , strlen (name )))) {
9391024 return SYSCALL_FAULT_ (EFAULT );
0 commit comments