Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | /* * linux/fs/umsdos/file.c * * Written 1992 by Jacques Gelinas * inspired from linux/fs/msdos/file.c Werner Almesberger * * Extended MS-DOS regular file handling primitives */ #include <linux/sched.h> #include <linux/fs.h> #include <linux/msdos_fs.h> #include <linux/errno.h> #include <linux/fcntl.h> #include <linux/stat.h> #include <linux/umsdos_fs.h> #include <linux/malloc.h> #include <asm/segment.h> #include <asm/system.h> #define PRINTK(x) #define Printk(x) printk x /* Read the data associate with the symlink. Return length read in buffer or a negative error code. */ static int umsdos_readlink_x ( struct inode *inode, char *buffer, int (*msdos_read)(struct inode *, struct file *, char *, int), int bufsiz) { int ret = inode->i_size; struct file filp; filp.f_pos = 0; filp.f_reada = 0; if (ret > bufsiz) ret = bufsiz; if ((*msdos_read) (inode, &filp, buffer,ret) != ret){ ret = -EIO; } return ret; } /* Follow a symbolic link chain by calling open_namei recursively until an inode is found. Return 0 if ok, or a negative error code if not. */ static int UMSDOS_follow_link( struct inode * dir, struct inode * inode, int flag, int mode, struct inode ** res_inode) { int ret = -ELOOP; *res_inode = NULL; if (current->link_count < 5) { char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL); if (path == NULL){ ret = -ENOMEM; }else{ if (!dir) { dir = current->fs[1].root; dir->i_count++; } if (!inode){ PRINTK (("symlink: inode = NULL\n")); ret = -ENOENT; }else if (!S_ISLNK(inode->i_mode)){ PRINTK (("symlink: Not ISLNK\n")); *res_inode = inode; inode = NULL; ret = 0; }else{ ret = umsdos_readlink_x (inode,path ,umsdos_file_read_kmem,PATH_MAX-1); if (ret > 0){ path[ret] = '\0'; PRINTK (("follow :%s: %d ",path,ret)); iput(inode); inode = NULL; current->link_count++; ret = open_namei(path,flag,mode,res_inode,dir); current->link_count--; dir = NULL; }else{ ret = -EIO; } } kfree (path); } } iput(inode); iput(dir); PRINTK (("follow_link ret %d\n",ret)); return ret; } static int UMSDOS_readlink(struct inode * inode, char * buffer, int buflen) { int ret = -EINVAL; if (S_ISLNK(inode->i_mode)) { ret = umsdos_readlink_x (inode,buffer,msdos_file_read,buflen); } PRINTK (("readlink %d %x bufsiz %d\n",ret,inode->i_mode,buflen)); iput(inode); return ret; } static struct file_operations umsdos_symlink_operations = { NULL, /* lseek - default */ NULL, /* read */ NULL, /* write */ NULL, /* readdir - bad */ NULL, /* select - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open is needed */ NULL, /* release */ NULL /* fsync */ }; struct inode_operations umsdos_symlink_inode_operations = { &umsdos_symlink_operations, /* default file operations */ NULL, /* create */ NULL, /* lookup */ NULL, /* link */ NULL, /* unlink */ NULL, /* symlink */ NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ UMSDOS_readlink, /* readlink */ UMSDOS_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ NULL /* permission */ }; |