static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *d) { struct inode *res=0; char *item=0; ntfs_iterate_s walk; int error; ntfs_debug(DEBUG_NAME1, "Looking up %s in %x\n",d->d_name.name, (unsigned)dir->i_ino); /* convert to wide string */ error=ntfs_decodeuni(NTFS_INO2VOL(dir),(char*)d->d_name.name, d->d_name.len,&walk.name,&walk.namelen); if(error) return ERR_PTR(-error); item=ntfs_malloc(ITEM_SIZE); if( !item ) return ERR_PTR(-ENOMEM); /* ntfs_getdir will place the directory entry into item, and the first long long is the MFT record number */ walk.type=BY_NAME; walk.dir=NTFS_LINO2NINO(dir); walk.result=item; if(ntfs_getdir_byname(&walk)) { res=iget(dir->i_sb,NTFS_GETU32(item)); } d_add(d,res); ntfs_free(item); ntfs_free(walk.name); /* Always return success, the dcache will handle negative entries. */ return NULL; }
void ntfsCloseDir (ntfs_dir_state *dir) { // Sanity check if (!dir || !dir->vd) return; // Free the directory entries (if any) while (dir->first) { ntfs_dir_entry *next = dir->first->next; ntfs_free(dir->first->name); ntfs_free(dir->first); dir->first = next; } // Close the directory (if open) if (dir->ni) ntfsCloseEntry(dir->vd, dir->ni); // Reset the directory state dir->ni = NULL; dir->first = NULL; dir->current = NULL; return; }
int ntfsMountAll (ntfs_md **mounts, u32 flags) { const INTERFACE_ID *discs = ntfsGetDiscInterfaces(); const INTERFACE_ID *disc = NULL; ntfs_md mount_points[NTFS_MAX_MOUNTS]; sec_t *partitions = NULL; int mount_count = 0; int partition_count = 0; char name[128]; int i, j, k; // Initialise ntfs-3g ntfsInit(); // Find and mount all NTFS partitions on all known devices for (i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++) { disc = &discs[i]; partition_count = ntfsFindPartitions(disc->interface, &partitions); if (partition_count > 0 && partitions) { for (j = 0, k = 0; j < partition_count; j++) { // Find the next unused mount name do { sprintf(name, "%s%i", NTFS_MOUNT_PREFIX, k++); if (k >= NTFS_MAX_MOUNTS) { ntfs_free(partitions); errno = EADDRNOTAVAIL; return -1; } } while (ntfsGetDevice(name, false)); // Mount the partition if (mount_count < NTFS_MAX_MOUNTS) { if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags)) { strcpy(mount_points[mount_count].name, name); mount_points[mount_count].interface = disc->interface; mount_points[mount_count].startSector = partitions[j]; mount_count++; } } } ntfs_free(partitions); } } // Return the mounts (if any) if (mount_count > 0 && mounts) { *mounts = (ntfs_md*)ntfs_alloc(sizeof(ntfs_md) * mount_count); if (*mounts) { memcpy(*mounts, &mount_points, sizeof(ntfs_md) * mount_count); return mount_count; } } return 0; }
void _NTFS_cache_destructor (NTFS_CACHE* cache) { unsigned int i; if(cache==NULL) return; // Clear out cache before destroying it _NTFS_cache_flush(cache); // Free memory in reverse allocation order for (i = 0; i < cache->numberOfPages; i++) { ntfs_free (cache->cacheEntries[i].cache); } ntfs_free (cache->cacheEntries); ntfs_free (cache); }
void ntfsRemoveDevice (const char *path) { const devoptab_t *devoptab = NULL; char name[128] = {0}; int i; // Get the device name from the path strncpy(name, path, 127); strtok(name, ":/"); // Find and remove the specified device from the devoptab table // NOTE: We do this manually due to a 'bug' in RemoveDevice // which ignores names with suffixes and causes names // like "ntfs" and "ntfs1" to be seen as equals for (i = 0; i < STD_MAX; i++) { devoptab = devoptab_list[i]; if (devoptab && devoptab->name) { if (strcmp(name, devoptab->name) == 0) { devoptab_list[i] = devoptab_list[0]; ntfs_free((devoptab_t*)devoptab); break; } } } return; }
static int ntfs_device_uefi_io_close(struct ntfs_device *dev) { struct _uefi_fd *fd = DEV_FD(dev); ntfs_log_trace("dev %p\n", dev); //AsciiPrint("ntfs_device_uefi_io_close\n\r"); // Get the device driver descriptor if (!fd) { errno = EBADF; return -1; } // Check that the device is actually open if (!NDevOpen(dev)) { ntfs_log_perror("device is not open\n"); errno = EIO; return -1; } // Mark the device as closed NDevClearOpen(dev); NDevClearBlock(dev); // Flush the device (if dirty and not read-only) if (NDevDirty(dev) && !NDevReadOnly(dev)) { ntfs_log_debug("device is dirty, will now sync\n"); // ...? // Mark the device as clean NDevClearDirty(dev); } // Flush and destroy the cache (if required) if (fd->cache) { //_NTFS_cache_flush(fd->cache); //_NTFS_cache_destructor(fd->cache); } // Shutdown the device interface /*const DISC_INTERFACE* interface = fd->interface; if (interface) { interface->shutdown(); }*/ // Free the device driver private data ntfs_free(dev->d_private); dev->d_private = NULL; return 0; }
static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *d) { struct inode *res = 0; char *item = 0; ntfs_iterate_s walk; int err; ntfs_debug(DEBUG_NAME1, __FUNCTION__ "(): Looking up %s in directory " "ino 0x%x.\n", d->d_name.name, (unsigned)dir->i_ino); walk.name = NULL; walk.namelen = 0; /* Convert to wide string. */ err = ntfs_decodeuni(NTFS_INO2VOL(dir), (char*)d->d_name.name, d->d_name.len, &walk.name, &walk.namelen); if (err) goto err_ret; item = ntfs_malloc(ITEM_SIZE); if (!item) { err = -ENOMEM; goto err_ret; } /* ntfs_getdir will place the directory entry into item, and the first * long long is the MFT record number. */ walk.type = BY_NAME; walk.dir = NTFS_LINO2NINO(dir); walk.result = item; if (ntfs_getdir_byname(&walk)) res = iget(dir->i_sb, NTFS_GETU32(item)); d_add(d, res); ntfs_free(item); ntfs_free(walk.name); /* Always return success, the dcache will handle negative entries. */ return NULL; err_ret: ntfs_free(walk.name); return ERR_PTR(err); }
/* Called when umounting a filesystem by do_umount() in fs/super.c */ static void ntfs_put_super(struct super_block *sb) { ntfs_volume *vol; ntfs_debug(DEBUG_OTHER, "ntfs_put_super\n"); vol=NTFS_SB2VOL(sb); ntfs_release_volume(vol); if(vol->nls_map) unload_nls(vol->nls_map); #ifndef NTFS_IN_LINUX_KERNEL ntfs_free(vol); #endif ntfs_debug(DEBUG_OTHER, "ntfs_put_super: done\n"); }
static void _ntfs_clear_inode(struct inode *ino) { ntfs_debug(DEBUG_OTHER, "ntfs_clear_inode %lx\n",ino->i_ino); #ifdef NTFS_IN_LINUX_KERNEL if(ino->i_ino!=FILE_MFT) ntfs_clear_inode(&ino->u.ntfs_i); #else if(ino->i_ino!=FILE_MFT && ino->u.generic_ip) { ntfs_clear_inode(ino->u.generic_ip); ntfs_free(ino->u.generic_ip); ino->u.generic_ip=0; } #endif return; }
NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t startOfPartition, sec_t endOfPartition, sec_t sectorSize) { NTFS_CACHE* cache; unsigned int i; NTFS_CACHE_ENTRY* cacheEntries; if(numberOfPages==0 || sectorsPerPage==0) return NULL; if (numberOfPages < 4) { numberOfPages = 4; } if (sectorsPerPage < 32) { sectorsPerPage = 32; } cache = (NTFS_CACHE*) ntfs_alloc (sizeof(NTFS_CACHE)); if (cache == NULL) { return NULL; } cache->disc = discInterface; cache->startOfPartition = startOfPartition; cache->endOfPartition = endOfPartition; cache->numberOfPages = numberOfPages; cache->sectorsPerPage = sectorsPerPage; cache->sectorSize = sectorSize; cacheEntries = (NTFS_CACHE_ENTRY*) ntfs_alloc ( sizeof(NTFS_CACHE_ENTRY) * numberOfPages); if (cacheEntries == NULL) { ntfs_free (cache); return NULL; } for (i = 0; i < numberOfPages; i++) { cacheEntries[i].sector = CACHE_FREE; cacheEntries[i].count = 0; cacheEntries[i].last_access = 0; cacheEntries[i].dirty = false; cacheEntries[i].cache = (uint8_t*) ntfs_align ( sectorsPerPage * cache->sectorSize ); } cache->cacheEntries = cacheEntries; return cache; }
void ntfsUnmount (const char *name, bool force) { ntfs_vd *vd = NULL; // Get the devices volume descriptor vd = ntfsGetVolume(name); if (!vd) return; // Remove the device from the devoptab table ntfsRemoveDevice(name); // Deinitialise the volume descriptor ntfsDeinitVolume(vd); // Unmount the volume ntfs_umount(vd->vol, force); // Free the volume descriptor ntfs_free(vd); return; }
static s64 ntfs_device_uefi_io_readbytes(struct ntfs_device *dev, s64 offset, s64 count, void *buf) { struct _uefi_fd *fd = DEV_FD(dev); sec_t sec_start = (sec_t) fd->startSector; sec_t sec_count = 1; u32 buffer_offset = (u32) (offset % fd->sectorSize); u8 *buffer = NULL; //const DISC_INTERFACE* interface; ntfs_log_trace("dev %p, offset %li, count %li\n", dev, offset, count); // Get the device driver descriptor if (!fd) { //AsciiPrint("ntfs_device_uefi_io_readbytes EBADF\n\r"); ntfs_log_perror("EBADF"); errno = EBADF; return -1; } //// Get the device interface //interface = fd->interface; //if (!interface) { // errno = ENODEV; // return -1; //} if(offset < 0) { //AsciiPrint("ntfs_device_uefi_io_readbytes EROFS\n\r"); errno = EROFS; ntfs_log_perror("EROFS"); return -1; } if(!count) return 0; // Determine the range of sectors required for this read if (offset > 0) { sec_start += (sec_t) offset / fd->sectorSize; } if (buffer_offset+count > fd->sectorSize) { sec_count = (sec_t) (buffer_offset+count) / fd->sectorSize; if (((buffer_offset+count) % fd->sectorSize) != 0) sec_count++; } // If this read happens to be on the sector boundaries then do the read straight into the destination buffer if((buffer_offset == 0) && (count % fd->sectorSize == 0)) { // Read from the device ntfs_log_trace("direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count); if (!ntfs_device_uefi_io_readsectors(dev, sec_start, sec_count, buf)) { ntfs_log_perror("direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count); //AsciiPrint("ntfs_device_uefi_io_readbytes EIO\n\r"); errno = EIO; return -1; } // Else read into a buffer and copy over only what was requested } else { // Allocate a buffer to hold the read data buffer = (u8*)ntfs_alloc(sec_count * fd->sectorSize); if (!buffer) { errno = ENOMEM; return -1; } // Read from the device ntfs_log_trace("buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count); ntfs_log_trace("count: %d sec_count:%d fd->sectorSize: %d )\n", (u32)count, (u32)sec_count,(u32)fd->sectorSize); if (!ntfs_device_uefi_io_readsectors(dev, sec_start, sec_count, buffer)) { //AsciiPrint("ntfs_device_uefi_io_readbytes buffered read failure\n\r"); ntfs_log_perror("buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count); ntfs_free(buffer); errno = EIO; return -1; } // Copy what was requested to the destination buffer memcpy(buf, buffer + buffer_offset, count); ntfs_free(buffer); } //ntfs_log_perror("Read %d sectors", count); return count; }
/* Called to mount a filesystem by read_super() in fs/super.c * Return a super block, the main structure of a filesystem * * NOTE : Don't store a pointer to an option, as the page containing the * options is freed after ntfs_read_super() returns. * * NOTE : A context switch can happen in kernel code only if the code blocks * (= calls schedule() in kernel/sched.c). */ struct super_block * ntfs_read_super(struct super_block *sb, void *options, int silent) { ntfs_volume *vol; struct buffer_head *bh; int i; ntfs_debug(DEBUG_OTHER, "ntfs_read_super\n"); #ifdef NTFS_IN_LINUX_KERNEL vol = NTFS_SB2VOL(sb); #else if(!(vol = ntfs_malloc(sizeof(ntfs_volume)))) goto ntfs_read_super_dec; NTFS_SB2VOL(sb)=vol; #endif if(!parse_options(vol,(char*)options)) goto ntfs_read_super_vol; #if 0 /* Set to read only, user option might reset it */ sb->s_flags |= MS_RDONLY; #endif /* Assume a 512 bytes block device for now */ set_blocksize(sb->s_dev, 512); /* Read the super block (boot block) */ if(!(bh=bread(sb->s_dev,0,512))) { ntfs_error("Reading super block failed\n"); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "Done reading boot block\n"); /* Check for 'NTFS' magic number */ if(!IS_NTFS_VOLUME(bh->b_data)){ ntfs_debug(DEBUG_OTHER, "Not a NTFS volume\n"); brelse(bh); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "Going to init volume\n"); ntfs_init_volume(vol,bh->b_data); ntfs_debug(DEBUG_OTHER, "MFT record at cluster 0x%X\n",vol->mft_cluster); brelse(bh); NTFS_SB(vol)=sb; ntfs_debug(DEBUG_OTHER, "Done to init volume\n"); /* Inform the kernel that a device block is a NTFS cluster */ sb->s_blocksize=vol->clustersize; for(i=sb->s_blocksize,sb->s_blocksize_bits=0;i != 1;i>>=1) sb->s_blocksize_bits++; set_blocksize(sb->s_dev,sb->s_blocksize); ntfs_debug(DEBUG_OTHER, "set_blocksize\n"); /* Allocate a MFT record (MFT record can be smaller than a cluster) */ if(!(vol->mft=ntfs_malloc(max(vol->mft_recordsize,vol->clustersize)))) goto ntfs_read_super_unl; /* Read at least the MFT record for $MFT */ for(i=0;i<max(vol->mft_clusters_per_record,1);i++){ if(!(bh=bread(sb->s_dev,vol->mft_cluster+i,vol->clustersize))) { ntfs_error("Could not read MFT record 0\n"); goto ntfs_read_super_mft; } ntfs_memcpy(vol->mft+i*vol->clustersize,bh->b_data,vol->clustersize); brelse(bh); ntfs_debug(DEBUG_OTHER, "Read cluster %x\n",vol->mft_cluster+i); } /* Check and fixup this MFT record */ if(!ntfs_check_mft_record(vol,vol->mft)){ ntfs_error("Invalid MFT record 0\n"); goto ntfs_read_super_mft; } /* Inform the kernel about which super operations are available */ sb->s_op = &ntfs_super_operations; sb->s_magic = NTFS_SUPER_MAGIC; ntfs_debug(DEBUG_OTHER, "Reading special files\n"); if(ntfs_load_special_files(vol)){ ntfs_error("Error loading special files\n"); goto ntfs_read_super_mft; } ntfs_debug(DEBUG_OTHER, "Getting RootDir\n"); /* Get the root directory */ if(!(sb->s_root=d_alloc_root(iget(sb,FILE_ROOT)))){ ntfs_error("Could not get root dir inode\n"); goto ntfs_read_super_mft; } ntfs_debug(DEBUG_OTHER, "read_super: done\n"); return sb; ntfs_read_super_mft: ntfs_free(vol->mft); ntfs_read_super_unl: ntfs_read_super_vol: #ifndef NTFS_IN_LINUX_KERNEL ntfs_free(vol); ntfs_read_super_dec: #endif ntfs_debug(DEBUG_OTHER, "read_super: done\n"); return NULL; }
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; }
bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags) { ntfs_vd *vd = NULL; gekko_fd *fd = NULL; // Sanity check if (!name || !interface) { errno = EINVAL; return -1; } // Initialise ntfs-3g ntfsInit(); // Check that the requested mount name is free if (ntfsGetDevice(name, false)) { errno = EADDRINUSE; return false; } // Check that we can at least read from this device if (!(interface->features & FEATURE_MEDIUM_CANREAD)) { errno = EPERM; return false; } // Allocate the volume descriptor vd = (ntfs_vd*)ntfs_alloc(sizeof(ntfs_vd)); if (!vd) { errno = ENOMEM; return false; } // Setup the volume descriptor vd->id = interface->ioType; vd->flags = 0; vd->uid = 0; vd->gid = 0; vd->fmask = 0; vd->dmask = 0; vd->atime = ((flags & NTFS_UPDATE_ACCESS_TIMES) ? ATIME_ENABLED : ATIME_DISABLED); vd->showHiddenFiles = (flags & NTFS_SHOW_HIDDEN_FILES); vd->showSystemFiles = (flags & NTFS_SHOW_SYSTEM_FILES); // Allocate the device driver descriptor fd = (gekko_fd*)ntfs_alloc(sizeof(gekko_fd)); if (!fd) { ntfs_free(vd); errno = ENOMEM; return false; } // Setup the device driver descriptor fd->interface = interface; fd->startSector = startSector; fd->sectorSize = 0; fd->sectorCount = 0; fd->cachePageCount = cachePageCount; fd->cachePageSize = cachePageSize; // Allocate the device driver vd->dev = ntfs_device_alloc(name, 0, &ntfs_device_gekko_io_ops, fd); if (!vd->dev) { ntfs_free(fd); ntfs_free(vd); return false; } // Build the mount flags if (flags & NTFS_READ_ONLY) vd->flags |= MS_RDONLY; else { if (!(interface->features & FEATURE_MEDIUM_CANWRITE)) vd->flags |= MS_RDONLY; if ((interface->features & FEATURE_MEDIUM_CANREAD) && (interface->features & FEATURE_MEDIUM_CANWRITE)) vd->flags |= MS_EXCLUSIVE; } if (flags & NTFS_RECOVER) vd->flags |= MS_RECOVER; if (flags & NTFS_IGNORE_HIBERFILE) vd->flags |= MS_IGNORE_HIBERFILE; if (vd->flags & MS_RDONLY) ntfs_log_debug("Mounting \"%s\" as read-only\n", name); // Mount the device vd->vol = ntfs_device_mount(vd->dev, vd->flags); if (!vd->vol) { switch(ntfs_volume_error(errno)) { case NTFS_VOLUME_NOT_NTFS: errno = EINVALPART; break; case NTFS_VOLUME_CORRUPT: errno = EINVALPART; break; case NTFS_VOLUME_HIBERNATED: errno = EHIBERNATED; break; case NTFS_VOLUME_UNCLEAN_UNMOUNT: errno = EDIRTY; break; default: errno = EINVAL; break; } ntfs_device_free(vd->dev); ntfs_free(vd); return false; } // Initialise the volume descriptor if (ntfsInitVolume(vd)) { ntfs_umount(vd->vol, true); ntfs_free(vd); return false; } // Add the device to the devoptab table if (ntfsAddDevice(name, vd)) { ntfsDeinitVolume(vd); ntfs_umount(vd->vol, true); ntfs_free(vd); return false; } return true; }
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; }
/** * PRIVATE: Callback for directory walking */ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int name_len, const int name_type, const s64 pos, const MFT_REF mref, const unsigned dt_type) { ntfs_dir_state *dir = STATE(dirState); ntfs_dir_entry *entry = NULL; char *entry_name = NULL; // Sanity check if (!dir || !dir->vd) { errno = EINVAL; return -1; } // Ignore DOS file names if (name_type == FILE_NAME_DOS) { return 0; } // Preliminary check that this entry can be enumerated (as described by the volume descriptor) if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user || dir->vd->showSystemFiles) { // Convert the entry name to our current local if (ntfsUnicodeToLocal(name, name_len, &entry_name, 0) < 0) { ntfs_free(entry); return -1; } // If this is not the parent or self directory reference if ((strcmp(entry_name, ".") != 0) && (strcmp(entry_name, "..") != 0)) { // Open the entry ntfs_inode *ni = ntfs_pathname_to_inode(dir->vd->vol, dir->ni, entry_name); if (!ni) { ntfs_free(entry); return -1; } // Double check that this entry can be emuerated (as described by the volume descriptor) if (((ni->flags & FILE_ATTR_HIDDEN) && !dir->vd->showHiddenFiles) || ((ni->flags & FILE_ATTR_SYSTEM) && !dir->vd->showSystemFiles)) { ntfs_inode_close(ni); return 0; } // Close the entry ntfs_inode_close(ni); } // Allocate a new directory entry entry = ntfs_alloc(sizeof(ntfs_dir_entry)); if (!entry) return -1; // Setup the entry entry->name = entry_name; entry->next = NULL; // Link the entry to the directory if (!dir->first) { dir->first = entry; } else { ntfs_dir_entry *last = dir->first; while (last->next) last = last->next; last->next = entry; } } return 0; }
static s64 ntfs_device_uefi_io_writebytes(struct ntfs_device *dev, s64 offset, s64 count, const void *buf) { struct _uefi_fd *fd = DEV_FD(dev); sec_t sec_start; sec_t sec_count; u32 buffer_offset; u8 *buffer; ntfs_log_trace("dev %p, offset %l, count %l\n", dev, offset, count); // Get the device driver descriptor if (!fd) { errno = EBADF; return -1; } // Get the device interface //const DISC_INTERFACE* interface = fd->interface; //if (!interface) { // errno = ENODEV; // return -1; //} // Check that the device can be written to if (NDevReadOnly(dev)) { errno = EROFS; return -1; } if(count < 0 || offset < 0) { errno = EROFS; return -1; } if(count == 0) return 0; sec_start = (sec_t) fd->startSector; sec_count = 1; buffer_offset = (u32) (offset % fd->sectorSize); buffer = NULL; // Determine the range of sectors required for this write if (offset > 0) { sec_start += (sec_t) offset / fd->sectorSize; } if ((buffer_offset+count) > fd->sectorSize) { sec_count = (sec_t) ((buffer_offset+count) / fd->sectorSize); if (((buffer_offset+count) % fd->sectorSize) != 0) sec_count++; } // If this write happens to be on the sector boundaries then do the write straight to disc if((buffer_offset == 0) && (count % fd->sectorSize == 0)) { // Write to the device ntfs_log_trace("direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count); if (!ntfs_device_uefi_io_writesectors(dev, sec_start, sec_count, buf)) { ntfs_log_perror("direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count); errno = EIO; return -1; } // Else write from a buffer aligned to the sector boundaries } else { // Allocate a buffer to hold the write data buffer = (u8 *) ntfs_alloc(sec_count * fd->sectorSize); if (!buffer) { errno = ENOMEM; return -1; } // Read the first and last sectors of the buffer from disc (if required) // NOTE: This is done because the data does not line up with the sector boundaries, // we just read in the buffer edges where the data overlaps with the rest of the disc if(buffer_offset != 0) { if (!ntfs_device_uefi_io_readsectors(dev, sec_start, 1, buffer)) { ntfs_log_perror("read failure @ sector %d\n", sec_start); ntfs_free(buffer); errno = EIO; return -1; } } if((buffer_offset+count) % fd->sectorSize != 0) { if (!ntfs_device_uefi_io_readsectors(dev, sec_start + sec_count - 1, 1, buffer + ((sec_count-1) * fd->sectorSize))) { ntfs_log_perror("read failure @ sector %d\n", sec_start + sec_count - 1); ntfs_free(buffer); errno = EIO; return -1; } } // Copy the data into the write buffer memcpy(buffer + buffer_offset, buf, count); // Write to the device ntfs_log_trace("buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count); if (!ntfs_device_uefi_io_writesectors(dev, sec_start, sec_count, buffer)) { ntfs_log_perror("buffered write failure @ sector %d\n", sec_start); ntfs_free(buffer); errno = EIO; return -1; } // Free the buffer ntfs_free(buffer); } // Mark the device as dirty (if we actually wrote anything) NDevSetDirty(dev); return count; }
/* Called to mount a filesystem by read_super() in fs/super.c. * Return a super block, the main structure of a filesystem. * * NOTE : Don't store a pointer to an option, as the page containing the * options is freed after ntfs_read_super() returns. * * NOTE : A context switch can happen in kernel code only if the code blocks * (= calls schedule() in kernel/sched.c). */ struct super_block *ntfs_read_super(struct super_block *sb, void *options, int silent) { ntfs_volume *vol; struct buffer_head *bh; int i, to_read, blocksize; ntfs_debug(DEBUG_OTHER, "ntfs_read_super\n"); vol = NTFS_SB2VOL(sb); init_ntfs_super_block(vol); if (!parse_options(vol, (char*)options)) goto ntfs_read_super_vol; blocksize = get_hardsect_size(sb->s_dev); if (blocksize < 512) blocksize = 512; if (set_blocksize(sb->s_dev, blocksize) < 0) { ntfs_error("Unable to set blocksize %d.\n", blocksize); goto ntfs_read_super_vol; } sb->s_blocksize = blocksize; /* Read the super block (boot block). */ if (!(bh = sb_bread(sb, 0))) { ntfs_error("Reading super block failed\n"); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "Done reading boot block\n"); /* Check for valid 'NTFS' boot sector. */ if (!is_boot_sector_ntfs(bh->b_data)) { ntfs_debug(DEBUG_OTHER, "Not a NTFS volume\n"); bforget(bh); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "Going to init volume\n"); if (ntfs_init_volume(vol, bh->b_data) < 0) { ntfs_debug(DEBUG_OTHER, "Init volume failed.\n"); bforget(bh); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "$Mft at cluster 0x%lx\n", vol->mft_lcn); brelse(bh); NTFS_SB(vol) = sb; if (vol->cluster_size > PAGE_SIZE) { ntfs_error("Partition cluster size is not supported yet (it " "is > max kernel blocksize).\n"); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "Done to init volume\n"); /* Inform the kernel that a device block is a NTFS cluster. */ sb->s_blocksize = vol->cluster_size; sb->s_blocksize_bits = vol->cluster_size_bits; if (blocksize != vol->cluster_size && set_blocksize(sb->s_dev, sb->s_blocksize) < 0) { ntfs_error("Cluster size too small for device.\n"); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "set_blocksize\n"); /* Allocate an MFT record (MFT record can be smaller than a cluster). */ i = vol->cluster_size; if (i < vol->mft_record_size) i = vol->mft_record_size; if (!(vol->mft = ntfs_malloc(i))) goto ntfs_read_super_unl; /* Read at least the MFT record for $Mft. */ to_read = vol->mft_clusters_per_record; if (to_read < 1) to_read = 1; for (i = 0; i < to_read; i++) { if (!(bh = sb_bread(sb, vol->mft_lcn + i))) { ntfs_error("Could not read $Mft record 0\n"); goto ntfs_read_super_mft; } ntfs_memcpy(vol->mft + ((__s64)i << vol->cluster_size_bits), bh->b_data, vol->cluster_size); brelse(bh); ntfs_debug(DEBUG_OTHER, "Read cluster 0x%x\n", vol->mft_lcn + i); } /* Check and fixup this MFT record */ if (!ntfs_check_mft_record(vol, vol->mft)){ ntfs_error("Invalid $Mft record 0\n"); goto ntfs_read_super_mft; } /* Inform the kernel about which super operations are available. */ sb->s_op = &ntfs_super_operations; sb->s_magic = NTFS_SUPER_MAGIC; sb->s_maxbytes = ~0ULL >> 1; ntfs_debug(DEBUG_OTHER, "Reading special files\n"); if (ntfs_load_special_files(vol)) { ntfs_error("Error loading special files\n"); goto ntfs_read_super_mft; } ntfs_debug(DEBUG_OTHER, "Getting RootDir\n"); /* Get the root directory. */ if (!(sb->s_root = d_alloc_root(iget(sb, FILE_root)))) { ntfs_error("Could not get root dir inode\n"); goto ntfs_read_super_mft; } ntfs_read_super_ret: ntfs_debug(DEBUG_OTHER, "read_super: done\n"); return sb; ntfs_read_super_mft: ntfs_free(vol->mft); ntfs_read_super_unl: ntfs_read_super_vol: sb = NULL; goto ntfs_read_super_ret; }
static int ntfs_device_uefi_io_open(struct ntfs_device *dev, int flags) { NTFS_BOOT_SECTOR *boot; EFI_DISK_IO_PROTOCOL *DiskIo; NTFS_VOLUME *Volume; struct _uefi_fd *fd = DEV_FD(dev); Volume = fd->interface; ntfs_log_trace("dev %p, flags %i\n", dev, flags); // Get the device driver descriptor if (!fd) { errno = EBADF; return -1; } // Get the device interface DiskIo = Volume->DiskIo; if (!DiskIo) { errno = ENODEV; return -1; } // Start the device interface and ensure that it is inserted //if (!interface->startup()) { // ntfs_log_perror("device failed to start\n"); // errno = EIO; // return -1; // } //if (!interface->isInserted()) { // ntfs_log_perror("device media is not inserted\n"); // errno = EIO; // return -1; //} // Check that the device isn't already open (used by another volume?) if (NDevOpen(dev)) { //AsciiPrint("ntfs_device_uefi_io_open...BUSY\n\r"); ntfs_log_perror("device is busy (already open)\n"); errno = EBUSY; return -1; } // Check that there is a valid NTFS boot sector at the start of the device boot = (NTFS_BOOT_SECTOR *) ntfs_alloc(MAX_SECTOR_SIZE); if(boot == NULL) { //AsciiPrint("ntfs_device_uefi_io_open...ENOMEM\n\r"); errno = ENOMEM; return -1; } if (DiskIo->ReadDisk(DiskIo, Volume->MediaId, 0, sizeof(NTFS_BOOT_SECTOR), boot) != EFI_SUCCESS) { //AsciiPrint("DiskIo ptr %x\n\r", DiskIo); //AsciiPrint("interface ptr %x\n\r", fd->interface); //AsciiPrint("DiskIo->ReadDisk(%x,%x,%x)\n\r", fd->interface->MediaId, fd->startSector * fd->sectorSize, sizeof(NTFS_BOOT_SECTOR)); //AsciiPrint("Sector size: %x\n\r", fd->sectorSize); //AsciiPrint("ntfs_device_uefi_io_open...read failure boot sector\n\r"); ntfs_log_perror("read failure @ sector %x\n", fd->startSector); errno = EIO; ntfs_free(boot); return -1; } if (!ntfs_boot_sector_is_ntfs(boot)) { //AsciiPrint("ntfs_device_uefi_io_open...EINVALIDPART\n\r"); errno = EINVALPART; ntfs_free(boot); return -1; } // Parse the boot sector fd->hiddenSectors = le32_to_cpu(boot->bpb.hidden_sectors); fd->sectorSize = le16_to_cpu(boot->bpb.bytes_per_sector); fd->sectorCount = sle64_to_cpu(boot->number_of_sectors); fd->pos = 0; fd->len = (fd->sectorCount * fd->sectorSize); fd->ino = le64_to_cpu(boot->volume_serial_number); // Free memory for boot sector ntfs_free(boot); // Mark the device as read-only (if required) if (flags & O_RDONLY) { NDevSetReadOnly(dev); } // cache disabled! fd->cache = NULL; //_NTFS_cache_constructor(fd->cachePageCount, fd->cachePageSize, interface, fd->startSector + fd->sectorCount, fd->sectorSize); // Mark the device as open NDevSetBlock(dev); NDevSetOpen(dev); //AsciiPrint("ntfs_device_uefi_io_open...success\n\r"); return 0; }
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; }
static int ntfs_printcb(ntfs_u8 *entry, void *param) { unsigned long inum = NTFS_GETU64(entry) & 0xffffffffffff; struct ntfs_filldir *nf = param; u32 flags = NTFS_GETU32(entry + 0x48); char show_sys_files = 0; u8 name_len = NTFS_GETU8(entry + 0x50); u8 name_type = NTFS_GETU8(entry + 0x51); int err; unsigned file_type; switch (nf->type) { case ngt_dos: /* Don't display long names. */ if (!(name_type & 2)) return 0; break; case ngt_nt: /* Don't display short-only names. */ if ((name_type & 3) == 2) return 0; break; case ngt_posix: break; case ngt_full: show_sys_files = 1; break; default: BUG(); } err = ntfs_encodeuni(NTFS_INO2VOL(nf->dir), (ntfs_u16*)(entry + 0x52), name_len, &nf->name, &nf->namelen); if (err) { ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Skipping " "unrepresentable file.\n"); err = 0; goto err_ret; } if (!show_sys_files && inum < 0x10UL) { ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Skipping system " "file (%s).\n", nf->name); err = 0; goto err_ret; } /* Do not return ".", as this is faked. */ if (nf->namelen == 1 && nf->name[0] == '.') { ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Skipping \".\"\n"); err = 0; goto err_ret; } nf->name[nf->namelen] = 0; if (flags & 0x10000000) /* FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT */ file_type = DT_DIR; else file_type = DT_REG; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Calling filldir for %s with " "len %i, f_pos 0x%Lx, inode %lu, %s.\n", nf->name, nf->namelen, (loff_t)(nf->ph << 16) | nf->pl, inum, file_type == DT_DIR ? "DT_DIR" : "DT_REG"); /* * Userspace side of filldir expects an off_t rather than an loff_t. * And it also doesn't like the most significant bit being set as it * then considers the value to be negative. Thus this implementation * limits the number of index records to 32766, which should be plenty. */ err = nf->filldir(nf->dirent, nf->name, nf->namelen, (loff_t)(nf->ph << 16) | nf->pl, inum, file_type); if (err) nf->ret_code = err; err_ret: nf->namelen = 0; ntfs_free(nf->name); nf->name = NULL; return err; }
static int ntfs_printcb(ntfs_u8 *entry,void *param) { struct ntfs_filldir* nf=param; int flags=NTFS_GETU8(entry+0x51); int show_hidden=0; int length=NTFS_GETU8(entry+0x50); int inum=NTFS_GETU32(entry); int error; #ifdef NTFS_NGT_NT_DOES_LOWER int i,to_lower=0; #endif switch(nf->type){ case ngt_dos: /* Don't display long names */ if((flags & 2)==0) return 0; break; case ngt_nt: /* Don't display short-only names */ switch(flags&3){ case 2: return 0; #ifdef NTFS_NGT_NT_DOES_LOWER case 3: to_lower=1; #endif } break; case ngt_posix: break; case ngt_full: show_hidden=1; break; } if(!show_hidden && ((NTFS_GETU8(entry+0x48) & 2)==2)){ ntfs_debug(DEBUG_OTHER,"Skipping hidden file\n"); return 0; } nf->name=0; if(ntfs_encodeuni(NTFS_INO2VOL(nf->dir),(ntfs_u16*)(entry+0x52), length,&nf->name,&nf->namelen)){ ntfs_debug(DEBUG_OTHER,"Skipping unrepresentable file\n"); if(nf->name)ntfs_free(nf->name); return 0; } /* Do not return ".", as this is faked */ if(length==1 && *nf->name=='.') return 0; #ifdef NTFS_NGT_NT_DOES_LOWER if(to_lower) for(i=0;i<nf->namelen;i++) /* This supports ASCII only. Since only DOS-only names get converted, and since those are restricted to ASCII, this should be correct */ if(nf->name[i]>='A' && nf->name[i]<='Z') nf->name[i]+='a'-'A'; #endif nf->name[nf->namelen]=0; ntfs_debug(DEBUG_OTHER, "readdir got %s,len %d\n",nf->name,nf->namelen); /* filldir expects an off_t rather than an loff_t. Hope we don't have more than 65535 index records */ error=nf->filldir(nf->dirent,nf->name,nf->namelen, (nf->ph<<16)|nf->pl,inum,DT_UNKNOWN); ntfs_free(nf->name); /* Linux filldir errors are negative, other errors positive */ return error; }
/* ntfs_read_inode() is called by the Virtual File System (the kernel layer * that deals with filesystems) when iget is called requesting an inode not * already present in the inode table. Typically filesystems have separate * inode_operations for directories, files and symlinks. */ static void ntfs_read_inode(struct inode* inode) { ntfs_volume *vol; ntfs_inode *ino; ntfs_attribute *data; ntfs_attribute *si; vol = NTFS_INO2VOL(inode); inode->i_mode = 0; ntfs_debug(DEBUG_OTHER, "ntfs_read_inode 0x%lx\n", inode->i_ino); switch (inode->i_ino) { /* Those are loaded special files. */ case FILE_Mft: if (!vol->mft_ino || ((vol->ino_flags & 1) == 0)) goto sys_file_error; ntfs_memcpy(&inode->u.ntfs_i, vol->mft_ino, sizeof(ntfs_inode)); ino = vol->mft_ino; vol->mft_ino = &inode->u.ntfs_i; vol->ino_flags &= ~1; ntfs_free(ino); ino = vol->mft_ino; ntfs_debug(DEBUG_OTHER, "Opening $MFT!\n"); break; case FILE_MftMirr: if (!vol->mftmirr || ((vol->ino_flags & 2) == 0)) goto sys_file_error; ntfs_memcpy(&inode->u.ntfs_i, vol->mftmirr, sizeof(ntfs_inode)); ino = vol->mftmirr; vol->mftmirr = &inode->u.ntfs_i; vol->ino_flags &= ~2; ntfs_free(ino); ino = vol->mftmirr; ntfs_debug(DEBUG_OTHER, "Opening $MFTMirr!\n"); break; case FILE_BitMap: if (!vol->bitmap || ((vol->ino_flags & 4) == 0)) goto sys_file_error; ntfs_memcpy(&inode->u.ntfs_i, vol->bitmap, sizeof(ntfs_inode)); ino = vol->bitmap; vol->bitmap = &inode->u.ntfs_i; vol->ino_flags &= ~4; ntfs_free(ino); ino = vol->bitmap; ntfs_debug(DEBUG_OTHER, "Opening $Bitmap!\n"); break; case FILE_LogFile ... FILE_AttrDef: /* No need to log root directory accesses. */ case FILE_Boot ... FILE_UpCase: ntfs_debug(DEBUG_OTHER, "Opening system file %i!\n", inode->i_ino); default: ino = &inode->u.ntfs_i; if (!ino || ntfs_init_inode(ino, NTFS_INO2VOL(inode), inode->i_ino)) { ntfs_debug(DEBUG_OTHER, "NTFS: Error loading inode " "0x%x\n", (unsigned int)inode->i_ino); return; } } /* Set uid/gid from mount options */ inode->i_uid = vol->uid; inode->i_gid = vol->gid; inode->i_nlink = 1; /* Use the size of the data attribute as file size */ data = ntfs_find_attr(ino, vol->at_data, NULL); if (!data) inode->i_size = 0; else inode->i_size = data->size; /* Get the file modification times from the standard information. */ si = ntfs_find_attr(ino, vol->at_standard_information, NULL); if (si) { char *attr = si->d.data; inode->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 0x18)); inode->i_ctime = ntfs_ntutc2unixutc(NTFS_GETU64(attr)); inode->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 8)); } /* If it has an index root, it's a directory. */ if (ntfs_find_attr(ino, vol->at_index_root, "$I30")) { ntfs_attribute *at; at = ntfs_find_attr(ino, vol->at_index_allocation, "$I30"); inode->i_size = at ? at->size : 0; inode->i_op = &ntfs_dir_inode_operations; inode->i_fop = &ntfs_dir_operations; inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; } else { inode->i_op = &ntfs_inode_operations; inode->i_fop = &ntfs_file_operations; inode->i_mode = S_IFREG | S_IRUGO; } #ifdef CONFIG_NTFS_RW if (!data || !(data->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED))) inode->i_mode |= S_IWUGO; #endif inode->i_mode &= ~vol->umask; return; sys_file_error: ntfs_error("Critical error. Tried to call ntfs_read_inode() before we " "have completed read_super() or VFS error.\n"); // FIXME: Should we panic() at this stage? }
static int ntfs_create(struct inode* dir,struct dentry *d,int mode) { struct inode *r=0; ntfs_inode *ino=0; ntfs_volume *vol; int error=0; ntfs_attribute *si; r=new_inode(dir->i_sb); if(!r){ error=ENOMEM; goto fail; } ntfs_debug(DEBUG_OTHER, "ntfs_create %s\n",d->d_name.name); vol=NTFS_INO2VOL(dir); #ifdef NTFS_IN_LINUX_KERNEL ino=NTFS_LINO2NINO(r); #else ino=ntfs_malloc(sizeof(ntfs_inode)); if(!ino){ error=ENOMEM; goto fail; } r->u.generic_ip=ino; #endif error=ntfs_alloc_file(NTFS_LINO2NINO(dir),ino,(char*)d->d_name.name, d->d_name.len); if(error)goto fail; error=ntfs_update_inode(ino); if(error)goto fail; error=ntfs_update_inode(NTFS_LINO2NINO(dir)); if(error)goto fail; r->i_uid=vol->uid; r->i_gid=vol->gid; /* FIXME: dirty? dev? */ /* get the file modification times from the standard information */ si=ntfs_find_attr(ino,vol->at_standard_information,NULL); if(si){ char *attr=si->d.data; r->i_atime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+0x18)); r->i_ctime=ntfs_ntutc2unixutc(NTFS_GETU64(attr)); r->i_mtime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+8)); } /* It's not a directory */ r->i_op=&ntfs_inode_operations_nobmap; r->i_fop=&ntfs_file_operations_nommap, r->i_mode=S_IFREG|S_IRUGO; #ifdef CONFIG_NTFS_RW r->i_mode|=S_IWUGO; #endif r->i_mode &= ~vol->umask; insert_inode_hash(r); d_instantiate(d,r); return 0; fail: #ifndef NTFS_IN_LINUX_KERNEL if(ino)ntfs_free(ino); #endif if(r)iput(r); return -error; }
ntfs_vd *ntfsMount (const char *name, struct _NTFS_VOLUME *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags) { ntfs_vd *vd = NULL; struct _uefi_fd *fd = NULL; const devoptab_t *mnt; //Print(L"ntfsMount %a\n", name); //CpuBreakpoint(); // Sanity check if (!name || !interface) { //Print(L"ntfsMount EINVAL\n"); errno = EINVAL; return false; } // Initialise ntfs-3g ntfsInit(); mnt = ntfsGetDevice(name, false); // Check that the requested mount name is free if (mnt) { //Print(L"ntfsMount EADDRINUSE\n"); errno = 99; //EADDRINUSE; return (ntfs_vd*) mnt->deviceData; // previous mnt data! } // Allocate the volume descriptor vd = (ntfs_vd*)ntfs_alloc(sizeof(ntfs_vd)); if (!vd) { //Print(L"ntfsMount ENOMEM\n"); errno = ENOMEM; return false; } else { //Print(L"ntfsMount ntfs_vd!\n"); } // Setup the volume descriptor //Print(L"vd.id! [%x]\n", vd); vd->id = 0;//interface->ioType; //Print(L"vd.flags!\n"); vd->flags = 0; vd->uid = 0; vd->gid = 0; vd->fmask = 0; vd->dmask = 0; vd->atime = ((flags & NTFS_UPDATE_ACCESS_TIMES) ? ATIME_ENABLED : ATIME_DISABLED); vd->showHiddenFiles = (flags & NTFS_SHOW_HIDDEN_FILES); vd->showSystemFiles = (flags & NTFS_SHOW_SYSTEM_FILES); //Print(L"invoking ntfs_alloc!\n"); // Allocate the device driver descriptor fd = (struct _uefi_fd *)ntfs_alloc(sizeof(struct _uefi_fd)); if (!fd) { //Print(L"ntfsMount ENOMEM(2)\n"); ntfs_free(vd); errno = ENOMEM; return false; } else { //Print(L"ntfs_alloc uefi_fd\n"); } // Setup the device driver descriptor fd->interface = interface; fd->startSector = startSector; fd->sectorSize = 0x200; fd->sectorCount = 0x200; fd->cachePageCount = cachePageCount; fd->cachePageSize = cachePageSize; // Allocate the device driver vd->dev = ntfs_device_alloc(name, 0, &ntfs_device_uefi_io_ops, fd); if (!vd->dev) { //Print(L"ntfsMount ntfs_device_alloc failed\n"); ntfs_free(fd); ntfs_free(vd); return false; } //Print(L"ntfs_device_alloc success\n"); // Build the mount flags if (flags & NTFS_READ_ONLY) vd->flags |= NTFS_MNT_RDONLY; if (flags & NTFS_RECOVER) vd->flags |= NTFS_MNT_RECOVER; if (flags & NTFS_IGNORE_HIBERFILE) vd->flags |= NTFS_MNT_IGNORE_HIBERFILE; if (vd->flags & NTFS_MNT_RDONLY) ntfs_log_debug("Mounting \"%s\" as read-only\n", name); // Mount the device //Print(L"Invoking ntfs_device_mount\n"); vd->vol = ntfs_device_mount(vd->dev, vd->flags); if (!vd->vol) { switch(ntfs_volume_error(errno)) { case NTFS_VOLUME_NOT_NTFS: errno = EINVALPART; break; case NTFS_VOLUME_CORRUPT: errno = EINVALPART; break; case NTFS_VOLUME_HIBERNATED: errno = EHIBERNATED; break; case NTFS_VOLUME_UNCLEAN_UNMOUNT: errno = EDIRTY; break; default: errno = EINVAL; break; } ntfs_device_free(vd->dev); ntfs_free(vd); //Print(L"ntfsMount ntfs_device_mount FAILED (%x)\n", errno); return NULL; } if (flags & NTFS_IGNORE_CASE) ntfs_set_ignore_case(vd->vol); // Initialise the volume descriptor if (ntfsInitVolume(vd)) { ntfs_umount(vd->vol, true); ntfs_free(vd); //Print(L"ntfsMount ntfsInitVolume failed\n"); return NULL; } // Add the device to the devoptab table if (ntfsAddDevice(name, vd)) { //Print(L"ntfsMount ntfsAddDevice failed\n"); ntfsDeinitVolume(vd); ntfs_umount(vd->vol, true); ntfs_free(vd); return NULL; } //Print(L"ntfsMount done.\n"); return vd; }
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; }