Exemple #1
0
status_t
fs_rstat(fs_volume *_vol, fs_vnode *_node, struct stat *stbuf)
{
	nspace *ns = (nspace*)_vol->private_volume;
	vnode *node = (vnode*)_node->private_node;
	ntfs_inode *ni = NULL;
	ntfs_attr *na;
	status_t result = B_NO_ERROR;

	LOCK_VOL(ns);

	ERRPRINT("fs_rstat - ENTER:\n");

	if (ns == NULL || node == NULL ||stbuf == NULL) {
		result = ENOENT;
		goto exit;
	}

	ni = ntfs_inode_open(ns->ntvol, node->vnid);
	if (ni == NULL) {
		result = ENOENT;
		goto exit;
	}
	if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
		// Directory
		stbuf->st_mode = FS_DIR_MODE;
		na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
		if (na) {
			stbuf->st_size = na->data_size;
			stbuf->st_blocks = na->allocated_size >> 9;
			ntfs_attr_close(na);
		}
		stbuf->st_nlink = 1;
	} else {
Exemple #2
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;
}
Exemple #3
0
int ntfs_delete_object_id_index(ntfs_inode *ni)
{
	ntfs_index_context *xo;
	ntfs_inode *xoni;
	ntfs_attr *na;
	OBJECT_ID_ATTR old_attr;
	int res;

	res = 0;
	na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0);
	if (na) {
			/*
			 * read the existing object id
			 * and un-index it
			 */
		xo = open_object_id_index(ni->vol);
		if (xo) {
			if (remove_object_id_index(na,xo,&old_attr) < 0)
				res = -1;
			xoni = xo->ni;
			ntfs_index_entry_mark_dirty(xo);
			NInoSetDirty(xoni);
			ntfs_index_ctx_put(xo);
			ntfs_inode_close(xoni);
		}
		ntfs_attr_close(na);
	}
	return (res);
}
Exemple #4
0
int ntfs_delete_reparse_index(ntfs_inode *ni)
{
	ntfs_index_context *xr;
	ntfs_inode *xrni;
	ntfs_attr *na;
	le32 reparse_tag;
	int res;

	res = 0;
	na = ntfs_attr_open(ni, AT_REPARSE_POINT, AT_UNNAMED, 0);
	if (na) {
			/*
			 * read the existing reparse data (the tag is enough)
			 * and un-index it
			 */
		xr = open_reparse_index(ni->vol);
		if (xr) {
			if (remove_reparse_index(na,xr,&reparse_tag) < 0)
				res = -1;
			xrni = xr->ni;
			ntfs_index_entry_mark_dirty(xr);
			NInoSetDirty(xrni);
			ntfs_index_ctx_put(xr);
			ntfs_inode_close(xrni);
		}
		ntfs_attr_close(na);
	}
	return (res);
}
Exemple #5
0
/**
 * cat
 */
static int cat(ntfs_volume *vol, ntfs_inode *inode, ATTR_TYPES type,
		ntfschar *name, int namelen)
{
	const int bufsize = 4096;
	char *buffer;
	ntfs_attr *attr;
	s64 bytes_read, written;
	s64 offset;
	u32 block_size;

	buffer = malloc(bufsize);
	if (!buffer)
		return 1;

	attr = ntfs_attr_open(inode, type, name, namelen);
	if (!attr) {
		ntfs_log_error("Cannot find attribute type 0x%x.\n",
				le32_to_cpu(type));
		free(buffer);
		return 1;
	}

	if ((inode->mft_no < 2) && (attr->type == AT_DATA))
		block_size = vol->mft_record_size;
	else if (attr->type == AT_INDEX_ALLOCATION)
		block_size = index_get_size(inode);
	else
		block_size = 0;

	offset = 0;
	for (;;) {
		if (!opts.raw && block_size > 0) {
			// These types have fixup
			bytes_read = ntfs_attr_mst_pread(attr, offset, 1, block_size, buffer);
			if (bytes_read > 0)
				bytes_read *= block_size;
		} else {
			bytes_read = ntfs_attr_pread(attr, offset, bufsize, buffer);
		}
		//ntfs_log_info("read %lld bytes\n", bytes_read);
		if (bytes_read == -1) {
			ntfs_log_perror("ERROR: Couldn't read file");
			break;
		}
		if (!bytes_read)
			break;

		written = fwrite(buffer, 1, bytes_read, stdout);
		if (written != bytes_read) {
			ntfs_log_perror("ERROR: Couldn't output all data!");
			break;
		}
		offset += bytes_read;
	}

	ntfs_attr_close(attr);
	free(buffer);
	return 0;
}
Exemple #6
0
static status_t
get_node_type(ntfs_inode* ni, int* _type)
{
	ntfs_attr* na;

	if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
		// Directory
		*_type = S_IFDIR;
		return B_OK;
	} else {
		// Regular or Interix (INTX) file
		*_type = S_IFREG;

		if (ni->flags & FILE_ATTR_SYSTEM) {
			na = ntfs_attr_open(ni, AT_DATA, NULL,0);
			if (!na) {
				return ENOENT;
			}
			// Check whether it's Interix symbolic link
			if (na->data_size <= sizeof(INTX_FILE_TYPES) +
			    sizeof(ntfschar) * PATH_MAX &&
			    na->data_size > sizeof(INTX_FILE_TYPES)) {
				INTX_FILE *intx_file;

				intx_file = ntfs_malloc(na->data_size);
				if (!intx_file) {
					ntfs_attr_close(na);
					return EINVAL;
				}
				if (ntfs_attr_pread(na, 0, na->data_size,
						intx_file) != na->data_size) {
					free(intx_file);
					ntfs_attr_close(na);
					return EINVAL;
				}
				if (intx_file->magic == INTX_SYMBOLIC_LINK)
					*_type = FS_SLNK_MODE;
				free(intx_file);
			}
			ntfs_attr_close(na);
		}
	}

	return B_OK;
}
Exemple #7
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);
}
Exemple #8
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);
}
Exemple #9
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;
}
status_t
fs_free_attrib_cookie(fs_volume *_vol, fs_vnode *_node, void *_cookie)
{
	nspace *ns = (nspace*)_vol->private_volume;
	attrcookie *cookie = (attrcookie *)_cookie;

	LOCK_VOL(ns);

	if (cookie->stream)
		ntfs_attr_close(cookie->stream);
	if (cookie->inode)
		ntfs_inode_close(cookie->inode);

	UNLOCK_VOL(ns);

	free(cookie);
	return B_NO_ERROR;
}
Exemple #11
0
void ntfsCloseFile(ntfs_file_state *file)
{
	// Sanity check
	if (!file || !file->vd)
		return;

	// Special case fix ups for compressed and/or encrypted files
	if (file->compressed)
		ntfs_attr_pclose(file->data_na);
#ifdef HAVE_SETXATTR
	if (file->encrypted)
		ntfs_efs_fixup_attribute(NULL, file->data_na);
#endif
	// Close the file data attribute (if open)
	if (file->data_na)
		ntfs_attr_close(file->data_na);

	// Sync the file (and its attributes) to disc
	if (file->write)
	{
		ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME | NTFS_UPDATE_CTIME);
		ntfsSync(file->vd, file->ni);
	}

	if (file->read)
		ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME);

	// Close the file (if open)
	if (file->ni)
		ntfsCloseEntry(file->vd, file->ni);

	// Reset the file state
	file->ni = NULL;
	file->data_na = NULL;
	file->flags = 0;
	file->read = false;
	file->write = false;
	file->append = false;
	file->pos = 0;
	file->len = 0;

	return;
}
Exemple #12
0
int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
{
    ntfs_attr *na = NULL;
    int res = 0;

    // Sanity check
    if (!vd) {
        errno = ENODEV;
        return -1;
    }

    // Sanity check
    if (!ni) {
        errno = ENOENT;
        return -1;
    }

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

    // Lock
    ntfsLock(vd);

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

    // Is this entry a directory
    if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
        st->st_mode = S_IFDIR | (0777 & ~vd->dmask);
        st->st_nlink = 1;

        // Open the directories index allocation table attribute
        na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
        if (na) {
            st->st_size = na->data_size;
            st->st_blocks = na->allocated_size >> 9;
            ntfs_attr_close(na);
        }

    // Else it must be a file
    } else {
Exemple #13
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);
}
Exemple #14
0
status_t 
fs_read_attrib_stat(fs_volume *_vol, fs_vnode *_node, void *_cookie,
	struct stat *stat)
{
	nspace *ns = (nspace *)_vol->private_volume;
	vnode *node = (vnode *)_node->private_node;
	attrcookie *cookie = (attrcookie *)_cookie;
	ntfs_inode *ni = NULL;
	ntfs_attr *na = NULL;	
	status_t result = B_NO_ERROR;	

	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;		
	}

	stat->st_type = cookie->type;
	stat->st_size = na ? na->data_size - sizeof(uint32) : 0;

exit:
	if (na != NULL)
		ntfs_attr_close(na);
	if (ni != NULL)
		ntfs_inode_close(ni);	

	UNLOCK_VOL(ns);
	
	return B_NO_ERROR;
}
Exemple #15
0
void ntfsCloseFile (ntfs_file_state *file)
{
    // Sanity check
    if (!file || !file->vd)
        return;

    // Special case fix ups for compressed and/or encrypted files
    if (file->compressed)
        ntfs_attr_pclose(file->data_na);        
    if (file->encrypted)
        ntfs_efs_fixup_attribute(NULL, file->data_na);
        
    // Close the file data attribute (if open)
    if (file->data_na)
        ntfs_attr_close(file->data_na);
    
    // Sync the file (and its attributes) to disc
    if(file->write)
        ntfsSync(file->vd, file->ni);
    
    // Close the file (if open)
    if (file->ni)
        ntfsCloseEntry(file->vd, file->ni);
    
    // Reset the file state
    file->ni = NULL;
    file->data_na = NULL;
    file->flags = 0;
    file->read = false;
    file->write = false;
    file->append = false;
    file->pos = 0;
    file->len = 0;

    return;
}
Exemple #16
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;
}
Exemple #17
0
static int ntfs_copy(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const file_info_t *file)
{
  const unsigned long int first_inode=file->st_ino;
  ntfs_inode *inode;
  struct ntfs_dir_struct *ls=(struct ntfs_dir_struct*)dir_data->private_dir_data;
  inode = ntfs_inode_open (ls->vol, first_inode);
  if (!inode) {
    log_error("ntfs_copy: ntfs_inode_open failed for %s\n", dir_data->current_directory);
    return -1;
  }
  {
    char *buffer;
    char *new_file;
    ntfs_attr *attr=NULL;
    FILE *f_out;
    char *stream_name;
    s64 offset;
    u32 block_size;
    buffer = (char *)MALLOC(bufsize);
    if (!buffer)
    {
      ntfs_inode_close(inode);
      return -2;
    }
    stream_name=strrchr(dir_data->current_directory, ':');
    if(stream_name)
      stream_name++;
    if(stream_name != NULL)
    {
      ntfschar *stream_name_ucs=NULL;
#ifdef NTFS_MBSTOUCS_HAVE_TWO_ARGUMENTS
      const int len=ntfs_mbstoucs(stream_name, &stream_name_ucs);
#else
      const int len=ntfs_mbstoucs(stream_name, &stream_name_ucs, 0);
#endif
      if(len < 0)
	log_error("ntfs_mbstoucs failed\n");
      else
	attr = ntfs_attr_open(inode, AT_DATA, stream_name_ucs, len);
    }
    else
      attr = ntfs_attr_open(inode, AT_DATA, NULL, 0);
    if (!attr)
    {
      log_error("Cannot find attribute type 0x%lx.\n", (long) AT_DATA);
      free(buffer);
      ntfs_inode_close(inode);
      return -3;
    }
    if ((inode->mft_no < 2) && (attr->type == AT_DATA))
      block_size = ls->vol->mft_record_size;
    else if (attr->type == AT_INDEX_ALLOCATION)
      block_size = index_get_size(inode);
    else
      block_size = 0;
#if defined(__CYGWIN__) || defined(__MINGW32__)
    if(stream_name)
    {
      /* fopen() create normal files instead of ADS with ':' replaced by an UTF char
       * replace ':' by '_' instead */
      stream_name--;
      *stream_name='_';
      f_out=fopen_local(&new_file, dir_data->local_dir, dir_data->current_directory);
    }
    else
      f_out=fopen_local(&new_file, dir_data->local_dir, dir_data->current_directory);
#else
    f_out=fopen_local(&new_file, dir_data->local_dir, dir_data->current_directory);
#endif
    if(!f_out)
    {
      log_critical("Can't create file %s: %s\n",new_file, strerror(errno));
      free(new_file);
      ntfs_attr_close(attr);
      free(buffer);
      ntfs_inode_close(inode);
      return -4;
    }
    offset = 0;
    for (;;)
    {
      s64 bytes_read, written;
      if (block_size > 0) {
	// These types have fixup
	bytes_read = ntfs_attr_mst_pread(attr, offset, 1, block_size, buffer);
	bytes_read *= block_size;
      } else {
	bytes_read = ntfs_attr_pread(attr, offset, bufsize, buffer);
      }
      //ntfs_log_info("read %lld bytes\n", bytes_read);
      if (bytes_read < 0) {
	log_error("ERROR: Couldn't read file");
	break;
      }
      if (!bytes_read)
	break;

      written = fwrite(buffer, 1, bytes_read, f_out);
      if (written != bytes_read)
      {
	log_error("ERROR: Couldn't output all data!");
	break;
      }
      offset += bytes_read;
    }
    fclose(f_out);
    set_date(new_file, file->td_atime, file->td_mtime);
    free(new_file);
    ntfs_attr_close(attr);
    free(buffer);
  }
  /* Finished with the inode; release it. */
  ntfs_inode_close(inode);
  return 0;
}
Exemple #18
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;
}
Exemple #19
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;
}
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;
}
Exemple #21
0
/**
 * ntfs_inode_sync - write the inode (and its dirty extents) to disk
 * @ni:		ntfs inode to write
 *
 * Write the inode @ni to disk as well as its dirty extent inodes if such
 * exist and @ni is a base inode. If @ni is an extent inode, only @ni is
 * written completely disregarding its base inode and any other extent inodes.
 *
 * For a base inode with dirty extent inodes if any writes fail for whatever
 * reason, the failing inode is skipped and the sync process is continued. At
 * the end the error condition that brought about the failure is returned. Thus
 * the smallest amount of data loss possible occurs.
 *
 * 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.
 *	EBUSY	- Inode and/or one of its extents is busy, try again later.
 *	EIO	- I/O error while writing the inode (or one of its extents).
 */
int ntfs_inode_sync(ntfs_inode *ni)
{
	int ret = 0;
	int err = 0;

	if (!ni) {
		errno = EINVAL;
		ntfs_log_error("Failed to sync NULL inode\n");
		return -1;
	}

	ntfs_log_enter("Entering for inode %lld\n", (long long)ni->mft_no);

	/* Update STANDARD_INFORMATION. */
	if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&
			ntfs_inode_sync_standard_information(ni)) {
		if (!err || errno == EIO) {
			err = errno;
			if (err != EIO)
				err = EBUSY;
		}
	}

	/* Update FILE_NAME's in the index. */
	if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&
			NInoFileNameTestAndClearDirty(ni) &&
			ntfs_inode_sync_file_name(ni)) {
		if (!err || errno == EIO) {
			err = errno;
			if (err != EIO)
				err = EBUSY;
		}
		ntfs_log_perror("Failed to sync FILE_NAME (inode %lld)",
				(long long)ni->mft_no);
		NInoFileNameSetDirty(ni);
	}

	/* Write out attribute list from cache to disk. */
	if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&
			NInoAttrList(ni) && NInoAttrListTestAndClearDirty(ni)) {
		ntfs_attr *na;

		na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
		if (!na) {
			if (!err || errno == EIO) {
				err = errno;
				if (err != EIO)
					err = EBUSY;
				ntfs_log_perror("Attribute list sync failed "
						"(open, inode %lld)",
						(long long)ni->mft_no);
			}
			NInoAttrListSetDirty(ni);
			goto sync_inode;
		}

		if (na->data_size == ni->attr_list_size) {
			if (ntfs_attr_pwrite(na, 0, ni->attr_list_size,
				        ni->attr_list) != ni->attr_list_size) {
				if (!err || errno == EIO) {
					err = errno;
					if (err != EIO)
						err = EBUSY;
					ntfs_log_perror("Attribute list sync "
						"failed (write, inode %lld)",
						(long long)ni->mft_no);
				}
				NInoAttrListSetDirty(ni);
			}
		} else {
			err = EIO;
			ntfs_log_error("Attribute list sync failed (bad size, "
				       "inode %lld)\n", (long long)ni->mft_no);
			NInoAttrListSetDirty(ni);
		}
		ntfs_attr_close(na);
	}

sync_inode:
	/* Write this inode out to the $MFT (and $MFTMirr if applicable). */
	if (NInoTestAndClearDirty(ni)) {
		if (ntfs_mft_record_write(ni->vol, ni->mft_no, ni->mrec)) {
			if (!err || errno == EIO) {
				err = errno;
				if (err != EIO)
					err = EBUSY;
			}
			NInoSetDirty(ni);
			ntfs_log_perror("MFT record sync failed, inode %lld",
					(long long)ni->mft_no);
		}
	}

	/* If this is a base inode with extents write all dirty extents, too. */
	if (ni->nr_extents > 0) {
		s32 i;

		for (i = 0; i < ni->nr_extents; ++i) {
			ntfs_inode *eni;

			eni = ni->extent_nis[i];
			if (!NInoTestAndClearDirty(eni))
				continue;

			if (ntfs_mft_record_write(eni->vol, eni->mft_no,
						  eni->mrec)) {
				if (!err || errno == EIO) {
					err = errno;
					if (err != EIO)
						err = EBUSY;
				}
				NInoSetDirty(eni);
				ntfs_log_perror("Extent MFT record sync failed,"
						" inode %lld/%lld",
						(long long)ni->mft_no,
						(long long)eni->mft_no);
			}
		}
	}

	if (err) {
		errno = err;
		ret = -1;
	}

	ntfs_log_leave("\n");
	return ret;
}
Exemple #22
0
int ntfs_file_to_sectors(struct _reent *r, const char *path, uint32_t *sec_out, uint32_t *size_out, int max, int phys)
{
	ntfs_file_state fileStruct;
	ntfs_file_state* file = &fileStruct;
	uint32_t s_count = 0;
	//size_t len;
	off64_t len;

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

	// Lock
	ntfsLock(file->vd);

	// 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;
	}

	// 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;
	}

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

	struct ntfs_device *dev = file->vd->dev;
	gekko_fd *fd = DEV_FD(dev);

	while (len && s_count < max) {
		//size_t ret = ntfs_attr_to_sectors(file->data_na, file->pos, len, sec_out, size_out, max, &s_count, (u32) fd->sectorSize);
		off64_t ret = ntfs_attr_to_sectors(file->data_na, file->pos, len, sec_out, size_out, max, &s_count, (u32) fd->sectorSize);
		if (ret <= 0 || ret > len) {
			ntfsUnlock(file->vd);
			r->_errno = errno;
			return -1;
		}
		len -= ret;
		file->pos += ret;
	}

	if (phys)
	{
		uint32_t i;

		for (i = 0; i < s_count; i++)
		{
			sec_out[i] += fd->startSector;
		}
	}

	ntfs_attr_close(file->data_na);
	ntfsCloseEntry(file->vd, file->ni);
	// Unlock
	ntfsUnlock(file->vd);

	return s_count;
}
Exemple #23
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;
}
Exemple #24
0
static int ntfs_fallocate(ntfs_inode *ni, s64 alloc_offs, s64 alloc_len)
{
	s64 allocated_size;
	s64 data_size;
	ntfs_attr_search_ctx *ctx;
	ntfs_attr *na;
	runlist_element *oldrl;
	const char *errmess;
	int save_errno;
	int err;

	err = 0;
	/* Open the specified attribute. */
	na = ntfs_attr_open(ni, attr_type, attr_name, attr_name_len);
	if (!na) {
		ntfs_log_perror("Failed to open attribute 0x%lx: ",
				(unsigned long)le32_to_cpu(attr_type));
		err = -1;
	} else {
		errmess = (const char*)NULL;
		if (na->data_flags & ATTR_IS_COMPRESSED) {
			errmess= "Cannot fallocate a compressed file";
		}

		/* Locate the attribute record, needed for updating sizes */
		ctx = ntfs_attr_get_search_ctx(ni, NULL);
		if (!ctx) {
			errmess = "Failed to allocate a search context";
		}
		if (errmess) {
			ntfs_log_error("%s\n",errmess);
			err = -1;
		} else {
			/* Get and save the initial allocations */
			allocated_size = na->allocated_size;
			data_size = ni->data_size;
			err = ntfs_attr_map_whole_runlist(na);
			if (!err) {
				oldrl = ntfs_save_rl(na->rl);
				if (oldrl) {
					err = ntfs_full_allocation(na, ctx,
							alloc_offs, alloc_len);
					if (err) {
						save_errno = errno;
						ni->allocated_size
							= allocated_size;
						ni->data_size = data_size;
						ntfs_restore_rl(na, oldrl);
						errno = save_errno;
					} else {
						free(oldrl);
	/* Mark file name dirty, to update the sizes in directories */
						NInoFileNameSetDirty(ni);
						NInoSetDirty(ni);
					}
				} else
					err = -1;
			}
			ntfs_attr_put_search_ctx(ctx);
		}
		/* Close the attribute. */
		ntfs_attr_close(na);
	}
	return (err);
}
Exemple #25
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;
}
Exemple #26
0
/**
 * ntfs_cat_decrypt - Decrypt the contents of an encrypted file to stdout.
 * @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_cat_decrypt(ntfs_inode *inode, ntfs_fek *fek)
{
    int bufsize = 512;
    unsigned char *buffer;
    ntfs_attr *attr;
    s64 bytes_read, written, offset, total;
    s64 old_data_size, old_initialized_size;
    int i;

    buffer = malloc(bufsize);
    if (!buffer)
        return 1;
    attr = ntfs_attr_open(inode, AT_DATA, NULL, 0);
    if (!attr) {
        ntfs_log_error("Cannot cat a directory.\n");
        free(buffer);
        return 1;
    }
    total = attr->data_size;

    // hack: make sure attr will not be commited to disk if you use this.
    // clear the encrypted bit, otherwise the library won't allow reading.
    NAttrClearEncrypted(attr);
    // extend the size, we may need to read past the end of the stream.
    old_data_size = attr->data_size;
    old_initialized_size = attr->initialized_size;
    attr->data_size = attr->initialized_size = attr->allocated_size;

    offset = 0;
    while (total > 0) {
        bytes_read = ntfs_attr_pread(attr, offset, 512, buffer);
        if (bytes_read == -1) {
            ntfs_log_perror("ERROR: Couldn't read file");
            break;
        }
        if (!bytes_read)
            break;
        if ((i = ntfs_fek_decrypt_sector(fek, buffer, offset)) <
                bytes_read) {
            ntfs_log_perror("ERROR: Couldn't decrypt all data!");
            ntfs_log_error("%u/%lld/%lld/%lld\n", i,
                           (long long)bytes_read, (long long)offset,
                           (long long)total);
            break;
        }
        if (bytes_read > total)
            bytes_read = total;
        written = fwrite(buffer, 1, bytes_read, stdout);
        if (written != bytes_read) {
            ntfs_log_perror("ERROR: Couldn't output all data!");
            break;
        }
        offset += bytes_read;
        total -= bytes_read;
    }
    attr->data_size = old_data_size;
    attr->initialized_size = old_initialized_size;
    NAttrSetEncrypted(attr);
    ntfs_attr_close(attr);
    free(buffer);
    return 0;
}
Exemple #27
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;
}
Exemple #28
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);
}
Exemple #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;
}
Exemple #30
0
status_t 
fs_read_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie, off_t pos,
	void *buffer, size_t *len)
{
	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 = *len;
	int total = 0;
	status_t result = B_NO_ERROR;

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

	LOCK_VOL(ns);

	TRACE("%s - ENTER  vnid: %d\n", __FUNCTION__, node->vnid);
	
	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 (pos + size > na->data_size)
			size = na->data_size - pos;

		while (size) {
			off_t bytesRead = ntfs_attr_pread(na, pos, size, buffer);
			if (bytesRead < (s64)size) {
				ERROR("ntfs_attr_pread returned less bytes than "
					"requested.\n");
			}
			if (bytesRead <= 0) {
				*len = 0;
				result = EINVAL;
				goto exit;
			}
			size -= bytesRead;
			pos += bytesRead;
			total += bytesRead;
		}

		*len = total;
	} else {
		*len = 0;
		result = ENOENT; // TODO
	}

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;
}