aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulo Alcantara <pcacjr@gmail.com>2011-07-27 01:35:36 +0000
committerPaulo Alcantara <pcacjr@gmail.com>2011-09-11 04:09:57 +0000
commit364a9f34bacbef821d894935a1f5564a4b3660f3 (patch)
treeeec7a8a3e8956bb25ded69ee95174b149bcdc768
parent93ada525f3ca9aead063096f0536dd84390e92a2 (diff)
downloadsyslinux-364a9f34bacbef821d894935a1f5564a4b3660f3.tar.gz
syslinux-364a9f34bacbef821d894935a1f5564a4b3660f3.tar.xz
syslinux-364a9f34bacbef821d894935a1f5564a4b3660f3.zip
ntfs: it's working, partially... :-/
My tests were: menu.c32 (worked), cat.32 (worked, ls.c32 (not worked). Looks like we have a bug in ntfs_readdir(). It will check it out later. Signed-off-by: Paulo Alcantara <pcacjr@gmail.com>
-rw-r--r--core/fs/ntfs/ntfs.c252
1 files changed, 132 insertions, 120 deletions
diff --git a/core/fs/ntfs/ntfs.c b/core/fs/ntfs/ntfs.c
index a69401e4..e1ba3e1e 100644
--- a/core/fs/ntfs/ntfs.c
+++ b/core/fs/ntfs/ntfs.c
@@ -61,44 +61,35 @@ static inline const void *get_right_block(struct fs_info *fs,
return get_cache(fs->fs_dev, NTFS_SB(fs)->mft_block + block);
}
-static int fixups_copyback(struct fs_info *fs, void *buf, NTFS_RECORD *nrec,
- uint64_t size)
+static int fixups_writeback(struct fs_info *fs, NTFS_RECORD *nrec)
{
- uint8_t *usa_start;
+ uint16_t *usa;
uint16_t usa_no;
- uint8_t *usa_end;
- unsigned sectors;
- uint64_t offset = 0;
- uint16_t *val;
- const unsigned byte_shift = 8;
+ uint16_t usa_count;
+ uint16_t *block;
if (nrec->magic != NTFS_MAGIC_FILE && nrec->magic != NTFS_MAGIC_INDX) {
- printf("Not a NTFS record\n");
+ printf("Not a valid NTFS record\n");
goto out;
}
- /* sectors per block */
- sectors = size >> SECTOR_SHIFT(fs);
-
- /* get the Update Sequence Array start address */
- usa_start = (uint8_t *)nrec + nrec->usa_ofs;
- /* get the Update Sequence Number */
- usa_no = *(uint16_t *)usa_start;
- /* get the Update Sequence Array end address */
- usa_end = usa_start + nrec->usa_count + 1;
+ /* get the Update Sequence Array offset */
+ usa = (uint16_t *)((uint8_t *)nrec + nrec->usa_ofs);
+ /* get the Update Sequence Array Number and skip it */
+ usa_no = *usa++;
+ /* get the Update Sequene Array count */
+ usa_count = nrec->usa_count - 1; /* exclude the USA number */
+ /* make it to point to the last two bytes of the RECORD's first sector */
+ block = (uint16_t *)((uint8_t *)nrec + SECTOR_SIZE(fs) - 2);
+
+ while (usa_count) {
+ if (*block != usa_no)
+ goto out;
- do {
- offset += SECTOR_SIZE(fs) - 2;
-
- val = (uint16_t *)((uint8_t *)buf + offset);
- /* compare it against the last two bytes of every sector */
- if (*val == usa_no) {
- if (usa_start < usa_end && usa_start + 1 < usa_end) {
- *val = *usa_start++;
- *val <<= byte_shift | *usa_start++;
- }
- }
- } while ((offset + SECTOR_SIZE(fs)) >> SECTOR_SHIFT(fs) < sectors);
+ *block = *usa++;
+ block = (uint16_t *)((uint8_t *)block + SECTOR_SIZE(fs));
+ usa_count--;
+ }
return 0;
@@ -113,16 +104,16 @@ static int64_t mft_record_lookup(uint32_t file, struct fs_info *fs,
const uint8_t *ret;
int err;
const uint64_t blk_size = UINT64_C(1) << BLOCK_SHIFT(fs);
- const uint64_t mft_record_size = NTFS_SB(fs)->mft_record_size;
MFT_RECORD *mrec;
goto jump_in;
for (;;) {
- err = fixups_copyback(fs, (uint8_t *)data + offset,
- (NTFS_RECORD *)data, mft_record_size);
- if (err)
+ err = fixups_writeback(fs, (NTFS_RECORD *)((uint8_t *)data + offset));
+ if (err) {
+ printf("Error in fixups_writeback()\n");
break;
+ }
mrec = (MFT_RECORD *)((uint8_t *)data + offset);
if (mrec->mft_record_no == file)
@@ -199,18 +190,6 @@ static bool ntfs_match_longname(const char *str, unsigned long mft_no,
len = fn->file_name_len;
match = fn->file_name;
- /*
- if (!strcmp("syslinux", str)) {
- const char *s = (const char *)fn->file_name;
- printf("Filename: ");
- while (*s) {
- printf("%c", *s);
- s += 2;
- }
- printf("\n");
- }
- */
-
while (len) {
cp = *match++;
len--;
@@ -253,6 +232,19 @@ struct mapping_chunk {
uint32_t flags; /* Specific flags of this chunk */
};
+static inline uint8_t *mapping_chunk_init(ATTR_RECORD *attr,
+ struct mapping_chunk *chunk,
+ uint32_t *offset)
+{
+ memset(chunk, 0, sizeof(*chunk));
+ chunk->cur_vcn = attr->data.non_resident.lowest_vcn;
+ chunk->cur_lcn = 0LL;
+
+ *offset = 0U;
+
+ return (uint8_t *)attr + attr->data.non_resident.mapping_pairs_offset;
+}
+
/* Parse data runs.
*
* return 0 on success or -1 on failure.
@@ -271,6 +263,8 @@ static int parse_data_run(const void *stream, uint32_t *offset,
uint8_t val;
int64_t res;
+ (void)attr_len;
+
chunk->flags &= ~MAP_MASK;
buf = (uint8_t *)stream + *offset;
@@ -411,7 +405,7 @@ static int index_inode_setup(struct fs_info *fs, unsigned long mft_no,
}
if (d_type == DT_DIR) { /* directory stuff */
- printf("Got a directory.\n");
+ dprintf("Got a directory.\n");
attr = attr_lookup(NTFS_AT_INDEX_ROOT, mrec);
if (!attr) {
dprintf("No attribute found!\n");
@@ -446,7 +440,7 @@ static int index_inode_setup(struct fs_info *fs, unsigned long mft_no,
NTFS_PVT(inode)->itype.index.vcn_size_shift = BLOCK_SHIFT(fs);
}
} else if (d_type == DT_REG) { /* file stuff */
- printf("Got a file.\n");
+ dprintf("Got a file.\n");
attr = attr_lookup(NTFS_AT_DATA, mrec);
if (!attr) {
dprintf("No attribute found!\n");
@@ -474,7 +468,7 @@ static int index_inode_setup(struct fs_info *fs, unsigned long mft_no,
for (;;) {
err = parse_data_run(stream, &droffset, attr_len, &chunk);
if (err) {
- printf("Non-resident $DATA attribute without any run\n");
+ printf("parse_data_run()\n");
goto out;
}
@@ -517,15 +511,18 @@ static struct inode *index_lookup(const char *dname, struct inode *dir)
INDEX_ROOT *ir;
uint32_t len;
INDEX_ENTRY *ie;
- uint8_t vcn_count;
uint8_t *ret;
INDEX_BLOCK *iblock;
- int64_t vcn;
+ int err;
uint8_t *stream;
uint8_t *attr_len;
struct mapping_chunk chunk;
uint32_t droffset;
- int err;
+ struct mapping_chunk *chunks;
+ unsigned chunks_count;
+ unsigned i;
+ int64_t vcn;
+ int64_t lcn;
struct inode *inode;
block = NTFS_PVT(dir)->start;
@@ -597,83 +594,105 @@ static struct inode *index_lookup(const char *dname, struct inode *dir)
attr_len = (uint8_t *)attr + attr->len;
- memset((void *)&chunk, 0, sizeof(chunk));
- chunk.cur_vcn = attr->data.non_resident.lowest_vcn;
- chunk.cur_lcn = 0LL;
+ stream = mapping_chunk_init(attr, &chunk, &droffset);
+ chunks_count = 0;
+ do {
+ err = parse_data_run(stream, &droffset, attr_len, &chunk);
+ if (err)
+ break;
- stream = (uint8_t *)attr + attr->data.non_resident.mapping_pairs_offset;
- droffset = 0U;
+ if (chunk.flags & MAP_UNALLOCATED)
+ continue;
- for (;;) {
+ if (chunk.flags & MAP_ALLOCATED)
+ chunks_count++;
+
+ } while (!(chunk.flags & MAP_END));
+
+ if (!chunks_count) {
+ printf("No data runs found, but claims non-resident attribute\n");
+ goto out;
+ }
+
+ chunks = malloc(chunks_count * sizeof *chunks);
+ if (!chunks)
+ malloc_error("mapping_chunk structure");
+
+ stream = mapping_chunk_init(attr, &chunk, &droffset);
+ i = 0;
+ do {
err = parse_data_run(stream, &droffset, attr_len, &chunk);
if (err)
- goto not_found;
+ break;
if (chunk.flags & MAP_UNALLOCATED)
continue;
- if (chunk.flags & MAP_END)
- break;
if (chunk.flags & MAP_ALLOCATED) {
- chunk.cur_lcn = 0x24de8;
- printf("%d cluster(s) starting at 0x%X\n", chunk.vcn_len,
+ dprintf("%d cluster(s) starting at 0x%X\n", chunk.vcn_len,
chunk.cur_lcn);
+ memcpy(&chunks[i++], &chunk, sizeof chunk);
+ }
- vcn_count = 0;
- vcn = chunk.cur_vcn; /* HUMMMMMMM!!!!! */
- while (vcn_count++ < chunk.vcn_len) {
- block = ((chunk.cur_lcn + vcn) << NTFS_SB(fs)->clust_shift) <<
- SECTOR_SHIFT(fs) >> BLOCK_SHIFT(fs);
+ } while (!(chunk.flags & MAP_END));
- ret = (uint8_t *)get_cache(fs->fs_dev, block);
- if (!ret) {
- printf("get_cache() returned NULL\n");
- goto not_found;
- }
+ i = 0;
+ while (chunks_count--) {
+ vcn = 0;
+ lcn = chunks[i].cur_lcn;
+ while (vcn < chunks[i].vcn_len) {
+ block = ((lcn + vcn) << NTFS_SB(fs)->clust_shift) <<
+ SECTOR_SHIFT(fs) >> BLOCK_SHIFT(fs);
- memcpy(data, ret, blk_size);
+ ret = (uint8_t *)get_cache(fs->fs_dev, block);
+ if (!ret) {
+ printf("get_cache() returned NULL\n");
+ goto not_found;
+ }
- err = fixups_copyback(fs, data, (NTFS_RECORD *)data, blk_size);
- if (err)
- goto not_found;
+ memcpy(data, ret, blk_size);
- iblock = (INDEX_BLOCK *)data;
- if (iblock->magic != NTFS_MAGIC_INDX) {
- printf("Not a valid INDX record\n");
- goto not_found;
- }
+ err = fixups_writeback(fs, (NTFS_RECORD *)&data[0]);
+ if (err) {
+ printf("Error in fixups_writeback()\n");
+ goto not_found;
+ }
- ie = (INDEX_ENTRY *)((uint8_t *)&iblock->index +
- iblock->index.entries_offset);
- for (;; ie = (INDEX_ENTRY *)((uint8_t *)ie + ie->len)) {
- /* bounds checks */
- if ((uint8_t *)ie < (uint8_t *)iblock || (uint8_t *)ie +
- sizeof(INDEX_ENTRY_HEADER) >
- (uint8_t *)&iblock->index + iblock->index.index_len ||
- (uint8_t *)ie + ie->len >
- (uint8_t *)&iblock->index + iblock->index.index_len)
- goto index_err;
-
- /* last entry cannot contain a key */
- if (ie->flags & INDEX_ENTRY_END)
- break;
-
- if (ntfs_match_longname(dname, ie->data.dir.indexed_file,
- fs)) {
- dprintf("Filename matches up!\n");
- dprintf("MFT record number = %d\n",
- ie->data.dir.indexed_file);
- goto found;
- }
- }
+ iblock = (INDEX_BLOCK *)&data[0];
+ if (iblock->magic != NTFS_MAGIC_INDX) {
+ printf("Not a valid INDX record\n");
+ goto not_found;
+ }
- ++vcn; /* go to the next VCN */
+ ie = (INDEX_ENTRY *)((uint8_t *)&iblock->index +
+ iblock->index.entries_offset);
+ for (;; ie = (INDEX_ENTRY *)((uint8_t *)ie + ie->len)) {
+ /* bounds checks */
+ if ((uint8_t *)ie < (uint8_t *)iblock || (uint8_t *)ie +
+ sizeof(INDEX_ENTRY_HEADER) >
+ (uint8_t *)&iblock->index + iblock->index.index_len ||
+ (uint8_t *)ie + ie->len >
+ (uint8_t *)&iblock->index + iblock->index.index_len)
+ goto index_err;
+
+ /* last entry cannot contain a key */
+ if (ie->flags & INDEX_ENTRY_END)
+ break;
+
+ if (ntfs_match_longname(dname, ie->data.dir.indexed_file, fs)) {
+ dprintf("Filename matches up!\n");
+ goto found;
+ }
}
+
+ vcn++; /* go to the next VCN */
}
+
+ i++; /* go to the next chunk */
}
not_found:
- dprintf("Index not found\n");
+ printf("Index not found\n");
out:
printf("%s not found!\n", dname);
@@ -782,7 +801,6 @@ static uint32_t ntfs_getfssec(struct file *file, char *buf, int sectors,
MFT_RECORD *mrec;
ATTR_RECORD *attr;
char *p;
- int err;
non_resident = NTFS_PVT(inode)->non_resident;
@@ -794,7 +812,7 @@ static uint32_t ntfs_getfssec(struct file *file, char *buf, int sectors,
dprintf("mft_no: %d\n", NTFS_PVT(inode)->mft_no);
offset = mft_record_lookup(NTFS_PVT(inode)->mft_no, fs, &block, &data);
if (offset < 0) {
- dprintf("No MFT record found!\n");
+ printf("No MFT record found!\n");
goto out;
}
@@ -802,19 +820,15 @@ static uint32_t ntfs_getfssec(struct file *file, char *buf, int sectors,
attr = attr_lookup(NTFS_AT_DATA, mrec);
if (!attr) {
- dprintf("No attribute found!\n");
+ printf("No attribute found!\n");
goto out;
}
- p = (char *)attr + attr->data.resident.value_offset;
+ p = (char *)((uint8_t *)attr + attr->data.resident.value_offset);
/* p now points to the data offset, so let's copy it into buf */
memcpy(buf, p, inode->size);
- err = fixups_copyback(fs, buf, (NTFS_RECORD *)mrec, inode->size);
- if (err)
- goto out;
-
ret = inode->size;
}
@@ -837,11 +851,9 @@ static int ntfs_readdir(struct file *file, struct dirent *dirent)
char filename[NTFS_MAX_FILE_NAME_LEN + 1];
int len;
- printf("in readdir()\n");
-
offset = mft_record_lookup(NTFS_PVT(inode)->mft_no, fs, &block, &data);
if (offset < 0) {
- dprintf("No MFT record found!\n");
+ printf("No MFT record found!\n");
goto out;
}
@@ -849,7 +861,7 @@ static int ntfs_readdir(struct file *file, struct dirent *dirent)
attr = attr_lookup(NTFS_AT_FILENAME, mrec);
if (!attr) {
- dprintf("No attribute found!\n");
+ printf("No attribute found!\n");
goto out;
}
@@ -858,7 +870,7 @@ static int ntfs_readdir(struct file *file, struct dirent *dirent)
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");
+ printf("Failed on converting UTF-16LE LFN to OEM LFN\n");
goto out;
}