Welcome to The Fiwix Project
A UNIX-like kernel for the i386 architecture
1 /* 2 * fiwix/kernel/syscalls/rename.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_rename(const char *oldpath, const char *newpath) 19 { 20 struct inode *i, *dir, *i_new, *dir_new; 21 char *tmp_oldpath, *tmp_newpath; 22 char *oldbasename, *newbasename; 23 int errno; 24 25 #ifdef __DEBUG__ 26 printk("(pid %d) sys_rename('%s', '%s')\n", current->pid, oldpath, newpath); 27 #endif /*__DEBUG__ */ 28 29 if((errno = malloc_name(oldpath, &tmp_oldpath)) < 0) { 30 return errno; 31 } 32 if((errno = namei(tmp_oldpath, &i, &dir, !FOLLOW_LINKS))) { 33 if(dir) { 34 iput(dir); 35 } 36 free_name(tmp_oldpath); 37 return errno; 38 } 39 if(IS_RDONLY_FS(i)) { 40 iput(i); 41 iput(dir); 42 free_name(tmp_oldpath); 43 return -EROFS; 44 } 45 46 if((errno = malloc_name(newpath, &tmp_newpath)) < 0) { 47 iput(i); 48 iput(dir); 49 free_name(tmp_oldpath); 50 return errno; 51 } 52 newbasename = remove_trailing_slash(tmp_newpath); 53 if((errno = namei(newbasename, &i_new, &dir_new, !FOLLOW_LINKS))) { 54 if(!dir_new) { 55 iput(i); 56 iput(dir); 57 free_name(tmp_oldpath); 58 free_name(tmp_newpath); 59 return errno; 60 } 61 } 62 if(dir->dev != dir_new->dev) { 63 errno = -EXDEV; 64 goto end; 65 } 66 newbasename = get_basename(newbasename); 67 if((newbasename[0] == '.' && newbasename[1] == NULL) || (newbasename[0] == '.' && newbasename[1] == '.' && newbasename[2] == NULL)) { 68 errno = -EINVAL; 69 goto end; 70 } 71 72 oldbasename = get_basename(tmp_oldpath); 73 oldbasename = remove_trailing_slash(oldbasename); 74 if((oldbasename[0] == '.' && oldbasename[1] == NULL) || (oldbasename[0] == '.' && oldbasename[1] == '.' && oldbasename[2] == NULL)) { 75 errno = -EINVAL; 76 goto end; 77 } 78 79 if(i_new) { 80 if(S_ISREG(i->i_mode)) { 81 if(S_ISDIR(i_new->i_mode)) { 82 errno = -EISDIR; 83 goto end; 84 } 85 } 86 if(S_ISDIR(i->i_mode)) { 87 if(!S_ISDIR(i_new->i_mode)) { 88 errno = -ENOTDIR; 89 goto end; 90 } 91 } 92 if(i->inode == i_new->inode) { 93 errno = 0; 94 goto end; 95 } 96 } 97 98 if(check_permission(TO_EXEC | TO_WRITE, dir_new) < 0) { 99 errno = -EACCES; 100 goto end; 101 } 102 103 if(dir_new->fsop && dir_new->fsop->rename) { 104 errno = dir_new->fsop->rename(i, dir, i_new, dir_new, oldbasename, newbasename); 105 } else { 106 errno = -EPERM; 107 } 108 109 end: 110 iput(i); 111 iput(dir); 112 iput(i_new); 113 iput(dir_new); 114 free_name(tmp_oldpath); 115 free_name(tmp_newpath); 116 return errno; 117 }