clPtr<FS> clArchPlugin::OpenFS( clPtr<FS> Fs, FSPath& Path ) const { FSString Uri = Fs->Uri( Path ); struct archive* Arch = ArchOpen( Uri.GetUtf8() ); if ( Arch == nullptr ) { return nullptr; } FSArchNode RootDir; RootDir.fsStat.mode = S_IFDIR; FSPath NodePath; struct archive_entry* entry = archive_entry_new2( Arch ); int Res; while ( ( Res = archive_read_next_header2( Arch, entry ) ) == ARCHIVE_OK ) { NodePath.Set( CS_UTF8, archive_entry_pathname( entry ) ); FSString* ItemName = NodePath.GetItem( NodePath.Count() - 1 ); if ( NodePath.Count() == 1 && ( ItemName->IsDot() || ItemName->IsEmpty() ) ) { // skip root dir continue; } const mode_t Mode = archive_entry_mode( entry ); const int64_t Size = archive_entry_size( entry ); RootDir.entryOffset += Size; FSStat ItemStat; ItemStat.mode = S_ISREG( Mode ) ? Mode : S_IFDIR; ItemStat.size = Size; ItemStat.m_CreationTime = archive_entry_ctime( entry ); ItemStat.m_LastAccessTime = archive_entry_atime( entry ); ItemStat.m_LastWriteTime = archive_entry_mtime( entry ); ItemStat.m_ChangeTime = ItemStat.m_LastWriteTime; FSArchNode* Dir = ArchGetParentDir( &RootDir, NodePath, ItemStat ); FSArchNode* Item = Dir->Add( FSArchNode( ItemName->GetUtf8(), ItemStat ) ); if (Item) { Item->entryOffset = archive_read_header_position( Arch ); } } if ( Res != ARCHIVE_EOF ) { dbg_printf( "Couldn't read archive entry: %s\n", archive_error_string( Arch ) ); } archive_entry_free( entry ); ArchClose( Arch ); return new FSArch( RootDir, Uri ); }
FSArchNode* ArchGetParentDir( FSArchNode* CurrDir, FSPath& ItemPath, const FSStat& ItemStat ) { for ( int i = 0; i < ItemPath.Count() - 1; i++ ) { FSString* Name = ItemPath.GetItem( i ); if ( i == 0 && ( Name->IsDot() || Name->IsEmpty() ) ) { // skip root dir continue; } FSArchNode* Dir = CurrDir->findByName( *Name ); if ( Dir == nullptr ) { FSStat Stat = ItemStat; Stat.mode = S_IFDIR; Stat.size = 0; Dir = CurrDir->Add( FSArchNode( Name->GetUtf8(), Stat ) ); } CurrDir = Dir; } return CurrDir; }
FSArchNode* FSArchNode::findByName( const FSString& name, bool isRecursive ) { dbg_printf( "FSArchNodeDir::findByName name=%s\n", name.GetUtf8() ); // first, try all nodes in current for ( FSArchNode& n : content ) { dbg_printf( "FSArchNodeDir::findByName n.name=%s\n", n.name.GetUtf8() ); if ( n.name.Cmp( ( FSString& ) name ) == 0 ) { return &n; } } // only if not found in current dir, try inside subdirs if ( isRecursive ) { for ( FSArchNode& n : content ) { if ( n.IsDir() ) { FSArchNode* pn = n.findByName( name, isRecursive ); if ( pn ) { return pn; } } } } return nullptr; }
int FSArch::OpenRead( FSPath& path, int flags, int* err, FSCInfo* info ) { dbg_printf( "FSArch::Open\n" ); FSArchNode* Node = m_RootDir.findByFsPath( path ); if ( Node == nullptr ) { FS::SetError( err, FSARCH_ERROR_FILE_NOT_FOUND ); return -1; } struct archive* Arch = ArchOpen( m_Uri.GetUtf8() ); if ( Arch == nullptr ) { FS::SetError( err, FSARCH_ERROR_FILE_NOT_FOUND ); return -1; } struct archive_entry* entry = archive_entry_new2( Arch ); int Res; // seek to the entry while ( ( Res = archive_read_next_header2( Arch, entry ) ) == ARCHIVE_OK ) { int64_t EntryOffset = archive_read_header_position( Arch ); if ( EntryOffset == Node->entryOffset ) { break; } } archive_entry_free( entry ); if ( Res != ARCHIVE_OK ) { ArchClose( Arch ); dbg_printf( "Couldn't read archive entry: %s\n", archive_error_string( Arch ) ); FS::SetError( err, FSARCH_ERROR_FILE_NOT_FOUND ); return -1; } const int fd = g_NextArchFD++; m_OpenFiles[ fd ] = Arch; return fd; }
void OpenHomeDir( PanelWin* p ) { #ifdef _WIN32 std::vector<unicode_t> homeUri = GetHomeUriWin(); if ( homeUri.data() ) { const std::vector<clPtr<FS>> checkFS = { p->GetFSPtr(), g_MainWin->GetOtherPanel( p )->GetFSPtr() }; FSPath path; clPtr<FS> fs = ParzeURI( homeUri.data(), path, checkFS ); if ( fs.IsNull() ) { char buf[4096]; FSString name = homeUri.data(); Lsnprintf( buf, sizeof( buf ), "bad home path: %s\n", name.GetUtf8() ); NCMessageBox( g_MainWin, "Home", buf, true ); } else { p->LoadPath( fs, path, 0, 0, PanelWin::SET ); } } #else const sys_char_t* home = (sys_char_t*) getenv( "HOME" ); if ( !home ) { return; } FSPath path( sys_charset_id, home ); p->LoadPath( new FSSys(), path, 0, 0, PanelWin::SET ); #endif }
void OperRDThread::Run() { if ( !fs.Ptr() ) { return; } int n = 8; int ret_err; int havePostponedStatError = 0; FSString postponedStrError; while ( true ) { if ( !( fs->Flags() & FS::HAVE_SYMLINK ) ) { break; } FSStat st; // if path is inaccessible, try .. path. Throw the exception later // This makes panel at least having some valid folder while ( fs->Stat( path, &st, &ret_err, Info() ) ) { havePostponedStatError = 1; postponedStrError = fs->StrError( ret_err ); if ( !path.IsAbsolute() || path.Count() <= 1 || !path.Pop() ) { throw_msg( "%s", postponedStrError.GetUtf8() ); } } // yell immediately if the path is inaccessible (orig behavior) //if (fs->Stat(path, &st, &ret_err, Info())) // throw_msg("%s", fs->StrError(ret_err).GetUtf8()); if ( !st.IsLnk() ) { break; } n--; if ( n < 0 ) { throw_msg( "too many symbolic links '%s'", path.GetUtf8() ); } path.Pop(); if ( !ParzeLink( path, st.link ) ) { throw_msg( "invalid symbolic link '%s'", path.GetUtf8() ); } } clPtr<FSList> list = new FSList; int havePostponedReadError = 0; // if directory is not readable, try .. path. Throw the exception later // "Stat" call above does not catch this: it checks only folder existence, but not accessibilly while ( fs->ReadDir( list.ptr(), path, &ret_err, Info() ) ) { havePostponedReadError = 1; postponedStrError = fs->StrError( ret_err ); if ( !path.IsAbsolute() || path.Count() <= 1 || !path.Pop() ) { throw_msg( "%s", postponedStrError.GetUtf8() ); } } // yell immediately if the dir is unreadable (orig behavior) //int ret = fs->ReadDir(list.ptr(), path, &ret_err, Info()); //if (ret) // throw_msg("%s", fs->StrError(ret_err).GetUtf8()); FSStatVfs vst; fs->StatVfs( path, &vst, &ret_err, Info() ); MutexLock lock( Node().GetMutex() ); //!!! if ( Node().NBStopped() ) { return; } OperRDData* data = ( ( OperRDData* )Node().Data() ); data->list = list; data->path = path; data->executed = true; data->vst = vst; if ( havePostponedReadError || havePostponedStatError ) { data->nonFatalErrorString = postponedStrError; } }