/*============================================================================== Copyright (C) 2007 Martin Furter This file is part of svntar svntar 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, or (at your option) any later version. svntar 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 svntar; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ==============================================================================*/ #include "svn_tar_url.h" #include "svn_path.h" #include "svn_props.h" #include typedef struct { apr_pool_t* pool; apr_pool_t* subpool; svn_tar_t* tar; svn_boolean_t baserev; const char* basepath; int pathlen; svn_wc_adm_access_t* adm_access; /* for use in the callbacks */ const char* path; apr_hash_t* props; apr_finfo_t finfo; } status_baton_t; static svn_error_t* copy_file_to_stream( const char* path, svn_stream_t* stream, apr_pool_t* pool ) { apr_file_t* aprfile; svn_stream_t* filestream; svn_error_t* err; SVN_ERR( svn_io_file_open( &aprfile, path, APR_READ | APR_BINARY, APR_OS_DEFAULT, pool ) ); filestream = svn_stream_from_aprfile2( aprfile, FALSE, pool ); err = svn_stream_copy( filestream, stream, pool ); svn_stream_close( filestream ); svn_stream_close( stream ); return err; } static svn_error_t* wc_propget( const char* name, const char** value, void* baton, apr_pool_t* pool ) { status_baton_t* sb = baton; if( sb->props ) { svn_string_t* s; s = apr_hash_get( sb->props, name, APR_HASH_KEY_STRING ); *value = s ? s->data : 0; } else { *value = 0; } return SVN_NO_ERROR; } static svn_error_t* wc_file_stream( svn_stream_t* filestream, void* baton, apr_pool_t* pool ) { status_baton_t* sb = baton; char linkdest[100+4]; if( sb->baserev || sb->finfo.filetype != APR_LNK ) { return copy_file_to_stream( sb->path, filestream, pool ); } if( readlink( sb->path, linkdest, sizeof( linkdest ) )< 0 ) { return svn_error_createf( 0, NULL, _( "Couldn't read link for '%s'" ), sb->path ); } return svn_stream_printf( filestream, pool, "link %s", linkdest ); } static svn_error_t* status_func_p( void* baton, const char* path, svn_wc_status2_t* status, apr_pool_t* pool ) { status_baton_t* sb = baton; svn_boolean_t add_special = FALSE; apr_status_t ast; svn_node_kind_t kind; int size; const char* relpath; sb->path = path; if( sb->baserev ) { switch( status->text_status ) { case svn_wc_status_normal: case svn_wc_status_missing: case svn_wc_status_deleted: case svn_wc_status_replaced: case svn_wc_status_modified: case svn_wc_status_merged: case svn_wc_status_conflicted: case svn_wc_status_obstructed: case svn_wc_status_incomplete: if( !status->entry ) { return SVN_NO_ERROR; } break; default: return SVN_NO_ERROR; } } else { switch( status->text_status ) { case svn_wc_status_normal: case svn_wc_status_replaced: case svn_wc_status_modified: case svn_wc_status_merged: case svn_wc_status_conflicted: case svn_wc_status_incomplete: break; case svn_wc_status_unversioned: if( 1 ) { return SVN_NO_ERROR; } break; case svn_wc_status_ignored: if( 1 ) { return SVN_NO_ERROR; } break; /* case svn_wc_status_obstructed: break; */ default: return SVN_NO_ERROR; } } ast = apr_stat( &sb->finfo, path, APR_FINFO_LINK | APR_FINFO_MTIME | APR_FINFO_SIZE | APR_FINFO_TYPE | APR_FINFO_UPROT, pool ); if( APR_STATUS_IS_ENOENT( ast ) ) { return svn_error_wrap_apr( ast, _( "lstat of '%s' failed" ), path ); } if( sb->finfo.filetype == APR_REG ) { kind = svn_node_file; size = sb->finfo.size; } else if( sb->finfo.filetype == APR_LNK ) { kind = svn_node_file; if( !sb->baserev && ( status->text_status == svn_wc_status_unversioned || status->text_status == svn_wc_status_ignored ) ) { add_special = TRUE; } } else if( sb->finfo.filetype == APR_DIR ) { kind = svn_node_dir; } else { return svn_error_createf( 0, NULL, _( "Unsupported file type" ) ); } /* cut away the base path */ if( strlen( path ) >= sb->pathlen ) { relpath = path + sb->pathlen; } else { relpath = ""; } /* get the properties */ if( sb->baserev ) { SVN_ERR( svn_wc_get_prop_diffs( 0, &sb->props, path, sb->adm_access, pool ) ); } else { SVN_ERR( svn_wc_prop_list( &sb->props, path, sb->adm_access, pool ) ); } if( add_special ) { char* key; svn_string_t* val; key = apr_pstrdup( pool, SVN_PROP_SPECIAL ); val = svn_string_create( "*", pool ); apr_hash_set( sb->props, key, strlen( key ), val ); } // printf( "'%s' ** %s **\n", relpath, path ); return svn_tar_add( relpath, kind, size, wc_propget, baton, wc_file_stream, baton, sb->tar, pool ); } static void status_func( void* baton, const char* path, svn_wc_status2_t* status ) { apr_pool_t* pool = ( (status_baton_t*)baton )->subpool; svn_error_t* err; apr_pool_clear( pool ); err = status_func_p( baton, path, status, pool ); if( err ) { svn_handle_warning2( stdout, err, "" ); svn_error_clear( err ); } } svn_error_t* svn_tar_wc( svn_tar_t* tar, const char* path, svn_boolean_t baserev, svn_client_ctx_t* ctx, apr_pool_t* pool ) { svn_opt_revision_t revision; status_baton_t sb; svn_error_t* err; svn_error_t* err2; sb.pool = pool; sb.subpool = svn_pool_create( pool ); sb.tar = tar; sb.baserev = baserev; svn_path_get_absolute( &sb.basepath, svn_path_canonicalize( path, pool ), pool ); sb.pathlen = strlen( sb.basepath )+ 1; printf( "%d %d '%s'\n", sb.baserev, sb.pathlen, sb.basepath ); revision.kind = svn_opt_revision_unspecified; /* lock everything readonly */ SVN_ERR( svn_wc_adm_open3( &sb.adm_access, NULL, sb.basepath, FALSE, -1, ctx->cancel_func, ctx->cancel_baton, pool ) ); err = svn_client_status2( 0 /* result_rev */, sb.basepath, &revision, status_func, &sb, TRUE /* recurse */, TRUE /* get_all */, FALSE /* update */, FALSE /* no_ignore */, TRUE /* ignore_externals */, ctx, pool ); err2 = svn_wc_adm_close( sb.adm_access ); if( err2 ) { svn_error_clear( err2 ); } return err; }