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