usbloadergx/source/libntfs/ntfsinternal.c

913 lines
20 KiB
C
Raw Normal View History

2009-12-19 15:06:57 +01:00
/**
* ntfsinternal.h - Internal support routines for NTFS-based devices.
*
* Copyright (c) 2010 Dimok
2009-12-19 15:06:57 +01:00
* Copyright (c) 2009 Rhys "Shareese" Koedijk
* Copyright (c) 2006 Michael "Chishm" Chisholm
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "ntfsinternal.h"
#include "ntfsdir.h"
#include "ntfsfile.h"
#if defined(__wii__)
#include <sdcard/wiisd_io.h>
#include <sdcard/gcsd.h>
#include <ogc/usbstorage.h>
2009-12-19 15:06:57 +01:00
const INTERFACE_ID ntfs_disc_interfaces[] =
{
2009-12-19 15:06:57 +01:00
{ "sd", &__io_wiisd },
{ "usb", &__io_usbstorage },
2009-12-19 15:06:57 +01:00
{ "carda", &__io_gcsda },
{ "cardb", &__io_gcsdb },
{ NULL, NULL }
};
#elif defined(__gamecube__)
#include <sdcard/gcsd.h>
const INTERFACE_ID ntfs_disc_interfaces[] =
{
2009-12-19 15:06:57 +01:00
{ "carda", &__io_gcsda },
{ "cardb", &__io_gcsdb },
{ NULL, NULL }
};
#endif
int ntfsAddDevice ( const char *name, void *deviceData )
{
2009-12-19 15:06:57 +01:00
const devoptab_t *devoptab_ntfs = ntfsGetDevOpTab();
devoptab_t *dev = NULL;
char *devname = NULL;
int i;
2009-12-19 15:06:57 +01:00
// Sanity check
if ( !name || !deviceData || !devoptab_ntfs )
{
2009-12-19 15:06:57 +01:00
errno = EINVAL;
return -1;
}
2009-12-19 15:06:57 +01:00
// Allocate a devoptab for this device
dev = ( devoptab_t * ) ntfs_alloc( sizeof( devoptab_t ) + strlen( name ) + 1 );
if ( !dev )
{
2009-12-19 15:06:57 +01:00
errno = ENOMEM;
return false;
}
2009-12-19 15:06:57 +01:00
// Use the space allocated at the end of the devoptab for storing the device name
devname = ( char* )( dev + 1 );
strcpy( devname, name );
2009-12-19 15:06:57 +01:00
// Setup the devoptab
memcpy( dev, devoptab_ntfs, sizeof( devoptab_t ) );
2009-12-19 15:06:57 +01:00
dev->name = devname;
dev->deviceData = deviceData;
// Add the device to the devoptab table (if there is a free slot)
for ( i = 0; i < STD_MAX; i++ )
{
if ( devoptab_list[i] == devoptab_list[0] && i != 0 )
{
2009-12-19 15:06:57 +01:00
devoptab_list[i] = dev;
return 0;
}
}
2009-12-19 15:06:57 +01:00
// If we reach here then there are no free slots in the devoptab table for this device
errno = EADDRNOTAVAIL;
return -1;
}
void ntfsRemoveDevice ( const char *path )
{
2009-12-19 15:06:57 +01:00
const devoptab_t *devoptab = NULL;
char name[128] = {0};
int i;
2009-12-19 15:06:57 +01:00
// Get the device name from the path
strncpy( name, path, 127 );
strtok( name, ":/" );
2009-12-19 15:06:57 +01:00
// 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++ )
{
2009-12-19 15:06:57 +01:00
devoptab = devoptab_list[i];
if ( devoptab && devoptab->name )
{
if ( strcmp( name, devoptab->name ) == 0 )
{
2009-12-19 15:06:57 +01:00
devoptab_list[i] = devoptab_list[0];
ntfs_free( ( devoptab_t* )devoptab );
2009-12-19 15:06:57 +01:00
break;
}
}
}
2009-12-19 15:06:57 +01:00
return;
}
const devoptab_t *ntfsGetDevice ( const char *path, bool useDefaultDevice )
{
2009-12-19 15:06:57 +01:00
const devoptab_t *devoptab = NULL;
char name[128] = {0};
int i;
2009-12-19 15:06:57 +01:00
// Get the device name from the path
strncpy( name, path, 127 );
strtok( name, ":/" );
2009-12-19 15:06:57 +01:00
// Search the devoptab table for the specified device name
// NOTE: We do this manually due to a 'bug' in GetDeviceOpTab
2009-12-19 15:06:57 +01:00
// which ignores names with suffixes and causes names
// like "ntfs" and "ntfs1" to be seen as equals
for ( i = 0; i < STD_MAX; i++ )
{
2009-12-19 15:06:57 +01:00
devoptab = devoptab_list[i];
if ( devoptab && devoptab->name )
{
if ( strcmp( name, devoptab->name ) == 0 )
{
2009-12-19 15:06:57 +01:00
return devoptab;
}
}
}
2009-12-19 15:06:57 +01:00
// If we reach here then we couldn't find the device name,
// chances are that this path has no device name in it.
2009-12-19 15:06:57 +01:00
// Call GetDeviceOpTab to get our default device (chdir).
if ( useDefaultDevice )
return GetDeviceOpTab( "" );
2009-12-19 15:06:57 +01:00
return NULL;
}
const INTERFACE_ID *ntfsGetDiscInterfaces ( void )
{
2009-12-19 15:06:57 +01:00
// Get all know disc interfaces on the host system
return ntfs_disc_interfaces;
}
ntfs_vd *ntfsGetVolume ( const char *path )
{
2009-12-19 15:06:57 +01:00
// Get the volume descriptor from the paths associated devoptab (if found)
const devoptab_t *devoptab_ntfs = ntfsGetDevOpTab();
const devoptab_t *devoptab = ntfsGetDevice( path, true );
if ( devoptab && devoptab_ntfs && ( devoptab->open_r == devoptab_ntfs->open_r ) )
return ( ntfs_vd* )devoptab->deviceData;
2009-12-19 15:06:57 +01:00
return NULL;
}
int ntfsInitVolume ( ntfs_vd *vd )
{
2009-12-19 15:06:57 +01:00
// Sanity check
if ( !vd )
{
2009-12-19 15:06:57 +01:00
errno = ENODEV;
return -1;
}
2009-12-19 15:06:57 +01:00
// Initialise the volume lock
LWP_MutexInit( &vd->lock, false );
// Reset the volumes name cache
vd->name[0] = '\0';
2009-12-19 15:06:57 +01:00
// Reset the volumes current directory
vd->cwd_ni = NULL;
2009-12-19 15:06:57 +01:00
// Reset open directory and file stats
vd->openDirCount = 0;
vd->openFileCount = 0;
vd->firstOpenDir = NULL;
vd->firstOpenFile = NULL;
2009-12-19 15:06:57 +01:00
return 0;
}
void ntfsDeinitVolume ( ntfs_vd *vd )
{
2009-12-19 15:06:57 +01:00
// Sanity check
if ( !vd )
{
2009-12-19 15:06:57 +01:00
errno = ENODEV;
return;
}
2009-12-19 15:06:57 +01:00
// Lock
ntfsLock( vd );
2009-12-19 15:06:57 +01:00
// 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 );
2009-12-19 15:06:57 +01:00
nextDir = nextDir->nextOpenDir;
}
2009-12-19 15:06:57 +01:00
// 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 );
2009-12-19 15:06:57 +01:00
nextFile = nextFile->nextOpenFile;
}
2009-12-19 15:06:57 +01:00
// Reset open directory and file stats
vd->openDirCount = 0;
vd->openFileCount = 0;
vd->firstOpenDir = NULL;
vd->firstOpenFile = NULL;
2009-12-19 15:06:57 +01:00
// Close the volumes current directory (if any)
//if (vd->cwd_ni) {
//ntfsCloseEntry(vd, vd->cwd_ni);
//vd->cwd_ni = NULL;
//}
2009-12-19 15:06:57 +01:00
// Force the underlying device to sync
vd->dev->d_ops->sync( vd->dev );
2009-12-19 15:06:57 +01:00
// Unlock
ntfsUnlock( vd );
2009-12-19 15:06:57 +01:00
// Deinitialise the volume lock
LWP_MutexDestroy( vd->lock );
2009-12-19 15:06:57 +01:00
return;
}
ntfs_inode *ntfsOpenEntry ( ntfs_vd *vd, const char *path )
{
return ntfsParseEntry( vd, path, 1 );
2009-12-19 15:06:57 +01:00
}
ntfs_inode *ntfsParseEntry ( ntfs_vd *vd, const char *path, int reparseLevel )
{
2009-12-19 15:06:57 +01:00
ntfs_inode *ni = NULL;
char *target = NULL;
int attr_size;
2009-12-19 15:06:57 +01:00
// Sanity check
if ( !vd )
{
2009-12-19 15:06:57 +01:00
errno = ENODEV;
return NULL;
}
2009-12-19 15:06:57 +01:00
// Get the actual path of the entry
path = ntfsRealPath( path );
if ( !path )
{
2009-12-19 15:06:57 +01:00
errno = EINVAL;
return NULL;
}
else if ( path[0] == '\0' )
{
2009-12-19 15:06:57 +01:00
path = ".";
}
// Find the entry, taking into account our current directory (if any)
if ( path[0] != PATH_SEP )
ni = ntfs_pathname_to_inode( vd->vol, vd->cwd_ni, path++ );
2009-12-19 15:06:57 +01:00
else
ni = ntfs_pathname_to_inode( vd->vol, NULL, path );
2009-12-19 15:06:57 +01:00
// If the entry was found and it has reparse data then parse its true path;
// this resolves the true location of symbolic links and directory junctions
if ( ni && ( ni->flags & FILE_ATTR_REPARSE_POINT ) )
{
if ( ntfs_possible_symlink( ni ) )
{
2009-12-19 15:06:57 +01:00
// Sanity check, give up if we are parsing to deep
if ( reparseLevel > NTFS_MAX_SYMLINK_DEPTH )
{
ntfsCloseEntry( vd, ni );
2009-12-19 15:06:57 +01:00
errno = ELOOP;
return NULL;
}
2009-12-19 15:06:57 +01:00
// Get the target path of this entry
target = ntfs_make_symlink( ni, path, &attr_size );
if ( !target )
{
ntfsCloseEntry( vd, ni );
2009-12-19 15:06:57 +01:00
return NULL;
}
2009-12-19 15:06:57 +01:00
// Close the entry (we are no longer interested in it)
ntfsCloseEntry( vd, ni );
2009-12-19 15:06:57 +01:00
// Parse the entries target
ni = ntfsParseEntry( vd, target, reparseLevel++ );
2009-12-19 15:06:57 +01:00
// Clean up
ntfs_free( target );
2009-12-19 15:06:57 +01:00
}
}
2009-12-19 15:06:57 +01:00
return ni;
}
void ntfsCloseEntry ( ntfs_vd *vd, ntfs_inode *ni )
{
2009-12-19 15:06:57 +01:00
// Sanity check
if ( !vd )
{
2009-12-19 15:06:57 +01:00
errno = ENODEV;
return;
}
2009-12-19 15:06:57 +01:00
// Lock
ntfsLock( vd );
2009-12-19 15:06:57 +01:00
// Sync the entry (if it is dirty)
if ( NInoDirty( ni ) )
ntfsSync( vd, ni );
2009-12-19 15:06:57 +01:00
// Close the entry
ntfs_inode_close( ni );
2009-12-19 15:06:57 +01:00
// Unlock
ntfsUnlock( vd );
2009-12-19 15:06:57 +01:00
return;
}
ntfs_inode *ntfsCreate ( ntfs_vd *vd, const char *path, mode_t type, const char *target )
{
2009-12-19 15:06:57 +01:00
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 )
{
2009-12-19 15:06:57 +01:00
errno = ENODEV;
return NULL;
}
2009-12-19 15:06:57 +01:00
// You cannot link between devices
if ( target )
{
if ( vd != ntfsGetVolume( target ) )
{
2009-12-19 15:06:57 +01:00
errno = EXDEV;
return NULL;
}
}
// Get the actual paths of the entry
path = ntfsRealPath( path );
target = ntfsRealPath( target );
if ( !path )
{
2009-12-19 15:06:57 +01:00
errno = EINVAL;
return NULL;
}
// Lock
ntfsLock( vd );
2009-12-19 15:06:57 +01:00
// Get the unicode name for the entry and find its parent directory
// TODO: This looks horrible, clean it up
dir = strdup( path );
if ( !dir )
{
2009-12-19 15:06:57 +01:00
errno = EINVAL;
goto cleanup;
}
name = strrchr( dir, '/' );
if ( name )
2009-12-19 15:06:57 +01:00
name++;
else
name = dir;
uname_len = ntfsLocalToUnicode( name, &uname );
if ( uname_len < 0 )
{
2009-12-19 15:06:57 +01:00
errno = EINVAL;
goto cleanup;
}
name = strrchr( dir, '/' );
if ( name )
{
name++;
name[0] = 0;
}
2009-12-19 15:06:57 +01:00
// Open the entries parent directory
dir_ni = ntfsOpenEntry( vd, dir );
if ( !dir_ni )
{
2009-12-19 15:06:57 +01:00
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;
2009-12-19 15:06:57 +01:00
}
// If the entry was created
if ( ni )
{
2009-12-19 15:06:57 +01:00
// Mark the entry for archiving
ni->flags |= FILE_ATTR_ARCHIVE;
2009-12-19 15:06:57 +01:00
// Mark the entry as dirty
NInoSetDirty( ni );
2009-12-19 15:06:57 +01:00
// Sync the entry to disc
ntfsSync( vd, ni );
2009-12-19 15:06:57 +01:00
// Update parent directories times
ntfsUpdateTimes( vd, dir_ni, NTFS_UPDATE_MCTIME );
2009-12-19 15:06:57 +01:00
}
2009-12-19 15:06:57 +01:00
cleanup:
if ( dir_ni )
ntfsCloseEntry( vd, dir_ni );
if ( utarget )
ntfs_free( utarget );
if ( uname )
ntfs_free( uname );
if ( dir )
ntfs_free( dir );
2009-12-19 15:06:57 +01:00
// Unlock
ntfsUnlock( vd );
2009-12-19 15:06:57 +01:00
return ni;
}
int ntfsLink ( ntfs_vd *vd, const char *old_path, const char *new_path )
{
2009-12-19 15:06:57 +01:00
ntfs_inode *dir_ni = NULL, *ni = NULL;
char *dir = NULL;
char *name = NULL;
ntfschar *uname = NULL;
int uname_len;
int res = 0;
2009-12-19 15:06:57 +01:00
// Sanity check
if ( !vd )
{
2009-12-19 15:06:57 +01:00
errno = ENODEV;
return -1;
}
2009-12-19 15:06:57 +01:00
// You cannot link between devices
if ( vd != ntfsGetVolume( new_path ) )
{
2009-12-19 15:06:57 +01:00
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 )
{
2009-12-19 15:06:57 +01:00
errno = EINVAL;
return -1;
}
// Lock
ntfsLock( vd );
2009-12-19 15:06:57 +01:00
// 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 )
{
2009-12-19 15:06:57 +01:00
errno = EINVAL;
goto cleanup;
}
name = strrchr( dir, '/' );
if ( name )
2009-12-19 15:06:57 +01:00
name++;
else
name = dir;
uname_len = ntfsLocalToUnicode( name, &uname );
if ( uname_len < 0 )
{
2009-12-19 15:06:57 +01:00
errno = EINVAL;
goto cleanup;
}
*name = 0;
2009-12-19 15:06:57 +01:00
// Find the entry
ni = ntfsOpenEntry( vd, old_path );
if ( !ni )
{
2009-12-19 15:06:57 +01:00
errno = ENOENT;
res = -1;
goto cleanup;
}
2009-12-19 15:06:57 +01:00
// Open the entries new parent directory
dir_ni = ntfsOpenEntry( vd, dir );
if ( !dir_ni )
{
2009-12-19 15:06:57 +01:00
errno = ENOENT;
res = -1;
goto cleanup;
}
2009-12-19 15:06:57 +01:00
// Link the entry to its new parent
if ( ntfs_link( ni, dir_ni, uname, uname_len ) )
{
2009-12-19 15:06:57 +01:00
res = -1;
goto cleanup;
}
2009-12-19 15:06:57 +01:00
// Update entry times
ntfsUpdateTimes( vd, dir_ni, NTFS_UPDATE_MCTIME );
2009-12-19 15:06:57 +01:00
// Sync the entry to disc
ntfsSync( vd, ni );
2009-12-19 15:06:57 +01:00
cleanup:
if ( dir_ni )
ntfsCloseEntry( vd, dir_ni );
2009-12-19 15:06:57 +01:00
if ( ni )
ntfsCloseEntry( vd, ni );
if ( uname )
ntfs_free( uname );
if ( dir )
ntfs_free( dir );
2009-12-19 15:06:57 +01:00
// Unlock
ntfsUnlock( vd );
2009-12-19 15:06:57 +01:00
return res;
}
int ntfsUnlink ( ntfs_vd *vd, const char *path )
{
2009-12-19 15:06:57 +01:00
ntfs_inode *dir_ni = NULL, *ni = NULL;
char *dir = NULL;
char *name = NULL;
ntfschar *uname = NULL;
int uname_len;
int res = 0;
2009-12-19 15:06:57 +01:00
// Sanity check
if ( !vd )
{
2009-12-19 15:06:57 +01:00
errno = ENODEV;
return -1;
}
2009-12-19 15:06:57 +01:00
// Get the actual path of the entry
path = ntfsRealPath( path );
if ( !path )
{
2009-12-19 15:06:57 +01:00
errno = EINVAL;
return -1;
}
2009-12-19 15:06:57 +01:00
// Lock
ntfsLock( vd );
2009-12-19 15:06:57 +01:00
// Get the unicode name for the entry and find its parent directory
// TODO: This looks horrible
dir = strdup( path );
if ( !dir )
{
2009-12-19 15:06:57 +01:00
errno = EINVAL;
goto cleanup;
}
name = strrchr( dir, '/' );
if ( name )
2009-12-19 15:06:57 +01:00
name++;
else
name = dir;
uname_len = ntfsLocalToUnicode( name, &uname );
if ( uname_len < 0 )
{
2009-12-19 15:06:57 +01:00
errno = EINVAL;
goto cleanup;
}
name = strrchr( dir, '/' );
if ( name )
{
name++;
name[0] = 0;
}
2009-12-19 15:06:57 +01:00
// Find the entry
ni = ntfsOpenEntry( vd, path );
if ( !ni )
{
2009-12-19 15:06:57 +01:00
errno = ENOENT;
res = -1;
goto cleanup;
}
2009-12-19 15:06:57 +01:00
// Open the entries parent directory
dir_ni = ntfsOpenEntry( vd, dir );
if ( !dir_ni )
{
2009-12-19 15:06:57 +01:00
errno = ENOENT;
res = -1;
goto cleanup;
}
2009-12-19 15:06:57 +01:00
// Unlink the entry from its parent
if ( ntfs_delete( vd->vol, path, ni, dir_ni, uname, uname_len ) )
{
2009-12-19 15:06:57 +01:00
res = -1;
}
2009-12-19 15:06:57 +01:00
// Force the underlying device to sync
vd->dev->d_ops->sync( vd->dev );
2009-12-19 15:06:57 +01:00
// ntfs_delete() ALWAYS closes ni and dir_ni; so no need for us to anymore
dir_ni = ni = NULL;
2009-12-19 15:06:57 +01:00
cleanup:
if ( dir_ni )
ntfsCloseEntry( vd, dir_ni );
if ( ni )
ntfsCloseEntry( vd, ni );
if ( uname )
ntfs_free( uname );
if ( dir )
ntfs_free( dir );
2009-12-19 15:06:57 +01:00
// Unlock
ntfsUnlock( vd );
2009-12-19 15:06:57 +01:00
return 0;
}
int ntfsSync ( ntfs_vd *vd, ntfs_inode *ni )
{
2009-12-19 15:06:57 +01:00
int res = 0;
2009-12-19 15:06:57 +01:00
// Sanity check
if ( !vd )
{
2009-12-19 15:06:57 +01:00
errno = ENODEV;
return -1;
}
2009-12-19 15:06:57 +01:00
// Sanity check
if ( !ni )
{
2009-12-19 15:06:57 +01:00
errno = ENOENT;
return -1;
}
2009-12-19 15:06:57 +01:00
// Lock
ntfsLock( vd );
2009-12-19 15:06:57 +01:00
// Sync the entry
res = ntfs_inode_sync( ni );
2009-12-19 15:06:57 +01:00
// Force the underlying device to sync
vd->dev->d_ops->sync( vd->dev );
2009-12-19 15:06:57 +01:00
// Unlock
ntfsUnlock( vd );
2009-12-19 15:06:57 +01:00
return res;
2009-12-19 15:06:57 +01:00
}
int ntfsStat ( ntfs_vd *vd, ntfs_inode *ni, struct stat *st )
{
2009-12-19 15:06:57 +01:00
ntfs_attr *na = NULL;
int res = 0;
2009-12-19 15:06:57 +01:00
// Sanity check
if ( !vd )
{
2009-12-19 15:06:57 +01:00
errno = ENODEV;
return -1;
}
// Sanity check
if ( !ni )
{
2009-12-19 15:06:57 +01:00
errno = ENOENT;
return -1;
}
2009-12-19 15:06:57 +01:00
// Short circuit cases were we don't actually have to do anything
if ( !st )
2009-12-19 15:06:57 +01:00
return 0;
2009-12-19 15:06:57 +01:00
// Lock
ntfsLock( vd );
2009-12-19 15:06:57 +01:00
// Zero out the stat buffer
memset( st, 0, sizeof( struct stat ) );
2009-12-19 15:06:57 +01:00
// Is this entry a directory
if ( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY )
{
st->st_mode = S_IFDIR | ( 0777 & ~vd->dmask );
2009-12-19 15:06:57 +01:00
st->st_nlink = 1;
2009-12-19 15:06:57 +01:00
// Open the directories index allocation table attribute
na = ntfs_attr_open( ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4 );
if ( na )
{
2009-12-19 15:06:57 +01:00
st->st_size = na->data_size;
st->st_blocks = na->allocated_size >> 9;
ntfs_attr_close( na );
2009-12-19 15:06:57 +01:00
}
// Else it must be a file
}
else
{
st->st_mode = S_IFREG | ( 0777 & ~vd->fmask );
2009-12-19 15:06:57 +01:00
st->st_size = ni->data_size;
st->st_blocks = ( ni->allocated_size + 511 ) >> 9;
st->st_nlink = le16_to_cpu( ni->mrec->link_count );
2009-12-19 15:06:57 +01:00
}
2009-12-19 15:06:57 +01:00
// Fill in the generic entry stats
st->st_dev = vd->id;
st->st_uid = vd->uid;
st->st_gid = vd->gid;
st->st_ino = ni->mft_no;
st->st_atime = ni->last_access_time;
st->st_ctime = ni->last_mft_change_time;
st->st_mtime = ni->last_data_change_time;
2009-12-19 15:06:57 +01:00
// Update entry times
ntfsUpdateTimes( vd, ni, NTFS_UPDATE_ATIME );
2009-12-19 15:06:57 +01:00
// Unlock
ntfsUnlock( vd );
2009-12-19 15:06:57 +01:00
return res;
}
void ntfsUpdateTimes ( ntfs_vd *vd, ntfs_inode *ni, ntfs_time_update_flags mask )
{
2009-12-19 15:06:57 +01:00
// Run the access time update strategy against the device driver settings first
if ( vd && vd->atime == ATIME_DISABLED )
2009-12-19 15:06:57 +01:00
mask &= ~NTFS_UPDATE_ATIME;
// Update entry times
if ( ni && mask )
ntfs_inode_update_times( ni, mask );
2009-12-19 15:06:57 +01:00
return;
}
const char *ntfsRealPath ( const char *path )
{
2009-12-19 15:06:57 +01:00
// Sanity check
if ( !path )
2009-12-19 15:06:57 +01:00
return NULL;
2009-12-19 15:06:57 +01:00
// Move the path pointer to the start of the actual path
if ( strchr( path, ':' ) != NULL )
{
path = strchr( path, ':' ) + 1;
2009-12-19 15:06:57 +01:00
}
if ( strchr( path, ':' ) != NULL )
{
2009-12-19 15:06:57 +01:00
return NULL;
}
2009-12-19 15:06:57 +01:00
return path;
}
int ntfsUnicodeToLocal ( const ntfschar *ins, const int ins_len, char **outs, int outs_len )
{
2009-12-19 15:06:57 +01:00
int len = 0;
int i;
2009-12-19 15:06:57 +01:00
// Sanity check
if ( !ins || !ins_len || !outs )
2009-12-19 15:06:57 +01:00
return 0;
2009-12-19 15:06:57 +01:00
// Convert the unicode string to our current local
len = ntfs_ucstombs( ins, ins_len, outs, outs_len );
if ( len == -1 && errno == EILSEQ )
{
2009-12-19 15:06:57 +01:00
// The string could not be converted to the current local,
// do it manually by replacing non-ASCII characters with underscores
if ( !*outs || outs_len >= ins_len )
{
if ( !*outs )
{
*outs = ( char * ) ntfs_alloc( ins_len + 1 );
if ( !*outs )
{
2009-12-19 15:06:57 +01:00
errno = ENOMEM;
return -1;
}
}
for ( i = 0; i < ins_len; i++ )
{
ntfschar uc = le16_to_cpu( ins[i] );
if ( uc > 0xff )
uc = ( ntfschar )'_';
*outs[i] = ( char )uc;
2009-12-19 15:06:57 +01:00
}
*outs[ins_len] = ( ntfschar )'\0';
2009-12-19 15:06:57 +01:00
len = ins_len;
}
2009-12-19 15:06:57 +01:00
}
2009-12-19 15:06:57 +01:00
return len;
}
int ntfsLocalToUnicode ( const char *ins, ntfschar **outs )
{
2009-12-19 15:06:57 +01:00
// Sanity check
if ( !ins || !outs )
2009-12-19 15:06:57 +01:00
return 0;
2009-12-19 15:06:57 +01:00
// Convert the local string to unicode
return ntfs_mbstoucs( ins, outs );
2009-12-19 15:06:57 +01:00
}