예제 #1
0
static int remove_reparse_index(ntfs_attr *na, ntfs_index_context *xr,
				le32 *preparse_tag)
{
	REPARSE_INDEX_KEY key;
	u64 file_id_cpu;
	le64 file_id;
	s64 size;
	le16 seqn;
	int ret;

	ret = na->data_size;
	if (ret) {
			/* read the existing reparse_tag */
		size = ntfs_attr_pread(na, 0, 4, preparse_tag);
		if (size == 4) {
			seqn = na->ni->mrec->sequence_number;
			file_id_cpu = MK_MREF(na->ni->mft_no,le16_to_cpu(seqn));
			file_id = cpu_to_le64(file_id_cpu);
			key.reparse_tag = *preparse_tag;
		/* danger on processors which require proper alignment ! */
			memcpy(&key.file_id, &file_id, 8);
			if (!ntfs_index_lookup(&key, sizeof(REPARSE_INDEX_KEY), xr)
			    && ntfs_index_rm(xr))
				ret = -1;
		} else {
			ret = -1;
			errno = ENODATA;
		}
	}
	return (ret);
}
예제 #2
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 = cookie->inode;
	ntfs_attr *na = cookie->stream;
	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\n", __FUNCTION__);

	// it is a named stream
	if (na) {
		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) {
				ntfs_log_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
	}

	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;
}
예제 #3
0
ssize_t ntfs_read_r(struct _reent *r, int fd, 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 read = 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 read from this file
	if (!file->read) {
		ntfsUnlock(file->vd);
		r->_errno = EACCES;
		return -1;
	}

	// Don't read past the end of file
	if (file->pos + len > file->len) {
		r->_errno = EOVERFLOW;
		len = file->len - file->pos;
		ntfs_log_trace("EOVERFLOW");
	}

	ntfs_log_trace("file->pos:%d, len:%d, file->len:%d \n", (u32)file->pos, (u32)len, (u32)file->len);

	// Read from the files data attribute
	while (len) {
		ssize_t ret = ntfs_attr_pread(file->data_na, file->pos, len, ptr);
		if (ret <= 0 || ret > len) {
			ntfsUnlock(file->vd);
			r->_errno = errno;
			return -1;
		}
		ptr += ret;
		len -= ret;
		file->pos += ret;
		read += ret;
	}
	//ntfs_log_trace("file->pos: %d \n", (u32)file->pos);
	// Update file times (if we actually read something)

	// Unlock
	ntfsUnlock(file->vd);

	return read;
}
예제 #4
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;
}
예제 #5
0
파일: index.c 프로젝트: AllardJ/Tomato
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;
}
예제 #6
0
파일: fs_func.c 프로젝트: mmanley/Antares
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;
}
예제 #7
0
int ntfs_calc_free_space(nspace *_ns)
{
	nspace		*ns = (nspace*)_ns;
	ntfs_volume *vol = ns->ntvol;	
	ntfs_attr 	*data = vol->lcnbmp_na;
	s64 		free_clusters = 0;
	off_t 	 	pos = 0;
	size_t 	 	readed;
	unsigned 	char *buf = NULL;
			
	if (ns == NULL || vol == NULL || data == NULL)
		return -1;
		
	if (vol->lcnbmp_na == NULL)
		return -1;

	if (!(ns->state & NF_FreeClustersOutdate))
		return -1;	

	buf = (unsigned char*)ntfs_malloc(vol->cluster_size);
	if (buf == NULL)
		goto exit;
	
	while (pos < data->data_size) {
		if (pos % vol->cluster_size == 0) {
			readed = ntfs_attr_pread(vol->lcnbmp_na, pos,
				min(data->data_size - pos, vol->cluster_size), buf);
			if (readed < B_NO_ERROR)
				goto error;
			if (readed != min(data->data_size - pos, vol->cluster_size))
				goto error;
		}

		free_clusters += ntfs_count_bits( buf[pos%vol->cluster_size],
			min((vol->nr_clusters) - (pos * 8), 8));
		pos++;
	}
error:
	free(buf);
exit:	
	ns->free_clusters = free_clusters;
	ns->state &= ~(NF_FreeClustersOutdate);
	
	return B_NO_ERROR;
}
예제 #8
0
static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo,
				OBJECT_ID_ATTR *old_attr)
{
	OBJECT_ID_INDEX_KEY key;
	struct OBJECT_ID_INDEX *entry;
	s64 size;
	int ret;

	ret = na->data_size;
	if (ret) {
			/* read the existing object id attribute */
		size = ntfs_attr_pread(na, 0, sizeof(GUID), old_attr);
		if (size >= (s64)sizeof(GUID)) {
			memcpy(&key.object_id,
				&old_attr->object_id,sizeof(GUID));
			if (!ntfs_index_lookup(&key,
					sizeof(OBJECT_ID_INDEX_KEY), xo)) {
				entry = (struct OBJECT_ID_INDEX*)xo->entry;
				memcpy(&old_attr->birth_volume_id,
					&entry->data.birth_volume_id,
					sizeof(GUID));
				memcpy(&old_attr->birth_object_id,
					&entry->data.birth_object_id,
					sizeof(GUID));
				memcpy(&old_attr->domain_id,
					&entry->data.domain_id,
					sizeof(GUID));
				if (ntfs_index_rm(xo))
					ret = -1;
			}
		} else {
			ret = -1;
			errno = ENODATA;
		}
	}
	return (ret);
}
예제 #9
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;
}
예제 #10
0
파일: attributes.c 프로젝트: DonCN/haiku
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;
}
예제 #11
0
파일: attributes.c 프로젝트: DonCN/haiku
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;
}
예제 #12
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;
}
예제 #13
0
static int ntfsrec_emit_file(struct ntfsrec_copy *state, ntfs_inode *inode, const char *name) {
    ntfs_attr *data_attribute;
    char *old_path_end;
    
    
    if (ntfsrec_append_filename(state, name, &old_path_end) == NR_FALSE) {
        printf("Error: path %s and filename %s are too long.\n", state->path, name);
        return NR_FALSE;
    }
    
    data_attribute = ntfs_attr_open(inode, AT_DATA, NULL, 0);

    if (data_attribute != NULL) {
        int output_fd;
        unsigned int block_size = 0, retries = 0;
        s64 offset = 0;
        
        output_fd = open(state->path, O_WRONLY | O_CREAT);
        
        if (output_fd != -1) {
            if (inode->mft_no < 2) {
                block_size = state->volume->mft_record_size;
            }
            
            for(;;) {
                s64 bytes_read = 0;
                
                if (block_size > 0) {
                    bytes_read = ntfs_attr_mst_pread(data_attribute, offset, 1, block_size, state->file_buffer);
                    bytes_read *= block_size;
                } else {
                    bytes_read = ntfs_attr_pread(data_attribute, offset, NR_FILE_BUFFER_SIZE, state->file_buffer);
                }
                
                if (bytes_read == -1) {
                    unsigned int actual_size = block_size > 0 ? block_size : NR_FILE_BUFFER_SIZE;
                    
                    if (retries++ < state->opt.retries) {
                        state->stats.retries++;
                        continue;
                    }
                    
                    state->stats.errors++;
                    printf("Error: failed %u times to read %s, skipping %d bytes\n", retries, name, actual_size);
                    
                    lseek(output_fd, actual_size, SEEK_CUR);
                    
                    offset += actual_size;
                    continue;
                }
                
                if (bytes_read == 0) {
                    break;
                }
                
                if (write(output_fd, state->file_buffer, bytes_read) < 0) {
                    printf("Error: unable to write to output file %s\n", state->path);
                    
                    if (retries++ < state->opt.retries) {
                        state->stats.retries++;
                        continue;
                    }
                    
                    break;
                }
                
                retries = 0;
                offset += bytes_read;
            }
            
            close(output_fd);
        }
        
        state->stats.files++;
        ntfs_attr_close(data_attribute);
    } else {
        printf("Error: can't access the data for %s\n", name);
    }

    *old_path_end = '\0';
    state->current_path_end = old_path_end;
    return NR_TRUE;
}