예제 #1
0
int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
{
    ntfs_log_trace("path %s, mode %i\n", path, mode);

    ntfs_vd *vd = NULL;
    ntfs_inode *ni = NULL;

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

    // Lock
    ntfsLock(vd);

    // Create the directory
    ni = ntfsCreate(vd, path, S_IFDIR, NULL);
    if (!ni) {
        ntfsUnlock(vd);
        r->_errno = errno;
        return -1;
    }

    // Close the directory
    ntfsCloseEntry(vd, ni);

    // Unlock
    ntfsUnlock(vd);

    return 0;
}
예제 #2
0
int ntfs_fsync_r(struct _reent *r, int fd)
{
	ntfs_log_trace("fd %p\n", (void *) fd);

	ntfs_file_state* file = STATE(((intptr_t)(s64)fd));
	//ntfs_file_state* file = STATE(((s64) fd));
	int ret = 0;

	// Sanity check
	if (!file || !file->vd || !file->ni || !file->data_na) {
		r->_errno = EINVAL;
		return -1;
	}

	// Lock
	ntfsLock(file->vd);

	// Sync the file (and its attributes) to disc
	ret = ntfsSync(file->vd, file->ni);
	if (ret)
		r->_errno = errno;

	// Unlock
	ntfsUnlock(file->vd);

	return ret;
}
예제 #3
0
int ntfs_dirclose_r (struct _reent *r, DIR_ITER *dirState)
{
    ntfs_log_trace("dirState %p\n", dirState);

    ntfs_dir_state* dir = STATE(dirState);

    // Sanity check
    if (!dir || !dir->vd) {
        r->_errno = EBADF;
        return -1;
    }

    // Lock
    ntfsLock(dir->vd);

    // Close the directory
    ntfsCloseDir(dir);

    // Remove the directory from the double-linked FILO list of open directories
    dir->vd->openDirCount--;
    if (dir->nextOpenDir)
        dir->nextOpenDir->prevOpenDir = dir->prevOpenDir;
    if (dir->prevOpenDir)
        dir->prevOpenDir->nextOpenDir = dir->nextOpenDir;
    else
        dir->vd->firstOpenDir = dir->nextOpenDir;

    // Unlock
    ntfsUnlock(dir->vd);

    return 0;
}
예제 #4
0
int ntfs_link_r (struct _reent *r, const char *existing, const char *newLink)
{
    ntfs_log_trace("existing %s, newLink %s\n", existing, newLink);

    ntfs_vd *vd = NULL;
    ntfs_inode *ni = NULL;

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

    // Lock
    ntfsLock(vd);

    // Create a symbolic link between the two paths
    ni = ntfsCreate(vd, existing, S_IFLNK, newLink);
    if (!ni) {
        ntfsUnlock(vd);
        r->_errno = errno;
        return -1;
    }

    // Close the symbolic link
    ntfsCloseEntry(vd, ni);

    // Unlock
    ntfsUnlock(vd);

    return 0;
}
예제 #5
0
int ntfsSync (ntfs_vd *vd, ntfs_inode *ni)
{
    int res = 0;

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

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

    // Lock
    ntfsLock(vd);

    // Sync the entry
    res = ntfs_inode_sync(ni);

    // Force the underlying device to sync
    ntfs_device_sync(vd->dev);

    // Unlock
    ntfsUnlock(vd);

    return res;

}
예제 #6
0
int ntfs_close_r(struct _reent *r, int fd)
{
	ntfs_log_trace("fd %p\n", (void *) fd);

	ntfs_file_state* file = STATE(((intptr_t)(s64)fd));
	//ntfs_file_state* file = STATE(((s64) fd));

	// Sanity check
	if (!file || !file->vd) {
		r->_errno = EBADF;
		return -1;
	}

	// Lock
	ntfsLock(file->vd);

	// Close the file
	ntfsCloseFile(file);

	// Remove the file from the double-linked FILO list of open files
	file->vd->openFileCount--;
	if (file->nextOpenFile)
		file->nextOpenFile->prevOpenFile = file->prevOpenFile;
	if (file->prevOpenFile)
		file->prevOpenFile->nextOpenFile = file->nextOpenFile;
	else
		file->vd->firstOpenFile = file->nextOpenFile;

	// Unlock
	ntfsUnlock(file->vd);

	return 0;
}
예제 #7
0
s64 ntfs_seek64_r(struct _reent *r, int fd, s64 pos, int dir)
{
	ntfs_log_trace("fd %p, pos %llu, dir %i\n", (void *) fd, pos, dir);

	ntfs_file_state* file = STATE(((intptr_t)(s64)fd));
	//ntfs_file_state* file = STATE(((s64) fd));
	s64 position = 0;

	// Sanity check
	if (!file || !file->vd || !file->ni || !file->data_na) {
		r->_errno = EINVAL;
		return -1;
	}

	// Lock
	ntfsLock(file->vd);

	// Set the files current position
	switch(dir) {
	case SEEK_SET:
		position = file->pos = MIN(MAX(pos, 0), file->len);
		break;
	case SEEK_CUR:
		position = file->pos = MIN(MAX(file->pos + pos, 0), file->len);
		break;
	case SEEK_END:
		position = file->pos = MIN(MAX(file->len + pos, 0), file->len);
		break;
	}

	// Unlock
	ntfsUnlock(file->vd);

	return position;
}
예제 #8
0
int ntfs_dirreset_r (struct _reent *r, DIR_ITER *dirState)
{
    ntfs_log_trace("dirState %p\n", dirState);

    ntfs_dir_state* dir = STATE(dirState);

    // Sanity check
    if (!dir || !dir->vd || !dir->ni) {
        r->_errno = EBADF;
        return -1;
    }

    // Lock
    ntfsLock(dir->vd);

    // Move to the first entry in the directory
    dir->current = dir->first;

    // Update directory times
    ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);

    // Unlock
    ntfsUnlock(dir->vd);

    return 0;
}
예제 #9
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;
}
예제 #10
0
int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
{
    ntfs_log_trace("oldName %s, newName %s\n", oldName, newName);

    ntfs_vd *vd = NULL;
    ntfs_inode *ni = NULL;

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

    // Lock
    ntfsLock(vd);

    // You cannot rename between devices
    if(vd != ntfsGetVolume(newName)) {
        ntfsUnlock(vd);
        r->_errno = EXDEV;
        return -1;
    }

    // Check that there is no existing entry with the new name
    ni = ntfsOpenEntry(vd, newName);
    if (ni) {
        ntfsCloseEntry(vd, ni);
        ntfsUnlock(vd);
        r->_errno = EEXIST;
        return -1;
    }

    // Link the old entry with the new one
    if (ntfsLink(vd, oldName, newName)) {
        ntfsUnlock(vd);
        return -1;
    }

    // Unlink the old entry
    if (ntfsUnlink(vd, oldName)) {
        if (ntfsUnlink(vd, newName)) {
            ntfsUnlock(vd);
            return -1;
        }
        ntfsUnlock(vd);
        return -1;
    }

    // Unlock
    ntfsUnlock(vd);

    return 0;
}
예제 #11
0
int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat)
{
    ntfs_log_trace("dirState %p, filename %p, filestat %p\n", dirState, filename, filestat);

    ntfs_dir_state* dir = STATE(dirState);
    ntfs_inode *ni = NULL;

    // Sanity check
    if (!dir || !dir->vd || !dir->ni) {
        r->_errno = EBADF;
        return -1;
    }

    // Lock
    ntfsLock(dir->vd);

    // Check that there is a entry waiting to be fetched
    if (!dir->current) {
        ntfsUnlock(dir->vd);
        r->_errno = ENOENT;
        return -1;
    }

    // Fetch the current entry
    strcpy(filename, dir->current->name);
    if(filestat != NULL)
    {
        if(strcmp(dir->current->name, ".") == 0 || strcmp(dir->current->name, "..") == 0)
        {
            memset(filestat, 0, sizeof(struct stat));
            filestat->st_mode = S_IFDIR;
        }
        else
        {
            ni = ntfsOpenEntry(dir->vd, dir->current->name);
            if (ni) {
                ntfsStat(dir->vd, ni, filestat);
                ntfsCloseEntry(dir->vd, ni);
            }
        }
    }

    // Move to the next entry in the directory
    dir->current = dir->current->next;

    // Update directory times
    ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);

    // Unlock
    ntfsUnlock(dir->vd);

    return 0;
}
예제 #12
0
void ntfsDeinitVolume (ntfs_vd *vd)
{
    // Sanity check
    if (!vd) {
        errno = ENODEV;
        return;
    }

    // Lock
    ntfsLock(vd);

    // Close any directories which are still open (lazy programmers!)
    ntfs_dir_state *nextDir = vd->firstOpenDir;
    while (nextDir) {
        ntfs_log_warning("Cleaning up orphaned directory @ %p\n", nextDir);
        ntfsCloseDir(nextDir);
        nextDir = nextDir->nextOpenDir;
    }

    // Close any files which are still open (lazy programmers!)
    ntfs_file_state *nextFile = vd->firstOpenFile;
    while (nextFile) {
        ntfs_log_warning("Cleaning up orphaned file @ %p\n", nextFile);
        ntfsCloseFile(nextFile);
        nextFile = nextFile->nextOpenFile;
    }

    // Reset open directory and file stats
    vd->openDirCount = 0;
    vd->openFileCount = 0;
    vd->firstOpenDir = NULL;
    vd->firstOpenFile = NULL;

    // Close the volumes current directory (if any)
    //if (vd->cwd_ni) {
        //ntfsCloseEntry(vd, vd->cwd_ni);
        //vd->cwd_ni = NULL;
    //}

    // Force the underlying device to sync
    ntfs_device_sync(vd->dev);

    // Unlock
    ntfsUnlock(vd);
#ifndef LIBXENON
    // Deinitialise the volume lock
    LWP_MutexDestroy(vd->lock);
#endif
    return;
}
예제 #13
0
int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
{
    // Short circuit cases were we don't actually have to do anything
    if (!st || !path)
        return 0;

    ntfs_log_trace("path %s, st %p\n", path, st);

    ntfs_vd *vd = NULL;
    ntfs_inode *ni = NULL;

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

    if(strcmp(path, ".") == 0 || strcmp(path, "..") == 0)
    {
        memset(st, 0, sizeof(struct stat));
        st->st_mode = S_IFDIR;
        return 0;
    }

    // Lock
    ntfsLock(vd);

    // Find the entry
    ni = ntfsOpenEntry(vd, path);
    if (!ni) {
        r->_errno = errno;
        ntfsUnlock(vd);
        return -1;
    }

    // Get the entry stats
    int ret = ntfsStat(vd, ni, st);
    if (ret)
        r->_errno = errno;

    // Close the entry
    ntfsCloseEntry(vd, ni);

    ntfsUnlock(vd);

    return 0;
}
예제 #14
0
int ntfs_chdir_r (struct _reent *r, const char *name)
{
    ntfs_log_trace("name %s\n", name);

    ntfs_vd *vd = NULL;
    ntfs_inode *ni = NULL;

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

    // Lock
    ntfsLock(vd);

    // Find the directory
    ni = ntfsOpenEntry(vd, name);
    if (!ni) {
        ntfsUnlock(vd);
        r->_errno = ENOENT;
        return -1;
    }

    // Ensure that this directory is indeed a directory
    if (!(ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
        ntfsCloseEntry(vd, ni);
        ntfsUnlock(vd);
        r->_errno = ENOTDIR;
        return -1;
    }

    // Close the old current directory (if any)
    if (vd->cwd_ni)
        ntfsCloseEntry(vd, vd->cwd_ni);

    // Set the new current directory
    vd->cwd_ni = ni;

    // Unlock
    ntfsUnlock(vd);

    return 0;
}
예제 #15
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 {
예제 #16
0
void ntfsCloseEntry (ntfs_vd *vd, ntfs_inode *ni)
{
    // Sanity check
    if (!vd) {
        errno = ENODEV;
        return;
    }

    // Lock
    ntfsLock(vd);

    // Sync the entry (if it is dirty)
    if (NInoDirty(ni))
        ntfsSync(vd, ni);

    // Close the entry
    ntfs_inode_close(ni);

    // Unlock
    ntfsUnlock(vd);

    return;
}
예제 #17
0
int ntfs_ftruncate_r(struct _reent *r, int fd, off_t len)
{
	ntfs_log_trace("fd %p, len %llu\n", (void *) fd, (u64) len);

	ntfs_file_state* file = STATE(((intptr_t)(s64)fd));
	//ntfs_file_state* file = STATE(((s64) fd));

	// Sanity check
	if (!file || !file->vd || !file->ni || !file->data_na) {
		r->_errno = EINVAL;
		return -1;
	}

	// Lock
	ntfsLock(file->vd);

	// Check that we are allowed to write to this file
	if (!file->write) {
		ntfsUnlock(file->vd);
		r->_errno = EACCES;
		return -1;
	}

	// For compressed files, only deleting and expanding contents are implemented
	if (file->compressed &&
		len > 0 &&
		len < file->data_na->initialized_size) {
		ntfsUnlock(file->vd);
		r->_errno = ENOTSUP;
		return -1;
	}

	// Resize the files data attribute, either by expanding or truncating
	if (file->compressed && len > file->data_na->initialized_size) {
		char zero = 0;
		if (ntfs_attr_pwrite(file->data_na, len - 1, 1, &zero) <= 0) {
			ntfsUnlock(file->vd);
			r->_errno = errno;
			return -1;
		}
	} else {
		if (ntfs_attr_truncate(file->data_na, len)) {
			ntfsUnlock(file->vd);
			r->_errno = errno;
			return -1;
		}
	}

	// Mark the file for archiving (if we actually changed something)
	if (file->len != file->data_na->data_size)
		file->ni->flags |= FILE_ATTR_ARCHIVE;

	// Update file times (if we actually changed something)
	if (file->len != file->data_na->data_size)
		ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_AMCTIME);

	// Update the files data length
	file->len = file->data_na->data_size;

	// Sync the file (and its attributes) to disc
	ntfsSync(file->vd, file->ni);

	// Unlock
	ntfsUnlock(file->vd);

	return 0;
}
예제 #18
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;
}
예제 #19
0
int _NTFS_get_fragments (const char *path,
        _ntfs_frag_append_t append_fragment, void *callback_data)
{
    struct _reent r;
    ntfs_file_state file_st, *file = &file_st;
    ssize_t read = 0;
    int ret_val = -11;

    // Open File
    r._errno = 0;
    int fd = ntfs_open_r(&r, file, path, O_RDONLY, 0);
    if (fd != (int)file) return -12;


    // Sanity check
    if (!file || !file->vd || !file->ni || !file->data_na) {
        //r->_errno = EINVAL;
        return -13;
    }
    /*
    // 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;
    }
    */

    u64 offset = 0;
    u64 len = file->len;

    // Read from the files data attribute
    while (len) {
        s64 ret = ntfs_attr_getfragments(file->data_na, file->pos,
                len, offset, append_fragment, callback_data);
        if (ret <= 0 || ret > len) {
            //r->_errno = errno;
            ret_val = -14;
			if (ret < 0) ret_val = ret;
            goto out;
        }
        offset += ret;
        len -= ret;
        file->pos += ret;
        read += ret;
    }

    // set file size
    append_fragment(callback_data, file->len >> 9, 0, 0);
    // success
    ret_val = 0;

    /*
    // Update file times (if we actually read something)
    if (read)
        ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME);
    */

out:
    // Unlock
    ntfsUnlock(file->vd);
    // Close the file
    ntfs_close_r (&r, fd);

    return ret_val;
}
예제 #20
0
int ntfsUnlink (ntfs_vd *vd, const char *path)
{
    ntfs_inode *dir_ni = NULL, *ni = NULL;
    char *dir = NULL;
    char *name = NULL;
    ntfschar *uname = NULL;
    int uname_len;
    int res = 0;

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

    // Get the actual path of the entry
    path = ntfsRealPath(path);
    if (!path) {
        errno = EINVAL;
        return -1;
    }

    // Lock
    ntfsLock(vd);

    // Get the unicode name for the entry and find its parent directory
    // TODO: This looks horrible
    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;
    }

    // Find the entry
    ni = ntfsOpenEntry(vd, path);
    if (!ni) {
        errno = ENOENT;
        res = -1;
        goto cleanup;
    }

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

    // Unlink the entry from its parent
    if (ntfs_delete(vd->vol, path, ni, dir_ni, uname, uname_len)) {
        res = -1;
    }

    // Force the underlying device to sync
    ntfs_device_sync(vd->dev);

    // ntfs_delete() ALWAYS closes ni and dir_ni; so no need for us to anymore
    dir_ni = ni = NULL;

cleanup:

    if(dir_ni)
        ntfsCloseEntry(vd, dir_ni);

    if(ni)
        ntfsCloseEntry(vd, ni);

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

    if(dir)
        ntfs_free(dir);

    // Unlock
    ntfsUnlock(vd);

    return 0;
}
예제 #21
0
ssize_t ntfs_write_r(struct _reent *r, int fd, const 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 written = 0;
	off_t old_pos = 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 write to this file
	if (!file->write) {
		ntfsUnlock(file->vd);
		r->_errno = EACCES;
		return -1;
	}

	// If we are in append mode, backup the current position and move to the end of the file
	if (file->append) {
		old_pos = file->pos;
		file->pos = file->len;
	}

	// Write to the files data atrribute
	while (len) {
		ssize_t ret = ntfs_attr_pwrite(file->data_na, file->pos, len, ptr);
		if (ret <= 0) {
			ntfsUnlock(file->vd);
			r->_errno = errno;
			return -1;
		}
		len -= ret;
		file->pos += ret;
		written += ret;
	}

	// If we are in append mode, restore the current position to were it was prior to this write
	if (file->append) {
		file->pos = old_pos;
	}

	// Mark the file for archiving (if we actually wrote something)
	if (written)
		file->ni->flags |= FILE_ATTR_ARCHIVE;

	// Update the files data length
	file->len = file->data_na->data_size;

	// Unlock
	ntfsUnlock(file->vd);

	return written;
}
예제 #22
0
파일: ntfs.c 프로젝트: gnils/usbloader-gx
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;
}
예제 #23
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;
}
예제 #24
0
int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
{
    ntfs_inode *dir_ni = NULL, *ni = NULL;
    char *dir = NULL;
    char *name = NULL;
    ntfschar *uname = NULL;
    int uname_len;
    int res = 0;

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

    // You cannot link between devices
    if(vd != ntfsGetVolume(new_path)) {
        errno = EXDEV;
        return -1;
    }

    // Get the actual paths of the entry
    old_path = ntfsRealPath(old_path);
    new_path = ntfsRealPath(new_path);
    if (!old_path || !new_path) {
        errno = EINVAL;
        return -1;
    }

    // Lock
    ntfsLock(vd);

    // Get the unicode name for the entry and find its parent directory
    // TODO: This looks horrible, clean it up
    dir = strdup(new_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 = 0;

    // Find the entry
    ni = ntfsOpenEntry(vd, old_path);
    if (!ni) {
        errno = ENOENT;
        res = -1;
        goto cleanup;
    }

    // Open the entries new parent directory
    dir_ni = ntfsOpenEntry(vd, dir);
    if (!dir_ni) {
        errno = ENOENT;
        res = -1;
        goto cleanup;
    }

    // Link the entry to its new parent
    if (ntfs_link(ni, dir_ni, uname, uname_len)) {
        res = -1;
        goto cleanup;
    }

    // Update entry times
    ntfsUpdateTimes(vd, dir_ni, NTFS_UPDATE_MCTIME);

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

cleanup:

    if(dir_ni)
        ntfsCloseEntry(vd, dir_ni);

    if(ni)
        ntfsCloseEntry(vd, ni);

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

    if(dir)
        ntfs_free(dir);

    // Unlock
    ntfsUnlock(vd);

    return res;
}
예제 #25
0
DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path)
{
    ntfs_log_trace("dirState %p, path %s\n", dirState, path);

    ntfs_dir_state* dir = STATE(dirState);
    s64 position = 0;

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

    // Lock
    ntfsLock(dir->vd);

    // Find the directory
    dir->ni = ntfsOpenEntry(dir->vd, path);
    if (!dir->ni) {
        ntfsUnlock(dir->vd);
        r->_errno = ENOENT;
        return NULL;
    }

    // Ensure that this directory is indeed a directory
    if (!(dir->ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
        ntfsCloseEntry(dir->vd, dir->ni);
        ntfsUnlock(dir->vd);
        r->_errno = ENOTDIR;
        return NULL;
    }

    // Read the directory
    dir->first = dir->current = NULL;
    if (ntfs_readdir(dir->ni, &position, dirState, (ntfs_filldir_t)ntfs_readdir_filler)) {
        ntfsCloseDir(dir);
        ntfsUnlock(dir->vd);
        r->_errno = errno;
        return NULL;
    }

    // Move to the first entry in the directory
    dir->current = dir->first;

    // Update directory times
    ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);

    // Insert the directory into the double-linked FILO list of open directories
    if (dir->vd->firstOpenDir) {
        dir->nextOpenDir = dir->vd->firstOpenDir;
        dir->vd->firstOpenDir->prevOpenDir = dir;
    } else {
        dir->nextOpenDir = NULL;
    }
    dir->prevOpenDir = NULL;
    dir->vd->cwd_ni = dir->ni;
    dir->vd->firstOpenDir = dir;
    dir->vd->openDirCount++;

    // Unlock
    ntfsUnlock(dir->vd);

    return dirState;
}
예제 #26
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;
}
예제 #27
0
int ntfs_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
{
    ntfs_log_trace("path %s, buf %p\n", path, buf);

    ntfs_vd *vd = NULL;
    s64 size;
    int delta_bits;

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

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

    // Lock
    ntfsLock(vd);

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

    if(ntfs_volume_get_free_space(vd->vol) < 0)
    {
        ntfsUnlock(vd);
        return -1;
    }

    // File system block size
    buf->f_bsize = vd->vol->cluster_size;

    // Fundamental file system block size
    buf->f_frsize = vd->vol->cluster_size;

    // Total number of blocks on file system in units of f_frsize
    buf->f_blocks = vd->vol->nr_clusters;

    // Free blocks available for all and for non-privileged processes
    size = MAX(vd->vol->free_clusters, 0);
    buf->f_bfree = buf->f_bavail = size;

    // Free inodes on the free space
    delta_bits = vd->vol->cluster_size_bits - vd->vol->mft_record_size_bits;
    if (delta_bits >= 0)
        size <<= delta_bits;
    else
        size >>= -delta_bits;

    // Number of inodes at this point in time
    buf->f_files = (vd->vol->mftbmp_na->allocated_size << 3) + size;

    // Free inodes available for all and for non-privileged processes
    size += vd->vol->free_mft_records;
    buf->f_ffree = buf->f_favail = MAX(size, 0);

    // File system id
    buf->f_fsid = vd->id;

    // Bit mask of f_flag values.
    buf->f_flag = (NVolReadOnly(vd->vol) ? ST_RDONLY : 0);

    // Maximum length of filenames
    buf->f_namemax = NTFS_MAX_NAME_LEN;

    // Unlock
    ntfsUnlock(vd);

    return 0;
}