summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErwan Velu <erwanaliasr1@gmail.com>2012-02-24 20:56:32 +0100
committerErwan Velu <erwanaliasr1@gmail.com>2012-02-24 20:56:32 +0100
commit02055a8310be4faf56040fee5713d24235d9786e (patch)
tree76f96a1f109a0c9614b877e5d06109e9f5c685a1
parent442c60166a9165e4253fd091aba92c04c699017d (diff)
parentd0564771471d41dce35d4c8b37ab6845930c3354 (diff)
downloadsyslinux-02055a8310be4faf56040fee5713d24235d9786e.tar.gz
Merge remote-tracking branch 'hpa/master'
-rw-r--r--NEWS2
-rw-r--r--com32/include/string.h2
-rw-r--r--com32/lib/strreplace.c44
-rw-r--r--core/bootsect.inc16
-rw-r--r--core/fs/ntfs/ntfs.c344
-rw-r--r--core/fs/ntfs/ntfs.h23
-rw-r--r--core/fs/ntfs/runlist.h2
-rw-r--r--core/ldlinux.asm4
-rw-r--r--[-rwxr-xr-x]extlinux/main.c147
-rwxr-xr-xwin32/find-mingw32.sh3
10 files changed, 431 insertions, 156 deletions
diff --git a/NEWS b/NEWS
index cbbd6d7d..a84b8901 100644
--- a/NEWS
+++ b/NEWS
@@ -3,7 +3,7 @@ or EXTLINUX apply to that specific program only; other changes apply
to all derivatives.
Changes in 4.06:
- * Support for NTFS, by Paulo Cezar.
+ * Support for NTFS, by Paulo Alcantara.
Changes in 4.05:
* HDT updated, and now supports uploading data to a TFTP
diff --git a/com32/include/string.h b/com32/include/string.h
index 014b8de9..d847440d 100644
--- a/com32/include/string.h
+++ b/com32/include/string.h
@@ -42,6 +42,6 @@ __extern char *strsep(char **, const char *);
__extern size_t strspn(const char *, const char *);
__extern char *strstr(const char *, const char *);
__extern char *strtok(char *, const char *);
-__extern char *strreplace( const char *string, const char *string_to_replace, const char *string_to_insert );
+__extern char *strreplace(const char *, const char *, const char *);
#endif /* _STRING_H */
diff --git a/com32/lib/strreplace.c b/com32/lib/strreplace.c
index 292b11da..d59efe0e 100644
--- a/com32/lib/strreplace.c
+++ b/com32/lib/strreplace.c
@@ -29,26 +29,30 @@
#include <string.h>
#include <stdlib.h>
-char *strreplace( const char *string, const char *string_to_replace, const char *string_to_insert ){
- char *token = NULL;
- char *output_buffer = NULL;
-
- token = strstr(string, string_to_replace);
-
- if(token == NULL)
- return strdup( string );
-
- output_buffer = malloc(strlen( string )-strlen( string_to_replace )+strlen(string_to_insert )+ 1);
-
- if(output_buffer == NULL)
+char *strreplace(const char *string, const char *string_to_replace,
+ const char *string_to_insert)
+{
+ char *token = NULL;
+ char *out = NULL;
+
+ size_t slen, srlen, silen;
+
+ token = strstr(string, string_to_replace);
+ if (!token)
+ return strdup(string);
+
+ slen = strlen(string);
+ srlen = strlen(string_to_replace);
+ silen = strlen(string_to_insert);
+
+ out = malloc(slen - srlen + silen + 1);
+ if (!out)
return NULL;
+
+ memcpy(out, string, token - string);
+ memcpy(out + (token - string), string_to_insert, silen);
+ memcpy(out + (token - string) + silen, token + srlen,
+ slen - srlen - (token - string) + 1);
- memcpy(output_buffer, string, token-string);
- memcpy(output_buffer + (token - string), string_to_insert, strlen(string_to_insert));
- memcpy(output_buffer + (token - string) + strlen(string_to_insert),
- token + strlen(string_to_replace),
- strlen(string) - strlen(string_to_replace) - (token - string));
- memset(output_buffer + strlen(string) - strlen(string_to_replace) + strlen(string_to_insert), 0, 1 );
-
- return output_buffer;
+ return out;
}
diff --git a/core/bootsect.inc b/core/bootsect.inc
index 6c204096..9e47e1a5 100644
--- a/core/bootsect.inc
+++ b/core/bootsect.inc
@@ -1,7 +1,7 @@
;; -----------------------------------------------------------------------
;;
;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
-;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;; Copyright 2009-2012 Intel Corporation; author: H. Peter Anvin
;;
;; 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
@@ -38,6 +38,7 @@ SuperSize equ $+1
load_bootsec:
mov edi,free_high_memory
mov [trackbuf+4],edi ; Copy from this address
+ mov eax,0xA0000 ; Maximum load
xor dx,dx ; No padding
mov bx,abort_check ; Don't print dots, but allow abort
call load_high
@@ -45,6 +46,9 @@ load_bootsec:
sub edi,free_high_memory
mov [trackbuf+8],edi ; Save length
+ cmp edi,0xA0000-7C00h
+ ja bs_too_big
+
mov eax,7C00h ; Entry point
mov [trackbuf],eax ; Copy to this address
@@ -237,3 +241,13 @@ replace_stub:
.csip equ $-4
section .text16
+bs_too_big:
+ call close
+ mov si,err_bs_too_big
+ jmp abort_load
+
+ section .data16
+err_bs_too_big db "Too large for a bootstrap (need LINUX instead of KERNEL?)"
+ db CR, LF, 0
+
+ section .text16
diff --git a/core/fs/ntfs/ntfs.c b/core/fs/ntfs/ntfs.c
index 9a0408d4..500d0fd3 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) 2011-2012 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
@@ -77,6 +77,8 @@ static void ntfs_fixups_writeback(struct fs_info *fs, struct ntfs_record *nrec)
uint16_t usa_count;
uint16_t *blk;
+ dprintf("in %s()\n", __func__);
+
if (nrec->magic != NTFS_MAGIC_FILE && nrec->magic != NTFS_MAGIC_INDX)
return;
@@ -112,6 +114,8 @@ static int ntfs_read(struct fs_info *fs, void *buf, size_t len, uint64_t count,
uint64_t loffset;
uint64_t k;
+ dprintf("in %s()\n", __func__);
+
if (count > len)
goto out;
@@ -188,6 +192,8 @@ static struct ntfs_mft_record *ntfs_mft_record_lookup_3_0(struct fs_info *fs,
int err;
struct ntfs_mft_record *mrec;
+ dprintf("in %s()\n", __func__);
+
buf = (uint8_t *)malloc(mft_record_size);
if (!buf)
malloc_error("uint8_t *");
@@ -201,7 +207,7 @@ static struct ntfs_mft_record *ntfs_mft_record_lookup_3_0(struct fs_info *fs,
err = ntfs_read(fs, buf, mft_record_size, mft_record_size, &right_blk,
&offset, &next_offset, &lcn);
if (err) {
- printf("Error on reading from cache.\n");
+ printf("Error while reading from cache.\n");
break;
}
@@ -248,6 +254,8 @@ static struct ntfs_mft_record *ntfs_mft_record_lookup_3_1(struct fs_info *fs,
int err;
struct ntfs_mft_record *mrec;
+ dprintf("in %s()\n", __func__);
+
buf = (uint8_t *)malloc(mft_record_size);
if (!buf)
malloc_error("uint8_t *");
@@ -260,7 +268,7 @@ static struct ntfs_mft_record *ntfs_mft_record_lookup_3_1(struct fs_info *fs,
err = ntfs_read(fs, buf, mft_record_size, mft_record_size, &right_blk,
&offset, &next_offset, &lcn);
if (err) {
- printf("Error on reading from cache.\n");
+ printf("Error while reading from cache.\n");
break;
}
@@ -291,34 +299,14 @@ static struct ntfs_mft_record *ntfs_mft_record_lookup_3_1(struct fs_info *fs,
return NULL;
}
-static struct ntfs_attr_record *ntfs_attr_lookup(uint32_t type,
- const struct ntfs_mft_record *mrec)
-{
- struct ntfs_attr_record *attr;
-
- /* sanity check */
- if (!mrec || type == NTFS_AT_END)
- return NULL;
-
- attr = (struct ntfs_attr_record *)((uint8_t *)mrec + mrec->attrs_offset);
- /* walk through the file attribute records */
- for (;; attr = (struct ntfs_attr_record *)((uint8_t *)attr + attr->len)) {
- if (attr->type == NTFS_AT_END)
- return NULL;
-
- if (attr->type == type)
- break;
- }
-
- return attr;
-}
-
static bool ntfs_filename_cmp(const char *dname, struct ntfs_idx_entry *ie)
{
const uint16_t *entry_fn;
uint8_t entry_fn_len;
unsigned i;
+ dprintf("in %s()\n", __func__);
+
entry_fn = ie->key.file_name.file_name;
entry_fn_len = ie->key.file_name.file_name_len;
@@ -369,6 +357,8 @@ static int parse_data_run(const void *stream, uint32_t *offset,
(void)attr_len;
+ dprintf("in %s()\n", __func__);
+
chunk->flags &= ~MAP_MASK;
buf = (uint8_t *)stream + *offset;
@@ -425,6 +415,204 @@ out:
return -1;
}
+static struct ntfs_mft_record *
+ntfs_attr_list_lookup(struct fs_info *fs, struct ntfs_attr_record *attr,
+ uint32_t type, struct ntfs_mft_record *mrec)
+{
+ uint8_t *attr_len;
+ struct mapping_chunk chunk;
+ uint32_t offset;
+ uint8_t *stream;
+ int err;
+ const uint64_t blk_size = UINT64_C(1) << BLOCK_SHIFT(fs);
+ uint8_t buf[blk_size];
+ uint64_t blk_offset;
+ int64_t vcn;
+ int64_t lcn;
+ int64_t last_lcn;
+ block_t blk;
+ struct ntfs_attr_list_entry *attr_entry;
+ uint32_t len = 0;
+ struct ntfs_mft_record *retval;
+ uint64_t start_blk = 0;
+
+ dprintf("in %s()\n", __func__);
+
+ if (attr->non_resident)
+ goto handle_non_resident_attr;
+
+ attr_entry = (struct ntfs_attr_list_entry *)
+ ((uint8_t *)attr + attr->data.resident.value_offset);
+ len = attr->data.resident.value_len;
+ for (; (uint8_t *)attr_entry < (uint8_t *)attr + len;
+ attr_entry = (struct ntfs_attr_list_entry *)((uint8_t *)attr_entry +
+ attr_entry->length)) {
+ dprintf("<$ATTRIBUTE_LIST> Attribute type: 0x%X\n",
+ attr_entry->type);
+ if (attr_entry->type == type)
+ goto found; /* We got the attribute! :-) */
+ }
+
+ printf("No attribute found.\n");
+ goto out;
+
+handle_non_resident_attr:
+ attr_len = (uint8_t *)attr + attr->len;
+ stream = mapping_chunk_init(attr, &chunk, &offset);
+ do {
+ err = parse_data_run(stream, &offset, attr_len, &chunk);
+ if (err) {
+ printf("parse_data_run()\n");
+ goto out;
+ }
+
+ if (chunk.flags & MAP_UNALLOCATED)
+ continue;
+ if (chunk.flags & MAP_END)
+ break;
+ if (chunk.flags & MAP_ALLOCATED) {
+ vcn = 0;
+ lcn = chunk.lcn;
+ while (vcn < chunk.len) {
+ blk = (lcn + vcn) << NTFS_SB(fs)->clust_byte_shift >>
+ BLOCK_SHIFT(fs);
+ blk_offset = 0;
+ last_lcn = lcn;
+ lcn += vcn;
+ err = ntfs_read(fs, buf, blk_size, blk_size, &blk,
+ &blk_offset, NULL, (uint64_t *)&lcn);
+ if (err) {
+ printf("Error while reading from cache.\n");
+ goto out;
+ }
+
+ attr_entry = (struct ntfs_attr_list_entry *)&buf;
+ len = attr->data.non_resident.data_size;
+ for (; (uint8_t *)attr_entry < (uint8_t *)&buf[0] + len;
+ attr_entry = (struct ntfs_attr_list_entry *)
+ ((uint8_t *)attr_entry + attr_entry->length)) {
+ dprintf("<$ATTRIBUTE_LIST> Attribute type: 0x%x\n",
+ attr_entry->type);
+ if (attr_entry->type == type)
+ goto found; /* We got the attribute! :-) */
+ }
+
+ lcn = last_lcn; /* restore original LCN */
+ /* go to the next VCN */
+ vcn += (blk_size / (1 << NTFS_SB(fs)->clust_byte_shift));
+ }
+ }
+ } while (!(chunk.flags & MAP_END));
+
+ printf("No attribute found.\n");
+
+out:
+ return NULL;
+
+found:
+ /* At this point we have the attribute we were looking for. Now we
+ * will look for the MFT record that stores information about this
+ * attribute.
+ */
+
+ /* Check if the attribute type we're looking for is in the same
+ * MFT record. If so, we do not need to look it up again - return it.
+ */
+ if (mrec->mft_record_no == attr_entry->mft_ref)
+ return mrec;
+
+ retval = NTFS_SB(fs)->mft_record_lookup(fs, attr_entry->mft_ref,
+ &start_blk);
+ if (!retval) {
+ printf("No MFT record found!\n");
+ goto out;
+ }
+
+ /* return the found MFT record */
+ return retval;
+}
+
+static struct ntfs_attr_record *
+__ntfs_attr_lookup(struct fs_info *fs, uint32_t type,
+ struct ntfs_mft_record **mrec)
+{
+ struct ntfs_mft_record *_mrec = *mrec;
+ struct ntfs_attr_record *attr;
+ struct ntfs_attr_record *attr_list_attr;
+
+ dprintf("in %s()\n", __func__);
+
+ if (!_mrec || type == NTFS_AT_END)
+ goto out;
+
+again:
+ attr_list_attr = NULL;
+
+ attr = (struct ntfs_attr_record *)((uint8_t *)_mrec + _mrec->attrs_offset);
+ /* walk through the file attribute records */
+ for (;; attr = (struct ntfs_attr_record *)((uint8_t *)attr + attr->len)) {
+ if (attr->type == NTFS_AT_END)
+ break;
+
+ if (attr->type == NTFS_AT_ATTR_LIST) {
+ dprintf("MFT record #%lu has an $ATTRIBUTE_LIST attribute.\n",
+ _mrec->mft_record_no);
+ attr_list_attr = attr;
+ continue;
+ }
+
+ if (attr->type == type)
+ break;
+ }
+
+ /* if the record has an $ATTRIBUTE_LIST attribute associated
+ * with it, then we need to look for the wanted attribute in
+ * it as well.
+ */
+ if (attr->type == NTFS_AT_END && attr_list_attr) {
+ struct ntfs_mft_record *retval;
+
+ retval = ntfs_attr_list_lookup(fs, attr_list_attr, type, _mrec);
+ if (!retval)
+ goto out;
+
+ _mrec = retval;
+ goto again;
+ } else if (attr->type == NTFS_AT_END && !attr_list_attr) {
+ attr = NULL;
+ }
+
+ return attr;
+
+out:
+ return NULL;
+}
+
+static inline struct ntfs_attr_record *
+ntfs_attr_lookup(struct fs_info *fs, uint32_t type,
+ struct ntfs_mft_record **mmrec,
+ struct ntfs_mft_record *mrec)
+{
+ struct ntfs_mft_record *_mrec = mrec;
+ struct ntfs_mft_record *other = *mmrec;
+ struct ntfs_attr_record *retval = NULL;
+
+ if (mrec == other)
+ return __ntfs_attr_lookup(fs, type, &other);
+
+ retval = __ntfs_attr_lookup(fs, type, &_mrec);
+ if (!retval) {
+ _mrec = other;
+ retval = __ntfs_attr_lookup(fs, type, &other);
+ if (!retval)
+ other = _mrec;
+ } else if (retval && (_mrec != mrec)) {
+ other = _mrec;
+ }
+
+ return retval;
+}
+
static inline enum dirent_type get_inode_mode(struct ntfs_mft_record *mrec)
{
return mrec->flags & MFT_RECORD_IS_DIRECTORY ? DT_DIR : DT_REG;
@@ -434,23 +622,25 @@ static int index_inode_setup(struct fs_info *fs, unsigned long mft_no,
struct inode *inode)
{
uint64_t start_blk = 0;
- struct ntfs_mft_record *mrec;
+ struct ntfs_mft_record *mrec, *lmrec;
struct ntfs_attr_record *attr;
enum dirent_type d_type;
- uint32_t len;
- struct ntfs_idx_root *ir;
uint8_t *attr_len;
struct mapping_chunk chunk;
int err;
uint8_t *stream;
uint32_t offset;
+ dprintf("in %s()\n", __func__);
+
mrec = NTFS_SB(fs)->mft_record_lookup(fs, mft_no, &start_blk);
if (!mrec) {
printf("No MFT record found.\n");
goto out;
}
+ lmrec = mrec;
+
NTFS_PVT(inode)->mft_no = mft_no;
NTFS_PVT(inode)->seq_no = mrec->seq_no;
@@ -460,22 +650,12 @@ static int index_inode_setup(struct fs_info *fs, unsigned long mft_no,
d_type = get_inode_mode(mrec);
if (d_type == DT_DIR) { /* directory stuff */
dprintf("Got a directory.\n");
- attr = ntfs_attr_lookup(NTFS_AT_INDEX_ROOT, mrec);
+ attr = ntfs_attr_lookup(fs, NTFS_AT_INDEX_ROOT, &mrec, lmrec);
if (!attr) {
printf("No attribute found.\n");
goto out;
}
- /* note: struct ntfs_idx_root is always resident */
- ir = (struct ntfs_idx_root *)((uint8_t *)attr +
- attr->data.resident.value_offset);
- len = attr->data.resident.value_len;
- if ((uint8_t *)ir + len > (uint8_t *)mrec +
- NTFS_SB(fs)->mft_record_size) {
- printf("Corrupt index.\n");
- goto out;
- }
-
/* check if we have a previous allocated state structure */
if (readdir_state) {
free(readdir_state);
@@ -492,7 +672,7 @@ static int index_inode_setup(struct fs_info *fs, unsigned long mft_no,
readdir_state->in_idx_root = true;
} else if (d_type == DT_REG) { /* file stuff */
dprintf("Got a file.\n");
- attr = ntfs_attr_lookup(NTFS_AT_DATA, mrec);
+ attr = ntfs_attr_lookup(fs, NTFS_AT_DATA, &mrec, lmrec);
if (!attr) {
printf("No attribute found.\n");
goto out;
@@ -554,12 +734,11 @@ out:
static struct inode *ntfs_index_lookup(const char *dname, struct inode *dir)
{
struct fs_info *fs = dir->fs;
- struct ntfs_mft_record *mrec;
+ struct ntfs_mft_record *mrec, *lmrec;
block_t blk;
uint64_t blk_offset;
struct ntfs_attr_record *attr;
struct ntfs_idx_root *ir;
- uint32_t len;
struct ntfs_idx_entry *ie;
const uint64_t blk_size = UINT64_C(1) << BLOCK_SHIFT(fs);
uint8_t buf[blk_size];
@@ -574,13 +753,16 @@ static struct inode *ntfs_index_lookup(const char *dname, struct inode *dir)
int64_t last_lcn;
struct inode *inode;
+ dprintf("in %s()\n", __func__);
+
mrec = NTFS_SB(fs)->mft_record_lookup(fs, NTFS_PVT(dir)->mft_no, NULL);
if (!mrec) {
printf("No MFT record found.\n");
goto out;
}
- attr = ntfs_attr_lookup(NTFS_AT_INDEX_ROOT, mrec);
+ lmrec = mrec;
+ attr = ntfs_attr_lookup(fs, NTFS_AT_INDEX_ROOT, &mrec, lmrec);
if (!attr) {
printf("No attribute found.\n");
goto out;
@@ -588,11 +770,6 @@ static struct inode *ntfs_index_lookup(const char *dname, struct inode *dir)
ir = (struct ntfs_idx_root *)((uint8_t *)attr +
attr->data.resident.value_offset);
- len = attr->data.resident.value_len;
- /* sanity check */
- if ((uint8_t *)ir + len > (uint8_t *)mrec + NTFS_SB(fs)->mft_record_size)
- goto index_err;
-
ie = (struct ntfs_idx_entry *)((uint8_t *)&ir->index +
ir->index.entries_offset);
for (;; ie = (struct ntfs_idx_entry *)((uint8_t *)ie + ie->len)) {
@@ -622,7 +799,7 @@ static struct inode *ntfs_index_lookup(const char *dname, struct inode *dir)
/* then descend into child node */
- attr = ntfs_attr_lookup(NTFS_AT_INDEX_ALLOCATION, mrec);
+ attr = ntfs_attr_lookup(fs, NTFS_AT_INDEX_ALLOCATION, &mrec, lmrec);
if (!attr) {
printf("No attribute found.\n");
goto out;
@@ -659,7 +836,7 @@ static struct inode *ntfs_index_lookup(const char *dname, struct inode *dir)
err = ntfs_read(fs, &buf, blk_size, blk_size, &blk,
&blk_offset, NULL, (uint64_t *)&lcn);
if (err) {
- printf("Error on reading from cache.\n");
+ printf("Error while reading from cache.\n");
goto not_found;
}
@@ -687,16 +864,6 @@ static struct inode *ntfs_index_lookup(const char *dname, struct inode *dir)
if (ie->flags & INDEX_ENTRY_END)
break;
- /* Do case-sensitive compares for Posix file names */
- if (ie->key.file_name.file_name_type == FILE_NAME_POSIX) {
- if (ie->key.file_name.file_name[0] > *dname)
- break;
- } else {
- if (tolower(ie->key.file_name.file_name[0]) >
- tolower(*dname))
- break;
- }
-
if (ntfs_filename_cmp(dname, ie))
goto found;
}
@@ -712,8 +879,6 @@ not_found:
dprintf("Index not found\n");
out:
- dprintf("%s not found!\n", dname);
-
free(mrec);
return NULL;
@@ -728,8 +893,6 @@ found:
goto out;
}
- dprintf("%s found!\n", dname);
-
free(mrec);
return inode;
@@ -768,6 +931,8 @@ static int ntfs_next_extent(struct inode *inode, uint32_t lstart)
const uint32_t sec_size = SECTOR_SIZE(fs);
const uint32_t sec_shift = SECTOR_SHIFT(fs);
+ dprintf("in %s()\n", __func__);
+
if (!NTFS_PVT(inode)->non_resident) {
pstart = (sbi->mft_blk + NTFS_PVT(inode)->here) << BLOCK_SHIFT(fs) >>
sec_shift;
@@ -811,10 +976,12 @@ static uint32_t ntfs_getfssec(struct file *file, char *buf, int sectors,
uint32_t ret;
struct fs_info *fs = file->fs;
struct inode *inode = file->inode;
- struct ntfs_mft_record *mrec;
+ struct ntfs_mft_record *mrec, *lmrec;
struct ntfs_attr_record *attr;
char *p;
+ dprintf("in %s()\n", __func__);
+
non_resident = NTFS_PVT(inode)->non_resident;
ret = generic_getfssec(file, buf, sectors, have_more);
@@ -823,13 +990,14 @@ static uint32_t ntfs_getfssec(struct file *file, char *buf, int sectors,
if (!non_resident) {
mrec = NTFS_SB(fs)->mft_record_lookup(fs, NTFS_PVT(inode)->mft_no,
- NULL);
+ NULL);
if (!mrec) {
printf("No MFT record found.\n");
goto out;
}
- attr = ntfs_attr_lookup(NTFS_AT_DATA, mrec);
+ lmrec = mrec;
+ attr = ntfs_attr_lookup(fs, NTFS_AT_DATA, &mrec, lmrec);
if (!attr) {
printf("No attribute found.\n");
goto out;
@@ -862,7 +1030,7 @@ static int ntfs_readdir(struct file *file, struct dirent *dirent)
{
struct fs_info *fs = file->fs;
struct inode *inode = file->inode;
- struct ntfs_mft_record *mrec;
+ struct ntfs_mft_record *mrec, *lmrec;
block_t blk;
uint64_t blk_offset;
const uint64_t blk_size = UINT64_C(1) << BLOCK_SHIFT(fs);
@@ -882,13 +1050,16 @@ static int ntfs_readdir(struct file *file, struct dirent *dirent)
int64_t lcn;
char filename[NTFS_MAX_FILE_NAME_LEN + 1];
+ dprintf("in %s()\n", __func__);
+
mrec = NTFS_SB(fs)->mft_record_lookup(fs, NTFS_PVT(inode)->mft_no, NULL);
if (!mrec) {
printf("No MFT record found.\n");
goto out;
}
- attr = ntfs_attr_lookup(NTFS_AT_INDEX_ROOT, mrec);
+ lmrec = mrec;
+ attr = ntfs_attr_lookup(fs, NTFS_AT_INDEX_ROOT, &mrec, lmrec);
if (!attr) {
printf("No attribute found.\n");
goto out;
@@ -896,10 +1067,6 @@ static int ntfs_readdir(struct file *file, struct dirent *dirent)
ir = (struct ntfs_idx_root *)((uint8_t *)attr +
attr->data.resident.value_offset);
- len = attr->data.resident.value_len;
- /* sanity check */
- if ((uint8_t *)ir + len > (uint8_t *)mrec + NTFS_SB(fs)->mft_record_size)
- goto index_err;
if (!file->offset && readdir_state->in_idx_root) {
file->offset = (uint32_t)((uint8_t *)&ir->index +
@@ -930,7 +1097,7 @@ descend_into_child_node:
if (!(ie->flags & INDEX_ENTRY_NODE))
goto out;
- attr = ntfs_attr_lookup(NTFS_AT_INDEX_ALLOCATION, mrec);
+ attr = ntfs_attr_lookup(fs, NTFS_AT_INDEX_ALLOCATION, &mrec, lmrec);
if (!attr)
goto out;
@@ -947,7 +1114,7 @@ next_run:
while (count--) {
err = parse_data_run(stream, &offset, attr_len, &chunk);
if (err) {
- printf("Error on parsing data runs.\n");
+ printf("Error while parsing data runs.\n");
goto out;
}
@@ -978,7 +1145,7 @@ next_vcn:
err = ntfs_read(fs, &buf, blk_size, blk_size, &blk, &blk_offset, NULL,
(uint64_t *)&lcn);
if (err) {
- printf("Error on reading from cache.\n");
+ printf("Error while reading from cache.\n");
goto not_found;
}
@@ -1014,6 +1181,14 @@ idx_block_next_entry:
}
readdir_state->entries_count++;
+
+ /* Need to check if this entry has INDEX_ENTRY_END flag set. If
+ * so, then it won't contain a indexed_file file, so continue the
+ * lookup on the next VCN/LCN (if any).
+ */
+ if (ie->flags & INDEX_ENTRY_END)
+ goto next_vcn;
+
len = ntfs_cvt_filename(filename, ie);
if (!is_filename_printable(filename))
goto idx_block_next_entry;
@@ -1056,7 +1231,7 @@ index_err:
goto out;
}
-static struct inode *ntfs_iget(const char *dname, struct inode *parent)
+static inline struct inode *ntfs_iget(const char *dname, struct inode *parent)
{
return ntfs_index_lookup(dname, parent);
}
@@ -1064,12 +1239,14 @@ static struct inode *ntfs_iget(const char *dname, struct inode *parent)
static struct inode *ntfs_iget_root(struct fs_info *fs)
{
uint64_t start_blk;
- struct ntfs_mft_record *mrec;
+ struct ntfs_mft_record *mrec, *lmrec;
struct ntfs_attr_record *attr;
struct ntfs_vol_info *vol_info;
struct inode *inode;
int err;
+ dprintf("in %s()\n", __func__);
+
/* Fetch the $Volume MFT record */
start_blk = 0;
mrec = NTFS_SB(fs)->mft_record_lookup(fs, FILE_Volume, &start_blk);
@@ -1078,8 +1255,10 @@ static struct inode *ntfs_iget_root(struct fs_info *fs)
goto err_mrec;
}
+ lmrec = mrec;
+
/* Fetch the volume information attribute */
- attr = ntfs_attr_lookup(NTFS_AT_VOL_INFO, mrec);
+ attr = ntfs_attr_lookup(fs, NTFS_AT_VOL_INFO, &mrec, lmrec);
if (!attr) {
printf("Could not find volume info attribute!\n");
goto err_attr;
@@ -1130,11 +1309,12 @@ static int ntfs_fs_init(struct fs_info *fs)
struct disk *disk = fs->fs_dev->disk;
uint8_t mft_record_shift;
+ dprintf("in %s()\n", __func__);
+
read_count = disk->rdwr_sectors(disk, &ntfs, 0, 1, 0);
if (!read_count)
- return -1;
+ return -1;
- /* sanity check */
if (!ntfs_check_sb_fields(&ntfs))
return -1;
@@ -1178,7 +1358,7 @@ static int ntfs_fs_init(struct fs_info *fs)
sbi->clusters = 0xFFFFFFFFFFF4ULL;
/*
- * Assume NTFS version 3.0 to begin with. If we find that the
+ * Assume NTFS version 3.0 to begin with. If we find that the
* volume is a different version later on, we will adjust at
* that time.
*/
diff --git a/core/fs/ntfs/ntfs.h b/core/fs/ntfs/ntfs.h
index 6620a27d..721a78d7 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) 2011-2012 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
@@ -17,6 +17,8 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include "runlist.h"
+
#ifndef _NTFS_H_
#define _NTFS_H_
@@ -290,12 +292,31 @@ struct ntfs_attr_record {
uint8_t compression_unit;
uint8_t reserved[5];
int64_t allocated_size;
+ int64_t data_size; /* Byte size of the attribute value.
+ * Note: it can be larger than
+ * allocated_size if attribute value is
+ * compressed or sparse.
+ */
int64_t initialized_size;
int64_t compressed_size;
} __attribute__((__packed__)) non_resident;
} __attribute__((__packed__)) data;
} __attribute__((__packed__));
+/* Attribute: Attribute List (0x20)
+ * Note: it can be either resident or non-resident
+ */
+struct ntfs_attr_list_entry {
+ uint32_t type;
+ uint16_t length;
+ uint8_t name_length;
+ uint8_t name_offset;
+ uint64_t lowest_vcn;
+ uint64_t mft_ref;
+ uint16_t instance;
+ uint16_t name[0];
+} __attribute__((__packed__));
+
#define NTFS_MAX_FILE_NAME_LEN 255
/* Possible namespaces for filenames in ntfs (8-bit) */
diff --git a/core/fs/ntfs/runlist.h b/core/fs/ntfs/runlist.h
index c1942338..4938696b 100644
--- a/core/fs/ntfs/runlist.h
+++ b/core/fs/ntfs/runlist.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) Paulo Alcantara <pcacjr@gmail.com>
+ * Copyright (C) 2011 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
diff --git a/core/ldlinux.asm b/core/ldlinux.asm
index d4c5eec4..a2f859d0 100644
--- a/core/ldlinux.asm
+++ b/core/ldlinux.asm
@@ -37,10 +37,10 @@ ROOT_FS_OPS:
dd vfat_fs_ops
extern ext2_fs_ops
dd ext2_fs_ops
+ extern ntfs_fs_ops
+ dd ntfs_fs_ops
extern btrfs_fs_ops
dd btrfs_fs_ops
- extern ntfs_fs_ops
- dd ntfs_fs_ops
dd 0
%include "diskfs.inc"
diff --git a/extlinux/main.c b/extlinux/main.c
index d85d03c8..5da89e2d 100755..100644
--- a/extlinux/main.c
+++ b/extlinux/main.c
@@ -1,7 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
- * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2009-2012 Intel Corporation; author: H. Peter Anvin
*
* 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
@@ -825,47 +825,46 @@ static const char *find_device(const char *mtab_file, dev_t dev)
/* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
switch (fs_type) {
case BTRFS:
- if (!strcmp(mnt->mnt_type, "btrfs") &&
- !stat(mnt->mnt_dir, &dst) &&
- dst.st_dev == dev) {
- if (!subvol[0]) {
- get_default_subvol(mnt->mnt_dir, subvol);
- }
- done = true;
- }
- break;
+ if (!strcmp(mnt->mnt_type, "btrfs") &&
+ !stat(mnt->mnt_dir, &dst) &&
+ dst.st_dev == dev) {
+ if (!subvol[0])
+ get_default_subvol(mnt->mnt_dir, subvol);
+ done = true;
+ }
+ break;
case EXT2:
- if ((!strcmp(mnt->mnt_type, "ext2") ||
- !strcmp(mnt->mnt_type, "ext3") ||
- !strcmp(mnt->mnt_type, "ext4")) &&
- !stat(mnt->mnt_fsname, &dst) &&
- dst.st_rdev == dev) {
- done = true;
- break;
- }
+ if ((!strcmp(mnt->mnt_type, "ext2") ||
+ !strcmp(mnt->mnt_type, "ext3") ||
+ !strcmp(mnt->mnt_type, "ext4")) &&
+ !stat(mnt->mnt_fsname, &dst) &&
+ dst.st_rdev == dev) {
+ done = true;
+ break;
+ }
case VFAT:
- if ((!strcmp(mnt->mnt_type, "vfat")) &&
- !stat(mnt->mnt_fsname, &dst) &&
- dst.st_rdev == dev) {
- done = true;
- break;
- }
- case NTFS:
- if ((!strcmp(mnt->mnt_type, "fuseblk") /* ntfs-3g */ ||
- !strcmp(mnt->mnt_type, "ntfs")) &&
- !stat(mnt->mnt_fsname, &dst) &&
- dst.st_rdev == dev) {
- done = true;
- break;
- }
+ if ((!strcmp(mnt->mnt_type, "vfat")) &&
+ !stat(mnt->mnt_fsname, &dst) &&
+ dst.st_rdev == dev) {
+ done = true;
+ break;
+ }
+ case NTFS:
+ if ((!strcmp(mnt->mnt_type, "fuseblk") /* ntfs-3g */ ||
+ !strcmp(mnt->mnt_type, "ntfs")) &&
+ !stat(mnt->mnt_fsname, &dst) &&
+ dst.st_rdev == dev) {
+ done = true;
+ break;
+ }
- break;
+ break;
case NONE:
break;
}
if (done) {
- devname = strdup(mnt->mnt_fsname);
- break;
+ devname = strdup(mnt->mnt_fsname);
+ break;
}
}
endmntent(mtab);
@@ -874,6 +873,54 @@ static const char *find_device(const char *mtab_file, dev_t dev)
}
#endif
+/*
+ * On newer Linux kernels we can use sysfs to get a backwards mapping
+ * from device names to standard filenames
+ */
+static const char *find_device_sysfs(dev_t dev)
+{
+ char sysname[64];
+ char linkname[PATH_MAX];
+ ssize_t llen;
+ char *p, *q;
+ char *buf = NULL;
+ struct stat st;
+
+ snprintf(sysname, sizeof sysname, "/sys/dev/block/%u:%u",
+ major(dev), minor(dev));
+
+ llen = readlink(sysname, linkname, sizeof linkname);
+ if (llen < 0 || llen >= sizeof linkname)
+ goto err;
+
+ linkname[llen] = '\0';
+
+ p = strrchr(linkname, '/');
+ p = p ? p+1 : linkname; /* Leave basename */
+
+ buf = q = malloc(strlen(p) + 6);
+ if (!buf)
+ goto err;
+
+ memcpy(q, "/dev/", 5);
+ q += 5;
+
+ while (*p) {
+ *q++ = (*p == '!') ? '/' : *p;
+ p++;
+ }
+
+ *q = '\0';
+
+ if (!stat(buf, &st) && st.st_dev == dev)
+ return buf; /* Found it! */
+
+err:
+ if (buf)
+ free(buf);
+ return NULL;
+}
+
static const char *get_devname(const char *path)
{
const char *devname = NULL;
@@ -888,21 +935,26 @@ static const char *get_devname(const char *path)
fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
return devname;
}
+
#ifdef __KLIBC__
- /* klibc doesn't have getmntent and friends; instead, just create
- a new device with the appropriate device type */
- snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
- major(st.st_dev), minor(st.st_dev));
+ devname = find_device_sysfs(st.st_dev);
- if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
- fprintf(stderr, "%s: cannot create device %s\n", program, devname);
- return devname;
+ if (!devname) {
+ /* klibc doesn't have getmntent and friends; instead, just create
+ a new device with the appropriate device type */
+ snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
+ major(st.st_dev), minor(st.st_dev));
+
+ if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
+ fprintf(stderr, "%s: cannot create device %s\n", program, devname);
+ return devname;
+ }
+
+ atexit(device_cleanup); /* unlink the device node on exit */
+ devname = devname_buf;
}
- atexit(device_cleanup); /* unlink the device node on exit */
- devname = devname_buf;
-
#else
devname = find_device("/proc/mounts", st.st_dev);
@@ -911,11 +963,14 @@ static const char *get_devname(const char *path)
devname = find_device("/etc/mtab", st.st_dev);
}
if (!devname) {
+ devname = find_device_sysfs(st.st_dev);
+
fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
return devname;
}
fprintf(stderr, "%s is device %s\n", path, devname);
+
#endif
return devname;
}
@@ -994,7 +1049,7 @@ static int ext_read_adv(const char *path, int devfd, const char **namep)
if (err == 2) /* ldlinux.sys does not exist */
err = read_adv(path, name = "extlinux.sys");
if (namep)
- *namep = name;
+ *namep = name;
return err;
}
}
diff --git a/win32/find-mingw32.sh b/win32/find-mingw32.sh
index f79949c7..51dcdd7e 100755
--- a/win32/find-mingw32.sh
+++ b/win32/find-mingw32.sh
@@ -20,7 +20,8 @@ for prefix in \
i386-mingw32msvc- \
i486-mingw32msvc- \
i586-mingw32msvc- \
- i686-mingw32msvc-; do
+ i686-mingw32msvc- \
+ i686-w64-mingw32-; do
if "${prefix}${cc}" -v > /dev/null 2>&1; then
echo "$prefix"
exit 0