Beispiel #1
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;
}
Beispiel #2
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;
}
Beispiel #3
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;
}
Beispiel #4
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;
}
Beispiel #5
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;
}
Beispiel #6
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;
}
Beispiel #7
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;
}
Beispiel #8
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;
}
Beispiel #9
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;
}
Beispiel #10
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;
}