summaryrefslogtreecommitdiffstats
path: root/fs/ext2/symlink.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1994-11-28 11:59:19 +0000
committer <ralf@linux-mips.org>1994-11-28 11:59:19 +0000
commit1513ff9b7899ab588401c89db0e99903dbf5f886 (patch)
treef69cc81a940a502ea23d664c3ffb2d215a479667 /fs/ext2/symlink.c
Import of Linus's Linux 1.1.68
Diffstat (limited to 'fs/ext2/symlink.c')
-rw-r--r--fs/ext2/symlink.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
new file mode 100644
index 000000000..7d85ed74c
--- /dev/null
+++ b/fs/ext2/symlink.c
@@ -0,0 +1,127 @@
+/*
+ * linux/fs/ext2/symlink.c
+ *
+ * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/fs/minix/symlink.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * ext2 symlink handling code
+ */
+
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+
+static int ext2_readlink (struct inode *, char *, int);
+static int ext2_follow_link (struct inode *, struct inode *, int, int,
+ struct inode **);
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations ext2_symlink_inode_operations = {
+ NULL, /* no file-operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ ext2_readlink, /* readlink */
+ ext2_follow_link, /* follow_link */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL /* smap */
+};
+
+static int ext2_follow_link(struct inode * dir, struct inode * inode,
+ int flag, int mode, struct inode ** res_inode)
+{
+ int error;
+ struct buffer_head * bh = NULL;
+ char * link;
+
+ *res_inode = NULL;
+ if (!dir) {
+ dir = current->fs->root;
+ dir->i_count++;
+ }
+ if (!inode) {
+ iput (dir);
+ return -ENOENT;
+ }
+ if (!S_ISLNK(inode->i_mode)) {
+ iput (dir);
+ *res_inode = inode;
+ return 0;
+ }
+ if (current->link_count > 5) {
+ iput (dir);
+ iput (inode);
+ return -ELOOP;
+ }
+ if (inode->i_blocks) {
+ if (!(bh = ext2_bread (inode, 0, 0, &error))) {
+ iput (dir);
+ iput (inode);
+ return -EIO;
+ }
+ link = bh->b_data;
+ } else
+ link = (char *) inode->u.ext2_i.i_data;
+ current->link_count++;
+ error = open_namei (link, flag, mode, res_inode, dir);
+ current->link_count--;
+ iput (inode);
+ if (bh)
+ brelse (bh);
+ return error;
+}
+
+static int ext2_readlink (struct inode * inode, char * buffer, int buflen)
+{
+ struct buffer_head * bh = NULL;
+ char * link;
+ int i, err;
+ char c;
+
+ if (!S_ISLNK(inode->i_mode)) {
+ iput (inode);
+ return -EINVAL;
+ }
+ if (buflen > inode->i_sb->s_blocksize - 1)
+ buflen = inode->i_sb->s_blocksize - 1;
+ if (inode->i_blocks) {
+ bh = ext2_bread (inode, 0, 0, &err);
+ if (!bh) {
+ iput (inode);
+ return 0;
+ }
+ link = bh->b_data;
+ }
+ else
+ link = (char *) inode->u.ext2_i.i_data;
+ i = 0;
+ while (i < buflen && (c = link[i])) {
+ i++;
+ put_fs_byte (c, buffer++);
+ }
+ iput (inode);
+ if (bh)
+ brelse (bh);
+ return i;
+}