1use std::ffi::{CStr, CString};
2use std::marker;
3use std::ops::Range;
4use std::path::Path;
5use std::ptr;
6use std::slice;
7
8use libc::{c_char, c_int, c_uint, c_void, size_t};
9
10use crate::util::{self, path_to_repo_path, Binding};
11use crate::IntoCString;
12use crate::{panic, raw, Error, IndexAddOption, IndexTime, Oid, Repository, Tree};
13
14pub struct Index {
18    raw: *mut raw::git_index,
19}
20
21pub struct IndexEntries<'index> {
23    range: Range<usize>,
24    index: &'index Index,
25}
26
27pub struct IndexConflicts<'index> {
29    conflict_iter: *mut raw::git_index_conflict_iterator,
30    _marker: marker::PhantomData<&'index Index>,
31}
32
33pub struct IndexConflict {
35    pub ancestor: Option<IndexEntry>,
37    pub our: Option<IndexEntry>,
40    pub their: Option<IndexEntry>,
43}
44
45pub type IndexMatchedPath<'a> = dyn FnMut(&Path, &[u8]) -> i32 + 'a;
51
52#[allow(missing_docs)]
57#[derive(Debug)]
58pub struct IndexEntry {
59    pub ctime: IndexTime,
60    pub mtime: IndexTime,
61    pub dev: u32,
62    pub ino: u32,
63    pub mode: u32,
64    pub uid: u32,
65    pub gid: u32,
66    pub file_size: u32,
67    pub id: Oid,
68    pub flags: u16,
69    pub flags_extended: u16,
70
71    pub path: Vec<u8>,
86}
87
88impl Index {
89    pub fn new() -> Result<Index, Error> {
94        crate::init();
95        let mut raw = ptr::null_mut();
96        unsafe {
97            try_call!(raw::git_index_new(&mut raw));
98            Ok(Binding::from_raw(raw))
99        }
100    }
101
102    pub fn open(index_path: &Path) -> Result<Index, Error> {
111        crate::init();
112        let mut raw = ptr::null_mut();
113        let index_path = index_path.into_c_string()?;
115        unsafe {
116            try_call!(raw::git_index_open(&mut raw, index_path));
117            Ok(Binding::from_raw(raw))
118        }
119    }
120
121    pub fn version(&self) -> u32 {
127        unsafe { raw::git_index_version(self.raw) }
128    }
129
130    pub fn set_version(&mut self, version: u32) -> Result<(), Error> {
136        unsafe {
137            try_call!(raw::git_index_set_version(self.raw, version));
138        }
139        Ok(())
140    }
141
142    pub fn add(&mut self, entry: &IndexEntry) -> Result<(), Error> {
148        let path = CString::new(&entry.path[..])?;
149
150        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));
183            Ok(())
184        }
185    }
186
187    pub fn add_frombuffer(&mut self, entry: &IndexEntry, data: &[u8]) -> Result<(), Error> {
205        let path = CString::new(&entry.path[..])?;
206
207        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));
243            Ok(())
244        }
245    }
246
247    pub fn add_path(&mut self, path: &Path) -> Result<(), Error> {
261        let posix_path = path_to_repo_path(path)?;
262        unsafe {
263            try_call!(raw::git_index_add_bypath(self.raw, posix_path));
264            Ok(())
265        }
266    }
267
268    pub fn add_all<T, I>(
315        &mut self,
316        pathspecs: I,
317        flag: IndexAddOption,
318        mut cb: Option<&mut IndexMatchedPath<'_>>,
319    ) -> Result<(), Error>
320    where
321        T: IntoCString,
322        I: IntoIterator<Item = T>,
323    {
324        let (_a, _b, raw_strarray) = crate::util::iter2cstrs_paths(pathspecs)?;
325        let ptr = cb.as_mut();
326        let callback = ptr
327            .as_ref()
328            .map(|_| index_matched_path_cb as extern "C" fn(_, _, _) -> _);
329        unsafe {
330            try_call!(raw::git_index_add_all(
331                self.raw,
332                &raw_strarray,
333                flag.bits() as c_uint,
334                callback,
335                ptr.map(|p| p as *mut _).unwrap_or(ptr::null_mut()) as *mut c_void
336            ));
337        }
338        Ok(())
339    }
340
341    pub fn clear(&mut self) -> Result<(), Error> {
346        unsafe {
347            try_call!(raw::git_index_clear(self.raw));
348        }
349        Ok(())
350    }
351
352    pub fn len(&self) -> usize {
354        unsafe { raw::git_index_entrycount(&*self.raw) as usize }
355    }
356
357    pub fn is_empty(&self) -> bool {
359        self.len() == 0
360    }
361
362    pub fn get(&self, n: usize) -> Option<IndexEntry> {
364        unsafe {
365            let ptr = raw::git_index_get_byindex(self.raw, n as size_t);
366            if ptr.is_null() {
367                None
368            } else {
369                Some(Binding::from_raw(*ptr))
370            }
371        }
372    }
373
374    pub fn iter(&self) -> IndexEntries<'_> {
376        IndexEntries {
377            range: 0..self.len(),
378            index: self,
379        }
380    }
381
382    pub fn conflicts(&self) -> Result<IndexConflicts<'_>, Error> {
384        crate::init();
385        let mut conflict_iter = ptr::null_mut();
386        unsafe {
387            try_call!(raw::git_index_conflict_iterator_new(
388                &mut conflict_iter,
389                self.raw
390            ));
391            Ok(Binding::from_raw(conflict_iter))
392        }
393    }
394
395    pub fn get_path(&self, path: &Path, stage: i32) -> Option<IndexEntry> {
397        let path = path_to_repo_path(path).unwrap();
398        unsafe {
399            let ptr = call!(raw::git_index_get_bypath(self.raw, path, stage as c_int));
400            if ptr.is_null() {
401                None
402            } else {
403                Some(Binding::from_raw(*ptr))
404            }
405        }
406    }
407
408    pub fn has_conflicts(&self) -> bool {
412        unsafe { raw::git_index_has_conflicts(self.raw) == 1 }
413    }
414
415    pub fn conflict_get(&self, path: &Path) -> Result<IndexConflict, Error> {
417        let path = path_to_repo_path(path)?;
418        let mut ancestor = ptr::null();
419        let mut our = ptr::null();
420        let mut their = ptr::null();
421
422        unsafe {
423            try_call!(raw::git_index_conflict_get(
424                &mut ancestor,
425                &mut our,
426                &mut their,
427                self.raw,
428                path
429            ));
430
431            Ok(IndexConflict {
432                ancestor: match ancestor.is_null() {
433                    false => Some(IndexEntry::from_raw(*ancestor)),
434                    true => None,
435                },
436                our: match our.is_null() {
437                    false => Some(IndexEntry::from_raw(*our)),
438                    true => None,
439                },
440                their: match their.is_null() {
441                    false => Some(IndexEntry::from_raw(*their)),
442                    true => None,
443                },
444            })
445        }
446    }
447
448    pub fn path(&self) -> Option<&Path> {
452        unsafe { crate::opt_bytes(self, raw::git_index_path(&*self.raw)).map(util::bytes2path) }
453    }
454
455    pub fn read(&mut self, force: bool) -> Result<(), Error> {
467        unsafe {
468            try_call!(raw::git_index_read(self.raw, force));
469        }
470        Ok(())
471    }
472
473    pub fn read_tree(&mut self, tree: &Tree<'_>) -> Result<(), Error> {
477        unsafe {
478            try_call!(raw::git_index_read_tree(self.raw, &*tree.raw()));
479        }
480        Ok(())
481    }
482
483    pub fn remove(&mut self, path: &Path, stage: i32) -> Result<(), Error> {
485        let path = path_to_repo_path(path)?;
486        unsafe {
487            try_call!(raw::git_index_remove(self.raw, path, stage as c_int));
488        }
489        Ok(())
490    }
491
492    pub fn remove_path(&mut self, path: &Path) -> Result<(), Error> {
501        let path = path_to_repo_path(path)?;
502        unsafe {
503            try_call!(raw::git_index_remove_bypath(self.raw, path));
504        }
505        Ok(())
506    }
507
508    pub fn remove_dir(&mut self, path: &Path, stage: i32) -> Result<(), Error> {
510        let path = path_to_repo_path(path)?;
511        unsafe {
512            try_call!(raw::git_index_remove_directory(
513                self.raw,
514                path,
515                stage as c_int
516            ));
517        }
518        Ok(())
519    }
520
521    pub fn conflict_remove(&mut self, path: &Path) -> Result<(), Error> {
523        let path = path_to_repo_path(path)?;
524        unsafe {
525            try_call!(raw::git_index_conflict_remove(self.raw, path));
526        }
527        Ok(())
528    }
529
530    pub fn remove_all<T, I>(
536        &mut self,
537        pathspecs: I,
538        mut cb: Option<&mut IndexMatchedPath<'_>>,
539    ) -> Result<(), Error>
540    where
541        T: IntoCString,
542        I: IntoIterator<Item = T>,
543    {
544        let (_a, _b, raw_strarray) = crate::util::iter2cstrs_paths(pathspecs)?;
545        let ptr = cb.as_mut();
546        let callback = ptr
547            .as_ref()
548            .map(|_| index_matched_path_cb as extern "C" fn(_, _, _) -> _);
549        unsafe {
550            try_call!(raw::git_index_remove_all(
551                self.raw,
552                &raw_strarray,
553                callback,
554                ptr.map(|p| p as *mut _).unwrap_or(ptr::null_mut()) as *mut c_void
555            ));
556        }
557        Ok(())
558    }
559
560    pub fn update_all<T, I>(
574        &mut self,
575        pathspecs: I,
576        mut cb: Option<&mut IndexMatchedPath<'_>>,
577    ) -> Result<(), Error>
578    where
579        T: IntoCString,
580        I: IntoIterator<Item = T>,
581    {
582        let (_a, _b, raw_strarray) = crate::util::iter2cstrs_paths(pathspecs)?;
583        let ptr = cb.as_mut();
584        let callback = ptr
585            .as_ref()
586            .map(|_| index_matched_path_cb as extern "C" fn(_, _, _) -> _);
587        unsafe {
588            try_call!(raw::git_index_update_all(
589                self.raw,
590                &raw_strarray,
591                callback,
592                ptr.map(|p| p as *mut _).unwrap_or(ptr::null_mut()) as *mut c_void
593            ));
594        }
595        Ok(())
596    }
597
598    pub fn write(&mut self) -> Result<(), Error> {
601        unsafe {
602            try_call!(raw::git_index_write(self.raw));
603        }
604        Ok(())
605    }
606
607    pub fn write_tree(&mut self) -> Result<Oid, Error> {
619        let mut raw = raw::git_oid {
620            id: [0; raw::GIT_OID_RAWSZ],
621        };
622        unsafe {
623            try_call!(raw::git_index_write_tree(&mut raw, self.raw));
624            Ok(Binding::from_raw(&raw as *const _))
625        }
626    }
627
628    pub fn write_tree_to(&mut self, repo: &Repository) -> Result<Oid, Error> {
633        let mut raw = raw::git_oid {
634            id: [0; raw::GIT_OID_RAWSZ],
635        };
636        unsafe {
637            try_call!(raw::git_index_write_tree_to(&mut raw, self.raw, repo.raw()));
638            Ok(Binding::from_raw(&raw as *const _))
639        }
640    }
641
642    pub fn find_prefix<T: IntoCString>(&self, prefix: T) -> Result<usize, Error> {
646        let mut at_pos: size_t = 0;
647        let entry_path = prefix.into_c_string()?;
648        unsafe {
649            try_call!(raw::git_index_find_prefix(
650                &mut at_pos,
651                self.raw,
652                entry_path
653            ));
654            Ok(at_pos)
655        }
656    }
657}
658
659impl IndexEntry {
660    pub(crate) unsafe fn to_raw(&self) -> Result<(raw::git_index_entry, CString), Error> {
665        let path = CString::new(&self.path[..])?;
666
667        let mut flags = self.flags & !raw::GIT_INDEX_ENTRY_NAMEMASK;
671
672        if self.path.len() < raw::GIT_INDEX_ENTRY_NAMEMASK as usize {
673            flags |= self.path.len() as u16;
674        } else {
675            flags |= raw::GIT_INDEX_ENTRY_NAMEMASK;
676        }
677
678        unsafe {
679            let raw = raw::git_index_entry {
680                dev: self.dev,
681                ino: self.ino,
682                mode: self.mode,
683                uid: self.uid,
684                gid: self.gid,
685                file_size: self.file_size,
686                id: *self.id.raw(),
687                flags,
688                flags_extended: self.flags_extended,
689                path: path.as_ptr(),
690                mtime: raw::git_index_time {
691                    seconds: self.mtime.seconds(),
692                    nanoseconds: self.mtime.nanoseconds(),
693                },
694                ctime: raw::git_index_time {
695                    seconds: self.ctime.seconds(),
696                    nanoseconds: self.ctime.nanoseconds(),
697                },
698            };
699
700            Ok((raw, path))
701        }
702    }
703}
704
705impl Binding for Index {
706    type Raw = *mut raw::git_index;
707    unsafe fn from_raw(raw: *mut raw::git_index) -> Index {
708        Index { raw }
709    }
710    fn raw(&self) -> *mut raw::git_index {
711        self.raw
712    }
713}
714
715impl<'index> Binding for IndexConflicts<'index> {
716    type Raw = *mut raw::git_index_conflict_iterator;
717
718    unsafe fn from_raw(raw: *mut raw::git_index_conflict_iterator) -> IndexConflicts<'index> {
719        IndexConflicts {
720            conflict_iter: raw,
721            _marker: marker::PhantomData,
722        }
723    }
724    fn raw(&self) -> *mut raw::git_index_conflict_iterator {
725        self.conflict_iter
726    }
727}
728
729extern "C" fn index_matched_path_cb(
730    path: *const c_char,
731    matched_pathspec: *const c_char,
732    payload: *mut c_void,
733) -> c_int {
734    unsafe {
735        let path = CStr::from_ptr(path).to_bytes();
736        let matched_pathspec = CStr::from_ptr(matched_pathspec).to_bytes();
737
738        panic::wrap(|| {
739            let payload = payload as *mut &mut IndexMatchedPath<'_>;
740            (*payload)(util::bytes2path(path), matched_pathspec) as c_int
741        })
742        .unwrap_or(-1)
743    }
744}
745
746impl Drop for Index {
747    fn drop(&mut self) {
748        unsafe { raw::git_index_free(self.raw) }
749    }
750}
751
752impl<'index> Drop for IndexConflicts<'index> {
753    fn drop(&mut self) {
754        unsafe { raw::git_index_conflict_iterator_free(self.conflict_iter) }
755    }
756}
757
758impl<'index> Iterator for IndexEntries<'index> {
759    type Item = IndexEntry;
760    fn next(&mut self) -> Option<IndexEntry> {
761        self.range.next().map(|i| self.index.get(i).unwrap())
762    }
763}
764
765impl<'index> Iterator for IndexConflicts<'index> {
766    type Item = Result<IndexConflict, Error>;
767    fn next(&mut self) -> Option<Result<IndexConflict, Error>> {
768        let mut ancestor = ptr::null();
769        let mut our = ptr::null();
770        let mut their = ptr::null();
771        unsafe {
772            try_call_iter!(raw::git_index_conflict_next(
773                &mut ancestor,
774                &mut our,
775                &mut their,
776                self.conflict_iter
777            ));
778            Some(Ok(IndexConflict {
779                ancestor: match ancestor.is_null() {
780                    false => Some(IndexEntry::from_raw(*ancestor)),
781                    true => None,
782                },
783                our: match our.is_null() {
784                    false => Some(IndexEntry::from_raw(*our)),
785                    true => None,
786                },
787                their: match their.is_null() {
788                    false => Some(IndexEntry::from_raw(*their)),
789                    true => None,
790                },
791            }))
792        }
793    }
794}
795
796impl Binding for IndexEntry {
797    type Raw = raw::git_index_entry;
798
799    unsafe fn from_raw(raw: raw::git_index_entry) -> IndexEntry {
800        let raw::git_index_entry {
801            ctime,
802            mtime,
803            dev,
804            ino,
805            mode,
806            uid,
807            gid,
808            file_size,
809            id,
810            flags,
811            flags_extended,
812            path,
813        } = raw;
814
815        let mut pathlen = (flags & raw::GIT_INDEX_ENTRY_NAMEMASK) as usize;
819        if pathlen == raw::GIT_INDEX_ENTRY_NAMEMASK as usize {
820            pathlen = CStr::from_ptr(path).to_bytes().len();
821        }
822
823        let path = slice::from_raw_parts(path as *const u8, pathlen);
824
825        IndexEntry {
826            dev,
827            ino,
828            mode,
829            uid,
830            gid,
831            file_size,
832            id: Binding::from_raw(&id as *const _),
833            flags,
834            flags_extended,
835            path: path.to_vec(),
836            mtime: Binding::from_raw(mtime),
837            ctime: Binding::from_raw(ctime),
838        }
839    }
840
841    fn raw(&self) -> raw::git_index_entry {
842        panic!()
844    }
845}
846
847#[cfg(test)]
848mod tests {
849    use std::fs::{self, File};
850    use std::path::Path;
851    use tempfile::TempDir;
852
853    use crate::{ErrorCode, Index, IndexEntry, IndexTime, Oid, Repository, ResetType};
854
855    #[test]
856    fn smoke() {
857        let mut index = Index::new().unwrap();
858        assert!(index.add_path(&Path::new(".")).is_err());
859        index.clear().unwrap();
860        assert_eq!(index.len(), 0);
861        assert!(index.get(0).is_none());
862        assert!(index.path().is_none());
863        assert!(index.read(true).is_err());
864    }
865
866    #[test]
867    fn smoke_from_repo() {
868        let (_td, repo) = crate::test::repo_init();
869        let mut index = repo.index().unwrap();
870        assert_eq!(
871            index.path().map(|s| s.to_path_buf()),
872            Some(repo.path().join("index"))
873        );
874        Index::open(&repo.path().join("index")).unwrap();
875
876        index.clear().unwrap();
877        index.read(true).unwrap();
878        index.write().unwrap();
879        index.write_tree().unwrap();
880        index.write_tree_to(&repo).unwrap();
881    }
882
883    #[test]
884    fn add_all() {
885        let (_td, repo) = crate::test::repo_init();
886        let mut index = repo.index().unwrap();
887
888        let root = repo.path().parent().unwrap();
889        fs::create_dir(&root.join("foo")).unwrap();
890        File::create(&root.join("foo/bar")).unwrap();
891        let mut called = false;
892        index
893            .add_all(
894                ["foo"].iter(),
895                crate::IndexAddOption::DEFAULT,
896                Some(&mut |a: &Path, b: &[u8]| {
897                    assert!(!called);
898                    called = true;
899                    assert_eq!(b, b"foo");
900                    assert_eq!(a, Path::new("foo/bar"));
901                    0
902                }),
903            )
904            .unwrap();
905        assert!(called);
906
907        called = false;
908        index
909            .remove_all(
910                ["."].iter(),
911                Some(&mut |a: &Path, b: &[u8]| {
912                    assert!(!called);
913                    called = true;
914                    assert_eq!(b, b".");
915                    assert_eq!(a, Path::new("foo/bar"));
916                    0
917                }),
918            )
919            .unwrap();
920        assert!(called);
921    }
922
923    #[test]
924    fn smoke_add() {
925        let (_td, repo) = crate::test::repo_init();
926        let mut index = repo.index().unwrap();
927
928        let root = repo.path().parent().unwrap();
929        fs::create_dir(&root.join("foo")).unwrap();
930        File::create(&root.join("foo/bar")).unwrap();
931        index.add_path(Path::new("foo/bar")).unwrap();
932        index.write().unwrap();
933        assert_eq!(index.iter().count(), 1);
934
935        let id = index.write_tree().unwrap();
937        let tree = repo.find_tree(id).unwrap();
938        let sig = repo.signature().unwrap();
939        let id = repo.refname_to_id("HEAD").unwrap();
940        let parent = repo.find_commit(id).unwrap();
941        let commit = repo
942            .commit(Some("HEAD"), &sig, &sig, "commit", &tree, &[&parent])
943            .unwrap();
944        let obj = repo.find_object(commit, None).unwrap();
945        repo.reset(&obj, ResetType::Hard, None).unwrap();
946
947        let td2 = TempDir::new().unwrap();
948        let url = crate::test::path2url(&root);
949        let repo = Repository::clone(&url, td2.path()).unwrap();
950        let obj = repo.find_object(commit, None).unwrap();
951        repo.reset(&obj, ResetType::Hard, None).unwrap();
952    }
953
954    #[test]
955    fn add_then_read() {
956        let mut index = Index::new().unwrap();
957        let mut e = entry();
958        e.path = b"foobar".to_vec();
959        index.add(&e).unwrap();
960        let e = index.get(0).unwrap();
961        assert_eq!(e.path.len(), 6);
962    }
963
964    #[test]
965    fn add_then_find() {
966        let mut index = Index::new().unwrap();
967        let mut e = entry();
968        e.path = b"foo/bar".to_vec();
969        index.add(&e).unwrap();
970        let mut e = entry();
971        e.path = b"foo2/bar".to_vec();
972        index.add(&e).unwrap();
973        assert_eq!(index.get(0).unwrap().path, b"foo/bar");
974        assert_eq!(
975            index.get_path(Path::new("foo/bar"), 0).unwrap().path,
976            b"foo/bar"
977        );
978        assert_eq!(index.find_prefix(Path::new("foo2/")), Ok(1));
979        assert_eq!(
980            index.find_prefix(Path::new("empty/")).unwrap_err().code(),
981            ErrorCode::NotFound
982        );
983    }
984
985    #[test]
986    fn add_frombuffer_then_read() {
987        let (_td, repo) = crate::test::repo_init();
988        let mut index = repo.index().unwrap();
989
990        let mut e = entry();
991        e.path = b"foobar".to_vec();
992        let content = b"the contents";
993        index.add_frombuffer(&e, content).unwrap();
994        let e = index.get(0).unwrap();
995        assert_eq!(e.path.len(), 6);
996
997        let b = repo.find_blob(e.id).unwrap();
998        assert_eq!(b.content(), content);
999    }
1000
1001    fn entry() -> IndexEntry {
1002        IndexEntry {
1003            ctime: IndexTime::new(0, 0),
1004            mtime: IndexTime::new(0, 0),
1005            dev: 0,
1006            ino: 0,
1007            mode: 0o100644,
1008            uid: 0,
1009            gid: 0,
1010            file_size: 0,
1011            id: Oid::from_bytes(&[0; 20]).unwrap(),
1012            flags: 0,
1013            flags_extended: 0,
1014            path: Vec::new(),
1015        }
1016    }
1017}