Skip to content

Commit

Permalink
[XrdCl] Support ZIP archive listing, closes #714
Browse files Browse the repository at this point in the history
  • Loading branch information
simonmichal committed Jun 4, 2018
1 parent 4b8df10 commit 09fcf19
Show file tree
Hide file tree
Showing 8 changed files with 350 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/XrdCl/CMakeLists.txt
Expand Up @@ -69,6 +69,7 @@ add_library(
XrdClXCpSrc.cc XrdClXCpSrc.hh
XrdClLocalFileHandler.cc XrdClLocalFileHandler.hh
XrdClLocalFileTask.cc XrdClLocalFileTask.hh
XrdClZipListHandler.cc XrdClZipListHandler.hh
)

target_link_libraries(
Expand Down
18 changes: 17 additions & 1 deletion src/XrdCl/XrdClFileSystem.cc
Expand Up @@ -35,12 +35,14 @@
#include "XrdCl/XrdClPlugInInterface.hh"
#include "XrdCl/XrdClPlugInManager.hh"
#include "XrdCl/XrdClLocalFileTask.hh"
#include "XrdCl/XrdClZipListHandler.hh"
#include "XrdSys/XrdSysPthread.hh"

#include <sys/stat.h>

#include <memory>


namespace
{

Expand Down Expand Up @@ -395,7 +397,7 @@ namespace
// Constructor
//------------------------------------------------------------------------
DirListStatHandler( XrdCl::DirectoryList *list,
uint32_t index,
uint32_t index,
XrdCl::RequestSync *sync ):
pList( list ),
pIndex( index ),
Expand Down Expand Up @@ -1384,6 +1386,20 @@ namespace XrdCl
URL url = URL( path );
std::string fPath = FilterXrdClCgi( path );

// check if it could be a ZIP archive
static const std::string zip_sufix = ".zip";
if( path.size() >= zip_sufix.size() &&
std::equal( zip_sufix.rbegin(), zip_sufix.rend(), path.rbegin() ) )
{
// stat the file to check if it is a directory or a file
// the ZIP handler will take care of the rest
ZipListHandler *zipHandler = new ZipListHandler( *pUrl, path, flags, handler, timeout );
XRootDStatus st = Stat( path, zipHandler, timeout );
if( !st.IsOK() )
delete zipHandler;
return st;
}

Message *msg;
ClientDirlistRequest *req;
MessageUtils::CreateRequest( msg, req, fPath.length() );
Expand Down
11 changes: 11 additions & 0 deletions src/XrdCl/XrdClXRootDResponses.cc
Expand Up @@ -113,6 +113,17 @@ namespace XrdCl
{
}

//------------------------------------------------------------------------
//! Constructor
//------------------------------------------------------------------------
StatInfo::StatInfo( const std::string &id, uint64_t size, uint32_t flags,
uint64_t modTime) :
pId( id ), pSize( size ), pFlags( flags ),
pModTime( modTime )
{

}

//----------------------------------------------------------------------------
// Parse the stat info returned by the server
//----------------------------------------------------------------------------
Expand Down
6 changes: 6 additions & 0 deletions src/XrdCl/XrdClXRootDResponses.hh
Expand Up @@ -353,6 +353,12 @@ namespace XrdCl
//------------------------------------------------------------------------
StatInfo();

//------------------------------------------------------------------------
//! Constructor
//------------------------------------------------------------------------
StatInfo( const std::string &id, uint64_t size, uint32_t flags,
uint64_t modTime);

//------------------------------------------------------------------------
//! Get id
//------------------------------------------------------------------------
Expand Down
45 changes: 44 additions & 1 deletion src/XrdCl/XrdClZipArchiveReader.cc
Expand Up @@ -28,6 +28,7 @@
#include "XrdCl/XrdClDefaultEnv.hh"
#include "XrdCl/XrdClLog.hh"
#include "XrdCl/XrdClConstants.hh"
#include "XrdCl/XrdClXRootDResponses.hh"

#include "XrdSys/XrdSysPthread.hh"

Expand Down Expand Up @@ -182,6 +183,8 @@ class ZipArchiveReaderImpl
return Read( pBoundFile, relativeOffset, size, buffer, userHandler, timeout );
}

DirectoryList* List();

XRootDStatus Close( ResponseHandler *handler, uint16_t timeout )
{
XRootDStatus st = pArchive.Close( handler, timeout );
Expand Down Expand Up @@ -308,7 +311,6 @@ class ZipArchiveReaderImpl
}

File &pArchive;
std::string pFilename;
uint64_t pArchiveSize;
std::unique_ptr<char[]> pBuffer;
std::unique_ptr<EOCD> pEocd;
Expand Down Expand Up @@ -760,6 +762,18 @@ XRootDStatus ZipArchiveReader::Read( uint64_t offset, uint32_t size, void *buffe
return status;
}

//------------------------------------------------------------------------
// Sync list
//------------------------------------------------------------------------
XRootDStatus ZipArchiveReader::List( DirectoryList *&list )
{
if( !pImpl->IsOpen() )
return XRootDStatus( stError, errInvalidOp );

list = pImpl->List();
return XRootDStatus();
}

XRootDStatus ZipArchiveReaderImpl::Read( const std::string &filename, uint64_t relativeOffset, uint32_t size, void *buffer, ResponseHandler *userHandler, uint16_t timeout )
{
if( !pArchive.IsOpen() ) return XRootDStatus( stError, errInvalidOp, errInvalidOp, "Archive not opened." );
Expand Down Expand Up @@ -810,6 +824,35 @@ XRootDStatus ZipArchiveReaderImpl::Read( const std::string &filename, uint64_t r
return st;
}

DirectoryList* ZipArchiveReaderImpl::List()
{
std::string value;
pArchive.GetProperty( "LastURL", value );
URL url( value );

StatInfo *infoptr = 0;
pArchive.Stat( false, infoptr );
std::unique_ptr<StatInfo> info( infoptr );

DirectoryList *list = new DirectoryList();
list->SetParentName( url.GetPath() );

auto itr = pCdRecords.begin();
for( ; itr != pCdRecords.end() ; ++itr )
{
CDFH *cdfh = *itr;
StatInfo *entry_info = new StatInfo( info->GetId(),
cdfh->pCdfhSize,
info->GetFlags() & ( ~StatInfo::IsWritable ), // make sure it is not listed as writable
info->GetModTime() );
DirectoryList::ListEntry *entry =
new DirectoryList::ListEntry( url.GetHostId(), cdfh->pFilename, entry_info );
list->Add( entry );
}

return list;
}

XRootDStatus ZipArchiveReader::Close( ResponseHandler *handler, uint16_t timeout )
{
return pImpl->Close( handler, timeout );
Expand Down
13 changes: 9 additions & 4 deletions src/XrdCl/XrdClZipArchiveReader.hh
Expand Up @@ -98,25 +98,30 @@ class ZipArchiveReader
XRootDStatus Read( const std::string &filename, uint64_t offset, uint32_t size, void *buffer, ResponseHandler *handler, uint16_t timeout = 0 );

//------------------------------------------------------------------------
// Sync read.
//! Sync read.
//------------------------------------------------------------------------
XRootDStatus Read( const std::string &filename, uint64_t offset, uint32_t size, void *buffer, uint32_t &bytesRead, uint16_t timeout = 0 );

//------------------------------------------------------------------------
// Bounds the reader to a file inside the archive.
//! Bounds the reader to a file inside the archive.
//------------------------------------------------------------------------
XRootDStatus Bind( const std::string &filename );

//------------------------------------------------------------------------
// Async bound read.
//! Async bound read.
//------------------------------------------------------------------------
XRootDStatus Read( uint64_t offset, uint32_t size, void *buffer, ResponseHandler *handler, uint16_t timeout = 0 );

//------------------------------------------------------------------------
// Sync bound read.
//! Sync bound read.
//------------------------------------------------------------------------
XRootDStatus Read( uint64_t offset, uint32_t size, void *buffer, uint32_t &bytesRead, uint16_t timeout = 0 );

//------------------------------------------------------------------------
//! Sync list
//------------------------------------------------------------------------
XRootDStatus List( DirectoryList *&list );

//------------------------------------------------------------------------
//! Async close.
//!
Expand Down
132 changes: 132 additions & 0 deletions src/XrdCl/XrdClZipListHandler.cc
@@ -0,0 +1,132 @@
//------------------------------------------------------------------------------
// Copyright (c) 2011-2014 by European Organization for Nuclear Research (CERN)
// Author: Michal Simon <michal.simon@cern.ch>
//------------------------------------------------------------------------------
// This file is part of the XRootD software suite.
//
// XRootD is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// XRootD 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 Lesser General Public License
// along with XRootD. If not, see <http://www.gnu.org/licenses/>.
//
// In applying this licence, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
//------------------------------------------------------------------------------

#include "XrdClZipListHandler.hh"

namespace XrdCl
{

void ZipListHandler::HandleResponse( XrdCl::XRootDStatus *statusptr,
XrdCl::AnyObject *responseptr )
{
std::unique_ptr<XRootDStatus> status( statusptr );
std::unique_ptr<AnyObject> response( responseptr );

if( !status->IsOK() )
{
pHandler->HandleResponse( status.release(), response.release() );
delete this;
return;
}

time_t took = time( 0 ) - pStartTime;
if( took > pTimeout )
{
*status = XRootDStatus( stError, errOperationExpired );
pHandler->HandleResponse( status.release(), 0 );
delete this;
return;
}
uint16_t left = pTimeout - took;

switch( pStep )
{
case STAT:
{
StatInfo *info = 0;
response->Get( info );

if( info->TestFlags( StatInfo::IsDir ) )
DoDirList( left );
else
DoZipOpen( left );

break;
}

case OPEN:
{
DirectoryList *list = 0;
XRootDStatus st = pZip.List( list );
if( !st.IsOK() )
{
pHandler->HandleResponse( new XRootDStatus( st ), 0 );
pStep = DONE;
}
else
{
pDirList.reset( list );
DoZipClose( left );
}
break;
}

case CLOSE:
{
AnyObject *resp = new AnyObject();
resp->Set( pDirList.release() );
pHandler->HandleResponse( new XRootDStatus(), resp );
pStep = DONE;
break;
}
}

if( pStep == DONE )
delete this;
}

void ZipListHandler::DoDirList( time_t timeLeft )
{
FileSystem fs( pUrl );
XRootDStatus st = fs.DirList( pUrl.GetPath(), pFlags, pHandler , timeLeft );
pStep = DONE; // no matter whether it works or not, either way we are done
if( !st.IsOK() )
pHandler->HandleResponse( new XRootDStatus( st ), 0 );
}

void ZipListHandler::DoZipOpen( time_t timeLeft )
{
XRootDStatus st = pZip.Open( pUrl.GetURL(), this, timeLeft );
if( !st.IsOK() )
{
pHandler->HandleResponse( new XRootDStatus( st ), 0 );
pStep = DONE;
}
else
pStep = OPEN;
}

void ZipListHandler::DoZipClose( time_t timeLeft )
{
XRootDStatus st = pZip.Close( this, timeLeft );
if( !st.IsOK() )
{
pHandler->HandleResponse( new XRootDStatus( st ), 0 );
pStep = DONE;
}
else
pStep = CLOSE;
}

} /* namespace XrdCl */

0 comments on commit 09fcf19

Please sign in to comment.