/*
- * 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
#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)
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) {
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;
}
}
{
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;
/*
- * 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
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 {
};
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)
--- /dev/null
+/*
+ * 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_ */