/* * 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 */ #ifdef MODULE #include #endif #include #include #include #include #include #include #include #include #include #include #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, /* bmap */ NULL, /* truncate */ NULL /* permission */ };