Skip to content

Commit 96c6508

Browse files
committed
Add helper function to construct raw::git_index_entry's
1 parent 65b1ca1 commit 96c6508

File tree

1 file changed

+85
-191
lines changed

1 file changed

+85
-191
lines changed

src/index.rs

+85-191
Original file line numberDiff line numberDiff line change
@@ -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+
88152
impl 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

Comments
 (0)