diff options
author | Paulo Alcantara <pcacjr@gmail.com> | 2011-07-20 23:27:13 +0000 |
---|---|---|
committer | Paulo Alcantara <pcacjr@gmail.com> | 2011-09-07 07:19:07 +0000 |
commit | bb57a2fbf93317d5aff31403cac38b2e73759fa8 (patch) | |
tree | d1cfc40f36fb0a9d5ce0c18a4cf7eb9452d60bcf | |
parent | 67d3a82846f2029d24e2226be89e35848e5d78ba (diff) | |
download | syslinux-bb57a2fbf93317d5aff31403cac38b2e73759fa8.tar.gz syslinux-bb57a2fbf93317d5aff31403cac38b2e73759fa8.tar.xz syslinux-bb57a2fbf93317d5aff31403cac38b2e73759fa8.zip |
ntfs: implement ntfs_readdir()
Read one directory entry at one time.
Signed-off-by: Paulo Alcantara <pcacjr@gmail.com>
-rw-r--r-- | 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 ffd1d1fe..30c81c2c 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, |