[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