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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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 {
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }