Welcome to The Fiwix Project
Your small UNIX-like kernel
1 /* 2 * fiwix/fs/ext2/symlink.c 3 * 4 * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved. 5 * Distributed under the terms of the Fiwix License. 6 */ 7 8 #include <fiwix/types.h> 9 #include <fiwix/errno.h> 10 #include <fiwix/buffer.h> 11 #include <fiwix/fs.h> 12 #include <fiwix/filesystems.h> 13 #include <fiwix/stat.h> 14 #include <fiwix/mm.h> 15 #include <fiwix/stdio.h> 16 #include <fiwix/string.h> 17 18 struct fs_operations ext2_symlink_fsop = { 19 0, 20 0, 21 22 NULL, /* open */ 23 NULL, /* close */ 24 NULL, /* read */ 25 NULL, /* write */ 26 NULL, /* ioctl */ 27 NULL, /* lseek */ 28 NULL, /* readdir */ 29 NULL, /* mmap */ 30 NULL, /* select */ 31 32 ext2_readlink, 33 ext2_followlink, 34 NULL, /* bmap */ 35 NULL, /* lookup */ 36 NULL, /* rmdir */ 37 NULL, /* link */ 38 NULL, /* unlink */ 39 NULL, /* symlink */ 40 NULL, /* mkdir */ 41 NULL, /* mknod */ 42 NULL, /* truncate */ 43 NULL, /* create */ 44 NULL, /* rename */ 45 46 NULL, /* read_block */ 47 NULL, /* write_block */ 48 49 NULL, /* read_inode */ 50 NULL, /* write_inode */ 51 NULL, /* ialloc */ 52 NULL, /* ifree */ 53 NULL, /* statfs */ 54 NULL, /* read_superblock */ 55 NULL, /* remount_fs */ 56 NULL, /* write_superblock */ 57 NULL /* release_superblock */ 58 }; 59 60 int ext2_readlink(struct inode *i, char *buffer, __size_t count) 61 { 62 __u32 blksize; 63 struct buffer *buf; 64 65 if(!S_ISLNK(i->i_mode)) { 66 printk("%s(): Oops, inode '%d' is not a symlink (!?).\n", __FUNCTION__, i->inode); 67 return 0; 68 } 69 70 inode_lock(i); 71 blksize = i->sb->s_blocksize; 72 count = MIN(count, i->i_size); 73 if(!count) { 74 inode_unlock(i); 75 return 0; 76 } 77 count = MIN(count, blksize); 78 if(i->i_blocks) { /* slow symlink */ 79 if(!(buf = bread(i->dev, i->u.ext2.i_data[0], blksize))) { 80 inode_unlock(i); 81 return -EIO; 82 } 83 memcpy_b(buffer, buf->data, count); 84 brelse(buf); 85 } else { /* fast symlink */ 86 memcpy_b(buffer, (char *)i->u.ext2.i_data, count); 87 } 88 buffer[count] = 0; 89 inode_unlock(i); 90 return count; 91 } 92 93 int ext2_followlink(struct inode *dir, struct inode *i, struct inode **i_res) 94 { 95 struct buffer *buf; 96 char *name; 97 __ino_t errno; 98 99 if(!i) { 100 return -ENOENT; 101 } 102 103 if(!S_ISLNK(i->i_mode)) { 104 printk("%s(): Oops, inode '%d' is not a symlink (!?).\n", __FUNCTION__, i->inode); 105 return 0; 106 } 107 108 if(current->loopcnt > MAX_SYMLINKS) { 109 printk("%s(): too many nested symbolic links!\n", __FUNCTION__); 110 return -ELOOP; 111 } 112 113 inode_lock(i); 114 if(i->i_blocks) { /* slow symlink */ 115 if(!(buf = bread(i->dev, i->u.ext2.i_data[0], i->sb->s_blocksize))) { 116 inode_unlock(i); 117 return -EIO; 118 } 119 name = buf->data; 120 } else { /* fast symlink */ 121 buf = NULL; 122 name = (char *)i->u.ext2.i_data; 123 } 124 inode_unlock(i); 125 126 current->loopcnt++; 127 iput(i); 128 if(buf) { 129 brelse(buf); 130 } 131 errno = parse_namei(name, dir, i_res, NULL, FOLLOW_LINKS); 132 current->loopcnt--; 133 return errno; 134 }