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;
}
Exemplo n.º 5
0
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
}
Exemplo n.º 6
0
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;
	}
}