Example #1
0
static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn)
{
	u32 ib_size = (unsigned)le32_to_cpu(ib->index.allocated_size) + 0x18;
	
	ntfs_log_trace("Entering\n");
	
	if (!ntfs_is_indx_record(ib->magic)) {
		
		ntfs_log_error("Corrupt index block signature: vcn %lld inode "
			       "%llu\n", (long long)vcn,
			       (unsigned long long)icx->ni->mft_no);
		return -1;
	}
	
	if (sle64_to_cpu(ib->index_block_vcn) != vcn) {
		
		ntfs_log_error("Corrupt index block: VCN (%lld) is different "
			       "from expected VCN (%lld) in inode %llu\n",
			       (long long)sle64_to_cpu(ib->index_block_vcn),
			       (long long)vcn,
			       (unsigned long long)icx->ni->mft_no);
		return -1;
	}
	
	if (ib_size != icx->block_size) {
		
		ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu "
			       "has a size (%u) differing from the index "
			       "specified size (%u)\n", (long long)vcn, 
			       (unsigned long long)icx->ni->mft_no, ib_size,
			       icx->block_size);
		return -1;
	}
	return 0;
}
Example #2
0
/**
 * ntfs_usnjrnl_stamp - stamp the transaction log ($UsnJrnl) on an ntfs volume
 * @vol:	ntfs volume on which to stamp the transaction log
 *
 * Stamp the transaction log ($UsnJrnl) on the ntfs volume @vol and return 0
 * on success and errno on error.
 *
 * This function assumes that the transaction log has already been loaded and
 * consistency checked by a call to ntfs_vfsops.c::ntfs_usnjrnl_load().
 */
errno_t ntfs_usnjrnl_stamp(ntfs_volume *vol)
{
	ntfs_debug("Entering.");
	if (!NVolUsnJrnlStamped(vol)) {
		sle64 j_size, stamp;
		upl_t upl;
		upl_page_info_array_t pl;
		USN_HEADER *uh;
		ntfs_inode *max_ni;
		errno_t err;

		mtx_lock_spin(&vol->usnjrnl_j_ni->size_lock);
		j_size = vol->usnjrnl_j_ni->data_size;
		mtx_unlock_spin(&vol->usnjrnl_j_ni->size_lock);
		max_ni = vol->usnjrnl_max_ni;
		/*
		 * FIXME: Next If statement always false because of
		 * replacing vnode_get() with vhold()
		 */
		vhold(max_ni->vn);
		if (0) {
			ntfs_error(vol->mp, "Failed to get vnode for "
					"$UsnJrnl/$DATA/$Max.");
			return err;
		}
		sx_slock(&max_ni->lock);
		err = ntfs_page_map(max_ni, 0, &upl, &pl, (u8**)&uh, TRUE);
		if (err) {
			ntfs_error(vol->mp, "Failed to read from "
					"$UsnJrnl/$DATA/$Max attribute.");
			vdrop(max_ni->vn);
			return err;
		}
		stamp = ntfs_current_time();
		ntfs_debug("Stamping transaction log ($UsnJrnl): old "
				"journal_id 0x%llx, old lowest_valid_usn "
				"0x%llx, new journal_id 0x%llx, new "
				"lowest_valid_usn 0x%llx.",
				(unsigned long long)
				sle64_to_cpu(uh->journal_id),
				(unsigned long long)
				sle64_to_cpu(uh->lowest_valid_usn),
				(unsigned long long)sle64_to_cpu(stamp),
				(unsigned long long)j_size);
		uh->lowest_valid_usn = cpu_to_sle64(j_size);
		uh->journal_id = stamp;
		ntfs_page_unmap(max_ni, upl, pl, TRUE);
		sx_sunlock(&max_ni->lock);
		vdrop(max_ni->vn);
		/* Set the flag so we do not have to do it again on remount. */
		NVolSetUsnJrnlStamped(vol);
		// TODO: Should we mark any times on the base inode $UsnJrnl
		// for update here?
	}
	ntfs_debug("Done.");
	return 0;
}
Example #3
0
/**
 * ntfs_debug_attr_list_dump - dump an attribute list attribute
 * @al:		attribute list attribute value to dump
 * @size:	size of attribute list attribute value
 *
 * Dump the attribute list attribute value @al of size @size bytes.
 */
void ntfs_debug_attr_list_dump(const u8 *al, const unsigned size)
{
	const u8 *end;
	ATTR_LIST_ENTRY *entry;
	unsigned u;

	if (!ntfs_debug_messages)
		return;
	end = al + size;
	printf("NTFS-fs DEBUG: Dumping attribute list (size 0x%x):\n", size);
	for (entry = (ATTR_LIST_ENTRY*)al, u = 1; (u8*)entry < end;
			entry = (ATTR_LIST_ENTRY*)((u8*)entry +
			le16_to_cpu(entry->length)), u++) {
		printf("--------------- Entry %u ---------------\n", u);
		printf("Attribute type: 0x%x\n",
				(unsigned)le32_to_cpu(entry->type));
		printf("Record length: 0x%x\n",
				(unsigned)le16_to_cpu(entry->length));
		printf("Name length: 0x%x\n", (unsigned)entry->name_length);
		printf("Name offset: 0x%x\n", (unsigned)entry->name_offset);
		printf("Starting VCN: 0x%llx\n", (unsigned long long)
				sle64_to_cpu(entry->lowest_vcn));
		printf("MFT reference: 0x%llx\n", (unsigned long long)
				MREF_LE(entry->mft_reference));
		printf("Instance: 0x%x\n",
				(unsigned)le16_to_cpu(entry->instance));
	}
	printf("--------------- End of attribute list ---------------\n");
}
Example #4
0
File: time.c Project: killvxk/NT_OS
/**
 * ntfs2utc - convert NTFS time to Linux time
 * @time:		NTFS time (little endian) to convert to Linux
 *
 * Convert the little endian NTFS time @time to its corresponding Linux time
 * and return that in cpu format.
 *
 * Linux stores time in a long at present and measures it as the number of
 * 1-second intervals since 1st January 1970, 00:00:00 UTC.
 *
 * NTFS uses Microsoft's standard time format which is stored in a s64 and is
 * measured as the number of 100 nano-second intervals since 1st January 1601,
 * 00:00:00 UTC.
 */
inline time_t ntfs2utc(const s64 time)
{
	/* Subtract the NTFS time offset, then convert to 1s intervals. */
	s64 t = sle64_to_cpu(time) - NTFS_TIME_OFFSET;
	do_div(t, 10000000);
	return (time_t)t;
}
Example #5
0
status_t
fs_scan_partition(int fd, partition_data *partition, void *_cookie)
{
	identify_cookie *cookie = (identify_cookie *)_cookie;
	partition->status = B_PARTITION_VALID;
	partition->flags |= B_PARTITION_FILE_SYSTEM;
	partition->content_size = sle64_to_cpu(cookie->boot.number_of_sectors)
		* le16_to_cpu(cookie->boot.bpb.bytes_per_sector);
	partition->block_size = le16_to_cpu(cookie->boot.bpb.bytes_per_sector);
	partition->content_name = strdup(cookie->label);
	return B_OK;
}
Example #6
0
/**
 * ntfs_stamp_usnjrnl - stamp the transaction log ($UsnJrnl) on an ntfs volume
 * @vol:	ntfs volume on which to stamp the transaction log
 *
 * Stamp the transaction log ($UsnJrnl) on the ntfs volume @vol and return
 * 'true' on success and 'false' on error.
 *
 * This function assumes that the transaction log has already been loaded and
 * consistency checked by a call to fs/ntfs/super.c::load_and_init_usnjrnl().
 */
bool ntfs_stamp_usnjrnl(ntfs_volume *vol)
{
	ntfs_debug("Entering.");
	if (likely(!NVolUsnJrnlStamped(vol))) {
		sle64 stamp;
		struct page *page;
		USN_HEADER *uh;

		page = ntfs_map_page(vol->usnjrnl_max_ino->i_mapping, 0);
		if (IS_ERR(page)) {
			ntfs_error(vol->sb, "Failed to read from "
					"$UsnJrnl/$DATA/$Max attribute.");
			return false;
		}
		uh = (USN_HEADER*)page_address(page);
		stamp = get_current_ntfs_time();
		ntfs_debug("Stamping transaction log ($UsnJrnl): old "
				"journal_id 0x%llx, old lowest_valid_usn "
				"0x%llx, new journal_id 0x%llx, new "
				"lowest_valid_usn 0x%llx.",
				(long long)sle64_to_cpu(uh->journal_id),
				(long long)sle64_to_cpu(uh->lowest_valid_usn),
				(long long)sle64_to_cpu(stamp),
				i_size_read(vol->usnjrnl_j_ino));
		uh->lowest_valid_usn =
				cpu_to_sle64(i_size_read(vol->usnjrnl_j_ino));
		uh->journal_id = stamp;
		flush_dcache_page(page);
		set_page_dirty(page);
		ntfs_unmap_page(page);
		/* Set the flag so we do not have to do it again on remount. */
		NVolSetUsnJrnlStamped(vol);
	}
	ntfs_debug("Done.");
	return true;
}
Example #7
0
static int ntfs_ib_write(ntfs_index_context *icx, INDEX_BLOCK *ib)
{
	s64 ret, vcn = sle64_to_cpu(ib->index_block_vcn);
	
	ntfs_log_trace("vcn: %lld\n", (long long)vcn);
	
	ret = ntfs_attr_mst_pwrite(icx->ia_na, ntfs_ib_vcn_to_pos(icx, vcn),
				   1, icx->block_size, ib);
	if (ret != 1) {
		ntfs_log_perror("Failed to write index block %lld, inode %llu",
			(long long)vcn, (unsigned long long)icx->ni->mft_no);
		return STATUS_ERROR;
	}
	
	return STATUS_OK;
}
Example #8
0
/**
 * ntfs_attrlist_entry_rm - remove an attribute list attribute entry
 * @ctx:	attribute search context describing the attribute list entry
 *
 * Remove the attribute list entry @ctx->al_entry from the attribute list.
 *
 * Return 0 on success and -1 on error with errno set to the error code.
 */
int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
{
	u8 *new_al;
	int new_al_len;
	ntfs_inode *base_ni;
	ntfs_attr *na;
	ATTR_LIST_ENTRY *ale;
	int err;

	if (!ctx || !ctx->ntfs_ino || !ctx->al_entry) {
		ntfs_log_trace("Invalid arguments.\n");
		errno = EINVAL;
		return -1;
	}

	if (ctx->base_ntfs_ino)
		base_ni = ctx->base_ntfs_ino;
	else
		base_ni = ctx->ntfs_ino;
	ale = ctx->al_entry;

	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld."
			"\n", (long long) ctx->ntfs_ino->mft_no,
			(unsigned) le32_to_cpu(ctx->al_entry->type),
			(long long) sle64_to_cpu(ctx->al_entry->lowest_vcn));

	if (!NInoAttrList(base_ni)) {
		ntfs_log_trace("Attribute list isn't present.\n");
		errno = ENOENT;
		return -1;
	}

	/* Allocate memory for new attribute list. */
	new_al_len = base_ni->attr_list_size - le16_to_cpu(ale->length);
	new_al = malloc(new_al_len);
	if (!new_al) {
		ntfs_log_trace("Not enough memory.\n");
		errno = ENOMEM;
		return -1;
	}

	/* Reisze $ATTRIBUTE_LIST to new length. */
	na = ntfs_attr_open(base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
	if (!na) {
		err = errno;
		ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n");
		goto err_out;
	}
	if (ntfs_attr_truncate(na, new_al_len)) {
		err = errno;
		ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
		goto err_out;
	}

	/* Copy entries from old attribute list to new. */
	memcpy(new_al, base_ni->attr_list, (u8*)ale - base_ni->attr_list);
	memcpy(new_al + ((u8*)ale - base_ni->attr_list), (u8*)ale + le16_to_cpu(
		ale->length), new_al_len - ((u8*)ale - base_ni->attr_list));

	/* Set new runlist. */
	free(base_ni->attr_list);
	base_ni->attr_list = new_al;
	base_ni->attr_list_size = new_al_len;
	NInoAttrListSetDirty(base_ni);
	/* Done! */
	ntfs_attr_close(na);
	return 0;
err_out:
	if (na)
		ntfs_attr_close(na);
	free(new_al);
	errno = err;
	return -1;
}
Example #9
0
/**
 * ntfs_attrlist_entry_add - add an attribute list attribute entry
 * @ni:		opened ntfs inode, which contains that attribute
 * @attr:	attribute record to add to attribute list
 *
 * Return 0 on success and -1 on error with errno set to the error code. The
 * following error codes are defined:
 *	EINVAL	- Invalid arguments passed to function.
 *	ENOMEM	- Not enough memory to allocate necessary buffers.
 *	EIO	- I/O error occurred or damaged filesystem.
 *	EEXIST	- Such attribute already present in attribute list.
 */
int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
{
	ATTR_LIST_ENTRY *ale;
	leMFT_REF mref;
	ntfs_attr *na = NULL;
	ntfs_attr_search_ctx *ctx;
	u8 *new_al;
	int entry_len, entry_offset, err;

	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n",
			(long long) ni->mft_no,
			(unsigned) le32_to_cpu(attr->type));

	if (!ni || !attr) {
		ntfs_log_trace("Invalid arguments.\n");
		errno = EINVAL;
		return -1;
	}

	mref = MK_LE_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number));

	if (ni->nr_extents == -1)
		ni = ni->u.base_ni;

	if (!NInoAttrList(ni)) {
		ntfs_log_trace("Attribute list isn't present.\n");
		errno = ENOENT;
		return -1;
	}

	/* Determine size and allocate memory for new attribute list. */
	entry_len = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) *
			attr->name_length + 7) & ~7;
	new_al = malloc(ni->attr_list_size + entry_len);
	if (!new_al) {
		ntfs_log_trace("Not enough memory.\n");
		err = ENOMEM;
		return -1;
	}

	/* Find place for the new entry. */
	ctx = ntfs_attr_get_search_ctx(ni, NULL);
	if (!ctx) {
		err = errno;
		ntfs_log_trace("Failed to obtain attribute search context.\n");
		goto err_out;
	}
	if (!ntfs_attr_lookup(attr->type, (attr->name_length) ? (ntfschar*)
			((u8*)attr + le16_to_cpu(attr->name_offset)) :
			AT_UNNAMED, attr->name_length, CASE_SENSITIVE,
			(attr->non_resident) ? sle64_to_cpu(attr->u.nonres.lowest_vcn) :
			0, (attr->non_resident) ? NULL : ((u8*)attr +
			le16_to_cpu(attr->u.res.value_offset)), (attr->non_resident) ?
			0 : le32_to_cpu(attr->u.res.value_length), ctx)) {
		/* Found some extent, check it to be before new extent. */
		if (ctx->al_entry->lowest_vcn == attr->u.nonres.lowest_vcn) {
			err = EEXIST;
			ntfs_log_trace("Such attribute already present in the "
					"attribute list.\n");
			ntfs_attr_put_search_ctx(ctx);
			goto err_out;
		}
		/* Add new entry after this extent. */
		ale = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry +
				le16_to_cpu(ctx->al_entry->length));
	} else {
		/* Check for real errors. */
		if (errno != ENOENT) {
			err = errno;
			ntfs_log_trace("Attribute lookup failed.\n");
			ntfs_attr_put_search_ctx(ctx);
			goto err_out;
		}
		/* No previous extents found. */
		ale = ctx->al_entry;
	}
	/* Don't need it anymore, @ctx->al_entry points to @ni->attr_list. */
	ntfs_attr_put_search_ctx(ctx);

	/* Determine new entry offset. */
	entry_offset = ((u8 *)ale - ni->attr_list);
	/* Set pointer to new entry. */
	ale = (ATTR_LIST_ENTRY *)(new_al + entry_offset);
	/* Form new entry. */
	ale->type = attr->type;
	ale->length = cpu_to_le16(entry_len);
	ale->name_length = attr->name_length;
	ale->name_offset = offsetof(ATTR_LIST_ENTRY, name);
	if (attr->non_resident)
		ale->lowest_vcn = attr->u.nonres.lowest_vcn;
	else
		ale->lowest_vcn = 0;
	ale->mft_reference = mref;
	ale->instance = attr->instance;
	NTFS_ON_DEBUG(memset(ale->name, 0, ((u8*)((u8*)ale + entry_len)) -
				((u8*)ale->name))); /* Shut up, valgrind. */
	memcpy(ale->name, (u8 *)attr + le16_to_cpu(attr->name_offset),
			attr->name_length * sizeof(ntfschar));

	/* Resize $ATTRIBUTE_LIST to new length. */
	na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
	if (!na) {
		err = errno;
		ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n");
		goto err_out;
	}
	if (ntfs_attr_truncate(na, ni->attr_list_size + entry_len)) {
		err = errno;
		ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
		goto err_out;
	}

	/* Copy entries from old attribute list to new. */
	memcpy(new_al, ni->attr_list, entry_offset);
	memcpy(new_al + entry_offset + entry_len, ni->attr_list +
			entry_offset, ni->attr_list_size - entry_offset);

	/* Set new runlist. */
	free(ni->attr_list);
	ni->attr_list = new_al;
	ni->attr_list_size = ni->attr_list_size + entry_len;
	NInoAttrListSetDirty(ni);
	/* Done! */
	ntfs_attr_close(na);
	return 0;
err_out:
	if (na)
		ntfs_attr_close(na);
	free(new_al);
	errno = err;
	return -1;
}
Example #10
0
static int ntfs_device_uefi_io_open(struct ntfs_device *dev, int flags)
{
	NTFS_BOOT_SECTOR *boot;
	EFI_DISK_IO_PROTOCOL *DiskIo;
	NTFS_VOLUME *Volume;

	struct _uefi_fd *fd = DEV_FD(dev);
	Volume = fd->interface;

	ntfs_log_trace("dev %p, flags %i\n", dev, flags);

	
    // Get the device driver descriptor
    if (!fd) {
        errno = EBADF;
        return -1;
    }

    // Get the device interface
	DiskIo = Volume->DiskIo;

    if (!DiskIo) {
        errno = ENODEV;
        return -1;
    }

    // Start the device interface and ensure that it is inserted
    //if (!interface->startup()) {
     //   ntfs_log_perror("device failed to start\n");
      //  errno = EIO;
      //  return -1;
   // }
    //if (!interface->isInserted()) {
     //   ntfs_log_perror("device media is not inserted\n");
      //  errno = EIO;
       // return -1;
    //}

    // Check that the device isn't already open (used by another volume?)
    if (NDevOpen(dev)) {
		//AsciiPrint("ntfs_device_uefi_io_open...BUSY\n\r");
        ntfs_log_perror("device is busy (already open)\n");
        errno = EBUSY;
        return -1;
    }

    // Check that there is a valid NTFS boot sector at the start of the device
    boot = (NTFS_BOOT_SECTOR *) ntfs_alloc(MAX_SECTOR_SIZE);
    if(boot == NULL) {
		//AsciiPrint("ntfs_device_uefi_io_open...ENOMEM\n\r");
        errno = ENOMEM;
        return -1;
    }

	 
	
	 if (DiskIo->ReadDisk(DiskIo, Volume->MediaId, 0, sizeof(NTFS_BOOT_SECTOR), boot) != EFI_SUCCESS) {
		//AsciiPrint("DiskIo ptr %x\n\r", DiskIo);
		//AsciiPrint("interface ptr %x\n\r", fd->interface);
		//AsciiPrint("DiskIo->ReadDisk(%x,%x,%x)\n\r", fd->interface->MediaId, fd->startSector * fd->sectorSize, sizeof(NTFS_BOOT_SECTOR));
		//AsciiPrint("Sector size: %x\n\r", fd->sectorSize);
		//AsciiPrint("ntfs_device_uefi_io_open...read failure boot sector\n\r");
		ntfs_log_perror("read failure @ sector %x\n", fd->startSector);
        errno = EIO;
        ntfs_free(boot);
        return -1;
	}

    if (!ntfs_boot_sector_is_ntfs(boot)) {
		//AsciiPrint("ntfs_device_uefi_io_open...EINVALIDPART\n\r");
        errno = EINVALPART;
        ntfs_free(boot);
        return -1;
    }

    // Parse the boot sector
    fd->hiddenSectors = le32_to_cpu(boot->bpb.hidden_sectors);
    fd->sectorSize = le16_to_cpu(boot->bpb.bytes_per_sector);
    fd->sectorCount = sle64_to_cpu(boot->number_of_sectors);
    fd->pos = 0;
    fd->len = (fd->sectorCount * fd->sectorSize);
    fd->ino = le64_to_cpu(boot->volume_serial_number);

    // Free memory for boot sector
    ntfs_free(boot);

    // Mark the device as read-only (if required)
    if (flags & O_RDONLY) {
        NDevSetReadOnly(dev);
    }

    // cache disabled!
    fd->cache = NULL;
		//_NTFS_cache_constructor(fd->cachePageCount, fd->cachePageSize, interface, fd->startSector + fd->sectorCount, fd->sectorSize);

    // Mark the device as open
    NDevSetBlock(dev);
    NDevSetOpen(dev);

	//AsciiPrint("ntfs_device_uefi_io_open...success\n\r");
    return 0;
}
Example #11
0
/**
 * ntfs_td_list_entry
 * FIXME: Should we print errors as we go along? (AIA)
 */
static int ntfs_td_list_entry(  struct ntfs_dir_struct *ls, const ntfschar *name, 
		const int name_len, const int name_type, const s64 pos,
		const MFT_REF mref, const unsigned dt_type)
{
  int result = 0;
  char *filename;
  ntfs_inode *ni;
  ntfs_attr_search_ctx *ctx_si = NULL;
  file_info_t *new_file=NULL;
  /* Keep FILE_NAME_WIN32 and FILE_NAME_POSIX */
  if ((name_type & FILE_NAME_WIN32_AND_DOS) == FILE_NAME_DOS)
    return 0;

  filename = (char *)calloc (1, MAX_PATH);
  if (!filename)
  {
    log_critical("ntfs_td_list_entry calloc failed\n");
    return -1;
  }

#ifdef HAVE_ICONV
  if (ntfs_ucstoutf8(ls->cd, name, name_len, &filename, MAX_PATH) < 0 &&
      ntfs_ucstombs (name, name_len, &filename, MAX_PATH) < 0) {
    log_error("Cannot represent filename in current locale.\n");
    goto freefn;
  }
#else
  if (ntfs_ucstombs (name, name_len, &filename, MAX_PATH) < 0) {
    log_error("Cannot represent filename in current locale.\n");
    goto freefn;
  }
#endif

  result = 0;					/* These are successful */
  if ((ls->dir_data->param & FLAG_LIST_SYSTEM)!=FLAG_LIST_SYSTEM &&
      MREF(mref) < FILE_first_user && filename[0] == '$')	/* Hide system file */
      goto freefn;
  result = -1;				/* Everything else is bad */

  ni = ntfs_inode_open(ls->vol, mref);
  if (!ni)
    goto freefn;
  new_file=(file_info_t*)MALLOC(sizeof(*new_file));
  new_file->status=0;
  new_file->st_ino=MREF(mref);
  new_file->st_uid=0;
  new_file->st_gid=0;

  ctx_si = ntfs_attr_get_search_ctx(ni, ni->mrec);
  if (ctx_si)
  {
    if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, CASE_SENSITIVE, 0, NULL, 0, ctx_si)==0)
    {
      const ATTR_RECORD *attr = ctx_si->attr;
      const STANDARD_INFORMATION *si = (const STANDARD_INFORMATION*)((const char*)attr +
	  le16_to_cpu(attr->value_offset));
      if(si)
      {
	new_file->td_atime=td_ntfs2utc(sle64_to_cpu(si->last_access_time));
	new_file->td_mtime=td_ntfs2utc(sle64_to_cpu(si->last_data_change_time));
	new_file->td_ctime=td_ntfs2utc(sle64_to_cpu(si->creation_time));
      }
    }
    ntfs_attr_put_search_ctx(ctx_si);
  }
  {
    ATTR_RECORD *rec;
    int first=1;
    ntfs_attr_search_ctx *ctx = NULL;
    if (dt_type == NTFS_DT_DIR)
    {
      new_file->name=strdup(filename);
      new_file->st_mode = LINUX_S_IFDIR| LINUX_S_IRUGO | LINUX_S_IXUGO;
      new_file->st_size=0;
      td_list_add_tail(&new_file->list, &ls->dir_list->list);
      first=0;
    }
    ctx = ntfs_attr_get_search_ctx(ni, ni->mrec);
    /* A file has always an unnamed date stream and
     * may have named alternate data streams (ADS) */
    while((rec = find_attribute(AT_DATA, ctx)))
    {
      const s64 filesize = ntfs_get_attribute_value_length(ctx->attr);
      if(rec->name_length &&
	  (ls->dir_data->param & FLAG_LIST_ADS)!=FLAG_LIST_ADS)
	continue;
      if(first==0)
      {
	const file_info_t *old_file=new_file;
	new_file=(file_info_t *)MALLOC(sizeof(*new_file));
	memcpy(new_file, old_file, sizeof(*new_file));
      }
      new_file->st_mode = LINUX_S_IFREG | LINUX_S_IRUGO;
      new_file->st_size=filesize;
      if (rec->name_length)
      {
	char *stream_name=NULL;
	new_file->status=FILE_STATUS_ADS;
	new_file->name = (char *)MALLOC(MAX_PATH);
	if (ntfs_ucstombs((ntfschar *) ((char *) rec + le16_to_cpu(rec->name_offset)),
	      rec->name_length, &stream_name, 0) < 0)
	{
	  log_error("ERROR: Cannot translate name into current locale.\n");
	  snprintf(new_file->name, MAX_PATH, "%s:???", filename);
	}
	else
	{
	  snprintf(new_file->name, MAX_PATH, "%s:%s", filename, stream_name);
	}
	free(stream_name);
      }
      else
      {
	new_file->name=strdup(filename);
      }
      td_list_add_tail(&new_file->list, &ls->dir_list->list);
      first=0;
    }
    ntfs_attr_put_search_ctx(ctx);
    if(first)
    {
      free(new_file);
    }
  }

  result = 0;
  /* close the inode. */
  ntfs_inode_close(ni);
freefn:
  free (filename);
  return result;
}
Example #12
0
/**
 * ntfs_boot_sector_parse - setup an ntfs volume from an ntfs boot sector
 * @vol:	ntfs_volume to setup
 * @bs:		buffer containing ntfs boot sector to parse
 *
 * Parse the ntfs bootsector @bs and setup the ntfs volume @vol with the
 * obtained values.
 *
 * Return 0 on success or -1 on error with errno set to the error code EINVAL.
 */
int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
{
	s64 sectors;
	u8  sectors_per_cluster;
	s8  c;

	/* We return -1 with errno = EINVAL on error. */
	errno = EINVAL;

	vol->sector_size = le16_to_cpu(bs->bpb.bytes_per_sector);
	vol->sector_size_bits = ffs(vol->sector_size) - 1;
	ntfs_log_debug("SectorSize = 0x%x\n", vol->sector_size);
	ntfs_log_debug("SectorSizeBits = %u\n", vol->sector_size_bits);
	/*
	 * The bounds checks on mft_lcn and mft_mirr_lcn (i.e. them being
	 * below or equal the number_of_clusters) really belong in the
	 * ntfs_boot_sector_is_ntfs but in this way we can just do this once.
	 */
	sectors_per_cluster = bs->bpb.sectors_per_cluster;
	ntfs_log_debug("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
	if (sectors_per_cluster & (sectors_per_cluster - 1)) {
		ntfs_log_error("sectors_per_cluster (%d) is not a power of 2."
			       "\n", sectors_per_cluster);
		return -1;
	}
	
	sectors = sle64_to_cpu(bs->number_of_sectors);
	ntfs_log_debug("NumberOfSectors = %lld\n", (long long)sectors);
	if (!sectors) {
		ntfs_log_error("Volume size is set to zero.\n");
		return -1;
	}
	if (vol->dev->d_ops->seek(vol->dev, 
				  (sectors - 1) << vol->sector_size_bits,
				  SEEK_SET) == -1) {
		ntfs_log_perror("Failed to read last sector (%lld)",
			       	(long long)sectors);
		ntfs_log_error("%s", last_sector_error);
		return -1;
	}
	
	vol->nr_clusters =  sectors >> (ffs(sectors_per_cluster) - 1);

	vol->mft_lcn = sle64_to_cpu(bs->mft_lcn);
	vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn);
	ntfs_log_debug("MFT LCN = %lld\n", (long long)vol->mft_lcn);
	ntfs_log_debug("MFTMirr LCN = %lld\n", (long long)vol->mftmirr_lcn);
	if (vol->mft_lcn     > vol->nr_clusters ||
	    vol->mftmirr_lcn > vol->nr_clusters) {
		ntfs_log_error("$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
			      "greater than the number of clusters (%lld).\n",
			      (long long)vol->mft_lcn, (long long)vol->mftmirr_lcn,
			      (long long)vol->nr_clusters);
		return -1;
	}
	
	vol->cluster_size = sectors_per_cluster * vol->sector_size;
	if (vol->cluster_size & (vol->cluster_size - 1)) {
		ntfs_log_error("cluster_size (%d) is not a power of 2.\n",
			       vol->cluster_size);
		return -1;
	}
	vol->cluster_size_bits = ffs(vol->cluster_size) - 1;
	/*
	 * Need to get the clusters per mft record and handle it if it is
	 * negative. Then calculate the mft_record_size. A value of 0x80 is
	 * illegal, thus signed char is actually ok!
	 */
	c = bs->clusters_per_mft_record;
	ntfs_log_debug("ClusterSize = 0x%x\n", (unsigned)vol->cluster_size);
	ntfs_log_debug("ClusterSizeBits = %u\n", vol->cluster_size_bits);
	ntfs_log_debug("ClustersPerMftRecord = 0x%x\n", c);
	/*
	 * When clusters_per_mft_record is negative, it means that it is to
	 * be taken to be the negative base 2 logarithm of the mft_record_size
	 * min bytes. Then:
	 *	 mft_record_size = 2^(-clusters_per_mft_record) bytes.
	 */
	if (c < 0)
		vol->mft_record_size = 1 << -c;
	else
		vol->mft_record_size = c << vol->cluster_size_bits;
	if (vol->mft_record_size & (vol->mft_record_size - 1)) {
		ntfs_log_error("mft_record_size (%d) is not a power of 2.\n",
			       vol->mft_record_size);
		return -1;
	}
	vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1;
	ntfs_log_debug("MftRecordSize = 0x%x\n", (unsigned)vol->mft_record_size);
	ntfs_log_debug("MftRecordSizeBits = %u\n", vol->mft_record_size_bits);
	/* Same as above for INDX record. */
	c = bs->clusters_per_index_record;
	ntfs_log_debug("ClustersPerINDXRecord = 0x%x\n", c);
	if (c < 0)
		vol->indx_record_size = 1 << -c;
	else
		vol->indx_record_size = c << vol->cluster_size_bits;
	vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1;
	ntfs_log_debug("INDXRecordSize = 0x%x\n", (unsigned)vol->indx_record_size);
	ntfs_log_debug("INDXRecordSizeBits = %u\n", vol->indx_record_size_bits);
	/*
	 * Work out the size of the MFT mirror in number of mft records. If the
	 * cluster size is less than or equal to the size taken by four mft
	 * records, the mft mirror stores the first four mft records. If the
	 * cluster size is bigger than the size taken by four mft records, the
	 * mft mirror contains as many mft records as will fit into one
	 * cluster.
	 */
	if (vol->cluster_size <= 4 * vol->mft_record_size)
		vol->mftmirr_size = 4;
	else
		vol->mftmirr_size = vol->cluster_size / vol->mft_record_size;
	return 0;
}
Example #13
0
/**
 * ntfs_feed_encrypt - Encrypt the contents of stdin to an encrypted file
 * @inode:	An encrypted file's inode structure, as obtained by
 * 		ntfs_inode_open().
 * @fek:	A file encryption key. As obtained by ntfs_inode_fek_get().
 */
static int ntfs_feed_encrypt(ntfs_inode *inode, ntfs_fek *fek)
{
	const int bufsize = 512;
	unsigned char *buffer;
	ntfs_attr *attr;
	s64 bytes_read, written, offset, total;
	unsigned char *b;
	long val;
	int count;
	int i;

	buffer = (unsigned char*)malloc(bufsize);
	if (!buffer)
		return 1;
	attr = ntfs_attr_open(inode, AT_DATA, NULL, 0);
	if (!attr) {
		ntfs_log_error("Cannot feed into a directory.\n");
		goto rejected;
	}
	total = 0;

	if (!(attr->data_flags & ATTR_IS_ENCRYPTED)) {
		ntfs_log_error("The data stream was not encrypted\n");
		goto rejected;
	}
	inode->vol->efs_raw = TRUE;

	if (ntfs_attr_truncate(attr, 0)) {
		ntfs_log_error("Failed to truncate the data stream\n");
		goto rejected;
	}
	offset = 0;
	do {
		bytes_read = fread(buffer, 1, bufsize, stdin);
		if (bytes_read <= 0) {
			if (bytes_read < 0)
				ntfs_log_perror("ERROR: Couldn't read data");
		} else {
			if (bytes_read < bufsize) {
				/* Fill with random data */
				srandom((unsigned int)(sle64_to_cpu(
					inode->last_data_change_time)
					/100000000));
				count = bufsize - bytes_read;
				b = &buffer[bytes_read];
				do {
					val = random();
					switch (count) {
						default :
							*b++ = val;
							val >>= 8;
						case 3 :
							*b++ = val;
							val >>= 8;
						case 2 :
							*b++ = val;
							val >>= 8;
						case 1 :
							*b++ = val;
							val >>= 8;
					}
					count -= 4;
				} while (count > 0);
			}
			if ((i = ntfs_fek_encrypt_sector(fek, buffer, offset))
					< bufsize) {
				ntfs_log_perror("ERROR: Couldn't encrypt all data!");
				ntfs_log_error("%u/%lld/%lld/%lld\n", i,
					(long long)bytes_read, (long long)offset,
					(long long)total);
				break;
			}
		written = ntfs_attr_pwrite(attr, offset, bufsize, buffer);
		if (written != bufsize) {
			ntfs_log_perror("ERROR: Couldn't output all data!");
			break;
		}
		offset += bufsize;
		total += bytes_read;
		}
	} while (bytes_read == bufsize);
	ntfs_attr_truncate(attr, total);
	inode->last_data_change_time = ntfs_current_time();
	NAttrSetEncrypted(attr);
	ntfs_attr_close(attr);
	free(buffer);
	return 0;
rejected :
	free(buffer);
	return (-1);
}
Example #14
0
/**
 * ntfs_inode_add_attrlist - add attribute list to inode and fill it
 * @ni: opened ntfs inode to which add attribute list
 *
 * Return 0 on success or -1 on error with errno set to the error code.
 * The following error codes are defined:
 *	EINVAL	- Invalid arguments were passed to the function.
 *	EEXIST	- Attribute list already exist.
 *	EIO	- Input/Ouput error occurred.
 *	ENOMEM	- Not enough memory to perform add.
 */
int ntfs_inode_add_attrlist(ntfs_inode *ni)
{
	int err;
	ntfs_attr_search_ctx *ctx;
	u8 *al = NULL, *aln;
	int al_len = 0;
	ATTR_LIST_ENTRY *ale = NULL;
	ntfs_attr *na;

	if (!ni) {
		errno = EINVAL;
		ntfs_log_perror("%s", __FUNCTION__);
		return -1;
	}

	ntfs_log_trace("inode %llu\n", (unsigned long long) ni->mft_no);

	if (NInoAttrList(ni) || ni->nr_extents) {
		errno = EEXIST;
		ntfs_log_perror("Inode already has attribute list");
		return -1;
	}

	/* Form attribute list. */
	ctx = ntfs_attr_get_search_ctx(ni, NULL);
	if (!ctx) {
		err = errno;
		goto err_out;
	}
	/* Walk through all attributes. */
	while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) {

		int ale_size;

		if (ctx->attr->type == AT_ATTRIBUTE_LIST) {
			err = EIO;
			ntfs_log_perror("Attribute list already present");
			goto put_err_out;
		}

		ale_size = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) *
					ctx->attr->name_length + 7) & ~7;
		al_len += ale_size;

		aln = realloc(al, al_len);
		if (!aln) {
			err = errno;
			ntfs_log_perror("Failed to realloc %d bytes", al_len);
			goto put_err_out;
		}
		ale = (ATTR_LIST_ENTRY *)(aln + ((u8 *)ale - al));
		al = aln;

		memset(ale, 0, ale_size);

		/* Add attribute to attribute list. */
		ale->type = ctx->attr->type;
		ale->length = cpu_to_le16((sizeof(ATTR_LIST_ENTRY) +
			sizeof(ntfschar) * ctx->attr->name_length + 7) & ~7);
		ale->name_length = ctx->attr->name_length;
		ale->name_offset = (u8 *)ale->name - (u8 *)ale;
		if (ctx->attr->non_resident)
			ale->lowest_vcn = ctx->attr->lowest_vcn;
		else
			ale->lowest_vcn = 0;
		ale->mft_reference = MK_LE_MREF(ni->mft_no,
			le16_to_cpu(ni->mrec->sequence_number));
		ale->instance = ctx->attr->instance;
		memcpy(ale->name, (u8 *)ctx->attr +
				le16_to_cpu(ctx->attr->name_offset),
				ctx->attr->name_length * sizeof(ntfschar));
		ale = (ATTR_LIST_ENTRY *)(al + al_len);
	}
	/* Check for real error occurred. */
	if (errno != ENOENT) {
		err = errno;
		ntfs_log_perror("%s: Attribute lookup failed, inode %lld",
				__FUNCTION__, (long long)ni->mft_no);
		goto put_err_out;
	}

	/* Set in-memory attribute list. */
	ni->attr_list = al;
	ni->attr_list_size = al_len;
	NInoSetAttrList(ni);
	NInoAttrListSetDirty(ni);

	/* Free space if there is not enough it for $ATTRIBUTE_LIST. */
	if (le32_to_cpu(ni->mrec->bytes_allocated) -
			le32_to_cpu(ni->mrec->bytes_in_use) <
			offsetof(ATTR_RECORD, resident_end)) {
		if (ntfs_inode_free_space(ni,
				offsetof(ATTR_RECORD, resident_end))) {
			/* Failed to free space. */
			err = errno;
			ntfs_log_perror("Failed to free space for attrlist");
			goto rollback;
		}
	}

	/* Add $ATTRIBUTE_LIST to mft record. */
	if (ntfs_resident_attr_record_add(ni,
				AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) {
		err = errno;
		ntfs_log_perror("Couldn't add $ATTRIBUTE_LIST to MFT");
		goto rollback;
	}

	/* Resize it. */
	na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
	if (!na) {
		err = errno;
		ntfs_log_perror("Failed to open just added $ATTRIBUTE_LIST");
		goto remove_attrlist_record;
	}
	if (ntfs_attr_truncate(na, al_len)) {
		err = errno;
		ntfs_log_perror("Failed to resize just added $ATTRIBUTE_LIST");
		ntfs_attr_close(na);
		goto remove_attrlist_record;;
	}

	ntfs_attr_put_search_ctx(ctx);
	ntfs_attr_close(na);
	return 0;

remove_attrlist_record:
	/* Prevent ntfs_attr_recorm_rm from freeing attribute list. */
	ni->attr_list = NULL;
	NInoClearAttrList(ni);
	/* Remove $ATTRIBUTE_LIST record. */
	ntfs_attr_reinit_search_ctx(ctx);
	if (!ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0,
				CASE_SENSITIVE, 0, NULL, 0, ctx)) {
		if (ntfs_attr_record_rm(ctx))
			ntfs_log_perror("Rollback failed to remove attrlist");
	} else
		ntfs_log_perror("Rollback failed to find attrlist");
	/* Setup back in-memory runlist. */
	ni->attr_list = al;
	ni->attr_list_size = al_len;
	NInoSetAttrList(ni);
rollback:
	/*
	 * Scan attribute list for attributes that placed not in the base MFT
	 * record and move them to it.
	 */
	ntfs_attr_reinit_search_ctx(ctx);
	ale = (ATTR_LIST_ENTRY*)al;
	while ((u8*)ale < al + al_len) {
		if (MREF_LE(ale->mft_reference) != ni->mft_no) {
			if (!ntfs_attr_lookup(ale->type, ale->name,
						ale->name_length,
						CASE_SENSITIVE,
						sle64_to_cpu(ale->lowest_vcn),
						NULL, 0, ctx)) {
				if (ntfs_attr_record_move_to(ctx, ni))
					ntfs_log_perror("Rollback failed to "
							"move attribute");
			} else
				ntfs_log_perror("Rollback failed to find attr");
			ntfs_attr_reinit_search_ctx(ctx);
		}
		ale = (ATTR_LIST_ENTRY*)((u8*)ale + le16_to_cpu(ale->length));
	}
	/* Remove in-memory attribute list. */
	ni->attr_list = NULL;
	ni->attr_list_size = 0;
	NInoClearAttrList(ni);
	NInoAttrListClearDirty(ni);
put_err_out:
	ntfs_attr_put_search_ctx(ctx);
err_out:
	free(al);
	errno = err;
	return -1;
}
Example #15
0
/**
 * ntfs_inode_open - open an inode ready for access
 * @vol:	volume to get the inode from
 * @mref:	inode number / mft record number to open
 *
 * Allocate an ntfs_inode structure and initialize it for the given inode
 * specified by @mref. @mref specifies the inode number / mft record to read,
 * including the sequence number, which can be 0 if no sequence number checking
 * is to be performed.
 *
 * Then, allocate a buffer for the mft record, read the mft record from the
 * volume @vol, and attach it to the ntfs_inode structure (->mrec). The
 * mft record is mst deprotected and sanity checked for validity and we abort
 * if deprotection or checks fail.
 *
 * Finally, search for an attribute list attribute in the mft record and if one
 * is found, load the attribute list attribute value and attach it to the
 * ntfs_inode structure (->attr_list). Also set the NI_AttrList bit to indicate
 * this.
 *
 * Return a pointer to the ntfs_inode structure on success or NULL on error,
 * with errno set to the error code.
 */
ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
{
	s64 l;
	ntfs_inode *ni = NULL;
	ntfs_attr_search_ctx *ctx;
	STANDARD_INFORMATION *std_info;
	le32 lthle;
	int olderrno;

	ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref));
	if (!vol) {
		errno = EINVAL;
		goto out;
	}
	ni = __ntfs_inode_allocate(vol);
	if (!ni)
		goto out;
	if (ntfs_file_record_read(vol, mref, &ni->mrec, NULL))
		goto err_out;
	if (!(ni->mrec->flags & MFT_RECORD_IN_USE)) {
		errno = ENOENT;
		goto err_out;
	}
	ni->mft_no = MREF(mref);
	ctx = ntfs_attr_get_search_ctx(ni, NULL);
	if (!ctx)
		goto err_out;
	/* Receive some basic information about inode. */
	if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED,
				0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
		if (!ni->mrec->base_mft_record)
			ntfs_log_perror("No STANDARD_INFORMATION in base record"
					" %lld", (long long)MREF(mref));
		goto put_err_out;
	}
	std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr +
			le16_to_cpu(ctx->attr->value_offset));
	ni->flags = std_info->file_attributes;
	ni->creation_time = ntfs2utc(std_info->creation_time);
	ni->last_data_change_time = ntfs2utc(std_info->last_data_change_time);
	ni->last_mft_change_time = ntfs2utc(std_info->last_mft_change_time);
	ni->last_access_time = ntfs2utc(std_info->last_access_time);
  		/* JPA insert v3 extensions if present */
                /* length may be seen as 72 (v1.x) or 96 (v3.x) */
	lthle = ctx->attr->length;
	if (le32_to_cpu(lthle) > sizeof(STANDARD_INFORMATION)) {
		set_nino_flag(ni, v3_Extensions);
		ni->owner_id = std_info->owner_id;
		ni->security_id = std_info->security_id;
		ni->quota_charged = std_info->quota_charged;
		ni->usn = std_info->usn;
	} else {
		clear_nino_flag(ni, v3_Extensions);
		ni->owner_id = 0;
		ni->security_id = 0;
	}
	/* Set attribute list information. */
	olderrno = errno;
	if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0,
			ctx)) {
		if (errno != ENOENT)
			goto put_err_out;
		/* Attribute list attribute does not present. */
		/* restore previous errno to avoid misinterpretation */
		errno = olderrno;
		goto get_size;
	}
	NInoSetAttrList(ni);
	l = ntfs_get_attribute_value_length(ctx->attr);
	if (!l)
		goto put_err_out;
	if (l > 0x40000) {
		errno = EIO;
		ntfs_log_perror("Too large attrlist attribute (%lld), inode "
				"%lld", (long long)l, (long long)MREF(mref));
		goto put_err_out;
	}
	ni->attr_list_size = l;
	ni->attr_list = ntfs_malloc(ni->attr_list_size);
	if (!ni->attr_list)
		goto put_err_out;
	l = ntfs_get_attribute_value(vol, ctx->attr, ni->attr_list);
	if (!l)
		goto put_err_out;
	if (l != ni->attr_list_size) {
		errno = EIO;
		ntfs_log_perror("Unexpected attrlist size (%lld <> %u), inode "
				"%lld", (long long)l, ni->attr_list_size,
				(long long)MREF(mref));
		goto put_err_out;
	}
get_size:
	olderrno = errno;
	if (ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
		if (errno != ENOENT)
			goto put_err_out;
		/* Directory or special file. */
		/* restore previous errno to avoid misinterpretation */
		errno = olderrno;
		ni->data_size = ni->allocated_size = 0;
	} else {
		if (ctx->attr->non_resident) {
			ni->data_size = sle64_to_cpu(ctx->attr->data_size);
			if (ctx->attr->flags &
					(ATTR_IS_COMPRESSED | ATTR_IS_SPARSE))
				ni->allocated_size = sle64_to_cpu(
						ctx->attr->compressed_size);
			else
				ni->allocated_size = sle64_to_cpu(
						ctx->attr->allocated_size);
		} else {
			ni->data_size = le32_to_cpu(ctx->attr->value_length);
			ni->allocated_size = (ni->data_size + 7) & ~7;
		}
	}
	ntfs_attr_put_search_ctx(ctx);
out:
	ntfs_log_leave("\n");
	return ni;

put_err_out:
	ntfs_attr_put_search_ctx(ctx);
err_out:
	__ntfs_inode_release(ni);
	ni = NULL;
	goto out;
}