/** * Create a new temporary file in @a dstPath. If @a dstPath * is empty (""), then construct the temporary filename * from the temporary directory and the filename component * of @a path. The file-extension of @a path will be transformed * to @a dstPath and @a dstPath will be a unique filename * * @param dstPath path to temporary file. Will be constructed * from @a path and temporary dir (and unique elements) * if empty string * @param path existing filename. Necessary only for construction * of @a dstPath * @param pool pool to use * @return open file */ static apr_file_t * openTempFile(Path & dstPath, const Path & path, const Revision & revision, Pool & pool) throw(ClientException) { apr_file_t * file = 0; if (dstPath.length() > 0) { apr_status_t status = apr_file_open(&file, dstPath.c_str(), APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY, APR_OS_DEFAULT, pool); if (status != 0) throw ClientException(status); } else { // split the path into its components std::string dir, filename, ext; path.split(dir, filename, ext); // add the revision number to the filename char revstring[20]; if (revision.kind() == revision.HEAD) strcpy(revstring, "HEAD"); else sprintf(revstring, "%" SVN_REVNUM_T_FMT, revision.revnum()); filename += "-"; filename += revstring; // replace the dir component with tempdir Path tempPath = Path::getTempDir(); tempPath.addComponent(filename); const char * unique_name; svn_error_t * error = svn_io_open_unique_file( &file, &unique_name, tempPath.c_str(), // path ext.c_str(), // suffix 0, // dont delete on close pool); if (error != 0) throw ClientException(error); dstPath = unique_name; } return file; }
void open_unique_file( const std::string &tmp_dir ) { #if defined( PYSVN_HAS_IO_OPEN_UNIQUE_FILE3 ) svn_error_t *error = svn_io_open_unique_file3 ( &m_apr_file, &m_filename, tmp_dir.c_str(), svn_io_file_del_none, m_pool, m_pool ); #elif defined( PYSVN_HAS_IO_OPEN_UNIQUE_FILE2 ) svn_error_t *error = svn_io_open_unique_file2 ( &m_apr_file, &m_filename, tmp_dir.c_str(), ".tmp", svn_io_file_del_none, m_pool ); #else svn_error_t *error = svn_io_open_unique_file ( &m_apr_file, &m_filename, tmp_dir.c_str(), ".tmp", false, m_pool ); #endif if( error != NULL ) { throw SvnException( error ); } }
std::string Client::diff(const Path & tmpPath, const Path & path, const Revision & revision1, const Revision & revision2, const bool recurse, const bool ignoreAncestry, const bool noDiffDeleted) throw(ClientException) { Pool pool; svn_error_t * error; apr_status_t status; apr_file_t * outfile = nullptr; const char * outfileName = nullptr; apr_file_t * errfile = nullptr; const char * errfileName = nullptr; apr_array_header_t * options; svn_stringbuf_t * stringbuf; // svn_client_diff needs an options array, even if it is empty options = apr_array_make(pool, 0, 0); // svn_client_diff needs a temporary file to write diff output to error = svn_io_open_unique_file(&outfile, &outfileName, tmpPath.c_str(), ".tmp", false, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } // and another one to write errors to error = svn_io_open_unique_file(&errfile, &errfileName, tmpPath.c_str(), ".tmp", false, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } // run diff error = svn_client_diff(options, path.c_str(), revision1.revision(), path.c_str(), revision2.revision(), recurse, ignoreAncestry, noDiffDeleted, outfile, errfile, *m_context, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } // then we reopen outfile for reading status = apr_file_close(outfile); if (status) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); fail(pool, status, "failed to close '%s'", outfileName); } status = apr_file_open(&outfile, outfileName, APR_READ, APR_OS_DEFAULT, pool); if (status) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); fail(pool, status, "failed to open '%s'", outfileName); } // now we can read the diff output from outfile and return that error = svn_stringbuf_from_aprfile(&stringbuf, outfile, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } diffCleanup(outfile, outfileName, errfile, errfileName, pool); return stringbuf->data; }
static svn_error_t * do_blame (const char *target, svn_ra_plugin_t *ra_lib, void *ra_session, struct file_rev_baton *frb) { struct log_message_baton lmb; apr_array_header_t *condensed_targets; apr_file_t *file; svn_stream_t *stream; struct rev *rev; svn_node_kind_t kind; apr_pool_t *pool = frb->mainpool; SVN_ERR (ra_lib->check_path (ra_session, target, frb->end_rev, &kind, pool)); if (kind == svn_node_dir) return svn_error_createf (SVN_ERR_CLIENT_IS_DIRECTORY, NULL, ("URL '%s' refers to a directory"), target); condensed_targets = apr_array_make (pool, 1, sizeof (const char *)); (*((const char **)apr_array_push (condensed_targets))) = ""; lmb.path = apr_pstrcat(pool, "/", target, NULL); lmb.eldest = NULL; lmb.pool = pool; /* Accumulate revision metadata by walking the revisions backwards; this allows us to follow moves/copies correctly. */ SVN_ERR (ra_lib->get_log (ra_session, condensed_targets, frb->end_rev, frb->start_rev, TRUE, FALSE, log_message_receiver, &lmb, pool)); /* Inspect the first revision's change metadata; if there are any prior revisions, compute a new starting revision/path. If no revisions were selected, no blame is assigned. A modified item certainly has a prior revision. It is reasonable for an added item to have none, but anything else is unexpected. */ if (!lmb.eldest) { lmb.eldest = apr_palloc (pool, sizeof (*rev)); lmb.eldest->revision = frb->end_rev; lmb.eldest->path = lmb.path; lmb.eldest->next = NULL; rev = apr_palloc (pool, sizeof (*rev)); rev->revision = SVN_INVALID_REVNUM; rev->author = NULL; rev->date = NULL; frb->blame = blame_create (frb, rev, 0); } else if (lmb.action == 'M' || SVN_IS_VALID_REVNUM (lmb.copyrev)) { rev = apr_palloc (pool, sizeof (*rev)); if (SVN_IS_VALID_REVNUM (lmb.copyrev)) rev->revision = lmb.copyrev; else rev->revision = lmb.eldest->revision - 1; rev->path = lmb.path; rev->next = lmb.eldest; lmb.eldest = rev; rev = apr_palloc (pool, sizeof (*rev)); rev->revision = SVN_INVALID_REVNUM; rev->author = NULL; rev->date = NULL; frb->blame = blame_create (frb, rev, 0); } else if (lmb.action == 'A') { frb->blame = blame_create (frb, lmb.eldest, 0); } else return svn_error_createf (APR_EGENERAL, NULL, ("Revision action '%c' for " "revision %ld of '%s' " "lacks a prior revision"), lmb.action, lmb.eldest->revision, lmb.eldest->path); /* Walk the revision list in chronological order, downloading each fulltext, diffing it with its predecessor, and accumulating the blame information into db.blame. Use two iteration pools rather than one, because the diff routines need to look at a sliding window of revisions. Two pools gives us a ring buffer of sorts. */ for (rev = lmb.eldest; rev; rev = rev->next) { const char *tmp; const char *temp_dir; apr_hash_t *props; svn_string_t *mimetype; apr_pool_clear (frb->currpool); SVN_ERR (svn_io_temp_dir (&temp_dir, frb->currpool)); SVN_ERR (svn_io_open_unique_file (&file, &tmp, svn_path_join (temp_dir, "tmp", frb->currpool), ".tmp", FALSE, frb->currpool)); apr_pool_cleanup_register (frb->currpool, file, cleanup_tempfile, apr_pool_cleanup_null); stream = svn_stream_from_aprfile (file, frb->currpool); SVN_ERR (ra_lib->get_file(ra_session, rev->path + 1, rev->revision, stream, NULL, &props, frb->currpool)); SVN_ERR (svn_stream_close (stream)); SVN_ERR (svn_io_file_close (file, frb->currpool)); /* If this file has a non-textual mime-type, bail out. */ if (props && ((mimetype = apr_hash_get (props, SVN_PROP_MIME_TYPE, sizeof (SVN_PROP_MIME_TYPE) - 1)))) { if (svn_mime_type_is_binary (mimetype->data)) return svn_error_createf (SVN_ERR_CLIENT_IS_BINARY_FILE, 0, ("Cannot calculate blame information for binary file '%s'"),target); } if (frb->last_filename) { frb->rev = rev; SVN_ERR (add_file_blame (frb->last_filename, tmp, frb)); } frb->last_filename = tmp; { apr_pool_t *tmppool = frb->currpool; frb->currpool = frb->lastpool; frb->lastpool = tmppool; } } return SVN_NO_ERROR; }