Skip to content

Commit ef37d1b

Browse files
committed
修复 tmpfs vfs 文件删除和软链接问题, 新增 umask chmod 系统调用.
1 parent 7ad8dbe commit ef37d1b

File tree

11 files changed

+249
-47
lines changed

11 files changed

+249
-47
lines changed

src/arch/x86_64/include/nr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@
6363
#define SYSCALL_UNLINK 87
6464
#define SYSCALL_SYMLINK 88
6565
#define SYSCALL_READLINK 89
66+
#define SYSCALL_CHMOD 90
6667
#define SYSCALL_CHOWN 92
68+
#define SYSCALL_UMASK 95
6769
#define SYSCALL_GETRLIMIT 97
6870
#define SYSCALL_SYSINFO 99
6971
#define SYSCALL_GETUID 102

src/arch/x86_64/syscall.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,10 @@ syscall_t syscall_handlers[MAX_SYSCALLS] = {
167167
[SYSCALL_EXECVE] = (syscall_t)syscall_execve,
168168
[SYSCALL_VFORK] = (syscall_t)syscall_vfork,
169169
[SYSCALL_CLONE] = (syscall_t)syscall_clone,
170-
[SYSCALL_LSTAT] = (syscall_t)syscall_stat,
170+
[SYSCALL_LSTAT] = (syscall_t)syscall_lstat,
171171
[SYSCALL_SYSINFO] = (syscall_t)syscall_sysinfo,
172172
[SYSCALL_READLINK] = (syscall_t)syscall_readlink,
173+
[SYSCALL_CHMOD] = (syscall_t)syscall_chmod,
173174
[SYSCALL_SENDFILE] = (syscall_t)syscall_sendfile,
174175
[SYSCALL_OPENAT] = (syscall_t)syscall_openat,
175176
[SYSCALL_FACCESSAT] = (syscall_t)syscall_faccessat,
@@ -184,6 +185,7 @@ syscall_t syscall_handlers[MAX_SYSCALLS] = {
184185
[SYSCALL_SETITIMER] = (syscall_t)syscall_setitimer,
185186
[SYSCALL_KILL] = (syscall_t)syscall_kill,
186187
[SYSCALL_CHOWN] = (syscall_t)syscall_chown,
188+
[SYSCALL_UMASK] = (syscall_t)syscall_umask,
187189
[SYSCALL_UTIMENSAT] = (syscall_t)syscall_utimensat,
188190
[SYSCALL_FUTIMESAT] = (syscall_t)syscall_futimensat,
189191
};

src/fs/fds.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ fd_t *fd_dup(fd_t *src) {
8989
src->node->refcount++;
9090
new->node = src->node;
9191
new->offset = src->offset;
92+
new->dir_last = src->dir_last;
9293
new->flags = src->flags;
9394
new->fd = src->fd;
9495
vfs_node_t node = new->node;

src/fs/fssys.c

Lines changed: 128 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -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

529553
syscall_(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

535563
syscall_(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

542573
syscall_(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

694736
syscall_(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) {
810858
syscall_(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

831879
syscall_(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

869922
syscall_(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+
888966
syscall_(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+
9371022
syscall_(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);

src/fs/tmpfs.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,25 @@ errno_t tmpfs_symlink(void *parent, const char *name, vfs_node_t node) {
130130
return EOK;
131131
}
132132

133+
size_t tmpfs_readlink(vfs_node_t node, void *addr, size_t offset, size_t size) {
134+
if (node == NULL || addr == NULL || size == 0) return 0;
135+
const char *target = node->linkto_path;
136+
if (target == NULL && node->linkto != NULL) {
137+
target = vfs_get_fullpath(node->linkto);
138+
if (target == NULL) return 0;
139+
}
140+
size_t len = strlen(target);
141+
if (offset >= len) {
142+
if (target != node->linkto_path) free((void *)target);
143+
return 0;
144+
}
145+
size_t to_copy = len - offset;
146+
if (to_copy > size) to_copy = size;
147+
memcpy(addr, target + offset, to_copy);
148+
if (target != node->linkto_path) free((void *)target);
149+
return to_copy;
150+
}
151+
133152
errno_t tmpfs_free(void *handle) {
134153
if(handle == NULL) return EOK;
135154
tmpfs_file_t *file = handle;
@@ -187,7 +206,7 @@ static struct vfs_callback tmpfs_callbacks = {
187206
.open = tmpfs_open,
188207
.read = tmpfs_read,
189208
.write = tmpfs_write,
190-
.readlink = (vfs_readlink_t)dummy,
209+
.readlink = tmpfs_readlink,
191210
.mkfile = tmpfs_mkfile,
192211
.link = (vfs_mk_t)dummy,
193212
.symlink = tmpfs_symlink,

0 commit comments

Comments
 (0)