From ac004ea51ab40395644f0bdd48c5e8f494300abc Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Fri, 5 Dec 2003 02:25:32 +0000 Subject: [PATCH] driver GetDirListing, write logic, fixes --- stepmania/src/RageFileDriver.cpp | 35 ++++++++++ stepmania/src/RageFileDriver.h | 2 + stepmania/src/RageFileDriverDirect.cpp | 26 +++++++- stepmania/src/RageFileDriverDirect.h | 1 + stepmania/src/RageFileManager.cpp | 91 ++++++++++++++++++++++++++ stepmania/src/RageFileManager.h | 5 ++ 6 files changed, 158 insertions(+), 2 deletions(-) diff --git a/stepmania/src/RageFileDriver.cpp b/stepmania/src/RageFileDriver.cpp index 9e23aca07b..ae19108095 100644 --- a/stepmania/src/RageFileDriver.cpp +++ b/stepmania/src/RageFileDriver.cpp @@ -1,5 +1,6 @@ #include "global.h" #include "RageFileDriver.h" +#include "RageUtil.h" void RageFileObj::SetError( const CString &err ) { @@ -58,6 +59,40 @@ int RageFileObj::GetFileSize() return ret; } +int RageFileDriver::GetPathValue( CString path ) +{ + vector parts; + split( path, SLASH, parts, true ); + + CString PartialPath; + + for( unsigned i = 0; i < parts.size(); ++i ) + { + PartialPath += parts[i]; + if( i+1 < parts.size() ) + PartialPath += SLASH; + + const RageFileManager::FileType Type = GetFileType( PartialPath ); + switch( Type ) + { + case RageFileManager::TYPE_NONE: + return parts.size()-i; + + /* If this is the last part (the whole path), it needs to be a file; otherwise a directory. */ + case RageFileManager::TYPE_FILE: + if( i != parts.size()-1 ) + return -1; + break; + case RageFileManager::TYPE_DIR: + if( i == parts.size()-1 ) + return -1; + break; + } + } + + return 0; +} + /* * Copyright (c) 2003 by the person(s) listed below. All rights reserved. * Glenn Maynard diff --git a/stepmania/src/RageFileDriver.h b/stepmania/src/RageFileDriver.h index 301cf69386..ea6747d1b2 100644 --- a/stepmania/src/RageFileDriver.h +++ b/stepmania/src/RageFileDriver.h @@ -9,9 +9,11 @@ class RageFileDriver { public: virtual RageFileObj *Open( CString path, RageFile::OpenMode mode, RageFile &p, int &err ) = 0; + virtual void GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo ) = 0; virtual RageFileManager::FileType GetFileType( CString sPath ) = 0; virtual int GetFileSizeInBytes( CString sFilePath ) = 0; virtual int GetFileModTime( CString sPath ) = 0; + virtual int GetPathValue( CString path ); virtual bool Ready() { return true; } /* see RageFileManager::MountpointIsReady */ }; diff --git a/stepmania/src/RageFileDriverDirect.cpp b/stepmania/src/RageFileDriverDirect.cpp index a6e5457ee4..ba22cde044 100644 --- a/stepmania/src/RageFileDriverDirect.cpp +++ b/stepmania/src/RageFileDriverDirect.cpp @@ -42,8 +42,24 @@ RageFileDriverDirect::RageFileDriverDirect( CString root_ ): { } +void FDB_GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo ); + +void RageFileDriverDirect::GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo ) +{ + const unsigned OldStart = AddTo.size(); + FDB_GetDirListing( root+sPath, AddTo, bOnlyDirs, bReturnPathToo ); + + if( bReturnPathToo ) + { + /* Remove the root path. */ + for( unsigned j = OldStart; j < AddTo.size(); ++j ) + AddTo[j].erase( 0, root.size() ); + } +} + RageFileObj *RageFileDriverDirect::Open( CString sPath, RageFile::OpenMode mode, RageFile &p, int &err ) { + sPath = root + sPath; ResolvePath( sPath ); int flags = O_BINARY; if( mode == RageFile::READ ) @@ -51,7 +67,7 @@ RageFileObj *RageFileDriverDirect::Open( CString sPath, RageFile::OpenMode mode, else flags |= O_WRONLY|O_CREAT|O_TRUNC; - int fd = open( root + sPath, flags, 0644 ); + int fd = open( sPath, flags, 0644 ); if( fd == -1 ) { err = errno; @@ -69,6 +85,8 @@ static bool DoStat(CString sPath, struct stat *st) RageFileManager::FileType RageFileDriverDirect::GetFileType( CString sPath ) { + sPath = root + sPath; + ResolvePath( sPath ); struct stat st; @@ -83,15 +101,19 @@ RageFileManager::FileType RageFileDriverDirect::GetFileType( CString sPath ) int RageFileDriverDirect::GetFileSizeInBytes( CString sPath ) { + sPath = root + sPath; + struct stat st; if( !DoStat(sPath, &st) ) - return 0; + return -1; return st.st_size; } int RageFileDriverDirect::GetFileModTime( CString sPath ) { + sPath = root + sPath; + struct stat st; if( !DoStat(sPath, &st) ) return -1; diff --git a/stepmania/src/RageFileDriverDirect.h b/stepmania/src/RageFileDriverDirect.h index 4d22dd9815..628bb410a7 100644 --- a/stepmania/src/RageFileDriverDirect.h +++ b/stepmania/src/RageFileDriverDirect.h @@ -10,6 +10,7 @@ public: virtual ~RageFileDriverDirect() { } RageFileObj *Open( CString path, RageFile::OpenMode mode, RageFile &p, int &err ); + void GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo ); RageFileManager::FileType GetFileType( CString sPath ); int GetFileSizeInBytes( CString sFilePath ); int GetFileModTime( CString sPath ); diff --git a/stepmania/src/RageFileManager.cpp b/stepmania/src/RageFileManager.cpp index 2261d7dce0..2883132d2c 100644 --- a/stepmania/src/RageFileManager.cpp +++ b/stepmania/src/RageFileManager.cpp @@ -70,6 +70,26 @@ CString LoadedDriver::GetPath( CString path ) return path.Right( path.size() - MountPoint.size() ); } +void RageFileManager::GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo ) +{ + for( unsigned i = 0; i < g_Drivers.size(); ++i ) + { + LoadedDriver &ld = g_Drivers[i]; + const CString p = ld.GetPath( sPath ); + if( p.size() == 0 ) + continue; + + const unsigned OldStart = AddTo.size(); + + g_Drivers[i].driver->GetDirListing( p, AddTo, bOnlyDirs, bReturnPathToo ); + + /* If returning the path, prepend the mountpoint name to the files this driver returned. */ + if( bReturnPathToo ) + for( unsigned j = OldStart; j < AddTo.size(); ++j ) + AddTo[j] = ld.MountPoint + AddTo[j]; + } + +} #include "RageFileDriverDirect.h" void RageFileManager::Mount( CString Type, CString Root, CString MountPoint ) @@ -165,11 +185,21 @@ int RageFileManager::GetFileModTime( const CString &sPath ) } +static bool SortBySecond( const pair &a, const pair &b ) +{ + return a.second < b.second; +} + /* Used only by RageFile: */ RageFileObj *RageFileManager::Open( const CString &sPath, RageFile::OpenMode mode, RageFile &p, int &err ) { err = ENOENT; + /* If writing, we need to do a heuristic to figure out which driver to write with--there + * may be several that will work. */ + if( mode == RageFile::WRITE ) + return OpenForWriting( sPath, mode, p, err ); + /* XXX: WRITE logic */ for( unsigned i = 0; i < g_Drivers.size(); ++i ) { @@ -190,6 +220,67 @@ RageFileObj *RageFileManager::Open( const CString &sPath, RageFile::OpenMode mod return NULL; } +RageFileObj *RageFileManager::OpenForWriting( const CString &sPath, RageFile::OpenMode mode, RageFile &p, int &err ) +{ + /* + * The value for a driver to open a file is the number of directories and/or files + * that would have to be created in order to write it, or 0 if the file already exists. + * For example, if we're opening "foo/bar/baz.txt", and only "foo/" exists in a + * driver, we'd have to create the "bar" directory and the "baz.txt" file, so the + * value is 2. If "foo/bar/" exists, we'd only have to create the file, so the + * value is 1. Create the file with the driver that returns the lowest value; + * in case of a tie, earliest-loaded driver wins. + * + * The purpose of this is to create files in the expected place. For example, if we + * have both C:/games/StepMania and C:/games/DWI loaded, and we're writing + * "Songs/Music/Waltz/waltz.sm", and the song was loaded out of + * "C:/games/DWI/Songs/Music/Waltz/waltz.dwi", we want to write the new SM into the + * same directory (if possible). Don't split up files in the same directory any + * more than we have to. + * + * If the given path can not be created, return -1. This happens if a path + * that needs to be a directory is a file, or vice versa. + */ + vector< pair > Values; + unsigned i; + for( i = 0; i < g_Drivers.size(); ++i ) + { + LoadedDriver &ld = g_Drivers[i]; + const CString path = ld.GetPath( sPath ); + if( path.size() == 0 ) + continue; + + const int value = ld.driver->GetPathValue( path ); + if( value == -1 ) + continue; + + Values.push_back( pair( i, value ) ); + } + + if( !Values.size() ) + { + err = EEXIST; + return NULL; + } + + stable_sort( Values.begin(), Values.end(), SortBySecond ); + + int error = 0; + for( i = 0; i < Values.size(); ++i ) + { + const int driver = Values[i].first; + LoadedDriver &ld = g_Drivers[driver]; + const CString path = ld.GetPath( sPath ); + ASSERT( path.size() ); + + RageFileObj *ret = ld.driver->Open( path, mode, p, error ); + if( ret ) + return ret; + } + err = error; + return NULL; +} + bool RageFileManager::IsAFile( const CString &sPath ) { return GetFileType(sPath) == TYPE_FILE; } bool RageFileManager::IsADirectory( const CString &sPath ) { return GetFileType(sPath) == TYPE_DIR; } bool RageFileManager::DoesFileExist( const CString &sPath ) { return GetFileType(sPath) != TYPE_NONE; } diff --git a/stepmania/src/RageFileManager.h b/stepmania/src/RageFileManager.h index cca23d22f1..fb43daa14a 100644 --- a/stepmania/src/RageFileManager.h +++ b/stepmania/src/RageFileManager.h @@ -10,6 +10,8 @@ public: RageFileManager(); ~RageFileManager(); + void GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo ); + enum FileType { TYPE_FILE, TYPE_DIR, TYPE_NONE }; FileType GetFileType( const CString &sPath ); @@ -26,6 +28,9 @@ public: /* Used only by RageFile: */ RageFileObj *Open( const CString &sPath, RageFile::OpenMode mode, RageFile &p, int &err ); + +private: + RageFileObj *OpenForWriting( const CString &sPath, RageFile::OpenMode mode, RageFile &p, int &err ); }; extern RageFileManager *FILEMAN;