@@ -85,6 +85,70 @@ pub struct IndexEntry {
8585 pub path : Vec < u8 > ,
8686}
8787
88+ // We cannot return raw::git_index_entry instances directly, as they rely on
89+ // a CString which is owned by the function. To make the pointer to the CString
90+ // valid during usage of raw::git_index_entry, we supply the index entry in a
91+ // callback where pointers to the CString are valid.
92+ fn try_raw_entries (
93+ entries : & [ Option < & IndexEntry > ] ,
94+ cb : impl FnOnce ( & [ * const raw:: git_index_entry ] ) -> Result < ( ) , Error > ,
95+ ) -> Result < ( ) , Error > {
96+ let paths = entries. iter ( )
97+ . map ( |entry| {
98+ if let Some ( entry) = entry {
99+ CString :: new ( & entry. path [ ..] ) . map ( |ok| Some ( ok) )
100+ } else {
101+ Ok ( None )
102+ }
103+ } )
104+ . collect :: < Result < Vec < Option < CString > > , std:: ffi:: NulError > > ( ) ?;
105+
106+ let raw_entries = entries. iter ( ) . zip ( & paths) . map ( |( entry, path) | {
107+ if let Some ( entry) = entry {
108+ // libgit2 encodes the length of the path in the lower bits of the
109+ // `flags` entry, so mask those out and recalculate here to ensure we
110+ // don't corrupt anything.
111+ let mut flags = entry. flags & !raw:: GIT_INDEX_ENTRY_NAMEMASK ;
112+
113+ if entry. path . len ( ) < raw:: GIT_INDEX_ENTRY_NAMEMASK as usize {
114+ flags |= entry. path . len ( ) as u16 ;
115+ } else {
116+ flags |= raw:: GIT_INDEX_ENTRY_NAMEMASK ;
117+ }
118+
119+ unsafe {
120+ Some ( raw:: git_index_entry {
121+ dev : entry. dev ,
122+ ino : entry. ino ,
123+ mode : entry. mode ,
124+ uid : entry. uid ,
125+ gid : entry. gid ,
126+ file_size : entry. file_size ,
127+ id : * entry. id . raw ( ) ,
128+ flags,
129+ flags_extended : entry. flags_extended ,
130+ path : path. as_ref ( ) . unwrap ( ) . as_ptr ( ) ,
131+ mtime : raw:: git_index_time {
132+ seconds : entry. mtime . seconds ( ) ,
133+ nanoseconds : entry. mtime . nanoseconds ( ) ,
134+ } ,
135+ ctime : raw:: git_index_time {
136+ seconds : entry. ctime . seconds ( ) ,
137+ nanoseconds : entry. ctime . nanoseconds ( ) ,
138+ } ,
139+ } )
140+ }
141+ } else {
142+ None
143+ }
144+ } ) . collect :: < Vec < _ > > ( ) ;
145+ let raw_entry_ptrs = raw_entries. iter ( )
146+ . map ( |opt| opt. as_ref ( ) . map_or_else ( std:: ptr:: null, |ptr| ptr) )
147+ . collect :: < Vec < _ > > ( ) ;
148+
149+ cb ( & raw_entry_ptrs)
150+ }
151+
88152impl Index {
89153 /// Creates a new in-memory index.
90154 ///
@@ -145,43 +209,12 @@ impl Index {
145209 /// given 'source_entry', it will be replaced. Otherwise, the 'source_entry'
146210 /// will be added.
147211 pub fn add ( & mut self , entry : & IndexEntry ) -> Result < ( ) , Error > {
148- let path = CString :: new ( & entry. path [ ..] ) ?;
149-
150- // libgit2 encodes the length of the path in the lower bits of the
151- // `flags` entry, so mask those out and recalculate here to ensure we
152- // don't corrupt anything.
153- let mut flags = entry. flags & !raw:: GIT_INDEX_ENTRY_NAMEMASK ;
154-
155- if entry. path . len ( ) < raw:: GIT_INDEX_ENTRY_NAMEMASK as usize {
156- flags |= entry. path . len ( ) as u16 ;
157- } else {
158- flags |= raw:: GIT_INDEX_ENTRY_NAMEMASK ;
159- }
160-
161- unsafe {
162- let raw = raw:: git_index_entry {
163- dev : entry. dev ,
164- ino : entry. ino ,
165- mode : entry. mode ,
166- uid : entry. uid ,
167- gid : entry. gid ,
168- file_size : entry. file_size ,
169- id : * entry. id . raw ( ) ,
170- flags,
171- flags_extended : entry. flags_extended ,
172- path : path. as_ptr ( ) ,
173- mtime : raw:: git_index_time {
174- seconds : entry. mtime . seconds ( ) ,
175- nanoseconds : entry. mtime . nanoseconds ( ) ,
176- } ,
177- ctime : raw:: git_index_time {
178- seconds : entry. ctime . seconds ( ) ,
179- nanoseconds : entry. ctime . nanoseconds ( ) ,
180- } ,
181- } ;
182- try_call ! ( raw:: git_index_add( self . raw, & raw) ) ;
212+ try_raw_entries ( & [ Some ( entry) ] , |raws| {
213+ unsafe {
214+ try_call ! ( raw:: git_index_add( self . raw, raws[ 0 ] ) ) ;
215+ }
183216 Ok ( ( ) )
184- }
217+ } )
185218 }
186219
187220 /// Add or update an index entry from a buffer in memory
@@ -202,46 +235,14 @@ impl Index {
202235 /// no longer be marked as conflicting. The data about the conflict will be
203236 /// moved to the "resolve undo" (REUC) section.
204237 pub fn add_frombuffer ( & mut self , entry : & IndexEntry , data : & [ u8 ] ) -> Result < ( ) , Error > {
205- let path = CString :: new ( & entry. path [ ..] ) ?;
206-
207- // libgit2 encodes the length of the path in the lower bits of the
208- // `flags` entry, so mask those out and recalculate here to ensure we
209- // don't corrupt anything.
210- let mut flags = entry. flags & !raw:: GIT_INDEX_ENTRY_NAMEMASK ;
211-
212- if entry. path . len ( ) < raw:: GIT_INDEX_ENTRY_NAMEMASK as usize {
213- flags |= entry. path . len ( ) as u16 ;
214- } else {
215- flags |= raw:: GIT_INDEX_ENTRY_NAMEMASK ;
216- }
217-
218- unsafe {
219- let raw = raw:: git_index_entry {
220- dev : entry. dev ,
221- ino : entry. ino ,
222- mode : entry. mode ,
223- uid : entry. uid ,
224- gid : entry. gid ,
225- file_size : entry. file_size ,
226- id : * entry. id . raw ( ) ,
227- flags,
228- flags_extended : entry. flags_extended ,
229- path : path. as_ptr ( ) ,
230- mtime : raw:: git_index_time {
231- seconds : entry. mtime . seconds ( ) ,
232- nanoseconds : entry. mtime . nanoseconds ( ) ,
233- } ,
234- ctime : raw:: git_index_time {
235- seconds : entry. ctime . seconds ( ) ,
236- nanoseconds : entry. ctime . nanoseconds ( ) ,
237- } ,
238- } ;
239-
240- let ptr = data. as_ptr ( ) as * const c_void ;
241- let len = data. len ( ) as size_t ;
242- try_call ! ( raw:: git_index_add_frombuffer( self . raw, & raw, ptr, len) ) ;
238+ try_raw_entries ( & [ Some ( entry) ] , |raws| {
239+ unsafe {
240+ let ptr = data. as_ptr ( ) as * const c_void ;
241+ let len = data. len ( ) as size_t ;
242+ try_call ! ( raw:: git_index_add_frombuffer( self . raw, raws[ 0 ] , ptr, len) ) ;
243+ }
243244 Ok ( ( ) )
244- }
245+ } )
245246 }
246247
247248 /// Add or update an index entry from a file on disk
@@ -425,124 +426,17 @@ impl Index {
425426 our_entry : Option < & IndexEntry > ,
426427 their_entry : Option < & IndexEntry > ,
427428 ) -> Result < ( ) , Error > {
428- let mut ancestor_raw: Option < raw:: git_index_entry > = None ;
429- let mut our_raw: Option < raw:: git_index_entry > = None ;
430- let mut their_raw: Option < raw:: git_index_entry > = None ;
431-
432- if let Some ( ancestor_entry) = ancestor_entry {
433- let ancestor_path = CString :: new ( & ancestor_entry. path [ ..] ) ?;
434- let mut ancestor_flags = ancestor_entry. flags & !raw:: GIT_INDEX_ENTRY_NAMEMASK ;
435-
436- if ancestor_entry. path . len ( ) < raw:: GIT_INDEX_ENTRY_NAMEMASK as usize {
437- ancestor_flags |= ancestor_entry. path . len ( ) as u16 ;
438- } else {
439- ancestor_flags |= raw:: GIT_INDEX_ENTRY_NAMEMASK ;
440- }
441-
442- unsafe {
443- ancestor_raw = Some ( raw:: git_index_entry {
444- dev : ancestor_entry. dev ,
445- ino : ancestor_entry. ino ,
446- mode : ancestor_entry. mode ,
447- uid : ancestor_entry. uid ,
448- gid : ancestor_entry. gid ,
449- file_size : ancestor_entry. file_size ,
450- id : * ancestor_entry. id . raw ( ) ,
451- flags : ancestor_flags,
452- flags_extended : ancestor_entry. flags_extended ,
453- path : ancestor_path. as_ptr ( ) ,
454- mtime : raw:: git_index_time {
455- seconds : ancestor_entry. mtime . seconds ( ) ,
456- nanoseconds : ancestor_entry. mtime . nanoseconds ( ) ,
457- } ,
458- ctime : raw:: git_index_time {
459- seconds : ancestor_entry. ctime . seconds ( ) ,
460- nanoseconds : ancestor_entry. ctime . nanoseconds ( ) ,
461- } ,
462- } ) ;
463- }
464- }
465-
466- if let Some ( our_entry) = our_entry {
467- let our_path = CString :: new ( & our_entry. path [ ..] ) ?;
468- let mut our_flags = our_entry. flags & !raw:: GIT_INDEX_ENTRY_NAMEMASK ;
469-
470- if our_entry. path . len ( ) < raw:: GIT_INDEX_ENTRY_NAMEMASK as usize {
471- our_flags |= our_entry. path . len ( ) as u16 ;
472- } else {
473- our_flags |= raw:: GIT_INDEX_ENTRY_NAMEMASK ;
474- }
475-
476- unsafe {
477- our_raw = Some ( raw:: git_index_entry {
478- dev : our_entry. dev ,
479- ino : our_entry. ino ,
480- mode : our_entry. mode ,
481- uid : our_entry. uid ,
482- gid : our_entry. gid ,
483- file_size : our_entry. file_size ,
484- id : * our_entry. id . raw ( ) ,
485- flags : our_flags,
486- flags_extended : our_entry. flags_extended ,
487- path : our_path. as_ptr ( ) ,
488- mtime : raw:: git_index_time {
489- seconds : our_entry. mtime . seconds ( ) ,
490- nanoseconds : our_entry. mtime . nanoseconds ( ) ,
491- } ,
492- ctime : raw:: git_index_time {
493- seconds : our_entry. ctime . seconds ( ) ,
494- nanoseconds : our_entry. ctime . nanoseconds ( ) ,
495- } ,
496- } ) ;
497- }
498- }
499-
500- if let Some ( their_entry) = their_entry {
501- let their_path = CString :: new ( & their_entry. path [ ..] ) ?;
502- let mut their_flags = their_entry. flags & !raw:: GIT_INDEX_ENTRY_NAMEMASK ;
503-
504- if their_entry. path . len ( ) < raw:: GIT_INDEX_ENTRY_NAMEMASK as usize {
505- their_flags |= their_entry. path . len ( ) as u16 ;
506- } else {
507- their_flags |= raw:: GIT_INDEX_ENTRY_NAMEMASK ;
508- }
509-
429+ try_raw_entries ( & [ ancestor_entry, our_entry, their_entry] , |raw_entries| {
510430 unsafe {
511- their_raw = Some ( raw:: git_index_entry {
512- dev : their_entry. dev ,
513- ino : their_entry. ino ,
514- mode : their_entry. mode ,
515- uid : their_entry. uid ,
516- gid : their_entry. gid ,
517- file_size : their_entry. file_size ,
518- id : * their_entry. id . raw ( ) ,
519- flags : their_flags,
520- flags_extended : their_entry. flags_extended ,
521- path : their_path. as_ptr ( ) ,
522- mtime : raw:: git_index_time {
523- seconds : their_entry. mtime . seconds ( ) ,
524- nanoseconds : their_entry. mtime . nanoseconds ( ) ,
525- } ,
526- ctime : raw:: git_index_time {
527- seconds : their_entry. ctime . seconds ( ) ,
528- nanoseconds : their_entry. ctime . nanoseconds ( ) ,
529- } ,
530- } ) ;
431+ try_call ! ( raw:: git_index_conflict_add(
432+ self . raw,
433+ raw_entries[ 0 ] ,
434+ raw_entries[ 1 ] ,
435+ raw_entries[ 2 ]
436+ ) ) ;
437+ Ok ( ( ) )
531438 }
532- }
533-
534- let ancestor_raw_ptr = ancestor_raw. as_ref ( ) . map_or_else ( std:: ptr:: null, |ptr| ptr) ;
535- let our_raw_ptr = our_raw. as_ref ( ) . map_or_else ( std:: ptr:: null, |ptr| ptr) ;
536- let their_raw_ptr = their_raw. as_ref ( ) . map_or_else ( std:: ptr:: null, |ptr| ptr) ;
537- unsafe {
538- try_call ! ( raw:: git_index_conflict_add(
539- self . raw,
540- ancestor_raw_ptr,
541- our_raw_ptr,
542- their_raw_ptr
543- ) ) ;
544- Ok ( ( ) )
545- }
439+ } )
546440 }
547441
548442 /// Remove all conflicts in the index (entries with a stage greater than 0).
0 commit comments