예제 #1
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);
}
예제 #2
0
파일: inode.c 프로젝트: gnils/usbloader-gx
/**
 * ntfs_inode_update_times - update selected time fields for ntfs inode
 * @ni:		ntfs inode for which update time fields
 * @mask:	select which time fields should be updated
 *
 * This function updates time fields to current time. Fields to update are
 * selected using @mask (see enum @ntfs_time_update_flags for posssible values).
 */
void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
{
	time_t now;

	if (!ni) {
		ntfs_log_error("%s(): Invalid arguments.\n", __FUNCTION__);
		return;
	}

	if ((ni->mft_no < FILE_first_user && ni->mft_no != FILE_root) ||
			NVolReadOnly(ni->vol) || !mask)
		return;

	now = time(NULL);
	if (mask & NTFS_UPDATE_ATIME)
		ni->last_access_time = now;
	if (mask & NTFS_UPDATE_MTIME)
		ni->last_data_change_time = now;
	if (mask & NTFS_UPDATE_CTIME)
		ni->last_mft_change_time = now;

	set_nino_flag(ni, TimesDirty);
	NInoFileNameSetDirty(ni);
	NInoSetDirty(ni);
}
예제 #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);
}
예제 #4
0
static int add_object_id(ntfs_inode *ni, int flags)
{
	int res;
	u8 dummy;

	res = -1; /* default return */
	if (!ntfs_attr_exist(ni,AT_OBJECT_ID, AT_UNNAMED,0)) {
		if (!(flags & XATTR_REPLACE)) {
			/*
			 * no object id 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_OBJECT_ID,
						AT_UNNAMED, 0, &dummy, (s64)0);
				NInoSetDirty(ni);
			} else
				errno = ENOTSUP;
		} else
			errno = ENODATA;
	} else {
		if (flags & XATTR_CREATE)
			errno = EEXIST;
		else
			res = 0;
	}
	return (res);
}
예제 #5
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);
}
예제 #6
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);
}
예제 #7
0
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);
}
예제 #8
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);
}
예제 #9
0
파일: inode.c 프로젝트: gnils/usbloader-gx
/**
 * ntfs_inode_mark_dirty - set the inode (and its base inode if it exists) dirty
 * @ni:		ntfs inode to set dirty
 *
 * Set the inode @ni dirty so it is written out later (at the latest at
 * ntfs_inode_close() time). If @ni is an extent inode, set the base inode
 * dirty, too.
 *
 * This function cannot fail.
 */
void ntfs_inode_mark_dirty(ntfs_inode *ni)
{
	NInoSetDirty(ni);
	if (ni->nr_extents == -1)
		NInoSetDirty(ni->base_ni);
}
예제 #10
0
파일: inode.c 프로젝트: gnils/usbloader-gx
/**
 * 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;
}
예제 #11
0
ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *target)
{
    ntfs_inode *dir_ni = NULL, *ni = NULL;
    char *dir = NULL;
    char *name = NULL;
    ntfschar *uname = NULL, *utarget = NULL;
    int uname_len, utarget_len;

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

    // You cannot link between devices
    if(target) {
        if(vd != ntfsGetVolume(target)) {
            errno = EXDEV;
            return NULL;
        }
    }

    // Get the actual paths of the entry
    path = ntfsRealPath(path);
    target = ntfsRealPath(target);
    if (!path) {
        errno = EINVAL;
        return NULL;
    }

    // Lock
    ntfsLock(vd);

    // Get the unicode name for the entry and find its parent directory
    // TODO: This looks horrible, clean it up
    dir = strdup(path);
    if (!dir) {
        errno = EINVAL;
        goto cleanup;
    }
    name = strrchr(dir, '/');
    if (name)
        name++;
    else
        name = dir;
    uname_len = ntfsLocalToUnicode(name, &uname);
    if (uname_len < 0) {
        errno = EINVAL;
        goto cleanup;
    }
    name = strrchr(dir, '/');
    if(name)
    {
        name++;
        name[0] = 0;
    }

    // Open the entries parent directory
    dir_ni = ntfsOpenEntry(vd, dir);
    if (!dir_ni) {
        goto cleanup;
    }

    // Create the entry
    switch (type) {

        // Symbolic link
        case S_IFLNK:
            if (!target) {
                errno = EINVAL;
                goto cleanup;
            }
            utarget_len = ntfsLocalToUnicode(target, &utarget);
            if (utarget_len < 0) {
                errno = EINVAL;
                goto cleanup;
            }
            ni = ntfs_create_symlink(dir_ni, 0, uname, uname_len,  utarget, utarget_len);
            break;

        // Directory or file
        case S_IFDIR:
        case S_IFREG:
            ni = ntfs_create(dir_ni, 0, uname, uname_len, type);
            break;

    }

    // If the entry was created
    if (ni) {

        // Mark the entry for archiving
        ni->flags |= FILE_ATTR_ARCHIVE;

        // Mark the entry as dirty
        NInoSetDirty(ni);

        // Sync the entry to disc
        ntfsSync(vd, ni);

        // Update parent directories times
        ntfsUpdateTimes(vd, dir_ni, NTFS_UPDATE_MCTIME);

    }

cleanup:

    if(dir_ni)
        ntfsCloseEntry(vd, dir_ni);

    // use free because the value was not allocated with ntfs_alloc
    if(utarget)
        free(utarget);

    if(uname)
        free(uname);

    if(dir)
        ntfs_free(dir);

    // Unlock
    ntfsUnlock(vd);

    return ni;
}
예제 #12
0
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);
}
예제 #13
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);
}
예제 #14
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);
}