예제 #1
0
static void ntfs_index_ctx_free(ntfs_index_context *icx)
{
	ntfs_log_trace("Entering\n");
	
	if (!icx->entry)
		return;

	if (icx->actx)
		ntfs_attr_put_search_ctx(icx->actx);

	if (!icx->is_in_root) {
		if (icx->ib_dirty) {
			/* FIXME: Error handling!!! */
			ntfs_ib_write(icx, icx->ib);
		}
		free(icx->ib);
	}
	
	ntfs_attr_close(icx->ia_na);
}
예제 #2
0
static void ntfs_ir_nill(INDEX_ROOT *ir)
{
	INDEX_ENTRY *ie_last;
	char *ies_start, *ies_end;
	
	ntfs_log_trace("Entering\n");
	/*
	 * TODO: This function could be much simpler.
	 */
	ies_start = (char *)ntfs_ie_get_first(&ir->index);
	ies_end   = (char *)ntfs_ie_get_end(&ir->index);
	ie_last   = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end);
	/* 
	 * Move the index root termination entry forward
	 */
	if ((char *)ie_last > ies_start) {
		memmove(ies_start, (char *)ie_last, le16_to_cpu(ie_last->length));
		ie_last = (INDEX_ENTRY *)ies_start;
	}
}
예제 #3
0
static int ntfs_ibm_add(ntfs_index_context *icx)
{
	u8 bmp[8];

	ntfs_log_trace("Entering\n");

	if (ntfs_attr_exist(icx->ni, AT_BITMAP, icx->name, icx->name_len))
		return STATUS_OK;
	/*
	 * AT_BITMAP must be at least 8 bytes.
	 */
	memset(bmp, 0, sizeof(bmp));
	if (ntfs_attr_add(icx->ni, AT_BITMAP, icx->name, icx->name_len,
			  bmp, sizeof(bmp))) {
		ntfs_log_perror("Failed to add AT_BITMAP");
		return STATUS_ERROR;
	}

	return STATUS_OK;
}
예제 #4
0
/**
 * ntfs_pwrite - positioned write to disk
 * @dev:	device to write to
 * @pos:	position in file descriptor to write to
 * @count:	number of bytes to write
 * @b:		data buffer to write to disk
 *
 * This function will write @count bytes from data buffer @b to the device @dev
 * at position @pos.
 *
 * On success, return the number of successfully written bytes. If this number
 * is lower than @count this means that the write has been interrupted in
 * flight or that an error was encountered during the write so that the write
 * is partial. 0 means nothing was written (also return 0 when @count is 0).
 *
 * On error and nothing has been written, return -1 with errno set
 * appropriately to the return code of either seek, write, or set
 * to EINVAL in case of invalid arguments.
 */
s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
		const void *b)
{
	s64 written, total, ret = -1;
	struct ntfs_device_operations *dops;

	ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count);

	if (!b || count < 0 || pos < 0) {
		errno = EINVAL;
		goto out;
	}
	if (!count)
		return 0;
	if (NDevReadOnly(dev)) {
		errno = EROFS;
		goto out;
	}
	
	dops = dev->d_ops;

	NDevSetDirty(dev);
	for (total = 0; count; count -= written, total += written) {
		written = dops->pwrite(dev, (const char*)b + total, count,
				       pos + total);
		/* If everything ok, continue. */
		if (written > 0)
			continue;
		/*
		 * If nothing written or error return number of bytes written.
		 */
		if (!written || total)
			break;
		/* Nothing written and error, return error status. */
		total = written;
		break;
	}
	ret = total;
out:	
	return ret;
}
예제 #5
0
static s64 ntfs_device_uefi_io_seek(struct ntfs_device *dev, s64 offset, int whence)
{
	struct _uefi_fd *fd = DEV_FD(dev);
    ntfs_log_trace("dev %p, offset %li, whence %i\n", dev, offset, whence);
	//AsciiPrint("ntfs_device_uefi_io_seek\n\r");
    // Get the device driver descriptor
    
    if (!fd) {
        errno = EBADF;
        return -1;
    }

    // Set the current position on the device (in bytes)
    switch(whence) {
        case SEEK_SET: fd->pos = MIN(MAX(offset, 0), fd->len); break;
        case SEEK_CUR: fd->pos = MIN(MAX(fd->pos + offset, 0), fd->len); break;
        case SEEK_END: fd->pos = MIN(MAX(fd->len + offset, 0), fd->len); break;
    }

    return 0;
}
예제 #6
0
파일: index.c 프로젝트: AllardJ/Tomato
/**
 * On success return STATUS_OK or STATUS_KEEP_SEARCHING.
 * On error return STATUS_ERROR.
 */
static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn)
{			  
	INDEX_BLOCK *ib;
	u32 idx_size, allocated_size;
	int err = STATUS_ERROR;
	VCN old_vcn;

	ntfs_log_trace("Entering\n");
	
	ib = ntfs_malloc(icx->block_size);
	if (!ib)
		return -1;
	
	old_vcn = ntfs_icx_parent_vcn(icx);
	
	if (ntfs_ib_read(icx, old_vcn, ib))
		goto err_out;

	idx_size       = le32_to_cpu(ib->index.index_length);
	allocated_size = le32_to_cpu(ib->index.allocated_size);
	/* FIXME: sizeof(VCN) should be included only if ie has no VCN */
	if (idx_size + le16_to_cpu(ie->length) + sizeof(VCN) > allocated_size) {
		err = ntfs_ib_split(icx, ib);
		if (err == STATUS_OK)
			err = STATUS_KEEP_SEARCHING;
		goto err_out;
	}
	
	if (ntfs_ih_insert(&ib->index, ie, new_vcn, ntfs_icx_parent_pos(icx)))
		goto err_out;
	
	if (ntfs_ib_write(icx, ib))
		goto err_out;
	
	err = STATUS_OK;
err_out:	
	free(ib);
	return err;
}
예제 #7
0
파일: index.c 프로젝트: AllardJ/Tomato
/**
 * ntfs_index_ctx_get - allocate and initialize a new index context
 * @ni:		ntfs inode with which to initialize the context
 * @name:	name of the which context describes
 * @name_len:	length of the index name
 *
 * Allocate a new index context, initialize it with @ni and return it.
 * Return NULL if allocation failed.
 */
ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
				       ntfschar *name, u32 name_len)
{
	ntfs_index_context *icx;

	ntfs_log_trace("Entering\n");
	
	if (!ni) {
		errno = EINVAL;
		return NULL;
	}
	if (ni->nr_extents == -1)
		ni = ni->base_ni;
	icx = ntfs_calloc(sizeof(ntfs_index_context));
	if (icx)
		*icx = (ntfs_index_context) {
			.ni = ni,
			.name = name,
			.name_len = name_len,
		};
	return icx;
}
예제 #8
0
파일: index.c 프로젝트: AllardJ/Tomato
static int ntfs_ia_add(ntfs_index_context *icx)
{
	ntfs_log_trace("Entering\n");

	if (ntfs_ibm_add(icx))
		return -1;
	
	if (!ntfs_attr_exist(icx->ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len)) {
	
		if (ntfs_attr_add(icx->ni, AT_INDEX_ALLOCATION, icx->name,
				  icx->name_len, NULL, 0)) {
			ntfs_log_perror("Failed to add AT_INDEX_ALLOCATION");
			return -1;
		}
	}
	
	icx->ia_na = ntfs_ia_open(icx, icx->ni);
	if (!icx->ia_na)
		return -1;

	return 0;
}
예제 #9
0
파일: index.c 프로젝트: AllardJ/Tomato
/**
 * ntfs_index_add_filename - add filename to directory index
 * @ni:		ntfs inode describing directory to which index add filename
 * @fn:		FILE_NAME attribute to add
 * @mref:	reference of the inode which @fn describes
 *
 * Return 0 on success or -1 on error with errno set to the error code.
 */
int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref)
{
	INDEX_ENTRY *ie;
	ntfs_index_context *icx;
	int fn_size, ie_size, err, ret = -1;

	ntfs_log_trace("Entering\n");
	
	if (!ni || !fn) {
		ntfs_log_error("Invalid arguments.\n");
		errno = EINVAL;
		return -1;
	}
	
	fn_size = (fn->file_name_length * sizeof(ntfschar)) +
			sizeof(FILE_NAME_ATTR);
	ie_size = (sizeof(INDEX_ENTRY_HEADER) + fn_size + 7) & ~7;
	
	ie = ntfs_calloc(ie_size);
	if (!ie)
		return -1;

	ie->indexed_file = cpu_to_le64(mref);
	ie->length 	 = cpu_to_le16(ie_size);
	ie->key_length 	 = cpu_to_le16(fn_size);
	memcpy(&ie->key, fn, fn_size);
	
	icx = ntfs_index_ctx_get(ni, NTFS_INDEX_I30, 4);
	if (!icx)
		goto out;
	
	ret = ntfs_ie_add(icx, ie);
	err = errno;
	ntfs_index_ctx_put(icx);
	errno = err;
out:
	free(ie);
	return ret;
}
예제 #10
0
파일: index.c 프로젝트: AllardJ/Tomato
static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst)
{
	s64 pos, ret;

	ntfs_log_trace("vcn: %lld\n", (long long)vcn);
	
	pos = ntfs_ib_vcn_to_pos(icx, vcn);

	ret = ntfs_attr_mst_pread(icx->ia_na, pos, 1, icx->block_size, (u8 *)dst);
	if (ret != 1) {
		if (ret == -1)
			ntfs_log_perror("Failed to read index block");
		else 
			ntfs_log_error("Failed to read full index block at "
				       "%lld\n", (long long)pos);
		return -1;
	}
	
	if (ntfs_ia_check(icx, dst, vcn))
		return -1;
	
	return 0;
}
예제 #11
0
static int ntfs_device_uefi_io_stat(struct ntfs_device *dev, struct stat *buf)
{
	// Get the device driver descriptor
    struct _uefi_fd *fd = DEV_FD(dev);
	mode_t mode;

    ntfs_log_trace("dev %p, buf %p\n", dev, buf);

    
    if (!fd) {
        errno = EBADF;
        return -1;
    }

    // Short circuit cases were we don't actually have to do anything
    if (!buf)
        return 0;

    // Build the device mode
    mode = (S_IFBLK) |
                  (S_IRUSR | S_IRGRP | S_IROTH) |
                  ((!NDevReadOnly(dev)) ? (S_IWUSR | S_IWGRP | S_IWOTH) : 0);

    // Zero out the stat buffer
    memset(buf, 0, sizeof(struct stat));

    // Build the device stats
    buf->st_dev = 0;//fd->interface->ioType;
    buf->st_ino = fd->ino;
    buf->st_mode = mode;
    buf->st_rdev = 0; //fd->interface->ioType;
    buf->st_blksize = fd->sectorSize;
    buf->st_blocks = fd->sectorCount;

    return 0;
}
예제 #12
0
int ntfs_fstat_r (struct _reent *r, int fd, struct stat *st)
{
    ntfs_log_trace("fd %p\n", fd);

    ntfs_file_state* file = STATE(fd);
    int ret = 0;
    
    // Sanity check
    if (!file || !file->vd || !file->ni || !file->data_na) {
        r->_errno = EINVAL;
        return -1;
    }
    
    // Short circuit cases were we don't actually have to do anything
    if (!st)
        return 0;
    
    // Get the file stats
    ret = ntfsStat(file->vd, file->ni, st);
    if (ret)
        r->_errno = errno;
    
    return ret;
}
예제 #13
0
DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path)
{
    ntfs_log_trace("dirState %p, path %s\n", dirState, path);

    ntfs_dir_state* dir = STATE(dirState);
    s64 position = 0;

    // Get the volume descriptor for this path
    dir->vd = ntfsGetVolume(path);
    if (!dir->vd) {
        r->_errno = ENODEV;
        return NULL;
    }

    // Lock
    ntfsLock(dir->vd);

    // Find the directory
    dir->ni = ntfsOpenEntry(dir->vd, path);
    if (!dir->ni) {
        ntfsUnlock(dir->vd);
        r->_errno = ENOENT;
        return NULL;
    }

    // Ensure that this directory is indeed a directory
    if (!(dir->ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
        ntfsCloseEntry(dir->vd, dir->ni);
        ntfsUnlock(dir->vd);
        r->_errno = ENOTDIR;
        return NULL;
    }

    // Read the directory
    dir->first = dir->current = NULL;
    if (ntfs_readdir(dir->ni, &position, dirState, (ntfs_filldir_t)ntfs_readdir_filler)) {
        ntfsCloseDir(dir);
        ntfsUnlock(dir->vd);
        r->_errno = errno;
        return NULL;
    }

    // Move to the first entry in the directory
    dir->current = dir->first;

    // Update directory times
    ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);

    // Insert the directory into the double-linked FILO list of open directories
    if (dir->vd->firstOpenDir) {
        dir->nextOpenDir = dir->vd->firstOpenDir;
        dir->vd->firstOpenDir->prevOpenDir = dir;
    } else {
        dir->nextOpenDir = NULL;
    }
    dir->prevOpenDir = NULL;
    dir->vd->cwd_ni = dir->ni;
    dir->vd->firstOpenDir = dir;
    dir->vd->openDirCount++;

    // Unlock
    ntfsUnlock(dir->vd);

    return dirState;
}
예제 #14
0
int ntfs_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
{
    ntfs_log_trace("path %s, buf %p\n", path, buf);

    ntfs_vd *vd = NULL;
    s64 size;
    int delta_bits;

    // Get the volume descriptor for this path
    vd = ntfsGetVolume(path);
    if (!vd) {
        r->_errno = ENODEV;
        return -1;
    }

    // Short circuit cases were we don't actually have to do anything
    if (!buf)
        return 0;

    // Lock
    ntfsLock(vd);

    // Zero out the stat buffer
    memset(buf, 0, sizeof(struct statvfs));

    if(ntfs_volume_get_free_space(vd->vol) < 0)
    {
        ntfsUnlock(vd);
        return -1;
    }

    // File system block size
    buf->f_bsize = vd->vol->cluster_size;

    // Fundamental file system block size
    buf->f_frsize = vd->vol->cluster_size;

    // Total number of blocks on file system in units of f_frsize
    buf->f_blocks = vd->vol->nr_clusters;

    // Free blocks available for all and for non-privileged processes
    size = MAX(vd->vol->free_clusters, 0);
    buf->f_bfree = buf->f_bavail = size;

    // Free inodes on the free space
    delta_bits = vd->vol->cluster_size_bits - vd->vol->mft_record_size_bits;
    if (delta_bits >= 0)
        size <<= delta_bits;
    else
        size >>= -delta_bits;

    // Number of inodes at this point in time
    buf->f_files = (vd->vol->mftbmp_na->allocated_size << 3) + size;

    // Free inodes available for all and for non-privileged processes
    size += vd->vol->free_mft_records;
    buf->f_ffree = buf->f_favail = MAX(size, 0);

    // File system id
    buf->f_fsid = vd->id;

    // Bit mask of f_flag values.
    buf->f_flag = (NVolReadOnly(vd->vol) ? ST_RDONLY : 0);

    // Maximum length of filenames
    buf->f_namemax = NTFS_MAX_NAME_LEN;

    // Unlock
    ntfsUnlock(vd);

    return 0;
}
예제 #15
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;
}
예제 #16
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;
}
예제 #17
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;
}
예제 #18
0
static int ntfs_device_uefi_io_ioctl(struct ntfs_device *dev, int request, void *argp)
{
	struct _uefi_fd *fd = DEV_FD(dev);
    ntfs_log_trace("dev %p, request %i, argp %p\n", dev, request, argp);

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

    // Figure out which i/o control was requested
    switch (request) {

        // Get block device size (sectors)
        #if defined(BLKGETSIZE)
        case BLKGETSIZE: {
            *(u32*)argp = fd->sectorCount;
            return 0;
        }
        #endif

        // Get block device size (bytes)
        #if defined(BLKGETSIZE64)
        case BLKGETSIZE64: {
            *(u64*)argp = (fd->sectorCount * fd->sectorSize);
            return 0;
        }
        #endif

        // Get hard drive geometry
        #if defined(HDIO_GETGEO)
        case HDIO_GETGEO: {
            struct hd_geometry *geo = (struct hd_geometry*)argp;
            geo->sectors = 0;
            geo->heads = 0;
            geo->cylinders = 0;
            geo->start = fd->hiddenSectors;
            return -1;
        }
        #endif

        // Get block device sector size (bytes)
        #if defined(BLKSSZGET)
        case BLKSSZGET: {
            *(int*)argp = fd->sectorSize;
            return 0;
        }
        #endif

        // Set block device block size (bytes)
        #if defined(BLKBSZSET)
        case BLKBSZSET: {
            int sectorSize = *(int*)argp;
            fd->sectorSize = sectorSize;
            return 0;
        }
        #endif

        // Unimplemented ioctrl
        default: {
            ntfs_log_perror("Unimplemented ioctrl %i\n", request);
            errno = EOPNOTSUPP;
            return -1;
        }

    }

    return 0;
}
예제 #19
0
static s64 ntfs_device_uefi_io_writebytes(struct ntfs_device *dev, s64 offset, s64 count, const void *buf)
{
	struct _uefi_fd *fd = DEV_FD(dev);
	sec_t sec_start;
    sec_t sec_count;
    u32 buffer_offset;
    u8 *buffer;

    ntfs_log_trace("dev %p, offset %l, count %l\n", dev, offset, count);

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

    // Get the device interface
//const DISC_INTERFACE* interface = fd->interface;
//if (!interface) {
//    errno = ENODEV;
//    return -1;
//}

    // Check that the device can be written to
    if (NDevReadOnly(dev)) {
        errno = EROFS;
        return -1;
    }

    if(count < 0 || offset < 0) {
        errno = EROFS;
        return -1;
    }

    if(count == 0)
        return 0;

    sec_start = (sec_t) fd->startSector;
    sec_count = 1;
    buffer_offset = (u32) (offset % fd->sectorSize);
    buffer = NULL;

    // Determine the range of sectors required for this write
    if (offset > 0) {
        sec_start += (sec_t) offset / fd->sectorSize;
    }
    if ((buffer_offset+count) > fd->sectorSize) {
        sec_count = (sec_t) ((buffer_offset+count) / fd->sectorSize);

		if (((buffer_offset+count) % fd->sectorSize) != 0)
			sec_count++;
    }

    // If this write happens to be on the sector boundaries then do the write straight to disc
    if((buffer_offset == 0) && (count % fd->sectorSize == 0))
    {
        // Write to the device
        ntfs_log_trace("direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count);
        if (!ntfs_device_uefi_io_writesectors(dev, sec_start, sec_count, buf)) {
            ntfs_log_perror("direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
            errno = EIO;
            return -1;
        }
    // Else write from a buffer aligned to the sector boundaries
    }
    else
    {
        // Allocate a buffer to hold the write data
        buffer = (u8 *) ntfs_alloc(sec_count * fd->sectorSize);
        if (!buffer) {
            errno = ENOMEM;
            return -1;
        }
        // Read the first and last sectors of the buffer from disc (if required)
        // NOTE: This is done because the data does not line up with the sector boundaries,
        //       we just read in the buffer edges where the data overlaps with the rest of the disc
        if(buffer_offset != 0)
        {
            if (!ntfs_device_uefi_io_readsectors(dev, sec_start, 1, buffer)) {
                ntfs_log_perror("read failure @ sector %d\n", sec_start);
                ntfs_free(buffer);
                errno = EIO;
                return -1;
            }
        }
        if((buffer_offset+count) % fd->sectorSize != 0)
        {
            if (!ntfs_device_uefi_io_readsectors(dev, sec_start + sec_count - 1, 1, buffer + ((sec_count-1) * fd->sectorSize))) {
                ntfs_log_perror("read failure @ sector %d\n", sec_start + sec_count - 1);
                ntfs_free(buffer);
                errno = EIO;
                return -1;
            }
        }

        // Copy the data into the write buffer
        memcpy(buffer + buffer_offset, buf, count);

        // Write to the device
        ntfs_log_trace("buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count);
        if (!ntfs_device_uefi_io_writesectors(dev, sec_start, sec_count, buffer)) {
            ntfs_log_perror("buffered write failure @ sector %d\n", sec_start);
            ntfs_free(buffer);
            errno = EIO;
            return -1;
        }

        // Free the buffer
        ntfs_free(buffer);
    }

    // Mark the device as dirty (if we actually wrote anything)
    NDevSetDirty(dev);

    return count;
}
예제 #20
0
static s64 ntfs_device_uefi_io_readbytes(struct ntfs_device *dev, s64 offset, s64 count, void *buf)
{
	struct _uefi_fd *fd = DEV_FD(dev);
    sec_t sec_start = (sec_t) fd->startSector;
    sec_t sec_count = 1;
    u32 buffer_offset = (u32) (offset % fd->sectorSize);
    u8 *buffer = NULL;

	//const DISC_INTERFACE* interface;

    ntfs_log_trace("dev %p, offset %li, count %li\n", dev, offset, count);
    // Get the device driver descriptor
    
    if (!fd) {
		//AsciiPrint("ntfs_device_uefi_io_readbytes EBADF\n\r");
		ntfs_log_perror("EBADF");
        errno = EBADF;
        return -1;
    }

    //// Get the device interface
    //interface = fd->interface;
    //if (!interface) {
    //    errno = ENODEV;
    //    return -1;
    //}

    if(offset < 0)
    {
		//AsciiPrint("ntfs_device_uefi_io_readbytes EROFS\n\r");
        errno = EROFS;
		ntfs_log_perror("EROFS");
        return -1;
    }

    if(!count)
        return 0;

    // Determine the range of sectors required for this read
    if (offset > 0) {
        sec_start += (sec_t) offset / fd->sectorSize;
    }
    if (buffer_offset+count > fd->sectorSize) {
        sec_count = (sec_t) (buffer_offset+count) / fd->sectorSize;

		if (((buffer_offset+count) % fd->sectorSize) != 0)
			sec_count++;
    }

    // If this read happens to be on the sector boundaries then do the read straight into the destination buffer

    if((buffer_offset == 0) && (count % fd->sectorSize == 0)) {

        // Read from the device
        ntfs_log_trace("direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count);
        if (!ntfs_device_uefi_io_readsectors(dev, sec_start, sec_count, buf)) {
            ntfs_log_perror("direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
			//AsciiPrint("ntfs_device_uefi_io_readbytes EIO\n\r");
            errno = EIO;
			
            return -1;
        }

    // Else read into a buffer and copy over only what was requested
    }
    else
	{

        // Allocate a buffer to hold the read data
        buffer = (u8*)ntfs_alloc(sec_count * fd->sectorSize);
        if (!buffer) {
            errno = ENOMEM;
            return -1;
        }

        // Read from the device
        ntfs_log_trace("buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count);
        ntfs_log_trace("count: %d  sec_count:%d  fd->sectorSize: %d )\n", (u32)count, (u32)sec_count,(u32)fd->sectorSize);
        if (!ntfs_device_uefi_io_readsectors(dev, sec_start, sec_count, buffer)) {
			//AsciiPrint("ntfs_device_uefi_io_readbytes buffered read failure\n\r");
            ntfs_log_perror("buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
            ntfs_free(buffer);
            errno = EIO;
            return -1;
        }

        // Copy what was requested to the destination buffer
        memcpy(buf, buffer + buffer_offset, count);
        ntfs_free(buffer);

    }

	//ntfs_log_perror("Read %d sectors", count);
    return count;
}
예제 #21
0
파일: index.c 프로젝트: AllardJ/Tomato
static int ntfs_ir_reparent(ntfs_index_context *icx)
{
	ntfs_attr_search_ctx *ctx = NULL;
	INDEX_ROOT *ir;
	INDEX_ENTRY *ie;
	INDEX_BLOCK *ib = NULL;
	VCN new_ib_vcn;
	int ix_root_size;
	int ret = STATUS_ERROR;

	ntfs_log_trace("Entering\n");
	
	ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
	if (!ir)
		goto out;
	
	if ((ir->index.ih_flags & NODE_MASK) == SMALL_INDEX)
		if (ntfs_ia_add(icx))
			goto out;
	
	new_ib_vcn = ntfs_ibm_get_free(icx);
	if (new_ib_vcn == -1)
		goto out;
		
	ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
	if (!ir)
		goto clear_bmp;
	
	ib = ntfs_ir_to_ib(ir, new_ib_vcn);
	if (ib == NULL) {
		ntfs_log_perror("Failed to move index root to index block");
		goto clear_bmp;
	}
		
	if (ntfs_ib_write(icx, ib))
		goto clear_bmp;
	
retry :
	ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx);
	if (!ir)
		goto clear_bmp;
	
	ntfs_ir_nill(ir);
	
	ie = ntfs_ie_get_first(&ir->index);
	ie->ie_flags |= INDEX_ENTRY_NODE;
	ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN));
	
	ir->index.ih_flags = LARGE_INDEX;
	ir->index.index_length = cpu_to_le32(le32_to_cpu(ir->index.entries_offset)
					     + le16_to_cpu(ie->length));
	ir->index.allocated_size = ir->index.index_length;
	ix_root_size = sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER)
			+ le32_to_cpu(ir->index.allocated_size);
	if (ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr,
					ix_root_size)) {
			/*
			 * When there is no space to build a non-resident
			 * index, we may have to move the root to an extent
			 */
		if ((errno == ENOSPC)
		    && !ctx->al_entry
		    && !ntfs_inode_add_attrlist(icx->ni)) {
			ntfs_attr_put_search_ctx(ctx);
			ctx = (ntfs_attr_search_ctx*)NULL;
			ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len,
							&ctx);
			if (ir
			    && !ntfs_attr_record_move_away(ctx, ix_root_size
				    - le32_to_cpu(ctx->attr->value_length))) {
				ntfs_attr_put_search_ctx(ctx);
				ctx = (ntfs_attr_search_ctx*)NULL;
				goto retry;
			}
		}
		/* FIXME: revert index root */
		goto clear_bmp;
	}
	/*
	 *  FIXME: do it earlier if we have enough space in IR (should always),
	 *  so in error case we wouldn't lose the IB.
	 */
	ntfs_ie_set_vcn(ie, new_ib_vcn);
	
	ret = STATUS_OK;
err_out:
	free(ib);
	ntfs_attr_put_search_ctx(ctx);
out:
	return ret;
clear_bmp:
	ntfs_ibm_clear(icx, new_ib_vcn);
	goto err_out;
}
예제 #22
0
//static size_t ntfs_attr_to_sectors(ntfs_attr *na, const s64 pos, s64 count, uint32_t *sec_out, uint32_t *size_out, int max, uint32_t *s_count, u32 sector_size)
static s64 ntfs_attr_to_sectors(ntfs_attr *na, const s64 pos, s64 count, uint32_t *sec_out, uint32_t *size_out, int max, uint32_t *s_count, u32 sector_size)
{
	s64 br, to_read, ofs, total, total2, max_read, max_init;
	ntfs_volume *vol;
	runlist_element *rl;
	uint64_t cur_sector, prev_sector;

	if (*s_count == 0)
	{
		prev_sector = 0xFFFFFFFF;
	}
	else
	{
		prev_sector = sec_out[*s_count-1];

		if (prev_sector != 0xFFFFFFFF)
		{
			prev_sector += size_out[*s_count]-1;
		}
	}

	if (*s_count >= max)
		return 0;

	vol = na->ni->vol;
	if (!count)
		return 0;

	max_read = na->data_size;
	max_init = na->initialized_size;
	if (pos + count > max_read) {
		if (pos >= max_read)
			return 0;
		count = max_read - pos;
	}
	total = total2 = 0;
	/* Zero out reads beyond initialized size. */
	if (pos + count > max_init) {
		if (pos >= max_init) {
			//memset(b, 0, count);
			return count;
		}
		total2 = pos + count - max_init;
		count -= total2;
		//memset((u8*)b + count, 0, total2);
	}

	/* Find the runlist element containing the vcn. */
	rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits);
	if (!rl) {
		/*
		 * If the vcn is not present it is an out of bounds read.
		 * However, we already truncated the read to the data_size,
		 * so getting this here is an error.
		 */
		if (errno == ENOENT) {
			errno = EIO;
			ntfs_log_perror("%s: Failed to find VCN #1", __FUNCTION__);
		}
		return -1;
	}

	ofs = pos - (rl->vcn << vol->cluster_size_bits);
	for (; count && *s_count < max; rl++, ofs = 0) {
		if (rl->lcn == LCN_RL_NOT_MAPPED) {
			rl = ntfs_attr_find_vcn(na, rl->vcn);
			if (!rl) {
				if (errno == ENOENT) {
					errno = EIO;
					ntfs_log_perror("%s: Failed to find VCN #2", __FUNCTION__);
				}
				goto rl_err_out;
			}
			/* Needed for case when runs merged. */
			ofs = pos + total - (rl->vcn << vol->cluster_size_bits);
		}
		if (!rl->length) {
			errno = EIO;
			ntfs_log_perror("%s: Zero run length", __FUNCTION__);
			goto rl_err_out;
		}
		if (rl->lcn < (LCN)0) {
			if (rl->lcn != (LCN)LCN_HOLE) {
				ntfs_log_perror("%s: Bad run (%lld)", __FUNCTION__, (long long)rl->lcn);
				goto rl_err_out;
			}
			/* It is a hole, just zero the matching @b range. */
			to_read = min(count, (rl->length << vol->cluster_size_bits) - ofs);

			if (to_read < sector_size)
				to_read = sector_size;

			if (*s_count == 0)
			{
				prev_sector = sec_out[0] = 0xFFFFFFFF;
				size_out[0] = to_read / sector_size;
				(*s_count)++;
			}
			else
			{
				if (prev_sector == 0xFFFFFFFF)
				{
					size_out[*s_count-1] += (to_read / sector_size);
				}
				else
				{
					prev_sector = sec_out[*s_count] = 0xFFFFFFFF;
					size_out[*s_count] = to_read / sector_size;
					(*s_count)++;
				}
			}
			/* Update progress counters. */
			total += to_read;
			count -= to_read;
			//b = (u8*)b + to_read;
			continue;
		}
		/* It is a real lcn, read it into @dst. */
		to_read = min(count, (rl->length << vol->cluster_size_bits) - ofs);

		ntfs_log_trace("Reading %lld bytes from vcn %lld, lcn %lld, ofs" " %lld.\n", (long long)to_read, (long long)rl->vcn, (long long)rl->lcn, (long long)ofs);
		br = to_read; /*ntfs_pread(vol->dev, (rl->lcn << vol->cluster_size_bits) +
				ofs, to_read, b);*/

		cur_sector = (rl->lcn << vol->cluster_size_bits) + ofs;
		cur_sector /= sector_size;

		if (to_read % sector_size)
		{
			to_read = to_read + sector_size - (to_read % sector_size);
		}

		if (prev_sector == cur_sector)
		{
			size_out[*s_count-1] += (to_read / sector_size);
			prev_sector += (to_read / sector_size);
		}
		else
		{
			sec_out[*s_count] = cur_sector;
			size_out[*s_count] = to_read / sector_size;
			prev_sector = sec_out[*s_count] + size_out[*s_count];
			(*s_count)++;
		}

		/* If everything ok, update progress counters and continue. */
		if (br > 0) {
			total += br;
			count -= br;
			//b = (u8*)b + br;
		}
		if (br == to_read)
			continue;

		if (total)
			return total;
		if (!br)
			errno = EIO;
		ntfs_log_perror("%s: ntfs_pread failed", __FUNCTION__);
		return -1;
	}
	/* Finally, return the number of bytes read. */
	return total + total2;
rl_err_out:
	if (total)
		return total;
	errno = EIO;
	return -1;
}
예제 #23
0
ssize_t ntfs_write_r(struct _reent *r, int fd, const char *ptr, size_t len)
{
	ntfs_log_trace("fd %p, ptr %p, len %u\n", (void *) fd, ptr, len);

	ntfs_file_state* file = STATE(((intptr_t)(s64)fd));
	//ntfs_file_state* file = STATE(((s64) fd));
	ssize_t written = 0;
	off_t old_pos = 0;

	// Sanity check
	if (!file || !file->vd || !file->ni || !file->data_na) {
		r->_errno = EINVAL;
		return -1;
	}

	// Short circuit cases where we don't actually have to do anything
	if (!ptr || len <= 0) {
		return 0;
	}

	// Lock
	ntfsLock(file->vd);

	// Check that we are allowed to write to this file
	if (!file->write) {
		ntfsUnlock(file->vd);
		r->_errno = EACCES;
		return -1;
	}

	// If we are in append mode, backup the current position and move to the end of the file
	if (file->append) {
		old_pos = file->pos;
		file->pos = file->len;
	}

	// Write to the files data atrribute
	while (len) {
		ssize_t ret = ntfs_attr_pwrite(file->data_na, file->pos, len, ptr);
		if (ret <= 0) {
			ntfsUnlock(file->vd);
			r->_errno = errno;
			return -1;
		}
		len -= ret;
		file->pos += ret;
		written += ret;
	}

	// If we are in append mode, restore the current position to were it was prior to this write
	if (file->append) {
		file->pos = old_pos;
	}

	// Mark the file for archiving (if we actually wrote something)
	if (written)
		file->ni->flags |= FILE_ATTR_ARCHIVE;

	// Update the files data length
	file->len = file->data_na->data_size;

	// Unlock
	ntfsUnlock(file->vd);

	return written;
}
예제 #24
0
파일: index.c 프로젝트: AllardJ/Tomato
/** 
 * Find a key in the index block.
 * 
 * Return values:
 *   STATUS_OK with errno set to ESUCCESS if we know for sure that the 
 *             entry exists and @ie_out points to this entry.
 *   STATUS_NOT_FOUND with errno set to ENOENT if we know for sure the
 *                    entry doesn't exist and @ie_out is the insertion point.
 *   STATUS_KEEP_SEARCHING if we can't answer the above question and
 *                         @vcn will contain the node index block.
 *   STATUS_ERROR with errno set if on unexpected error during lookup.
 */
static int ntfs_ie_lookup(const void *key, const int key_len,
			  ntfs_index_context *icx, INDEX_HEADER *ih,
			  VCN *vcn, INDEX_ENTRY **ie_out)
{
	INDEX_ENTRY *ie;
	u8 *index_end;
	int rc, item = 0;
	 
	ntfs_log_trace("Entering\n");
	
	index_end = ntfs_ie_get_end(ih);
	
	/*
	 * Loop until we exceed valid memory (corruption case) or until we
	 * reach the last entry.
	 */
	for (ie = ntfs_ie_get_first(ih); ; ie = ntfs_ie_get_next(ie)) {
		/* Bounds checks. */
		if ((u8 *)ie + sizeof(INDEX_ENTRY_HEADER) > index_end ||
		    (u8 *)ie + le16_to_cpu(ie->length) > index_end) {
			errno = ERANGE;
			ntfs_log_error("Index entry out of bounds in inode "
				       "%llu.\n",
				       (unsigned long long)icx->ni->mft_no);
			return STATUS_ERROR;
		}
		/*
		 * The last entry cannot contain a key.  It can however contain
		 * a pointer to a child node in the B+tree so we just break out.
		 */
		if (ntfs_ie_end(ie))
			break;
		/*
		 * Not a perfect match, need to do full blown collation so we
		 * know which way in the B+tree we have to go.
		 */
		if (!icx->collate) {
			ntfs_log_error("Collation function not defined\n");
			errno = EOPNOTSUPP;
			return STATUS_ERROR;
		}
		rc = icx->collate(icx->ni->vol, key, key_len,
					&ie->key, le16_to_cpu(ie->key_length));
		if (rc == NTFS_COLLATION_ERROR) {
			ntfs_log_error("Collation error. Perhaps a filename "
				       "contains invalid characters?\n");
			errno = ERANGE;
			return STATUS_ERROR;
		}
		/*
		 * If @key collates before the key of the current entry, there
		 * is definitely no such key in this index but we might need to
		 * descend into the B+tree so we just break out of the loop.
		 */
		if (rc == -1)
			break;
		
		if (!rc) {
			*ie_out = ie;
			errno = 0;
			icx->parent_pos[icx->pindex] = item;
			return STATUS_OK;
		}
		
		item++;
	}
	/*
	 * We have finished with this index block without success. Check for the
	 * presence of a child node and if not present return with errno ENOENT,
	 * otherwise we will keep searching in another index block.
	 */
	if (!(ie->ie_flags & INDEX_ENTRY_NODE)) {
		ntfs_log_debug("Index entry wasn't found.\n");
		*ie_out = ie;
		errno = ENOENT;
		return STATUS_NOT_FOUND;
	}
	
	/* Get the starting vcn of the index_block holding the child node. */
	*vcn = ntfs_ie_get_vcn(ie);
	if (*vcn < 0) {
		errno = EINVAL;
		ntfs_log_perror("Negative vcn in inode %llu",
			       	(unsigned long long)icx->ni->mft_no);
		return STATUS_ERROR;
	}

	ntfs_log_trace("Parent entry number %d\n", item);
	icx->parent_pos[icx->pindex] = item;
	
	return STATUS_KEEP_SEARCHING;
}
예제 #25
0
파일: index.c 프로젝트: AllardJ/Tomato
static int ntfs_index_rm_node(ntfs_index_context *icx)
{
	int entry_pos, pindex;
	VCN vcn;
	INDEX_BLOCK *ib = NULL;
	INDEX_ENTRY *ie_succ, *ie, *entry = icx->entry;
	INDEX_HEADER *ih;
	u32 new_size;
	int delta, ret = STATUS_ERROR;

	ntfs_log_trace("Entering\n");
	
	if (!icx->ia_na) {
		icx->ia_na = ntfs_ia_open(icx, icx->ni);
		if (!icx->ia_na)
			return STATUS_ERROR;
	}

	ib = ntfs_malloc(icx->block_size);
	if (!ib)
		return STATUS_ERROR;
	
	ie_succ = ntfs_ie_get_next(icx->entry);
	entry_pos = icx->parent_pos[icx->pindex]++;
	pindex = icx->pindex;
descend:
	vcn = ntfs_ie_get_vcn(ie_succ);
	if (ntfs_ib_read(icx, vcn, ib))
		goto out;
	
	ie_succ = ntfs_ie_get_first(&ib->index);

	if (ntfs_icx_parent_inc(icx))
		goto out;
	
	icx->parent_vcn[icx->pindex] = vcn;
	icx->parent_pos[icx->pindex] = 0;

	if ((ib->index.ih_flags & NODE_MASK) == INDEX_NODE)
		goto descend;

	if (ntfs_ih_zero_entry(&ib->index)) {
		errno = EIO;
		ntfs_log_perror("Empty index block");
		goto out;
	}

	ie = ntfs_ie_dup(ie_succ);
	if (!ie)
		goto out;
	
	if (ntfs_ie_add_vcn(&ie))
		goto out2;

	ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(icx->entry));

	if (icx->is_in_root)
		ih = &icx->ir->index;
	else
		ih = &icx->ib->index;

	delta = le16_to_cpu(ie->length) - le16_to_cpu(icx->entry->length);
	new_size = le32_to_cpu(ih->index_length) + delta;
	if (delta > 0) {
		if (icx->is_in_root) {
			ret = ntfs_ir_make_space(icx, new_size);
			if (ret != STATUS_OK)
				goto out2;
			
			ih = &icx->ir->index;
			entry = ntfs_ie_get_by_pos(ih, entry_pos);
			
		} else if (new_size > le32_to_cpu(ih->allocated_size)) {
			icx->pindex = pindex;
			ret = ntfs_ib_split(icx, icx->ib);
			if (ret == STATUS_OK)
				ret = STATUS_KEEP_SEARCHING;
			goto out2;
		}
	}

	ntfs_ie_delete(ih, entry);
	ntfs_ie_insert(ih, ie, entry);
	
	if (icx->is_in_root) {
		if (ntfs_ir_truncate(icx, new_size))
			goto out2;
	} else
		if (ntfs_icx_ib_write(icx))
			goto out2;
	
	ntfs_ie_delete(&ib->index, ie_succ);
	
	if (ntfs_ih_zero_entry(&ib->index)) {
		if (ntfs_index_rm_leaf(icx))
			goto out2;
	} else 
		if (ntfs_ib_write(icx, ib))
			goto out2;

	ret = STATUS_OK;
out2:
	free(ie);
out:
	free(ib);
	return ret;
}
예제 #26
0
파일: index.c 프로젝트: AllardJ/Tomato
/* JPA static */
int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie)
{
	INDEX_HEADER *ih;
	int allocated_size, new_size;
	int ret = STATUS_ERROR;
	
#ifdef DEBUG
/* removed by JPA to make function usable for security indexes
	char *fn;
	fn = ntfs_ie_filename_get(ie);
	ntfs_log_trace("file: '%s'\n", fn);
	ntfs_attr_name_free(&fn);
*/
#endif
	
	while (1) {
				
		if (!ntfs_index_lookup(&ie->key, le16_to_cpu(ie->key_length), icx)) {
			errno = EEXIST;
			ntfs_log_perror("Index already have such entry");
			goto err_out;
		}
		if (errno != ENOENT) {
			ntfs_log_perror("Failed to find place for new entry");
			goto err_out;
		}
		
		if (icx->is_in_root)
			ih = &icx->ir->index;
		else
			ih = &icx->ib->index;
		
		allocated_size = le32_to_cpu(ih->allocated_size);
		new_size = le32_to_cpu(ih->index_length) + le16_to_cpu(ie->length);
	
		if (new_size <= allocated_size)
			break;
		
		ntfs_log_trace("index block sizes: allocated: %d  needed: %d\n",
			       allocated_size, new_size);
		
		if (icx->is_in_root) {
			if (ntfs_ir_make_space(icx, new_size) == STATUS_ERROR)
				goto err_out;
		} else {
			if (ntfs_ib_split(icx, icx->ib) == STATUS_ERROR)
				goto err_out;
		}
		
		ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
		ntfs_index_ctx_reinit(icx);
	}
	
	ntfs_ie_insert(ih, ie, icx->entry);
	ntfs_index_entry_mark_dirty(icx);
	
	ret = STATUS_OK;
err_out:
	ntfs_log_trace("%s\n", ret ? "Failed" : "Done");
	return ret;
}
예제 #27
0
int ntfs_ftruncate_r(struct _reent *r, int fd, off_t len)
{
	ntfs_log_trace("fd %p, len %llu\n", (void *) fd, (u64) len);

	ntfs_file_state* file = STATE(((intptr_t)(s64)fd));
	//ntfs_file_state* file = STATE(((s64) fd));

	// Sanity check
	if (!file || !file->vd || !file->ni || !file->data_na) {
		r->_errno = EINVAL;
		return -1;
	}

	// Lock
	ntfsLock(file->vd);

	// Check that we are allowed to write to this file
	if (!file->write) {
		ntfsUnlock(file->vd);
		r->_errno = EACCES;
		return -1;
	}

	// For compressed files, only deleting and expanding contents are implemented
	if (file->compressed &&
		len > 0 &&
		len < file->data_na->initialized_size) {
		ntfsUnlock(file->vd);
		r->_errno = ENOTSUP;
		return -1;
	}

	// Resize the files data attribute, either by expanding or truncating
	if (file->compressed && len > file->data_na->initialized_size) {
		char zero = 0;
		if (ntfs_attr_pwrite(file->data_na, len - 1, 1, &zero) <= 0) {
			ntfsUnlock(file->vd);
			r->_errno = errno;
			return -1;
		}
	} else {
		if (ntfs_attr_truncate(file->data_na, len)) {
			ntfsUnlock(file->vd);
			r->_errno = errno;
			return -1;
		}
	}

	// Mark the file for archiving (if we actually changed something)
	if (file->len != file->data_na->data_size)
		file->ni->flags |= FILE_ATTR_ARCHIVE;

	// Update file times (if we actually changed something)
	if (file->len != file->data_na->data_size)
		ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_AMCTIME);

	// Update the files data length
	file->len = file->data_na->data_size;

	// Sync the file (and its attributes) to disc
	ntfsSync(file->vd, file->ni);

	// Unlock
	ntfsUnlock(file->vd);

	return 0;
}
예제 #28
0
파일: index.c 프로젝트: AllardJ/Tomato
/**
 * ntfs_index_lookup - find a key in an index and return its index entry
 * @key:	[IN] key for which to search in the index
 * @key_len:	[IN] length of @key in bytes
 * @icx:	[IN/OUT] context describing the index and the returned entry
 *
 * Before calling ntfs_index_lookup(), @icx must have been obtained from a
 * call to ntfs_index_ctx_get().
 *
 * Look for the @key in the index specified by the index lookup context @icx.
 * ntfs_index_lookup() walks the contents of the index looking for the @key.
 *
 * If the @key is found in the index, 0 is returned and @icx is setup to
 * describe the index entry containing the matching @key.  @icx->entry is the
 * index entry and @icx->data and @icx->data_len are the index entry data and
 * its length in bytes, respectively.
 *
 * If the @key is not found in the index, -1 is returned, errno = ENOENT and
 * @icx is setup to describe the index entry whose key collates immediately
 * after the search @key, i.e. this is the position in the index at which
 * an index entry with a key of @key would need to be inserted.
 *
 * If an error occurs return -1, set errno to error code and @icx is left
 * untouched.
 *
 * When finished with the entry and its data, call ntfs_index_ctx_put() to free
 * the context and other associated resources.
 *
 * If the index entry was modified, call ntfs_index_entry_mark_dirty() before
 * the call to ntfs_index_ctx_put() to ensure that the changes are written
 * to disk.
 */
int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *icx)
{
	VCN old_vcn, vcn;
	ntfs_inode *ni = icx->ni;
	INDEX_ROOT *ir;
	INDEX_ENTRY *ie;
	INDEX_BLOCK *ib = NULL;
	int ret, err = 0;

	ntfs_log_trace("Entering\n");
	
	if (!key || key_len <= 0) {
		errno = EINVAL;
		ntfs_log_perror("key: %p  key_len: %d", key, key_len);
		return -1;
	}

	ir = ntfs_ir_lookup(ni, icx->name, icx->name_len, &icx->actx);
	if (!ir) {
		if (errno == ENOENT)
			errno = EIO;
		return -1;
	}
	
	icx->block_size = le32_to_cpu(ir->index_block_size);
	if (icx->block_size < NTFS_BLOCK_SIZE) {
		errno = EINVAL;
		ntfs_log_perror("Index block size (%d) is smaller than the "
				"sector size (%d)", icx->block_size, NTFS_BLOCK_SIZE);
		goto err_out;
	}

	if (ni->vol->cluster_size <= icx->block_size)
		icx->vcn_size_bits = ni->vol->cluster_size_bits;
	else
		icx->vcn_size_bits = NTFS_BLOCK_SIZE_BITS;
			/* get the appropriate collation function */
	icx->collate = ntfs_get_collate_function(ir->collation_rule);
	if (!icx->collate) {
		err = errno = EOPNOTSUPP;
		ntfs_log_perror("Unknown collation rule 0x%x", 
				(unsigned)le32_to_cpu(ir->collation_rule));
		goto err_out;
	}
	
	old_vcn = VCN_INDEX_ROOT_PARENT;
	/* 
	 * FIXME: check for both ir and ib that the first index entry is
	 * within the index block.
	 */
	ret = ntfs_ie_lookup(key, key_len, icx, &ir->index, &vcn, &ie);
	if (ret == STATUS_ERROR) {
		err = errno;
		goto err_out;
	}
	
	icx->ir = ir;
	
	if (ret != STATUS_KEEP_SEARCHING) {
		/* STATUS_OK or STATUS_NOT_FOUND */
		err = errno;
		icx->is_in_root = TRUE;
		icx->parent_vcn[icx->pindex] = old_vcn;
		goto done;
	}
	
	/* Child node present, descend into it. */
	
	icx->ia_na = ntfs_ia_open(icx, ni);
	if (!icx->ia_na)
		goto err_out;
	
	ib = ntfs_malloc(icx->block_size);
	if (!ib) {
		err = errno;
		goto err_out;
	}
	
descend_into_child_node:

	icx->parent_vcn[icx->pindex] = old_vcn;
	if (ntfs_icx_parent_inc(icx)) {
		err = errno;
		goto err_out;
	}
	old_vcn = vcn;

	ntfs_log_debug("Descend into node with VCN %lld\n", (long long)vcn);
	
	if (ntfs_ib_read(icx, vcn, ib))
		goto err_out;
	
	ret = ntfs_ie_lookup(key, key_len, icx, &ib->index, &vcn, &ie);
	if (ret != STATUS_KEEP_SEARCHING) {
		err = errno;
		if (ret == STATUS_ERROR)
			goto err_out;
		
		/* STATUS_OK or STATUS_NOT_FOUND */
		icx->is_in_root = FALSE;
		icx->ib = ib;
		icx->parent_vcn[icx->pindex] = vcn;
		goto done;
	}

	if ((ib->index.ih_flags & NODE_MASK) == LEAF_NODE) {
		ntfs_log_error("Index entry with child node found in a leaf "
			       "node in inode 0x%llx.\n",
			       (unsigned long long)ni->mft_no);
		goto err_out;
	}
	
	goto descend_into_child_node;
err_out:
	free(ib);
	if (!err)
		err = EIO;
	errno = err;
	return -1;
done:
	icx->entry = ie;
	icx->data = (u8 *)ie + offsetof(INDEX_ENTRY, key);
	icx->data_len = le16_to_cpu(ie->key_length);
	ntfs_log_trace("Done.\n");
	if (err) {
		errno = err;
		return -1;
	}
	return 0;

}
예제 #29
0
int ntfs_open_r(struct _reent *r, void *fileStruct, const char *path, int flags, int mode)
{
	ntfs_log_trace("fileStruct %p, path %s, flags %i, mode %i\n", (void *) fileStruct, path, flags, mode);

	ntfs_file_state* file = STATE(fileStruct);

	// Get the volume descriptor for this path
	file->vd = ntfsGetVolume(path);
	if (!file->vd) {
		r->_errno = ENODEV;
		return -1;
	}

	// Lock
	ntfsLock(file->vd);


	// Determine which mode the file is opened for
	file->flags = flags;
	if ((flags & 0x03) == O_RDONLY) {
		file->read = true;
		file->write = false;
		file->append = false;
	} else if ((flags & 0x03) == O_WRONLY) {
		file->read = false;
		file->write = true;
		file->append = (flags & O_APPEND);
	} else if ((flags & 0x03) == O_RDWR) {
		file->read = true;
		file->write = true;
		file->append = (flags & O_APPEND);
	} else {
		r->_errno = EACCES;
		ntfsUnlock(file->vd);
		return -1;
	}

	// Try and find the file and (if found) ensure that it is not a directory
	file->ni = ntfsOpenEntry(file->vd, path);
	if (file->ni && (file->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
		ntfsCloseEntry(file->vd, file->ni);
		ntfsUnlock(file->vd);
		r->_errno = EISDIR;
		return -1;
	}

	// Are we creating this file?
	if ((flags & O_CREAT) && !file->ni) {

		// Create the file
		file->ni = ntfsCreate(file->vd, path, S_IFREG, NULL);
		if (!file->ni) {
			ntfsUnlock(file->vd);
			return -1;
		}

	}

	// Sanity check, the file should be open by now
	if (!file->ni) {
		ntfsUnlock(file->vd);
		r->_errno = ENOENT;
		return -1;
	}

	// Open the files data attribute
	file->data_na = ntfs_attr_open(file->ni, AT_DATA, AT_UNNAMED, 0);
	if (!file->data_na) {
		ntfsCloseEntry(file->vd, file->ni);
		ntfsUnlock(file->vd);
		return -1;
	}

	// Determine if this files data is compressed and/or encrypted
	file->compressed = NAttrCompressed(file->data_na) || (file->ni->flags & FILE_ATTR_COMPRESSED);
	file->encrypted = NAttrEncrypted(file->data_na) || (file->ni->flags & FILE_ATTR_ENCRYPTED);

	// We cannot read/write encrypted files
	if (file->encrypted) {
		ntfs_attr_close(file->data_na);
		ntfsCloseEntry(file->vd, file->ni);
		ntfsUnlock(file->vd);
		r->_errno = EACCES;
		return -1;
	}

	// Make sure we aren't trying to write to a read-only file
	if ((file->ni->flags & FILE_ATTR_READONLY) && file->write) {
		ntfs_attr_close(file->data_na);
		ntfsCloseEntry(file->vd, file->ni);
		ntfsUnlock(file->vd);
		r->_errno = EROFS;
		return -1;
	}

	// Truncate the file if requested
	if ((flags & O_TRUNC) && file->write) {
		if (ntfs_attr_truncate(file->data_na, 0)) {
			ntfs_attr_close(file->data_na);
			ntfsCloseEntry(file->vd, file->ni);
			ntfsUnlock(file->vd);
			r->_errno = errno;
			return -1;
		}
	}

	// Set the files current position and length
	file->pos = 0;
	file->len = file->data_na->data_size;

	ntfs_log_trace("file->len %llu\n", file->len);

	// Update file times
	ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME);

	// Insert the file into the double-linked FILO list of open files
	if (file->vd->firstOpenFile) {
		file->nextOpenFile = file->vd->firstOpenFile;
		file->vd->firstOpenFile->prevOpenFile = file;
	} else {
		file->nextOpenFile = NULL;
	}
	file->prevOpenFile = NULL;
	file->vd->firstOpenFile = file;
	file->vd->openFileCount++;

	file->is_ntfs = 1;
	// Unlock
	ntfsUnlock(file->vd);

	return (int)(intptr_t)fileStruct;
	//return (int)(s64) fileStruct;
}
예제 #30
0
int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat)
{
    ntfs_log_trace("dirState %p, filename %p, filestat %p\n", dirState, filename, filestat);

    ntfs_dir_state* dir = STATE(dirState);
    ntfs_inode *ni = NULL;

    // Sanity check
    if (!dir || !dir->vd || !dir->ni) {
        r->_errno = EBADF;
        return -1;
    }

    // Lock
    ntfsLock(dir->vd);

    // Check that there is a entry waiting to be fetched
    if (!dir->current) {
        ntfsUnlock(dir->vd);
        r->_errno = ENOENT;
        return -1;
    }

    // Fetch the current entry
    //strcpy(filename, dir->current->name);

    strcpy(filename, dir->current->name);


    if(filestat != NULL)
    {
        if(strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0)
        {
            memset(filestat, 0, sizeof(struct stat));
            filestat->st_mode = S_IFDIR;
        }
        else
        {
            ni = ntfsOpenEntry(dir->vd, filename);
            if (ni) {
                if(ntfsStat(dir->vd, ni, filestat)) {
                    r->_errno = errno;
                    ntfsUnlock(dir->vd);
                    return -1;
                }
                ntfsCloseEntry(dir->vd, ni);
            } else {
               
                r->_errno = errno;
                ntfsUnlock(dir->vd);
                return -1;
            }
        }
    }


    // Move to the next entry in the directory
    dir->current = dir->current->next; 


    // Update directory times
    ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);
    ntfsUnlock(dir->vd);
    return 0;
}