7777 mark it for removal?
7878*/
7979
80+ static svn_error_t *
81+ compare_exact (svn_boolean_t * modified_p ,
82+ svn_stream_t * stream ,
83+ const char * eol_str ,
84+ apr_hash_t * keywords ,
85+ const svn_checksum_t * pristine_checksum ,
86+ svn_stream_t * pristine_stream ,
87+ const char * pristine_eol_str ,
88+ apr_pool_t * scratch_pool )
89+ {
90+ svn_boolean_t same ;
91+
92+ /* For exact comparison, we check that contents remain the same when
93+ retranslated according to file properties. */
94+
95+ if (pristine_stream )
96+ {
97+ /* We have pristine contents: wrap a stream to translate it into working
98+ copy form, and check that contents remain the same. */
99+
100+ pristine_stream = svn_subst_stream_translated (pristine_stream ,
101+ eol_str , FALSE,
102+ keywords , TRUE,
103+ scratch_pool );
104+
105+ SVN_ERR (svn_stream_contents_same2 (& same , pristine_stream , stream ,
106+ scratch_pool ));
107+ }
108+ else
109+ {
110+ svn_checksum_t * working_checksum ;
111+ svn_checksum_t * detranslated_checksum ;
112+ svn_checksum_t * retranslated_checksum ;
113+
114+ /* We don't have pristine contents. To make the comparison work without
115+ it, let's check for two things:
116+
117+ 1) That the checksum of the detranslated contents matches the recorded
118+ pristine checksum, as in the case of a non-exact comparison, ...
119+
120+ 2) ...and additionally, that the contents of the working file does not
121+ change when retranslated according to its properties.
122+
123+ Technically we're going to do that with a single read of the file
124+ contents, while checksumming it's original, detranslated and
125+ retranslated versions.
126+ */
127+
128+ stream = svn_stream_checksummed2 (stream ,
129+ & working_checksum , NULL ,
130+ pristine_checksum -> kind , TRUE,
131+ scratch_pool );
132+
133+ stream = svn_subst_stream_translated (stream ,
134+ pristine_eol_str , TRUE,
135+ keywords , FALSE,
136+ scratch_pool );
137+ stream = svn_stream_checksummed2 (stream ,
138+ & detranslated_checksum , NULL ,
139+ pristine_checksum -> kind , TRUE,
140+ scratch_pool );
141+
142+ stream = svn_subst_stream_translated (stream , eol_str , FALSE,
143+ keywords , TRUE,
144+ scratch_pool );
145+ stream = svn_stream_checksummed2 (stream ,
146+ & retranslated_checksum , NULL ,
147+ pristine_checksum -> kind , TRUE,
148+ scratch_pool );
149+
150+ SVN_ERR (svn_stream_copy3 (stream , svn_stream_empty (scratch_pool ),
151+ NULL , NULL , scratch_pool ));
152+
153+ same = svn_checksum_match (detranslated_checksum , pristine_checksum ) &&
154+ svn_checksum_match (working_checksum , retranslated_checksum );
155+ }
156+
157+ * modified_p = !same ;
158+ return SVN_NO_ERROR ;
159+ }
80160
81161/* Set *MODIFIED_P to TRUE if (after translation) VERSIONED_FILE_ABSPATH
82- * (of VERSIONED_FILE_SIZE bytes) differs from pristine file with checksum
83- * PRISTINE_CHECKSUM, else to FALSE if not.
162+ * (of VERSIONED_FILE_SIZE bytes) differs from PRISTINE_STREAM (of
163+ * PRISTINE_SIZE bytes with PRISTINE_CHECKSUM), else to FALSE if not.
164+ *
165+ * If PRISTINE_STREAM is NULL, perform checksum-based content comparison.
166+ * If PRISTINE_STREAM is not NULL, perform bytewise content comparison
167+ * against the provided stream. PRISTINE_STREAM will be closed before
168+ * a successful return.
84169 *
85170 * If EXACT_COMPARISON is FALSE, translate VERSIONED_FILE_ABSPATH's EOL
86171 * style and keywords to repository-normal form according to its properties,
87- * calculate checksum and compare the result with PRISTINE_CHECKSUM .
172+ * and compare the result with pristine contents .
88173 * If EXACT_COMPARISON is TRUE, also check that VERSIONED_FILE_ABSPATH
89174 * contents remains the same when retranslated according to its properties.
90175 *
94179 * PROPS_MOD should be TRUE if the file's properties have been changed,
95180 * otherwise FALSE.
96181 *
182+ *
97183 * DB is a wc_db; use SCRATCH_POOL for temporary allocation.
98184 */
99185static svn_error_t *
100186compare_and_verify (svn_boolean_t * modified_p ,
101187 svn_wc__db_t * db ,
102188 const char * versioned_file_abspath ,
103189 svn_filesize_t versioned_file_size ,
190+ svn_stream_t * pristine_stream ,
191+ svn_filesize_t pristine_size ,
104192 const svn_checksum_t * pristine_checksum ,
105193 svn_boolean_t has_props ,
106194 svn_boolean_t props_mod ,
@@ -113,8 +201,7 @@ compare_and_verify(svn_boolean_t *modified_p,
113201 svn_boolean_t special = FALSE;
114202 svn_boolean_t need_translation ;
115203 svn_stream_t * v_stream ; /* versioned_file */
116- svn_checksum_t * v_checksum ;
117- svn_error_t * err ;
204+ svn_boolean_t same ;
118205
119206 SVN_ERR_ASSERT (svn_dirent_is_absolute (versioned_file_abspath ));
120207
@@ -140,20 +227,15 @@ compare_and_verify(svn_boolean_t *modified_p,
140227 else
141228 need_translation = FALSE;
142229
143- if (! need_translation )
230+ /* Easy out check: different sizes with no translation mean the
231+ * file was modified. */
232+ if (!need_translation && versioned_file_size != pristine_size )
144233 {
145- svn_filesize_t pristine_size ;
234+ if (pristine_stream )
235+ SVN_ERR (svn_stream_close (pristine_stream ));
146236
147- SVN_ERR (svn_wc__db_pristine_read (NULL , & pristine_size , db ,
148- versioned_file_abspath , pristine_checksum ,
149- scratch_pool , scratch_pool ));
150-
151- if (versioned_file_size != pristine_size )
152- {
153- * modified_p = TRUE;
154-
155- return SVN_NO_ERROR ;
156- }
237+ * modified_p = TRUE;
238+ return SVN_NO_ERROR ;
157239 }
158240
159241 /* ### Other checks possible? */
@@ -169,13 +251,8 @@ compare_and_verify(svn_boolean_t *modified_p,
169251 /* We don't use APR-level buffering because the comparison function
170252 * will do its own buffering. */
171253 apr_file_t * file ;
172- err = svn_io_file_open (& file , versioned_file_abspath , APR_READ ,
173- APR_OS_DEFAULT , scratch_pool );
174- /* Convert EACCESS on working copy path to WC specific error code. */
175- if (err && APR_STATUS_IS_EACCES (err -> apr_err ))
176- return svn_error_create (SVN_ERR_WC_PATH_ACCESS_DENIED , err , NULL );
177- else
178- SVN_ERR (err );
254+ SVN_ERR (svn_io_file_open (& file , versioned_file_abspath , APR_READ ,
255+ APR_OS_DEFAULT , scratch_pool ));
179256 v_stream = svn_stream_from_aprfile2 (file , FALSE, scratch_pool );
180257
181258 if (need_translation )
@@ -188,79 +265,41 @@ compare_and_verify(svn_boolean_t *modified_p,
188265 pristine_eol_str = eol_str ;
189266
190267 if (exact_comparison )
191- {
192- svn_checksum_t * working_checksum ;
193- svn_checksum_t * detranslated_checksum ;
194- svn_checksum_t * retranslated_checksum ;
195-
196- v_stream = svn_stream_checksummed2 (v_stream ,
197- & working_checksum , NULL ,
198- pristine_checksum -> kind , TRUE,
199- scratch_pool );
200-
201- v_stream = svn_subst_stream_translated (v_stream ,
202- pristine_eol_str , TRUE,
203- keywords , FALSE,
204- scratch_pool );
205- v_stream = svn_stream_checksummed2 (v_stream ,
206- & detranslated_checksum , NULL ,
207- pristine_checksum -> kind , TRUE,
208- scratch_pool );
209-
210- v_stream = svn_subst_stream_translated (v_stream , eol_str , FALSE,
211- keywords , TRUE,
212- scratch_pool );
213- v_stream = svn_stream_checksummed2 (v_stream ,
214- & retranslated_checksum , NULL ,
215- pristine_checksum -> kind , TRUE,
268+ return svn_error_trace (compare_exact (modified_p ,
269+ v_stream , eol_str , keywords ,
270+ pristine_checksum ,
271+ pristine_stream ,
272+ pristine_eol_str ,
273+ scratch_pool ));
274+
275+ /* Wrap file stream to detranslate into normal form,
276+ * "repairing" the EOL style if it is inconsistent. */
277+ v_stream = svn_subst_stream_translated (v_stream ,
278+ pristine_eol_str ,
279+ TRUE /* repair */ ,
280+ keywords ,
281+ FALSE /* expand */ ,
216282 scratch_pool );
217-
218- err = svn_stream_copy3 (v_stream , svn_stream_empty (scratch_pool ),
219- NULL , NULL , scratch_pool );
220- /* Convert EACCESS on working copy path to WC specific error code. */
221- if (err && APR_STATUS_IS_EACCES (err -> apr_err ))
222- return svn_error_create (SVN_ERR_WC_PATH_ACCESS_DENIED , err , NULL );
223- else
224- SVN_ERR (err );
225-
226- if (svn_checksum_match (detranslated_checksum , pristine_checksum ) &&
227- svn_checksum_match (working_checksum , retranslated_checksum ))
228- {
229- * modified_p = FALSE;
230- }
231- else
232- {
233- * modified_p = TRUE;
234- }
235-
236- return SVN_NO_ERROR ;
237- }
238- else
239- {
240- /* Wrap file stream to detranslate into normal form,
241- * "repairing" the EOL style if it is inconsistent. */
242- v_stream = svn_subst_stream_translated (v_stream ,
243- pristine_eol_str ,
244- TRUE /* repair */ ,
245- keywords ,
246- FALSE /* expand */ ,
247- scratch_pool );
248- }
249283 }
250284 }
251285
252- /* Get checksum of detranslated (normalized) content. */
253- err = svn_stream_contents_checksum (& v_checksum , v_stream ,
254- pristine_checksum -> kind ,
255- scratch_pool , scratch_pool );
256- /* Convert EACCESS on working copy path to WC specific error code. */
257- if (err && APR_STATUS_IS_EACCES (err -> apr_err ))
258- return svn_error_create (SVN_ERR_WC_PATH_ACCESS_DENIED , err , NULL );
286+ if (pristine_stream )
287+ {
288+ SVN_ERR (svn_stream_contents_same2 (& same , pristine_stream , v_stream ,
289+ scratch_pool ));
290+ }
259291 else
260- SVN_ERR (err );
292+ {
293+ svn_checksum_t * v_checksum ;
261294
262- * modified_p = (! svn_checksum_match (v_checksum , pristine_checksum ));
295+ SVN_ERR (svn_stream_contents_checksum (& v_checksum , v_stream ,
296+ pristine_checksum -> kind ,
297+ scratch_pool ,
298+ scratch_pool ));
299+ same = svn_checksum_match (v_checksum , pristine_checksum );
300+ }
263301
302+ * modified_p = !same ;
264303 return SVN_NO_ERROR ;
265304}
266305
@@ -279,6 +318,9 @@ svn_wc__internal_file_modified_p(svn_boolean_t *modified_p,
279318 svn_boolean_t has_props ;
280319 svn_boolean_t props_mod ;
281320 const svn_io_dirent2_t * dirent ;
321+ svn_stream_t * pristine_stream ;
322+ svn_filesize_t pristine_size ;
323+ svn_error_t * err ;
282324
283325 /* Read the relevant info */
284326 SVN_ERR (svn_wc__db_read_info (& status , & kind , NULL , NULL , NULL , NULL , NULL ,
@@ -358,12 +400,23 @@ svn_wc__internal_file_modified_p(svn_boolean_t *modified_p,
358400 }
359401
360402 compare_them :
361- /* Check all bytes, and verify checksum if requested. */
362- SVN_ERR (compare_and_verify (modified_p , db ,
363- local_abspath , dirent -> filesize ,
364- checksum , has_props , props_mod ,
365- exact_comparison ,
366- scratch_pool ));
403+ SVN_ERR (svn_wc__db_pristine_read (& pristine_stream , & pristine_size ,
404+ db , local_abspath , checksum ,
405+ scratch_pool , scratch_pool ));
406+
407+ err = compare_and_verify (modified_p , db ,
408+ local_abspath , dirent -> filesize ,
409+ pristine_stream , pristine_size ,
410+ checksum , has_props , props_mod ,
411+ exact_comparison ,
412+ scratch_pool );
413+
414+ /* At this point we already opened the pristine file, so we know that
415+ the access denied applies to the working copy path. */
416+ if (err && APR_STATUS_IS_EACCES (err -> apr_err ))
417+ return svn_error_create (SVN_ERR_WC_PATH_ACCESS_DENIED , err , NULL );
418+ else
419+ SVN_ERR (err );
367420
368421 if (!* modified_p )
369422 {
0 commit comments