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); }
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); }
int ntfs_set_ntfs_object_id(ntfs_inode *ni, const char *value, size_t size, int flags) { OBJECT_ID_INDEX_KEY key; ntfs_inode *xoni; ntfs_index_context *xo; int res; res = 0; if (ni && value && (size >= sizeof(GUID))) { xo = open_object_id_index(ni->vol); if (xo) { /* make sure the GUID was not used somewhere */ memcpy(&key.object_id, value, sizeof(GUID)); if (ntfs_index_lookup(&key, sizeof(OBJECT_ID_INDEX_KEY), xo)) { ntfs_index_ctx_reinit(xo); res = add_object_id(ni, flags); if (!res) { /* update value and index */ res = update_object_id(ni,xo, (const OBJECT_ID_ATTR*)value, size); } } else { /* GUID is present elsewhere */ res = -1; errno = EEXIST; } xoni = xo->ni; ntfs_index_entry_mark_dirty(xo); NInoSetDirty(xoni); ntfs_index_ctx_put(xo); ntfs_inode_close(xoni); } else { res = -1; } } else { errno = EINVAL; res = -1; } return (res ? -1 : 0); }
/* JPA static */ int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) { INDEX_HEADER *ih; int allocated_size, new_size; int ret = STATUS_ERROR; #ifdef DEBUG /* removed by JPA to make function usable for security indexes char *fn; fn = ntfs_ie_filename_get(ie); ntfs_log_trace("file: '%s'\n", fn); ntfs_attr_name_free(&fn); */ #endif while (1) { if (!ntfs_index_lookup(&ie->key, le16_to_cpu(ie->key_length), icx)) { errno = EEXIST; ntfs_log_perror("Index already have such entry"); goto err_out; } if (errno != ENOENT) { ntfs_log_perror("Failed to find place for new entry"); goto err_out; } if (icx->is_in_root) ih = &icx->ir->index; else ih = &icx->ib->index; allocated_size = le32_to_cpu(ih->allocated_size); new_size = le32_to_cpu(ih->index_length) + le16_to_cpu(ie->length); if (new_size <= allocated_size) break; ntfs_log_trace("index block sizes: allocated: %d needed: %d\n", allocated_size, new_size); if (icx->is_in_root) { if (ntfs_ir_make_space(icx, new_size) == STATUS_ERROR) goto err_out; } else { if (ntfs_ib_split(icx, icx->ib) == STATUS_ERROR) goto err_out; } ntfs_inode_mark_dirty(icx->actx->ntfs_ino); ntfs_index_ctx_reinit(icx); } ntfs_ie_insert(ih, ie, icx->entry); ntfs_index_entry_mark_dirty(icx); ret = STATUS_OK; err_out: ntfs_log_trace("%s\n", ret ? "Failed" : "Done"); return ret; }
/** * ntfs_mark_quotas_out_of_date - mark the quotas out of date on an ntfs volume * @vol: ntfs volume on which to mark the quotas out of date * * Mark the quotas out of date on the ntfs volume @vol and return TRUE on * success and FALSE on error. */ BOOL ntfs_mark_quotas_out_of_date(ntfs_volume *vol) { ntfs_index_context *ictx; QUOTA_CONTROL_ENTRY *qce; const le32 qid = QUOTA_DEFAULTS_ID; int err; ntfs_debug("Entering."); if (NVolQuotaOutOfDate(vol)) goto done; if (!vol->quota_ino || !vol->quota_q_ino) { ntfs_error(vol->sb, "Quota inodes are not open."); return FALSE; } down(&vol->quota_q_ino->i_sem); ictx = ntfs_index_ctx_get(NTFS_I(vol->quota_q_ino)); if (!ictx) { ntfs_error(vol->sb, "Failed to get index context."); goto err_out; } err = ntfs_index_lookup(&qid, sizeof(qid), ictx); if (err) { if (err == -ENOENT) ntfs_error(vol->sb, "Quota defaults entry is not " "present."); else ntfs_error(vol->sb, "Lookup of quota defaults entry " "failed."); goto err_out; } if (ictx->data_len < offsetof(QUOTA_CONTROL_ENTRY, sid)) { ntfs_error(vol->sb, "Quota defaults entry size is invalid. " "Run chkdsk."); goto err_out; } qce = (QUOTA_CONTROL_ENTRY*)ictx->data; if (le32_to_cpu(qce->version) != QUOTA_VERSION) { ntfs_error(vol->sb, "Quota defaults entry version 0x%x is not " "supported.", le32_to_cpu(qce->version)); goto err_out; } ntfs_debug("Quota defaults flags = 0x%x.", le32_to_cpu(qce->flags)); /* If quotas are already marked out of date, no need to do anything. */ if (qce->flags & QUOTA_FLAG_OUT_OF_DATE) goto set_done; /* * If quota tracking is neither requested, nor enabled and there are no * pending deletes, no need to mark the quotas out of date. */ if (!(qce->flags & (QUOTA_FLAG_TRACKING_ENABLED | QUOTA_FLAG_TRACKING_REQUESTED | QUOTA_FLAG_PENDING_DELETES))) goto set_done; /* * Set the QUOTA_FLAG_OUT_OF_DATE bit thus marking quotas out of date. * This is verified on WinXP to be sufficient to cause windows to * rescan the volume on boot and update all quota entries. */ qce->flags |= QUOTA_FLAG_OUT_OF_DATE; /* Ensure the modified flags are written to disk. */ ntfs_index_entry_flush_dcache_page(ictx); ntfs_index_entry_mark_dirty(ictx); set_done: ntfs_index_ctx_put(ictx); up(&vol->quota_q_ino->i_sem); /* * We set the flag so we do not try to mark the quotas out of date * again on remount. */ NVolSetQuotaOutOfDate(vol); done: ntfs_debug("Done."); return TRUE; err_out: if (ictx) ntfs_index_ctx_put(ictx); up(&vol->quota_q_ino->i_sem); return FALSE; }
/** * ntfs_inode_sync_file_name - update FILE_NAME attributes * @ni: ntfs inode to update FILE_NAME attributes * * Update all FILE_NAME attributes for inode @ni in the index. * * Return 0 on success or -1 on error with errno set to the error code. */ static int ntfs_inode_sync_file_name(ntfs_inode *ni) { ntfs_attr_search_ctx *ctx = NULL; ntfs_index_context *ictx; ntfs_inode *index_ni; FILE_NAME_ATTR *fn; int err = 0; ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no); ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) { err = errno; goto err_out; } /* Walk through all FILE_NAME attributes and update them. */ while (!ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx)) { fn = (FILE_NAME_ATTR *)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset)); if (MREF_LE(fn->parent_directory) == ni->mft_no) { /* * WARNING: We cheat here and obtain 2 attribute * search contexts for one inode (first we obtained * above, second will be obtained inside * ntfs_index_lookup), it's acceptable for library, * but will deadlock in the kernel. */ index_ni = ni; } else index_ni = ntfs_inode_open(ni->vol, le64_to_cpu(fn->parent_directory)); if (!index_ni) { if (!err) err = errno; ntfs_log_perror("Failed to open inode %lld with index", (long long)le64_to_cpu(fn->parent_directory)); continue; } ictx = ntfs_index_ctx_get(index_ni, NTFS_INDEX_I30, 4); if (!ictx) { if (!err) err = errno; ntfs_log_perror("Failed to get index ctx, inode %lld", (long long)index_ni->mft_no); if (ni != index_ni && ntfs_inode_close(index_ni) && !err) err = errno; continue; } if (ntfs_index_lookup(fn, sizeof(FILE_NAME_ATTR), ictx)) { if (!err) { if (errno == ENOENT) err = EIO; else err = errno; } ntfs_log_perror("Index lookup failed, inode %lld", (long long)index_ni->mft_no); ntfs_index_ctx_put(ictx); if (ni != index_ni && ntfs_inode_close(index_ni) && !err) err = errno; continue; } /* Update flags and file size. */ fn = (FILE_NAME_ATTR *)ictx->data; fn->file_attributes = (fn->file_attributes & ~FILE_ATTR_VALID_FLAGS) | (ni->flags & FILE_ATTR_VALID_FLAGS); fn->allocated_size = cpu_to_sle64(ni->allocated_size); fn->data_size = cpu_to_sle64(ni->data_size); if (test_nino_flag(ni, TimesDirty)) { fn->creation_time = utc2ntfs(ni->creation_time); fn->last_data_change_time = utc2ntfs(ni->last_data_change_time); fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time); fn->last_access_time = utc2ntfs(ni->last_access_time); } ntfs_index_entry_mark_dirty(ictx); ntfs_index_ctx_put(ictx); if ((ni != index_ni) && ntfs_inode_close(index_ni) && !err) err = errno; } /* Check for real error occurred. */ if (errno != ENOENT) { err = errno; ntfs_log_perror("Attribute lookup failed, inode %lld", (long long)ni->mft_no); goto err_out; } ntfs_attr_put_search_ctx(ctx); if (err) { errno = err; return -1; } return 0; err_out: if (ctx) ntfs_attr_put_search_ctx(ctx); errno = err; return -1; }
/** * ntfs_inode_sync_file_name - update FILE_NAME attributes * @ni: ntfs inode to update FILE_NAME attributes * * Update all FILE_NAME attributes for inode @ni in the index. * * Return 0 on success or -1 on error with errno set to the error code. */ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni) { ntfs_attr_search_ctx *ctx = NULL; ntfs_index_context *ictx; ntfs_inode *index_ni; FILE_NAME_ATTR *fn; FILE_NAME_ATTR *fnx; REPARSE_POINT *rpp; le32 reparse_tag; int err = 0; ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no); ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) { err = errno; goto err_out; } /* Collect the reparse tag, if any */ reparse_tag = cpu_to_le32(0); if (ni->flags & FILE_ATTR_REPARSE_POINT) { if (!ntfs_attr_lookup(AT_REPARSE_POINT, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { rpp = (REPARSE_POINT*)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset)); reparse_tag = rpp->reparse_tag; } ntfs_attr_reinit_search_ctx(ctx); } /* Walk through all FILE_NAME attributes and update them. */ while (!ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx)) { fn = (FILE_NAME_ATTR *)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset)); if (MREF_LE(fn->parent_directory) == ni->mft_no) { /* * WARNING: We cheat here and obtain 2 attribute * search contexts for one inode (first we obtained * above, second will be obtained inside * ntfs_index_lookup), it's acceptable for library, * but will deadlock in the kernel. */ index_ni = ni; } else if (dir_ni) index_ni = dir_ni; else index_ni = ntfs_inode_open(ni->vol, le64_to_cpu(fn->parent_directory)); if (!index_ni) { if (!err) err = errno; ntfs_log_perror("Failed to open inode %lld with index", (long long)le64_to_cpu(fn->parent_directory)); continue; } ictx = ntfs_index_ctx_get(index_ni, NTFS_INDEX_I30, 4); if (!ictx) { if (!err) err = errno; ntfs_log_perror("Failed to get index ctx, inode %lld", (long long)index_ni->mft_no); if ((ni != index_ni) && !dir_ni && ntfs_inode_close(index_ni) && !err) err = errno; continue; } if (ntfs_index_lookup(fn, sizeof(FILE_NAME_ATTR), ictx)) { if (!err) { if (errno == ENOENT) err = EIO; else err = errno; } ntfs_log_perror("Index lookup failed, inode %lld", (long long)index_ni->mft_no); ntfs_index_ctx_put(ictx); if (ni != index_ni && ntfs_inode_close(index_ni) && !err) err = errno; continue; } /* Update flags and file size. */ fnx = (FILE_NAME_ATTR *)ictx->data; fnx->file_attributes = (fnx->file_attributes & ~FILE_ATTR_VALID_FLAGS) | (ni->flags & FILE_ATTR_VALID_FLAGS); if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) fnx->data_size = fnx->allocated_size = const_cpu_to_le64(0); else { fnx->allocated_size = cpu_to_sle64(ni->allocated_size); fnx->data_size = cpu_to_sle64(ni->data_size); /* * The file name record has also to be fixed if some * attribute update implied the unnamed data to be * made non-resident */ fn->allocated_size = fnx->allocated_size; } /* update or clear the reparse tag in the index */ fnx->reparse_point_tag = reparse_tag; if (!test_nino_flag(ni, TimesSet)) { fnx->creation_time = ni->creation_time; fnx->last_data_change_time = ni->last_data_change_time; fnx->last_mft_change_time = ni->last_mft_change_time; fnx->last_access_time = ni->last_access_time; } else { fnx->creation_time = fn->creation_time; fnx->last_data_change_time = fn->last_data_change_time; fnx->last_mft_change_time = fn->last_mft_change_time; fnx->last_access_time = fn->last_access_time; } ntfs_index_entry_mark_dirty(ictx); ntfs_index_ctx_put(ictx); if ((ni != index_ni) && !dir_ni && ntfs_inode_close(index_ni) && !err) err = errno; } /* Check for real error occurred. */ if (errno != ENOENT) { err = errno; ntfs_log_perror("Attribute lookup failed, inode %lld", (long long)ni->mft_no); goto err_out; } ntfs_attr_put_search_ctx(ctx); if (err) { errno = err; return -1; } return 0; err_out: if (ctx) ntfs_attr_put_search_ctx(ctx); errno = err; return -1; }
int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni) { int res; int olderrno; ntfs_attr *na; ntfs_inode *xrni; ntfs_index_context *xr; le32 reparse_tag; res = 0; if (ni) { /* * open and delete the reparse data */ na = ntfs_attr_open(ni, AT_REPARSE_POINT, AT_UNNAMED,0); if (na) { /* first remove index (reparse data needed) */ xr = open_reparse_index(ni->vol); if (xr) { if (remove_reparse_index(na,xr, &reparse_tag) < 0) { res = -1; } else { /* now remove attribute */ res = ntfs_attr_rm(na); if (!res) { ni->flags &= ~FILE_ATTR_REPARSE_POINT; NInoFileNameSetDirty(ni); } else { /* * If we could not remove the * attribute, try to restore the * index and log the error. There * will be an inconsistency if * the reindexing fails. */ set_reparse_index(ni, xr, reparse_tag); ntfs_log_error( "Failed to remove reparse data." " Possible corruption.\n"); } } xrni = xr->ni; ntfs_index_entry_mark_dirty(xr); NInoSetDirty(xrni); ntfs_index_ctx_put(xr); ntfs_inode_close(xrni); } olderrno = errno; ntfs_attr_close(na); /* avoid errno pollution */ if (errno == ENOENT) errno = olderrno; } else { errno = ENODATA; res = -1; } NInoSetDirty(ni); } else { errno = EINVAL; res = -1; } return (res ? -1 : 0); }
int ntfs_set_ntfs_reparse_data(ntfs_inode *ni, const char *value, size_t size, int flags) { int res; u8 dummy; ntfs_inode *xrni; ntfs_index_context *xr; res = 0; if (ni && valid_reparse_data(ni, (const REPARSE_POINT*)value, size)) { xr = open_reparse_index(ni->vol); if (xr) { if (!ntfs_attr_exist(ni,AT_REPARSE_POINT, AT_UNNAMED,0)) { if (!(flags & XATTR_REPLACE)) { /* * no reparse data attribute : add one, * apparently, this does not feed the new value in * Note : NTFS version must be >= 3 */ if (ni->vol->major_ver >= 3) { res = ntfs_attr_add(ni, AT_REPARSE_POINT, AT_UNNAMED,0,&dummy, (s64)0); if (!res) { ni->flags |= FILE_ATTR_REPARSE_POINT; NInoFileNameSetDirty(ni); } NInoSetDirty(ni); } else { errno = EOPNOTSUPP; res = -1; } } else { errno = ENODATA; res = -1; } } else { if (flags & XATTR_CREATE) { errno = EEXIST; res = -1; } } if (!res) { /* update value and index */ res = update_reparse_data(ni,xr,value,size); } xrni = xr->ni; ntfs_index_entry_mark_dirty(xr); NInoSetDirty(xrni); ntfs_index_ctx_put(xr); ntfs_inode_close(xrni); } else { res = -1; } } else { errno = EINVAL; res = -1; } return (res ? -1 : 0); }
int ntfs_remove_ntfs_object_id(ntfs_inode *ni) { int res; int olderrno; ntfs_attr *na; ntfs_inode *xoni; ntfs_index_context *xo; int oldsize; OBJECT_ID_ATTR old_attr; res = 0; if (ni) { /* * open and delete the object id */ na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED,0); if (na) { /* first remove index (old object id needed) */ xo = open_object_id_index(ni->vol); if (xo) { oldsize = remove_object_id_index(na,xo, &old_attr); if (oldsize < 0) { res = -1; } else { /* now remove attribute */ res = ntfs_attr_rm(na); if (res && (oldsize > (int)sizeof(GUID))) { /* * If we could not remove the * attribute, try to restore the * index and log the error. There * will be an inconsistency if * the reindexing fails. */ set_object_id_index(ni, xo, &old_attr); ntfs_log_error( "Failed to remove object id." " Possible corruption.\n"); } } xoni = xo->ni; ntfs_index_entry_mark_dirty(xo); NInoSetDirty(xoni); ntfs_index_ctx_put(xo); ntfs_inode_close(xoni); } olderrno = errno; ntfs_attr_close(na); /* avoid errno pollution */ if (errno == ENOENT) errno = olderrno; } else { errno = ENODATA; res = -1; } NInoSetDirty(ni); } else { errno = EINVAL; res = -1; } return (res ? -1 : 0); }