[syslinux:master] ntfs: implement ntfs_readdir()

syslinux-bot for Paulo Alcantara pcacjr at gmail.com
Sat Dec 17 21:19:22 PST 2011


Commit-ID:  bb57a2fbf93317d5aff31403cac38b2e73759fa8
Gitweb:     http://www.syslinux.org/commit/bb57a2fbf93317d5aff31403cac38b2e73759fa8
Author:     Paulo Alcantara <pcacjr at gmail.com>
AuthorDate: Wed, 20 Jul 2011 23:27:13 +0000
Committer:  Paulo Alcantara <pcacjr at gmail.com>
CommitDate: Wed, 7 Sep 2011 07:19:07 +0000

ntfs: implement ntfs_readdir()

Read one directory entry at one time.

Signed-off-by: Paulo Alcantara <pcacjr at gmail.com>

---
 core/fs/ntfs/ntfs.c |   86 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 85 insertions(+), 1 deletions(-)

diff --git a/core/fs/ntfs/ntfs.c b/core/fs/ntfs/ntfs.c
index ffd1d1f..30c81c2 100644
--- a/core/fs/ntfs/ntfs.c
+++ b/core/fs/ntfs/ntfs.c
@@ -600,6 +600,90 @@ index_err:
     goto out;
 }
 
+/*
+ * Convert an UTF-16LE longname to the system codepage; return
+ * the length on success or -1 on failure.
+ */
+static int ntfs_cvt_longname(char *entry_name, const uint16_t *long_name)
+{
+    struct unicache {
+        uint16_t utf16;
+        uint8_t cp;
+    };
+    static struct unicache unicache[256];
+    struct unicache *uc;
+    uint16_t cp;
+    unsigned int c;
+    char *p = entry_name;
+
+    do {
+        cp = *long_name++;
+        uc = &unicache[cp % 256];
+
+        if (__likely(uc->utf16 == cp)) {
+            *p++ = uc->cp;
+        } else {
+            for (c = 0; c < 512; c++) {
+                if (codepage.uni[0][c] == cp) {
+                    uc->utf16 = cp;
+                    *p++ = uc->cp = (uint8_t)c;
+                    goto found;
+                }
+            }
+
+            return -1;
+            found:
+                ;
+        }
+    } while (cp);
+
+    return (p - entry_name) - 1;
+}
+
+static int ntfs_readdir(struct file *file, struct dirent *dirent)
+{
+    struct fs_info *fs = file->fs;
+    struct inode *inode = file->inode;
+    MFT_RECORD *mrec;
+    sector_t block = 0;
+    ATTR_RECORD *attr;
+    FILE_NAME_ATTR *fn;
+    char filename[NTFS_MAX_FILE_NAME_LEN + 1];
+    int len;
+
+    mrec = mft_record_lookup(NTFS_PVT(inode)->mft_no, fs, &block);
+    if (!mrec) {
+        dprintf("No MFT record found!\n");
+        goto out;
+    }
+
+    attr = attr_lookup(NTFS_AT_FILENAME, mrec);
+    if (!attr) {
+        dprintf("No attribute found!\n");
+        goto out;
+    }
+
+    fn = (FILE_NAME_ATTR *)((uint8_t *)attr +
+                            attr->data.resident.value_offset);
+
+    len = ntfs_cvt_longname(filename, fn->file_name);
+    if (len < 0 || len != fn->file_name_len) {
+        dprintf("Failed on converting UTF-16LE LFN to OEM LFN\n");
+        goto out;
+    }
+
+    dirent->d_ino = NTFS_PVT(inode)->mft_no;
+    dirent->d_off = file->offset;
+    dirent->d_reclen = offsetof(struct dirent, d_name) + len + 1;
+    dirent->d_type = get_inode_mode(mrec);
+    memcpy(dirent->d_name, filename, len + 1);
+
+    return 0;
+
+out:
+    return -1;
+}
+
 static struct inode *ntfs_iget(const char *dname, struct inode *parent)
 {
     return index_lookup(dname, parent);
@@ -680,7 +764,7 @@ const struct fs_ops ntfs_fs_ops = {
     .close_file     = NULL,
     .mangle_name    = NULL,
     .load_config    = NULL,
-    .readdir        = NULL,
+    .readdir        = ntfs_readdir,
     .iget_root      = ntfs_iget_root,
     .iget           = ntfs_iget,
     .next_extent    = NULL,


More information about the Syslinux-commits mailing list