Welcome to The Fiwix Project
A UNIX-like kernel for the i386 architecture
1 /* 2 * fiwix/kernel/syscalls/link.c 3 * 4 * Copyright 2018, Jordi Sanfeliu. All rights reserved. 5 * Distributed under the terms of the Fiwix License. 6 */ 7 8 #include <fiwix/fs.h> 9 #include <fiwix/stat.h> 10 #include <fiwix/errno.h> 11 #include <fiwix/string.h> 12 13 #ifdef __DEBUG__ 14 #include <fiwix/stdio.h> 15 #include <fiwix/process.h> 16 #endif /*__DEBUG__ */ 17 18 int sys_link(const char *oldname, const char *newname) 19 { 20 struct inode *i, *dir, *i_new, *dir_new; 21 char *tmp_oldname, *tmp_newname, *basename; 22 int errno; 23 24 #ifdef __DEBUG__ 25 printk("(pid %d) sys_link('%s', '%s')\n", current->pid, oldname, newname); 26 #endif /*__DEBUG__ */ 27 28 if((errno = malloc_name(oldname, &tmp_oldname)) < 0) { 29 return errno; 30 } 31 if((errno = malloc_name(newname, &tmp_newname)) < 0) { 32 free_name(tmp_oldname); 33 return errno; 34 } 35 36 if((errno = namei(tmp_oldname, &i, &dir, !FOLLOW_LINKS))) { 37 if(dir) { 38 iput(dir); 39 } 40 free_name(tmp_oldname); 41 free_name(tmp_newname); 42 return errno; 43 } 44 if(S_ISDIR(i->i_mode)) { 45 iput(i); 46 iput(dir); 47 free_name(tmp_oldname); 48 free_name(tmp_newname); 49 return -EPERM; 50 } 51 if(IS_RDONLY_FS(i)) { 52 iput(i); 53 iput(dir); 54 free_name(tmp_oldname); 55 free_name(tmp_newname); 56 return -EROFS; 57 } 58 if(i->i_nlink == LINK_MAX) { 59 iput(i); 60 iput(dir); 61 free_name(tmp_oldname); 62 free_name(tmp_newname); 63 return -EMLINK; 64 } 65 66 basename = get_basename(tmp_newname); 67 if((errno = namei(tmp_newname, &i_new, &dir_new, !FOLLOW_LINKS))) { 68 if(!dir_new) { 69 iput(i); 70 iput(dir); 71 free_name(tmp_oldname); 72 free_name(tmp_newname); 73 return errno; 74 } 75 } 76 if(!errno) { 77 iput(i); 78 iput(dir); 79 iput(i_new); 80 iput(dir_new); 81 free_name(tmp_oldname); 82 free_name(tmp_newname); 83 return -EEXIST; 84 } 85 if(i->dev != dir_new->dev) { 86 iput(i); 87 iput(dir); 88 iput(dir_new); 89 free_name(tmp_oldname); 90 free_name(tmp_newname); 91 return -EXDEV; 92 } 93 if(check_permission(TO_EXEC | TO_WRITE, dir_new) < 0) { 94 iput(i); 95 iput(dir); 96 iput(dir_new); 97 free_name(tmp_oldname); 98 free_name(tmp_newname); 99 return -EACCES; 100 } 101 102 if(dir_new->fsop && dir_new->fsop->link) { 103 errno = dir_new->fsop->link(i, dir_new, basename); 104 } else { 105 errno = -EPERM; 106 } 107 iput(i); 108 iput(dir); 109 iput(dir_new); 110 free_name(tmp_oldname); 111 free_name(tmp_newname); 112 return errno; 113 }