aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChen Baozi <baozich@gmail.com>2012-08-17 07:06:13 +0800
committerPaulo Alcantara <pcacjr@zytor.com>2012-09-02 19:38:11 -0300
commit013e648cb3d715f671e5b656a6d5c3bbf73c5044 (patch)
tree2ee53523f877e41169c4b0481c0f13efd0922f05
parent76db6d47b5262b4e0ba0ce4175a0a0cedf4513b3 (diff)
downloadsyslinux-013e648cb3d715f671e5b656a6d5c3bbf73c5044.tar.gz
syslinux-013e648cb3d715f671e5b656a6d5c3bbf73c5044.tar.xz
syslinux-013e648cb3d715f671e5b656a6d5c3bbf73c5044.zip
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@gmail.com> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
-rw-r--r--core/fs/xfs/xfs.c48
-rw-r--r--core/fs/xfs/xfs.h1
-rw-r--r--core/fs/xfs/xfs_dir2.c12
-rw-r--r--core/fs/xfs/xfs_readdir.c2
4 files changed, 63 insertions, 0 deletions
diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c
index 8dfdf137..bcb350d7 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 0043cec3..da57221a 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 3b0d8c2d..a7b121df 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 a3be247d..0e013e55 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);