diff options
author | Chen Baozi <baozich@gmail.com> | 2012-08-17 07:06:13 +0800 |
---|---|---|
committer | Paulo Alcantara <pcacjr@zytor.com> | 2012-09-02 19:38:11 -0300 |
commit | 013e648cb3d715f671e5b656a6d5c3bbf73c5044 (patch) | |
tree | 2ee53523f877e41169c4b0481c0f13efd0922f05 | |
parent | 76db6d47b5262b4e0ba0ce4175a0a0cedf4513b3 (diff) | |
download | syslinux-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.c | 48 | ||||
-rw-r--r-- | core/fs/xfs/xfs.h | 1 | ||||
-rw-r--r-- | core/fs/xfs/xfs_dir2.c | 12 | ||||
-rw-r--r-- | core/fs/xfs/xfs_readdir.c | 2 |
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); |