aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorPaulo Alcantara <pcacjr@gmail.com>2011-09-07 06:25:03 +0000
committerPaulo Alcantara <pcacjr@gmail.com>2011-09-11 04:09:59 +0000
commita0e388a0440a11a956f63b79b6c56e5b807ee950 (patch)
tree851bd01d1d923222bde68a9f2a9aa43659a5fdfe /core
parentd782f2a2aec66486a62d41dbd4bca3b95fa295a8 (diff)
downloadsyslinux-a0e388a0440a11a956f63b79b6c56e5b807ee950.tar.gz
syslinux-a0e388a0440a11a956f63b79b6c56e5b807ee950.tar.xz
syslinux-a0e388a0440a11a956f63b79b6c56e5b807ee950.zip
ntfs: use a runlist for handling multiple data runs
NTFS files can contain multiple data runs, so use a runlist for handling multiple data runs of a single file, and also modify ntfs_next_extent() in order to support this new feature. Signed-off-by: Paulo Alcantara <pcacjr@gmail.com>
Diffstat (limited to 'core')
-rw-r--r--core/fs/ntfs/ntfs.c58
-rw-r--r--core/fs/ntfs/ntfs.h10
-rw-r--r--core/fs/ntfs/runlist.h83
3 files changed, 128 insertions, 23 deletions
diff --git a/core/fs/ntfs/ntfs.c b/core/fs/ntfs/ntfs.c
index 14c275b9..95af54a2 100644
--- a/core/fs/ntfs/ntfs.c
+++ b/core/fs/ntfs/ntfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) Paulo Alcantara <pcacjr@gmail.com>
+ * Copyright (C) Paulo Alcantara <pcacjr@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,6 +33,7 @@
#include "codepage.h"
#include "ntfs.h"
+#include "runlist.h"
/* Check if there are specific zero fields in an NTFS boot sector */
static inline int ntfs_check_zero_fields(const struct ntfs_bpb *sb)
@@ -441,6 +442,7 @@ static int index_inode_setup(struct fs_info *fs, unsigned long mft_no,
attr_len = (uint8_t *)attr + attr->len;
stream = mapping_chunk_init(attr, &chunk, &offset);
+ NTFS_PVT(inode)->data.non_resident.rlist = NULL;
for (;;) {
err = parse_data_run(stream, &offset, attr_len, &chunk);
if (err) {
@@ -450,17 +452,22 @@ static int index_inode_setup(struct fs_info *fs, unsigned long mft_no,
if (chunk.flags & MAP_UNALLOCATED)
continue;
- if (chunk.flags & (MAP_ALLOCATED | MAP_END))
+ if (chunk.flags & MAP_END)
break;
+ if (chunk.flags & MAP_ALLOCATED) {
+ /* append new run to the runlist */
+ runlist_append(&NTFS_PVT(inode)->data.non_resident.rlist,
+ (struct runlist_element *)&chunk);
+ /* update for next VCN */
+ chunk.vcn += chunk.len;
+ }
}
- if (chunk.flags & MAP_END) {
- dprintf("No mapping found\n");
+ if (runlist_is_empty(NTFS_PVT(inode)->data.non_resident.rlist)) {
+ printf("No mapping found\n");
goto out;
}
- NTFS_PVT(inode)->data.non_resident.len = chunk.len;
- NTFS_PVT(inode)->data.non_resident.lcn = chunk.lcn;
inode->size = attr->data.non_resident.initialized_size;
}
}
@@ -689,26 +696,41 @@ static int ntfs_next_extent(struct inode *inode, uint32_t lstart)
{
struct fs_info *fs = inode->fs;
struct ntfs_sb_info *sbi = NTFS_SB(fs);
- uint32_t mcluster = lstart >> sbi->clust_shift;
- uint32_t tcluster;
- const uint32_t cluster_bytes = UINT32_C(1) << sbi->clust_byte_shift;
- sector_t pstart;
+ sector_t pstart = 0;
+ struct runlist *rlist;
+ struct runlist *ret;
const uint32_t sec_size = SECTOR_SIZE(fs);
const uint32_t sec_shift = SECTOR_SHIFT(fs);
- tcluster = (inode->size + cluster_bytes - 1) >> sbi->clust_byte_shift;
- if (mcluster >= tcluster)
- goto out; /* Requested cluster beyond end of file */
-
if (!NTFS_PVT(inode)->non_resident) {
- pstart = sbi->mft_blk + NTFS_PVT(inode)->here;
- pstart <<= BLOCK_SHIFT(fs) >> sec_shift;
+ pstart = (sbi->mft_blk + NTFS_PVT(inode)->here) << BLOCK_SHIFT(fs) >>
+ sec_shift;
+ inode->next_extent.len = (inode->size + sec_size - 1) >> sec_shift;
} else {
- pstart = NTFS_PVT(inode)->data.non_resident.lcn << sbi->clust_shift;
+ rlist = NTFS_PVT(inode)->data.non_resident.rlist;
+
+ if (!lstart || lstart >= NTFS_PVT(inode)->here) {
+ if (runlist_is_empty(rlist))
+ goto out; /* nothing to do ;-) */
+
+ ret = runlist_remove(&rlist);
+
+ NTFS_PVT(inode)->here =
+ ((ret->run.len << sbi->clust_byte_shift) >> sec_shift);
+
+ pstart = ret->run.lcn << sbi->clust_shift;
+ inode->next_extent.len =
+ ((ret->run.len << sbi->clust_byte_shift) + sec_size - 1) >>
+ sec_shift;
+
+ NTFS_PVT(inode)->data.non_resident.rlist = rlist;
+
+ free(ret);
+ ret = NULL;
+ }
}
inode->next_extent.pstart = pstart;
- inode->next_extent.len = (inode->size + sec_size - 1) >> sec_shift;
return 0;
diff --git a/core/fs/ntfs/ntfs.h b/core/fs/ntfs/ntfs.h
index 611ae3d9..6bd78ab5 100644
--- a/core/fs/ntfs/ntfs.h
+++ b/core/fs/ntfs/ntfs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) Paulo Alcantara <pcacjr@gmail.com>
+ * Copyright (C) Paulo Alcantara <pcacjr@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -82,8 +82,7 @@ struct ntfs_inode {
uint32_t offset; /* Data offset */
} resident;
struct { /* Used only if non_resident is set */
- uint64_t len;
- int64_t lcn; /* Logical Cluster Number offset */
+ struct runlist *rlist;
} non_resident;
} data;
union {
@@ -111,9 +110,10 @@ enum {
};
struct mapping_chunk {
+ uint64_t vcn;
+ int64_t lcn;
uint64_t len;
- int64_t lcn; /* Logical Cluster Number */
- uint32_t flags; /* Specific flags of this chunk */
+ uint32_t flags;
};
/* System defined attributes (32-bit)
diff --git a/core/fs/ntfs/runlist.h b/core/fs/ntfs/runlist.h
new file mode 100644
index 00000000..b74c7d85
--- /dev/null
+++ b/core/fs/ntfs/runlist.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) Paulo Alcantara <pcacjr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _RUNLIST_H_
+#define _RUNLIST_H_
+
+struct runlist_element {
+ uint64_t vcn;
+ int64_t lcn;
+ uint64_t len;
+};
+
+struct runlist {
+ struct runlist_element run;
+ struct runlist *next;
+};
+
+static struct runlist **tail;
+
+static inline bool runlist_is_empty(struct runlist *rlist)
+{
+ return !rlist;
+}
+
+static inline struct runlist *runlist_alloc(void)
+{
+ struct runlist *rlist;
+
+ rlist = malloc(sizeof *rlist);
+ if (!rlist)
+ malloc_error("runlist structure");
+
+ rlist->next = NULL;
+
+ return rlist;
+}
+
+static inline void runlist_append(struct runlist **rlist,
+ struct runlist_element *elem)
+{
+ struct runlist *n = runlist_alloc();
+
+ n->run = *elem;
+
+ if (runlist_is_empty(*rlist)) {
+ *rlist = n;
+ *tail = n;
+ } else {
+ (*tail)->next = n;
+ *tail = n;
+ }
+}
+
+static inline struct runlist *runlist_remove(struct runlist **rlist)
+{
+ struct runlist *ret;
+
+ if (runlist_is_empty(*rlist))
+ return NULL;
+
+ ret = *rlist;
+ *rlist = ret->next;
+
+ return ret;
+}
+
+#endif /* _RUNLIST_H_ */