[syslinux:elflink] xfs: Add xfs_readlink()
syslinux-bot for Chen Baozi
baozich at gmail.com
Tue Nov 27 12:57:26 PST 2012
Commit-ID: 013e648cb3d715f671e5b656a6d5c3bbf73c5044
Gitweb: http://www.syslinux.org/commit/013e648cb3d715f671e5b656a6d5c3bbf73c5044
Author: Chen Baozi <baozich at gmail.com>
AuthorDate: Fri, 17 Aug 2012 07:06:13 +0800
Committer: Paulo Alcantara <pcacjr at zytor.com>
CommitDate: Sun, 2 Sep 2012 19:38:11 -0300
xfs: Add xfs_readlink()
XFS's symbolic links to a file can be stored in one of two formats:
"local" and "extents". The length of the symlink contents is always
specified by the inode's di_size value. A symlink cannot be longer
than 1024 characters.
Signed-off-by: Chen Baozi <baozich at gmail.com>
Signed-off-by: Paulo Alcantara <pcacjr at zytor.com>
---
core/fs/xfs/xfs.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++
core/fs/xfs/xfs.h | 1 +
core/fs/xfs/xfs_dir2.c | 12 ++++++++++++
core/fs/xfs/xfs_readdir.c | 2 ++
4 files changed, 63 insertions(+)
diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c
index 8dfdf13..bcb350d 100644
--- a/core/fs/xfs/xfs.c
+++ b/core/fs/xfs/xfs.c
@@ -259,6 +259,53 @@ out:
return NULL;
}
+static int xfs_readlink(struct inode *inode, char *buf)
+{
+ struct fs_info *fs = inode->fs;
+ xfs_dinode_t *core;
+ int pathlen = -1;
+ xfs_bmbt_irec_t rec;
+ block_t db;
+ char *dir_buf;
+
+ xfs_debug("in");
+
+ core = xfs_dinode_get_core(fs, inode->ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino 0x%llx)", inode->ino);
+ goto out;
+ }
+
+ pathlen = be64_to_cpu(core->di_size);
+ if (!pathlen)
+ goto out;
+
+ if (pathlen < 0 || pathlen > MAXPATHLEN) {
+ xfs_error("inode (%llu) bad symlink length (%ldd)",
+ inode->ino, pathlen);
+ goto out;
+ }
+
+ if (core->di_format == XFS_DINODE_FMT_LOCAL) {
+ memcpy(buf, (char *)&core->di_literal_area[0], pathlen);
+ } else if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+ bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+ db = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs);
+ dir_buf = xfs_dir2_get_dirblks(fs, db, rec.br_blockcount);
+
+ /*
+ * Syslinux only supports filesystem block size larger than 4K.
+ * Thus, one directory block is far enough to hold the maxium symbolic
+ * link file content, which is only 1024 bytes.
+ */
+ memcpy(buf, dir_buf, pathlen);
+ free(dir_buf);
+ }
+
+out:
+ return pathlen;
+}
+
static struct inode *xfs_iget_root(struct fs_info *fs)
{
xfs_dinode_t *core = NULL;
@@ -390,4 +437,5 @@ const struct fs_ops xfs_fs_ops = {
.readdir = xfs_readdir,
.iget = xfs_iget,
.next_extent = xfs_next_extent,
+ .readlink = xfs_readlink,
};
diff --git a/core/fs/xfs/xfs.h b/core/fs/xfs/xfs.h
index 0043cec..da57221 100644
--- a/core/fs/xfs/xfs.h
+++ b/core/fs/xfs/xfs.h
@@ -123,6 +123,7 @@ struct xfs_fs_info;
#define S_ISGID 0002000
#define S_ISVTX 0001000
+#define MAXPATHLEN 1024
/*
* NOTE: The fields in the superblock are stored in big-endian format on disk.
*/
diff --git a/core/fs/xfs/xfs_dir2.c b/core/fs/xfs/xfs_dir2.c
index 3b0d8c2..a7b121d 100644
--- a/core/fs/xfs/xfs_dir2.c
+++ b/core/fs/xfs/xfs_dir2.c
@@ -165,6 +165,9 @@ found:
inode->mode = DT_REG;
xfs_debug("Found a file inode!");
xfs_debug("inode size %llu", inode->size);
+ } else if (be16_to_cpu(ncore->di_mode) & S_IFLNK) {
+ inode->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
}
return inode;
@@ -264,6 +267,9 @@ found:
inode->mode = DT_REG;
xfs_debug("Found a file inode!");
xfs_debug("inode size %llu", inode->size);
+ } else if (be16_to_cpu(ncore->di_mode) & S_IFLNK) {
+ inode->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
}
xfs_debug("entry inode's number %lu", ino);
@@ -415,6 +421,9 @@ found:
ip->mode = DT_REG;
xfs_debug("Found a file inode!");
xfs_debug("inode size %llu", ip->size);
+ } else if (be16_to_cpu(ncore->di_mode) & S_IFLNK) {
+ ip->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
}
xfs_debug("entry inode's number %lu", ino);
@@ -729,6 +738,9 @@ found:
ip->mode = DT_REG;
xfs_debug("Found a file inode!");
xfs_debug("inode size %llu", ip->size);
+ } else if (be16_to_cpu(ncore->di_mode) & S_IFLNK) {
+ ip->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
}
xfs_debug("entry inode's number %lu", ino);
diff --git a/core/fs/xfs/xfs_readdir.c b/core/fs/xfs/xfs_readdir.c
index a3be247..0e013e5 100644
--- a/core/fs/xfs/xfs_readdir.c
+++ b/core/fs/xfs/xfs_readdir.c
@@ -49,6 +49,8 @@ static int fill_dirent(struct fs_info *fs, struct dirent *dirent,
dirent->d_type = DT_DIR;
else if (be16_to_cpu(core->di_mode) & S_IFREG)
dirent->d_type = DT_REG;
+ else if (be16_to_cpu(core->di_mode) & S_IFLNK)
+ dirent->d_type = DT_LNK;
memcpy(dirent->d_name, name, namelen + 1);
More information about the Syslinux-commits
mailing list