diff options
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | com32/include/string.h | 2 | ||||
-rw-r--r-- | com32/lib/strreplace.c | 44 | ||||
-rw-r--r-- | core/bootsect.inc | 16 | ||||
-rw-r--r-- | core/fs/ntfs/ntfs.c | 344 | ||||
-rw-r--r-- | core/fs/ntfs/ntfs.h | 23 | ||||
-rw-r--r-- | core/fs/ntfs/runlist.h | 2 | ||||
-rw-r--r-- | core/ldlinux.asm | 4 | ||||
-rw-r--r--[-rwxr-xr-x] | extlinux/main.c | 147 | ||||
-rwxr-xr-x | win32/find-mingw32.sh | 3 |
10 files changed, 431 insertions, 156 deletions
@@ -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 |