Ejemplo n.º 1
0
/**
 * ntfs_ir_truncate - Truncate index root attribute
 * 
 * Returns STATUS_OK, STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT or STATUS_ERROR.
 */
static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size)
{			  
	ntfs_attr *na;
	int ret;

	ntfs_log_trace("Entering\n");
	
	na = ntfs_attr_open(icx->ni, AT_INDEX_ROOT, icx->name, icx->name_len);
	if (!na) {
		ntfs_log_perror("Failed to open INDEX_ROOT");
		return STATUS_ERROR;
	}
	/*
	 *  INDEX_ROOT must be resident and its entries can be moved to 
	 *  INDEX_BLOCK, so ENOSPC isn't a real error.
	 */
	ret = ntfs_attr_truncate(na, data_size + offsetof(INDEX_ROOT, index));
	if (ret == STATUS_OK) {
		
		icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
		if (!icx->ir)
			return STATUS_ERROR;
	
		icx->ir->index.allocated_size = cpu_to_le32(data_size);
		
	} else if (ret == STATUS_ERROR)
		ntfs_log_perror("Failed to truncate INDEX_ROOT");
	
	ntfs_attr_close(na);
	return ret;
}
Ejemplo n.º 2
0
static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo,
			const OBJECT_ID_ATTR *value, size_t size)
{
	OBJECT_ID_ATTR old_attr;
	ntfs_attr *na;
	int oldsize;
	int written;
	int res;

	res = 0;

	na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0);
	if (na) {

			/* remove the existing index entry */
		oldsize = remove_object_id_index(na,xo,&old_attr);
		if (oldsize < 0)
			res = -1;
		else {
			/* resize attribute */
			res = ntfs_attr_truncate(na, (s64)sizeof(GUID));
				/* write the object_id in attribute */
			if (!res && value) {
				written = (int)ntfs_attr_pwrite(na,
					(s64)0, (s64)sizeof(GUID),
					&value->object_id);
				if (written != (s64)sizeof(GUID)) {
					ntfs_log_error("Failed to update "
							"object id\n");
					errno = EIO;
					res = -1;
				}
			}
				/* write index part if provided */
			if (!res
			    && ((size < sizeof(OBJECT_ID_ATTR))
				 || set_object_id_index(ni,xo,value))) {
				/*
				 * If cannot index, try to remove the object
				 * id and log the error. There will be an
				 * inconsistency if removal fails.
				 */
				ntfs_attr_rm(na);
				ntfs_log_error("Failed to index object id."
						" Possible corruption.\n");
			}
		}
		ntfs_attr_close(na);
		NInoSetDirty(ni);
	} else
		res = -1;
	return (res);
}
Ejemplo n.º 3
0
static int update_reparse_data(ntfs_inode *ni, ntfs_index_context *xr,
			const char *value, size_t size)
{
	int res;
	int written;
	int oldsize;
	ntfs_attr *na;
	le32 reparse_tag;

	res = 0;
	na = ntfs_attr_open(ni, AT_REPARSE_POINT, AT_UNNAMED, 0);
	if (na) {
			/* remove the existing reparse data */
		oldsize = remove_reparse_index(na,xr,&reparse_tag);
		if (oldsize < 0)
			res = -1;
		else {
			/* resize attribute */
			res = ntfs_attr_truncate(na, (s64)size);
			/* overwrite value if any */
			if (!res && value) {
				written = (int)ntfs_attr_pwrite(na,
						 (s64)0, (s64)size, value);
				if (written != (s64)size) {
					ntfs_log_error("Failed to update "
						"reparse data\n");
					errno = EIO;
					res = -1;
				}
			}
			if (!res
			    && set_reparse_index(ni,xr,
				((const REPARSE_POINT*)value)->reparse_tag)
			    && (oldsize > 0)) {
				/*
				 * If cannot index, try to remove the reparse
				 * data and log the error. There will be an
				 * inconsistency if removal fails.
				 */
				ntfs_attr_rm(na);
				ntfs_log_error("Failed to index reparse data."
						" Possible corruption.\n");
			}
		}
		ntfs_attr_close(na);
		NInoSetDirty(ni);
	} else
		res = -1;
	return (res);
}
Ejemplo n.º 4
0
static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set)
{
	u8 byte;
	s64 pos = ntfs_ibm_vcn_to_pos(icx, vcn);
	u32 bpos = pos / 8;
	u32 bit = 1 << (pos % 8);
	ntfs_attr *na;
	int ret = STATUS_ERROR;

	ntfs_log_trace("%s vcn: %lld\n", set ? "set" : "clear", (long long)vcn);
	
	na = ntfs_attr_open(icx->ni, AT_BITMAP,  icx->name, icx->name_len);
	if (!na) {
		ntfs_log_perror("Failed to open $BITMAP attribute");
		return -1;
	}

	if (set) {
		if (na->data_size < bpos + 1) {
			if (ntfs_attr_truncate(na, (na->data_size + 8) & ~7)) {
				ntfs_log_perror("Failed to truncate AT_BITMAP");
				goto err_na;
			}
		}
	}
	
	if (ntfs_attr_pread(na, bpos, 1, &byte) != 1) {
		ntfs_log_perror("Failed to read $BITMAP");
		goto err_na;
	}

	if (set) 
		byte |= bit;
	else
		byte &= ~bit;
		
	if (ntfs_attr_pwrite(na, bpos, 1, &byte) != 1) {
		ntfs_log_perror("Failed to write $Bitmap");
		goto err_na;
	}

	ret = STATUS_OK;
err_na:
	ntfs_attr_close(na);
	return ret;
}
Ejemplo n.º 5
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;
}
Ejemplo n.º 6
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;
}
Ejemplo n.º 7
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;
}
Ejemplo n.º 8
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;
}
Ejemplo n.º 9
0
status_t
fs_write_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie,off_t pos,
	const void *buffer, size_t *_length)
{
	nspace *ns = (nspace *)_vol->private_volume;
	//vnode *node = (vnode *)_node->private_node;
	attrcookie *cookie = (attrcookie *)_cookie;
	ntfs_inode *ni = cookie->inode;
	ntfs_attr *na = cookie->stream;
	size_t  size = *_length;
	int total = 0;
	status_t result = B_NO_ERROR;

	TRACE("%s - ENTER!!\n", __FUNCTION__);
	if (ns->flags & B_FS_IS_READONLY) {
		ERROR("ntfs is read-only\n");
		return EROFS;
	}

	if (pos < 0) {
		*_length = 0;
		return EINVAL;
	}


	LOCK_VOL(ns);

	TRACE("%s - ENTER\n", __FUNCTION__);

	// it is a named stream
	if (na) {
		if (cookie->omode & O_APPEND)
			pos = na->data_size;

		if (pos + size > na->data_size) {
			ntfs_mark_free_space_outdated(ns);
			if (ntfs_attr_truncate(na, pos + size))
				size = na->data_size - pos;
			else
				notify_stat_changed(ns->id, MREF(ni->mft_no), B_STAT_SIZE);
		}

		while (size) {
			off_t bytesWritten = ntfs_attr_pwrite(na, pos, size, buffer);
			if (bytesWritten < (s64)size)
				ERROR("%s - ntfs_attr_pwrite returned less bytes than "
					"requested.\n", __FUNCTION__);
			if (bytesWritten <= 0) {
				ERROR(("%s - ntfs_attr_pwrite()<=0\n", __FUNCTION__));
				*_length = 0;
				result = EINVAL;
				goto exit;
			}
			size -= bytesWritten;
			pos += bytesWritten;
			total += bytesWritten;
		}

		*_length = total;
	} else {
		*_length = 0;
		return EINVAL;
	}

	
	if (total > 0)
		fs_ntfs_update_times(_vol, ni, NTFS_UPDATE_ATIME); // XXX needed ?

exit:
	
	TRACE("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));

	UNLOCK_VOL(ns);
	
	return result;
}
Ejemplo n.º 10
0
status_t
fs_open_attrib(fs_volume *_vol, fs_vnode *_node, const char *name,
	int openMode, void **_cookie)
{
	nspace *ns = (nspace*)_vol->private_volume;
	vnode *node = (vnode*)_node->private_node;
	attrcookie *cookie = NULL;
	ntfschar *uname = NULL;
	int ulen;
	ntfs_inode *ni = NULL;
	ntfs_attr *na = NULL;
	status_t result = B_NO_ERROR;

	TRACE("%s - ENTER\n", __FUNCTION__);

	LOCK_VOL(ns);

	if (node == NULL) {
		result = EINVAL;
		goto exit;
	}

	ni = ntfs_inode_open(ns->ntvol, node->vnid);
	if (ni == NULL) {
		result = errno;
		goto exit;
	}

	// UXA demangling TODO

	// check for EA first... TODO: WRITEME


	// check for a named stream
	if (true) {
		uname = ntfs_calloc(MAX_PATH);
		ulen = ntfs_mbstoucs(name, &uname);
		if (ulen < 0) {
			result = EILSEQ;
			goto exit;
		}

		na = ntfs_attr_open(ni, AT_DATA, uname, ulen);
		if (na) {
			if (openMode & O_TRUNC) {
				if (ntfs_attr_truncate(na, 0))
					result = errno;
			}
		} else {
			result = ENOENT;
			goto exit;
		}
	}


	cookie = (attrcookie*)ntfs_calloc(sizeof(attrcookie));

	if (cookie != NULL) {
		cookie->omode = openMode;
		*_cookie = (void*)cookie;
		cookie->inode = ni;
		cookie->stream = na;
		ni = NULL;
		na = NULL;
	} else
		result = ENOMEM;

exit:
	if (uname)
		free(uname);

	if (na)
		ntfs_attr_close(na);

	if (ni)
		ntfs_inode_close(ni);

	TRACE("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));

	UNLOCK_VOL(ns);

	return result;
}
Ejemplo n.º 11
0
bool ntfsSetVolumeName (const char *name, const char *volumeName)
{
    ntfs_vd *vd = NULL;
    ntfs_attr *na = NULL;
    ntfschar *ulabel = NULL;
    int ulabel_len;

    // Sanity check
    if (!name) {
        errno = EINVAL;
        return false;
    }

    // Get the devices volume descriptor
    vd = ntfsGetVolume(name);
    if (!vd) {
        errno = ENODEV;
        return false;
    }

    // Lock
    ntfsLock(vd);

    // Convert the new volume name to unicode
    ulabel_len = ntfsLocalToUnicode(volumeName, &ulabel) * sizeof(ntfschar);
    if (ulabel_len < 0) {
        ntfsUnlock(vd);
        errno = EINVAL;
        return false;
    }

    // Check if the volume name attribute exists
    na = ntfs_attr_open(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0);
    if (na) {

        // It does, resize it to match the length of the new volume name
        if (ntfs_attr_truncate(na, ulabel_len)) {
            ntfs_free(ulabel);
            ntfsUnlock(vd);
            return false;
        }

        // Write the new volume name
        if (ntfs_attr_pwrite(na, 0, ulabel_len, ulabel) != ulabel_len) {
            ntfs_free(ulabel);
            ntfsUnlock(vd);
            return false;
        }

    } else {

        // It doesn't, create it now
        if (ntfs_attr_add(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0, (u8*)ulabel, ulabel_len)) {
            ntfs_free(ulabel);
            ntfsUnlock(vd);
            return false;
        }

    }

    // Reset the volumes name cache (as it has now been changed)
    vd->name[0] = '\0';

    // Close the volume name attribute
    if (na)
        ntfs_attr_close(na);

    // Sync the volume node
    if (ntfs_inode_sync(vd->vol->vol_ni)) {
        ntfs_free(ulabel);
        ntfsUnlock(vd);
        return false;
    }

    // Clean up
    ntfs_free(ulabel);

    // Unlock
    ntfsUnlock(vd);

    return true;
}
Ejemplo n.º 12
0
status_t
fs_write_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie, off_t pos,
	const void *buffer, size_t *_length)
{
	nspace *ns = (nspace *)_vol->private_volume;
	vnode *node = (vnode *)_node->private_node;
	attrcookie *cookie = (attrcookie *)_cookie;
	ntfs_inode *ni = NULL;
	ntfs_attr *na = NULL;
	size_t  size = *_length;
	char *attr_name = NULL;
	char *real_name = NULL;
	int total = 0;
	status_t result = B_NO_ERROR;

	TRACE("%s - ENTER  vnode: %d\n", __FUNCTION__, node->vnid);
	
	if (ns->flags & B_FS_IS_READONLY) {		
		return B_READ_ONLY_DEVICE;
	}

	if (pos < 0) {
		*_length = 0;
		return EINVAL;
	}

	LOCK_VOL(ns);

	ni = ntfs_inode_open(ns->ntvol, node->vnid);
	if (ni == NULL) {
		result = errno;
		goto exit;
	}
	na = ntfs_attr_open(ni, AT_DATA, cookie->uname, cookie->uname_len);
	if (na == NULL) {
		result = errno;
		goto exit;		
	}		

	pos += sizeof(uint32);

	// it is a named stream
	if (na != NULL) {
		if (cookie->omode & O_APPEND)
			pos = na->data_size;

		if (pos + size > na->data_size) {
			ntfs_mark_free_space_outdated(ns);
			if (ntfs_attr_truncate(na, pos + size))
				size = na->data_size - pos;
			else
				notify_stat_changed(ns->id, MREF(ni->mft_no), B_STAT_SIZE);
		}

		while (size) {
			off_t bytesWritten = ntfs_attr_pwrite(na, pos, size, buffer);
			if (bytesWritten < (s64)size)
				ERROR("%s - ntfs_attr_pwrite returned less bytes than "
					"requested.\n", __FUNCTION__);
			if (bytesWritten <= 0) {
				ERROR("%s - ntfs_attr_pwrite()<=0\n", __FUNCTION__);
				*_length = 0;
				result = EINVAL;
				goto exit;
			}
			size -= bytesWritten;
			pos += bytesWritten;
			total += bytesWritten;
		}

		*_length = total;
	} else {
		*_length = 0;
		result =  EINVAL;
		goto exit;
	}
	
	if (ntfs_ucstombs(na->name, na->name_len, &attr_name, 0) >= 0) {
		if (attr_name != NULL) {
			if(strncmp(attr_name, kHaikuAttrPrefix, strlen(kHaikuAttrPrefix)) !=0 )
				goto exit;
			real_name = attr_name + strlen(kHaikuAttrPrefix);						
			notify_attribute_changed(ns->id, MREF(ni->mft_no),
				real_name, B_ATTR_CHANGED);
			free(attr_name);
		}
	}
		
exit:	
	if (na != NULL)
		ntfs_attr_close(na);
	if (ni != NULL)
		ntfs_inode_close(ni);
		
	TRACE("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));

	UNLOCK_VOL(ns);
	
	return result;
}
Ejemplo n.º 13
0
status_t
fs_open_attrib(fs_volume *_vol, fs_vnode *_node, const char *name,
	int openMode, void **_cookie)
{
	nspace *ns = (nspace*)_vol->private_volume;
	vnode *node = (vnode*)_node->private_node;
	attrcookie *cookie = NULL;
	ntfschar *uname = NULL;
	int ulen;
	ntfs_inode *ni = NULL;
	ntfs_attr *na = NULL;
	status_t result = B_NO_ERROR;
	uint32	type = B_XATTR_TYPE;

	TRACE("%s - ENTER - name: [%s] vnid: %d\n", __FUNCTION__, name,  node->vnid);

	LOCK_VOL(ns);

	if (node == NULL) {
		result = EINVAL;
		goto exit;
	}

	ni = ntfs_inode_open(ns->ntvol, node->vnid);
	if (ni == NULL) {
		result = errno;
		goto exit;
	}

	// UXA demangling TODO

	// check for EA first... TODO: WRITEME


	// check for a named stream
	if (true) {
		char ntfs_attr_name[MAX_PATH] = {0};
		strcat(ntfs_attr_name, kHaikuAttrPrefix);
		strcat(ntfs_attr_name, name);
		
		uname = ntfs_calloc(MAX_PATH);
		ulen = ntfs_mbstoucs(ntfs_attr_name, &uname);
		if (ulen < 0) {
			result = EILSEQ;
			goto exit;
		}

		na = ntfs_attr_open(ni, AT_DATA, uname, ulen);
		if (na != NULL) {
			if (openMode & O_TRUNC) {
				if (ns->flags & B_FS_IS_READONLY) {		
					result = B_READ_ONLY_DEVICE;
					goto exit;
				} else {
					if (ntfs_attr_truncate(na, sizeof(uint32))) {
						result = errno;
						goto exit;
					}
				}
			}
			if (ntfs_attr_pread(na, 0, sizeof(uint32), &type) != sizeof(uint32)) {
				result = errno;
				goto exit;
			}
		} else {
			result = ENOENT;
			goto exit;
		}
	}


	cookie = (attrcookie*)ntfs_calloc(sizeof(attrcookie));

	if (cookie != NULL) {
		cookie->omode = openMode;
		cookie->vnid = node->vnid;
		cookie->uname = uname;
		cookie->uname_len = ulen;
		cookie->type = type;
		*_cookie = (void*)cookie;
		uname = NULL;
	} else
		result = ENOMEM;

exit:
	if (uname != NULL)
		free(uname);

	if (na != NULL)
		ntfs_attr_close(na);

	if (ni != NULL)
		ntfs_inode_close(ni);

	TRACE("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result));

	UNLOCK_VOL(ns);

	return result;
}
Ejemplo n.º 14
0
static int ntfs_full_allocation(ntfs_attr *na, ntfs_attr_search_ctx *ctx,
				s64 alloc_offs, s64 alloc_len)
{
	ATTR_RECORD *attr;
	ntfs_inode *ni;
	s64 initialized_size;
	s64 data_size;
	int err;

	err = 0;
	initialized_size = na->initialized_size;
	data_size = na->data_size;

	if (na->allocated_size <= alloc_offs) {
		/*
		 * Request is fully beyond what was already allocated :
		 * only need to expand the attribute
		 */
		err = ntfs_attr_truncate(na, alloc_offs);
		if (!err)
			err = ntfs_attr_truncate_solid(na,
						alloc_offs + alloc_len);
	} else {
		/*
		 * Request overlaps what was already allocated :
		 * We may have to fill existing holes, and force zeroes
		 * into clusters which are visible.
		 */
		if ((alloc_offs + alloc_len) > na->allocated_size)
			err = ntfs_attr_truncate(na, alloc_offs + alloc_len);
		if (!err)
			err = ntfs_inner_allocation(na, alloc_offs, alloc_len);
	}
		/* Set the sizes, even after an error, to keep consistency */
	na->initialized_size = initialized_size;
		/* Restore the original apparent size if requested or error */
	if (err || opts.no_size_change
	    || ((alloc_offs + alloc_len) < data_size))
		na->data_size = data_size;
	else {
		/*
		 * "man 1 fallocate" does not define the new apparent size
		 * when size change is allowed (no --keep-size).
		 * Assuming the same as no FALLOC_FL_KEEP_SIZE in fallocate(2) :
		 * "the file size will be changed if offset + len is greater
		 * than the  file  size"
// TODO check the behavior of another file system
		 */
		na->data_size = alloc_offs + alloc_len;
	}

	if (!err) {
	/* Find the attribute, which may have been relocated for allocations */
		if (ntfs_attr_lookup(attr_type, attr_name, attr_name_len,
					CASE_SENSITIVE, 0, NULL, 0, ctx)) {
			err = -1;
			ntfs_log_error("Failed to locate the attribute\n");
		} else {
				/* Feed the sizes into the attribute */
			attr = ctx->attr;
			attr->data_size = cpu_to_le64(na->data_size);
			attr->initialized_size
				= cpu_to_le64(na->initialized_size);
			attr->allocated_size
				= cpu_to_le64(na->allocated_size);
			if (na->data_flags & ATTR_IS_SPARSE)
				attr->compressed_size
					= cpu_to_le64(na->compressed_size);
			/* Copy the unnamed data attribute sizes to inode */
			if ((attr_type == AT_DATA) && !attr_name_len) {
				ni = na->ni;
				ni->data_size = na->data_size;
				if (na->data_flags & ATTR_IS_SPARSE) {
					ni->allocated_size
						= na->compressed_size;
					ni->flags |= FILE_ATTR_SPARSE_FILE;
				} else
					ni->allocated_size
						= na->allocated_size;
			}
		}
	}
	return (err);
}
Ejemplo n.º 15
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);
}
Ejemplo n.º 16
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;
}