Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
a070f152
Commit
a070f152
authored
Jul 29, 2011
by
Carlos Martín Nieto
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move pack functions to their own file
parent
7d0cdf82
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
534 additions
and
557 deletions
+534
-557
src/indexer.c
+4
-4
src/odb_pack.c
+25
-525
src/pack.c
+490
-9
src/pack.h
+15
-19
No files found.
src/indexer.c
View file @
a070f152
...
...
@@ -33,7 +33,7 @@
#include "posix.h"
typedef
struct
git_indexer
{
struct
pack_file
*
pack
;
struct
git_
pack_file
*
pack
;
git_vector
objects
;
git_vector
deltas
;
struct
stat
st
;
...
...
@@ -42,7 +42,7 @@ typedef struct git_indexer {
static
int
parse_header
(
git_indexer
*
idx
)
{
struct
pack_header
hdr
;
struct
git_
pack_header
hdr
;
int
error
;
/* Verify we recognize this pack file format. */
...
...
@@ -96,11 +96,11 @@ int git_indexer_new(git_indexer **out, const char *packname)
memset
(
idx
,
0x0
,
sizeof
(
*
idx
));
namelen
=
strlen
(
packname
);
idx
->
pack
=
git__malloc
(
sizeof
(
struct
pack_file
)
+
namelen
+
1
);
idx
->
pack
=
git__malloc
(
sizeof
(
struct
git_
pack_file
)
+
namelen
+
1
);
if
(
idx
->
pack
==
NULL
)
goto
cleanup
;
memset
(
idx
->
pack
,
0x0
,
sizeof
(
struct
pack_file
));
memset
(
idx
->
pack
,
0x0
,
sizeof
(
struct
git_
pack_file
));
memcpy
(
idx
->
pack
->
pack_name
,
packname
,
namelen
);
ret
=
p_stat
(
packname
,
&
idx
->
st
);
...
...
src/odb_pack.c
View file @
a070f152
...
...
@@ -40,7 +40,7 @@
struct
pack_backend
{
git_odb_backend
parent
;
git_vector
packs
;
struct
pack_file
*
last_found
;
struct
git_
pack_file
*
last_found
;
char
*
pack_folder
;
time_t
pack_folder_mtime
;
};
...
...
@@ -146,45 +146,15 @@ struct pack_backend {
*
***********************************************************/
static
void
pack_window_free_all
(
struct
pack_backend
*
backend
,
struct
pack_file
*
p
);
static
void
pack_window_free_all
(
struct
pack_backend
*
backend
,
struct
git_
pack_file
*
p
);
static
int
pack_window_contains
(
git_mwindow
*
win
,
off_t
offset
);
static
int
packfile_sort__cb
(
const
void
*
a_
,
const
void
*
b_
);
static
void
pack_index_free
(
struct
pack_file
*
p
);
static
int
pack_index_check
(
const
char
*
path
,
struct
pack_file
*
p
);
static
int
pack_index_open
(
struct
pack_file
*
p
);
static
struct
pack_file
*
packfile_alloc
(
int
extra
);
static
int
packfile_open
(
struct
pack_file
*
p
);
static
int
packfile_check
(
struct
pack_file
**
pack_out
,
const
char
*
path
);
static
int
packfile_load__cb
(
void
*
_data
,
char
*
path
);
static
int
packfile_refresh_all
(
struct
pack_backend
*
backend
);
static
off_t
nth_packed_object_offset
(
const
struct
pack_file
*
p
,
uint32_t
n
);
/* Can find the offset of an object given
* a prefix of an identifier.
* Throws GIT_EAMBIGUOUSOIDPREFIX if short oid
* is ambiguous within the pack.
* This method assumes that len is between
* GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ.
*/
static
int
pack_entry_find_offset
(
off_t
*
offset_out
,
git_oid
*
found_oid
,
struct
pack_file
*
p
,
const
git_oid
*
short_oid
,
unsigned
int
len
);
static
int
pack_entry_find1
(
struct
pack_entry
*
e
,
struct
pack_file
*
p
,
const
git_oid
*
short_oid
,
unsigned
int
len
);
static
int
pack_entry_find
(
struct
pack_entry
*
e
,
static
int
pack_entry_find
(
struct
git_pack_entry
*
e
,
struct
pack_backend
*
backend
,
const
git_oid
*
oid
);
/* Can find the offset of an object given
...
...
@@ -194,7 +164,7 @@ static int pack_entry_find(struct pack_entry *e,
* This method assumes that len is between
* GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ.
*/
static
int
pack_entry_find_prefix
(
struct
pack_entry
*
e
,
static
int
pack_entry_find_prefix
(
struct
git_
pack_entry
*
e
,
struct
pack_backend
*
backend
,
const
git_oid
*
short_oid
,
unsigned
int
len
);
...
...
@@ -207,7 +177,7 @@ static int pack_entry_find_prefix(struct pack_entry *e,
*
***********************************************************/
GIT_INLINE
(
void
)
pack_window_free_all
(
struct
pack_backend
*
GIT_UNUSED
(
backend
),
struct
pack_file
*
p
)
GIT_INLINE
(
void
)
pack_window_free_all
(
struct
pack_backend
*
GIT_UNUSED
(
backend
),
struct
git_
pack_file
*
p
)
{
git_mwindow_free_all
(
&
p
->
mwf
);
}
...
...
@@ -223,173 +193,10 @@ GIT_INLINE(int) pack_window_contains(git_mwindow *win, off_t offset)
return
git_mwindow_contains
(
win
,
offset
+
20
);
}
/***********************************************************
*
* PACK INDEX METHODS
*
***********************************************************/
static
void
pack_index_free
(
struct
pack_file
*
p
)
{
if
(
p
->
index_map
.
data
)
{
git_futils_mmap_free
(
&
p
->
index_map
);
p
->
index_map
.
data
=
NULL
;
}
}
static
int
pack_index_check
(
const
char
*
path
,
struct
pack_file
*
p
)
{
struct
pack_idx_header
*
hdr
;
uint32_t
version
,
nr
,
i
,
*
index
;
void
*
idx_map
;
size_t
idx_size
;
struct
stat
st
;
/* TODO: properly open the file without access time */
git_file
fd
=
p_open
(
path
,
O_RDONLY
/*| O_NOATIME */
);
int
error
;
if
(
fd
<
0
)
return
git__throw
(
GIT_EOSERR
,
"Failed to check index. File missing or corrupted"
);
if
(
p_fstat
(
fd
,
&
st
)
<
GIT_SUCCESS
)
{
p_close
(
fd
);
return
git__throw
(
GIT_EOSERR
,
"Failed to check index. File appears to be corrupted"
);
}
if
(
!
git__is_sizet
(
st
.
st_size
))
return
GIT_ENOMEM
;
idx_size
=
(
size_t
)
st
.
st_size
;
if
(
idx_size
<
4
*
256
+
20
+
20
)
{
p_close
(
fd
);
return
git__throw
(
GIT_EOBJCORRUPTED
,
"Failed to check index. Object is corrupted"
);
}
error
=
git_futils_mmap_ro
(
&
p
->
index_map
,
fd
,
0
,
idx_size
);
p_close
(
fd
);
if
(
error
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to check index"
);
hdr
=
idx_map
=
p
->
index_map
.
data
;
if
(
hdr
->
idx_signature
==
htonl
(
PACK_IDX_SIGNATURE
))
{
version
=
ntohl
(
hdr
->
idx_version
);
if
(
version
<
2
||
version
>
2
)
{
git_futils_mmap_free
(
&
p
->
index_map
);
return
git__throw
(
GIT_EOBJCORRUPTED
,
"Failed to check index. Unsupported index version"
);
}
}
else
version
=
1
;
nr
=
0
;
index
=
idx_map
;
if
(
version
>
1
)
index
+=
2
;
/* skip index header */
for
(
i
=
0
;
i
<
256
;
i
++
)
{
uint32_t
n
=
ntohl
(
index
[
i
]);
if
(
n
<
nr
)
{
git_futils_mmap_free
(
&
p
->
index_map
);
return
git__throw
(
GIT_EOBJCORRUPTED
,
"Failed to check index. Index is non-monotonic"
);
}
nr
=
n
;
}
if
(
version
==
1
)
{
/*
* Total size:
* - 256 index entries 4 bytes each
* - 24-byte entries * nr (20-byte sha1 + 4-byte offset)
* - 20-byte SHA1 of the packfile
* - 20-byte SHA1 file checksum
*/
if
(
idx_size
!=
4
*
256
+
nr
*
24
+
20
+
20
)
{
git_futils_mmap_free
(
&
p
->
index_map
);
return
git__throw
(
GIT_EOBJCORRUPTED
,
"Failed to check index. Object is corrupted"
);
}
}
else
if
(
version
==
2
)
{
/*
* Minimum size:
* - 8 bytes of header
* - 256 index entries 4 bytes each
* - 20-byte sha1 entry * nr
* - 4-byte crc entry * nr
* - 4-byte offset entry * nr
* - 20-byte SHA1 of the packfile
* - 20-byte SHA1 file checksum
* And after the 4-byte offset table might be a
* variable sized table containing 8-byte entries
* for offsets larger than 2^31.
*/
unsigned
long
min_size
=
8
+
4
*
256
+
nr
*
(
20
+
4
+
4
)
+
20
+
20
;
unsigned
long
max_size
=
min_size
;
if
(
nr
)
max_size
+=
(
nr
-
1
)
*
8
;
if
(
idx_size
<
min_size
||
idx_size
>
max_size
)
{
git_futils_mmap_free
(
&
p
->
index_map
);
return
git__throw
(
GIT_EOBJCORRUPTED
,
"Failed to check index. Wrong index size"
);
}
/* Make sure that off_t is big enough to access the whole pack...
* Is this an issue in libgit2? It shouldn't. */
if
(
idx_size
!=
min_size
&&
(
sizeof
(
off_t
)
<=
4
))
{
git_futils_mmap_free
(
&
p
->
index_map
);
return
git__throw
(
GIT_EOSERR
,
"Failed to check index. off_t not big enough to access the whole pack"
);
}
}
p
->
index_version
=
version
;
p
->
num_objects
=
nr
;
return
GIT_SUCCESS
;
}
static
int
pack_index_open
(
struct
pack_file
*
p
)
{
char
*
idx_name
;
int
error
;
if
(
p
->
index_map
.
data
)
return
GIT_SUCCESS
;
idx_name
=
git__strdup
(
p
->
pack_name
);
strcpy
(
idx_name
+
strlen
(
idx_name
)
-
STRLEN
(
".pack"
),
".idx"
);
error
=
pack_index_check
(
idx_name
,
p
);
free
(
idx_name
);
return
error
==
GIT_SUCCESS
?
GIT_SUCCESS
:
git__rethrow
(
error
,
"Failed to open index"
);
}
/***********************************************************
*
* PACKFILE METHODS
*
***********************************************************/
static
int
packfile_sort__cb
(
const
void
*
a_
,
const
void
*
b_
)
{
const
struct
pack_file
*
a
=
a_
;
const
struct
pack_file
*
b
=
b_
;
const
struct
git_
pack_file
*
a
=
a_
;
const
struct
git_
pack_file
*
b
=
b_
;
int
st
;
/*
...
...
@@ -415,157 +222,12 @@ static int packfile_sort__cb(const void *a_, const void *b_)
return
-
1
;
}
static
struct
pack_file
*
packfile_alloc
(
int
extra
)
{
struct
pack_file
*
p
=
git__malloc
(
sizeof
(
*
p
)
+
extra
);
memset
(
p
,
0
,
sizeof
(
*
p
));
p
->
mwf
.
fd
=
-
1
;
return
p
;
}
static
void
packfile_free
(
struct
pack_backend
*
backend
,
struct
pack_file
*
p
)
{
assert
(
p
);
/* clear_delta_base_cache(); */
pack_window_free_all
(
backend
,
p
);
if
(
p
->
mwf
.
fd
!=
-
1
)
p_close
(
p
->
mwf
.
fd
);
pack_index_free
(
p
);
free
(
p
->
bad_object_sha1
);
free
(
p
);
}
static
int
packfile_open
(
struct
pack_file
*
p
)
{
struct
stat
st
;
struct
pack_header
hdr
;
git_oid
sha1
;
unsigned
char
*
idx_sha1
;
if
(
!
p
->
index_map
.
data
&&
pack_index_open
(
p
)
<
GIT_SUCCESS
)
return
git__throw
(
GIT_ENOTFOUND
,
"Failed to open packfile. File not found"
);
/* TODO: open with noatime */
p
->
mwf
.
fd
=
p_open
(
p
->
pack_name
,
O_RDONLY
);
if
(
p
->
mwf
.
fd
<
0
||
p_fstat
(
p
->
mwf
.
fd
,
&
st
)
<
GIT_SUCCESS
)
return
git__throw
(
GIT_EOSERR
,
"Failed to open packfile. File appears to be corrupted"
);
if
(
git_mwindow_file_register
(
&
p
->
mwf
)
<
GIT_SUCCESS
)
{
p_close
(
p
->
mwf
.
fd
);
return
git__throw
(
GIT_ERROR
,
"Failed to register packfile windows"
);
}
/* If we created the struct before we had the pack we lack size. */
if
(
!
p
->
mwf
.
size
)
{
if
(
!
S_ISREG
(
st
.
st_mode
))
goto
cleanup
;
p
->
mwf
.
size
=
(
off_t
)
st
.
st_size
;
}
else
if
(
p
->
mwf
.
size
!=
st
.
st_size
)
goto
cleanup
;
#if 0
/* We leave these file descriptors open with sliding mmap;
* there is no point keeping them open across exec(), though.
*/
fd_flag = fcntl(p->mwf.fd, F_GETFD, 0);
if (fd_flag < 0)
return error("cannot determine file descriptor flags");
fd_flag |= FD_CLOEXEC;
if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1)
return GIT_EOSERR;
#endif
/* Verify we recognize this pack file format. */
if
(
p_read
(
p
->
mwf
.
fd
,
&
hdr
,
sizeof
(
hdr
))
<
GIT_SUCCESS
)
goto
cleanup
;
if
(
hdr
.
hdr_signature
!=
htonl
(
PACK_SIGNATURE
))
goto
cleanup
;
if
(
!
pack_version_ok
(
hdr
.
hdr_version
))
goto
cleanup
;
/* Verify the pack matches its index. */
if
(
p
->
num_objects
!=
ntohl
(
hdr
.
hdr_entries
))
goto
cleanup
;
if
(
p_lseek
(
p
->
mwf
.
fd
,
p
->
mwf
.
size
-
GIT_OID_RAWSZ
,
SEEK_SET
)
==
-
1
)
goto
cleanup
;
if
(
p_read
(
p
->
mwf
.
fd
,
sha1
.
id
,
GIT_OID_RAWSZ
)
<
GIT_SUCCESS
)
goto
cleanup
;
idx_sha1
=
((
unsigned
char
*
)
p
->
index_map
.
data
)
+
p
->
index_map
.
len
-
40
;
if
(
git_oid_cmp
(
&
sha1
,
(
git_oid
*
)
idx_sha1
)
!=
0
)
goto
cleanup
;
return
GIT_SUCCESS
;
cleanup
:
p_close
(
p
->
mwf
.
fd
);
p
->
mwf
.
fd
=
-
1
;
return
git__throw
(
GIT_EPACKCORRUPTED
,
"Failed to packfile. Pack is corrupted"
);
}
static
int
packfile_check
(
struct
pack_file
**
pack_out
,
const
char
*
path
)
{
struct
stat
st
;
struct
pack_file
*
p
;
size_t
path_len
;
*
pack_out
=
NULL
;
path_len
=
strlen
(
path
);
p
=
packfile_alloc
(
path_len
+
2
);
/*
* Make sure a corresponding .pack file exists and that
* the index looks sane.
*/
path_len
-=
STRLEN
(
".idx"
);
if
(
path_len
<
1
)
{
free
(
p
);
return
git__throw
(
GIT_ENOTFOUND
,
"Failed to check packfile. Wrong path name"
);
}
memcpy
(
p
->
pack_name
,
path
,
path_len
);
strcpy
(
p
->
pack_name
+
path_len
,
".keep"
);
if
(
git_futils_exists
(
p
->
pack_name
)
==
GIT_SUCCESS
)
p
->
pack_keep
=
1
;
strcpy
(
p
->
pack_name
+
path_len
,
".pack"
);
if
(
p_stat
(
p
->
pack_name
,
&
st
)
<
GIT_SUCCESS
||
!
S_ISREG
(
st
.
st_mode
))
{
free
(
p
);
return
git__throw
(
GIT_ENOTFOUND
,
"Failed to check packfile. File not found"
);
}
/* ok, it looks sane as far as we can check without
* actually mapping the pack file.
*/
p
->
mwf
.
size
=
(
off_t
)
st
.
st_size
;
p
->
pack_local
=
1
;
p
->
mtime
=
(
git_time_t
)
st
.
st_mtime
;
/* see if we can parse the sha1 oid in the packfile name */
if
(
path_len
<
40
||
git_oid_fromstr
(
&
p
->
sha1
,
path
+
path_len
-
GIT_OID_HEXSZ
)
<
GIT_SUCCESS
)
memset
(
&
p
->
sha1
,
0x0
,
GIT_OID_RAWSZ
);
*
pack_out
=
p
;
return
GIT_SUCCESS
;
}
static
int
packfile_load__cb
(
void
*
_data
,
char
*
path
)
{
struct
pack_backend
*
backend
=
(
struct
pack_backend
*
)
_data
;
struct
pack_file
*
pack
;
struct
git_
pack_file
*
pack
;
int
error
;
size_t
i
;
...
...
@@ -573,12 +235,12 @@ static int packfile_load__cb(void *_data, char *path)
return
GIT_SUCCESS
;
/* not an index */
for
(
i
=
0
;
i
<
backend
->
packs
.
length
;
++
i
)
{
struct
pack_file
*
p
=
git_vector_get
(
&
backend
->
packs
,
i
);
struct
git_
pack_file
*
p
=
git_vector_get
(
&
backend
->
packs
,
i
);
if
(
memcmp
(
p
->
pack_name
,
path
,
strlen
(
path
)
-
STRLEN
(
".idx"
))
==
0
)
return
GIT_SUCCESS
;
}
error
=
packfile_check
(
&
pack
,
path
);
error
=
git_
packfile_check
(
&
pack
,
path
);
if
(
error
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to load packfile"
);
...
...
@@ -617,169 +279,7 @@ static int packfile_refresh_all(struct pack_backend *backend)
return
GIT_SUCCESS
;
}
/***********************************************************
*
* PACKFILE ENTRY SEARCH INTERNALS
*
***********************************************************/
static
off_t
nth_packed_object_offset
(
const
struct
pack_file
*
p
,
uint32_t
n
)
{
const
unsigned
char
*
index
=
p
->
index_map
.
data
;
index
+=
4
*
256
;
if
(
p
->
index_version
==
1
)
{
return
ntohl
(
*
((
const
uint32_t
*
)(
index
+
24
*
n
)));
}
else
{
uint32_t
off
;
index
+=
8
+
p
->
num_objects
*
(
20
+
4
);
off
=
ntohl
(
*
((
const
uint32_t
*
)(
index
+
4
*
n
)));
if
(
!
(
off
&
0x80000000
))
return
off
;
index
+=
p
->
num_objects
*
4
+
(
off
&
0x7fffffff
)
*
8
;
return
(((
uint64_t
)
ntohl
(
*
((
const
uint32_t
*
)(
index
+
0
))))
<<
32
)
|
ntohl
(
*
((
const
uint32_t
*
)(
index
+
4
)));
}
}
static
int
pack_entry_find_offset
(
off_t
*
offset_out
,
git_oid
*
found_oid
,
struct
pack_file
*
p
,
const
git_oid
*
short_oid
,
unsigned
int
len
)
{
const
uint32_t
*
level1_ofs
=
p
->
index_map
.
data
;
const
unsigned
char
*
index
=
p
->
index_map
.
data
;
unsigned
hi
,
lo
,
stride
;
int
pos
,
found
=
0
;
const
unsigned
char
*
current
=
0
;
*
offset_out
=
0
;
if
(
index
==
NULL
)
{
int
error
;
if
((
error
=
pack_index_open
(
p
))
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to find offset for pack entry"
);
assert
(
p
->
index_map
.
data
);
index
=
p
->
index_map
.
data
;
level1_ofs
=
p
->
index_map
.
data
;
}
if
(
p
->
index_version
>
1
)
{
level1_ofs
+=
2
;
index
+=
8
;
}
index
+=
4
*
256
;
hi
=
ntohl
(
level1_ofs
[(
int
)
short_oid
->
id
[
0
]]);
lo
=
((
short_oid
->
id
[
0
]
==
0x0
)
?
0
:
ntohl
(
level1_ofs
[(
int
)
short_oid
->
id
[
0
]
-
1
]));
if
(
p
->
index_version
>
1
)
{
stride
=
20
;
}
else
{
stride
=
24
;
index
+=
4
;
}
#ifdef INDEX_DEBUG_LOOKUP
printf
(
"%02x%02x%02x... lo %u hi %u nr %d
\n
"
,
short_oid
->
id
[
0
],
short_oid
->
id
[
1
],
short_oid
->
id
[
2
],
lo
,
hi
,
p
->
num_objects
);
#endif
/* Use git.git lookup code */
pos
=
sha1_entry_pos
(
index
,
stride
,
0
,
lo
,
hi
,
p
->
num_objects
,
short_oid
->
id
);
if
(
pos
>=
0
)
{
/* An object matching exactly the oid was found */
found
=
1
;
current
=
index
+
pos
*
stride
;
}
else
{
/* No object was found */
/* pos refers to the object with the "closest" oid to short_oid */
pos
=
-
1
-
pos
;
if
(
pos
<
(
int
)
p
->
num_objects
)
{
current
=
index
+
pos
*
stride
;
if
(
!
git_oid_ncmp
(
short_oid
,
(
const
git_oid
*
)
current
,
len
))
{
found
=
1
;
}
}
}
if
(
found
&&
pos
+
1
<
(
int
)
p
->
num_objects
)
{
/* Check for ambiguousity */
const
unsigned
char
*
next
=
current
+
stride
;
if
(
!
git_oid_ncmp
(
short_oid
,
(
const
git_oid
*
)
next
,
len
))
{
found
=
2
;
}
}
if
(
!
found
)
{
return
git__throw
(
GIT_ENOTFOUND
,
"Failed to find offset for pack entry. Entry not found"
);
}
else
if
(
found
>
1
)
{
return
git__throw
(
GIT_EAMBIGUOUSOIDPREFIX
,
"Failed to find offset for pack entry. Ambiguous sha1 prefix within pack"
);
}
else
{
*
offset_out
=
nth_packed_object_offset
(
p
,
pos
);
git_oid_fromraw
(
found_oid
,
current
);
#ifdef INDEX_DEBUG_LOOKUP
unsigned
char
hex_sha1
[
GIT_OID_HEXSZ
+
1
];
git_oid_fmt
(
hex_sha1
,
found_oid
);
hex_sha1
[
GIT_OID_HEXSZ
]
=
'\0'
;
printf
(
"found lo=%d %s
\n
"
,
lo
,
hex_sha1
);
#endif
return
GIT_SUCCESS
;
}
}
static
int
pack_entry_find1
(
struct
pack_entry
*
e
,
struct
pack_file
*
p
,
const
git_oid
*
short_oid
,
unsigned
int
len
)
{
off_t
offset
;
git_oid
found_oid
;
int
error
;
assert
(
p
);
if
(
len
==
GIT_OID_HEXSZ
&&
p
->
num_bad_objects
)
{
unsigned
i
;
for
(
i
=
0
;
i
<
p
->
num_bad_objects
;
i
++
)
if
(
git_oid_cmp
(
short_oid
,
&
p
->
bad_object_sha1
[
i
])
==
0
)
return
git__throw
(
GIT_ERROR
,
"Failed to find pack entry. Bad object found"
);
}
error
=
pack_entry_find_offset
(
&
offset
,
&
found_oid
,
p
,
short_oid
,
len
);
if
(
error
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to find pack entry. Couldn't find offset"
);
/* we found a unique entry in the index;
* make sure the packfile backing the index
* still exists on disk */
if
(
p
->
mwf
.
fd
==
-
1
&&
packfile_open
(
p
)
<
GIT_SUCCESS
)
return
git__throw
(
GIT_EOSERR
,
"Failed to find pack entry. Packfile doesn't exist on disk"
);
e
->
offset
=
offset
;
e
->
p
=
p
;
git_oid_cpy
(
&
e
->
sha1
,
&
found_oid
);
return
GIT_SUCCESS
;
}
static
int
pack_entry_find
(
struct
pack_entry
*
e
,
struct
pack_backend
*
backend
,
const
git_oid
*
oid
)
static
int
pack_entry_find
(
struct
git_pack_entry
*
e
,
struct
pack_backend
*
backend
,
const
git_oid
*
oid
)
{
int
error
;
size_t
i
;
...
...
@@ -788,17 +288,17 @@ static int pack_entry_find(struct pack_entry *e, struct pack_backend *backend, c
return
git__rethrow
(
error
,
"Failed to find pack entry"
);
if
(
backend
->
last_found
&&
pack_entry_find1
(
e
,
backend
->
last_found
,
oid
,
GIT_OID_HEXSZ
)
==
GIT_SUCCESS
)
git_pack_entry_find
(
e
,
backend
->
last_found
,
oid
,
GIT_OID_HEXSZ
)
==
GIT_SUCCESS
)
return
GIT_SUCCESS
;
for
(
i
=
0
;
i
<
backend
->
packs
.
length
;
++
i
)
{
struct
pack_file
*
p
;
struct
git_
pack_file
*
p
;
p
=
git_vector_get
(
&
backend
->
packs
,
i
);
if
(
p
==
backend
->
last_found
)
continue
;
if
(
pack_entry_find1
(
e
,
p
,
oid
,
GIT_OID_HEXSZ
)
==
GIT_SUCCESS
)
{
if
(
git_pack_entry_find
(
e
,
p
,
oid
,
GIT_OID_HEXSZ
)
==
GIT_SUCCESS
)
{
backend
->
last_found
=
p
;
return
GIT_SUCCESS
;
}
...
...
@@ -808,7 +308,7 @@ static int pack_entry_find(struct pack_entry *e, struct pack_backend *backend, c
}
static
int
pack_entry_find_prefix
(
struct
pack_entry
*
e
,
struct
git_
pack_entry
*
e
,
struct
pack_backend
*
backend
,
const
git_oid
*
short_oid
,
unsigned
int
len
)
...
...
@@ -821,7 +321,7 @@ static int pack_entry_find_prefix(
return
git__rethrow
(
error
,
"Failed to find pack entry"
);
if
(
backend
->
last_found
)
{
error
=
pack_entry_find1
(
e
,
backend
->
last_found
,
short_oid
,
len
);
error
=
git_pack_entry_find
(
e
,
backend
->
last_found
,
short_oid
,
len
);
if
(
error
==
GIT_EAMBIGUOUSOIDPREFIX
)
{
return
git__rethrow
(
error
,
"Failed to find pack entry. Ambiguous sha1 prefix"
);
}
else
if
(
error
==
GIT_SUCCESS
)
{
...
...
@@ -830,13 +330,13 @@ static int pack_entry_find_prefix(
}
for
(
i
=
0
;
i
<
backend
->
packs
.
length
;
++
i
)
{
struct
pack_file
*
p
;
struct
git_
pack_file
*
p
;
p
=
git_vector_get
(
&
backend
->
packs
,
i
);
if
(
p
==
backend
->
last_found
)
continue
;
error
=
pack_entry_find1
(
e
,
p
,
short_oid
,
len
);
error
=
git_pack_entry_find
(
e
,
p
,
short_oid
,
len
);
if
(
error
==
GIT_EAMBIGUOUSOIDPREFIX
)
{
return
git__rethrow
(
error
,
"Failed to find pack entry. Ambiguous sha1 prefix"
);
}
else
if
(
error
==
GIT_SUCCESS
)
{
...
...
@@ -882,14 +382,14 @@ int pack_backend__read_header(git_rawobj *obj, git_odb_backend *backend, const g
int
pack_backend__read
(
void
**
buffer_p
,
size_t
*
len_p
,
git_otype
*
type_p
,
git_odb_backend
*
backend
,
const
git_oid
*
oid
)
{
struct
pack_entry
e
;
struct
git_
pack_entry
e
;
git_rawobj
raw
;
int
error
;
if
((
error
=
pack_entry_find
(
&
e
,
(
struct
pack_backend
*
)
backend
,
oid
))
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to read pack backend"
);
if
((
error
=
packfile_unpack
(
&
raw
,
e
.
p
,
e
.
offset
))
<
GIT_SUCCESS
)
if
((
error
=
git_
packfile_unpack
(
&
raw
,
e
.
p
,
e
.
offset
))
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to read pack backend"
);
*
buffer_p
=
raw
.
data
;
...
...
@@ -919,14 +419,14 @@ int pack_backend__read_prefix(
return
error
;
}
else
{
struct
pack_entry
e
;
struct
git_
pack_entry
e
;
git_rawobj
raw
;
int
error
;
if
((
error
=
pack_entry_find_prefix
(
&
e
,
(
struct
pack_backend
*
)
backend
,
short_oid
,
len
))
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to read pack backend"
);
if
((
error
=
packfile_unpack
(
&
raw
,
e
.
p
,
e
.
offset
))
<
GIT_SUCCESS
)
if
((
error
=
git_
packfile_unpack
(
&
raw
,
e
.
p
,
e
.
offset
))
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to read pack backend"
);
*
buffer_p
=
raw
.
data
;
...
...
@@ -940,7 +440,7 @@ int pack_backend__read_prefix(
int
pack_backend__exists
(
git_odb_backend
*
backend
,
const
git_oid
*
oid
)
{
struct
pack_entry
e
;
struct
git_
pack_entry
e
;
return
pack_entry_find
(
&
e
,
(
struct
pack_backend
*
)
backend
,
oid
)
==
GIT_SUCCESS
;
}
...
...
@@ -954,8 +454,8 @@ void pack_backend__free(git_odb_backend *_backend)
backend
=
(
struct
pack_backend
*
)
_backend
;
for
(
i
=
0
;
i
<
backend
->
packs
.
length
;
++
i
)
{
struct
pack_file
*
p
=
git_vector_get
(
&
backend
->
packs
,
i
);
packfile_free
(
backend
,
p
);
struct
git_
pack_file
*
p
=
git_vector_get
(
&
backend
->
packs
,
i
);
packfile_free
(
p
);
}
git_vector_free
(
&
backend
->
packs
);
...
...
src/pack.c
View file @
a070f152
...
...
@@ -27,12 +27,185 @@
#include "odb.h"
#include "pack.h"
#include "delta-apply.h"
#include "sha1_lookup.h"
#include "git2/oid.h"
#include "git2/zlib.h"
unsigned
char
*
pack_window_open
(
struct
pack_file
*
p
,
static
int
packfile_open
(
struct
git_pack_file
*
p
);
static
off_t
nth_packed_object_offset
(
const
struct
git_pack_file
*
p
,
uint32_t
n
);
int
packfile_unpack_compressed
(
git_rawobj
*
obj
,
struct
git_pack_file
*
p
,
git_mwindow
**
w_curs
,
off_t
curpos
,
size_t
size
,
git_otype
type
);
/* Can find the offset of an object given
* a prefix of an identifier.
* Throws GIT_EAMBIGUOUSOIDPREFIX if short oid
* is ambiguous within the pack.
* This method assumes that len is between
* GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ.
*/
static
int
pack_entry_find_offset
(
off_t
*
offset_out
,
git_oid
*
found_oid
,
struct
git_pack_file
*
p
,
const
git_oid
*
short_oid
,
unsigned
int
len
);
/***********************************************************
*
* PACK INDEX METHODS
*
***********************************************************/
static
void
pack_index_free
(
struct
git_pack_file
*
p
)
{
if
(
p
->
index_map
.
data
)
{
git_futils_mmap_free
(
&
p
->
index_map
);
p
->
index_map
.
data
=
NULL
;
}
}
static
int
pack_index_check
(
const
char
*
path
,
struct
git_pack_file
*
p
)
{
struct
git_pack_idx_header
*
hdr
;
uint32_t
version
,
nr
,
i
,
*
index
;
void
*
idx_map
;
size_t
idx_size
;
struct
stat
st
;
/* TODO: properly open the file without access time */
git_file
fd
=
p_open
(
path
,
O_RDONLY
/*| O_NOATIME */
);
int
error
;
if
(
fd
<
0
)
return
git__throw
(
GIT_EOSERR
,
"Failed to check index. File missing or corrupted"
);
if
(
p_fstat
(
fd
,
&
st
)
<
GIT_SUCCESS
)
{
p_close
(
fd
);
return
git__throw
(
GIT_EOSERR
,
"Failed to check index. File appears to be corrupted"
);
}
if
(
!
git__is_sizet
(
st
.
st_size
))
return
GIT_ENOMEM
;
idx_size
=
(
size_t
)
st
.
st_size
;
if
(
idx_size
<
4
*
256
+
20
+
20
)
{
p_close
(
fd
);
return
git__throw
(
GIT_EOBJCORRUPTED
,
"Failed to check index. Object is corrupted"
);
}
error
=
git_futils_mmap_ro
(
&
p
->
index_map
,
fd
,
0
,
idx_size
);
p_close
(
fd
);
if
(
error
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to check index"
);
hdr
=
idx_map
=
p
->
index_map
.
data
;
if
(
hdr
->
idx_signature
==
htonl
(
PACK_IDX_SIGNATURE
))
{
version
=
ntohl
(
hdr
->
idx_version
);
if
(
version
<
2
||
version
>
2
)
{
git_futils_mmap_free
(
&
p
->
index_map
);
return
git__throw
(
GIT_EOBJCORRUPTED
,
"Failed to check index. Unsupported index version"
);
}
}
else
version
=
1
;
nr
=
0
;
index
=
idx_map
;
if
(
version
>
1
)
index
+=
2
;
/* skip index header */
for
(
i
=
0
;
i
<
256
;
i
++
)
{
uint32_t
n
=
ntohl
(
index
[
i
]);
if
(
n
<
nr
)
{
git_futils_mmap_free
(
&
p
->
index_map
);
return
git__throw
(
GIT_EOBJCORRUPTED
,
"Failed to check index. Index is non-monotonic"
);
}
nr
=
n
;
}
if
(
version
==
1
)
{
/*
* Total size:
* - 256 index entries 4 bytes each
* - 24-byte entries * nr (20-byte sha1 + 4-byte offset)
* - 20-byte SHA1 of the packfile
* - 20-byte SHA1 file checksum
*/
if
(
idx_size
!=
4
*
256
+
nr
*
24
+
20
+
20
)
{
git_futils_mmap_free
(
&
p
->
index_map
);
return
git__throw
(
GIT_EOBJCORRUPTED
,
"Failed to check index. Object is corrupted"
);
}
}
else
if
(
version
==
2
)
{
/*
* Minimum size:
* - 8 bytes of header
* - 256 index entries 4 bytes each
* - 20-byte sha1 entry * nr
* - 4-byte crc entry * nr
* - 4-byte offset entry * nr
* - 20-byte SHA1 of the packfile
* - 20-byte SHA1 file checksum
* And after the 4-byte offset table might be a
* variable sized table containing 8-byte entries
* for offsets larger than 2^31.
*/
unsigned
long
min_size
=
8
+
4
*
256
+
nr
*
(
20
+
4
+
4
)
+
20
+
20
;
unsigned
long
max_size
=
min_size
;
if
(
nr
)
max_size
+=
(
nr
-
1
)
*
8
;
if
(
idx_size
<
min_size
||
idx_size
>
max_size
)
{
git_futils_mmap_free
(
&
p
->
index_map
);
return
git__throw
(
GIT_EOBJCORRUPTED
,
"Failed to check index. Wrong index size"
);
}
/* Make sure that off_t is big enough to access the whole pack...
* Is this an issue in libgit2? It shouldn't. */
if
(
idx_size
!=
min_size
&&
(
sizeof
(
off_t
)
<=
4
))
{
git_futils_mmap_free
(
&
p
->
index_map
);
return
git__throw
(
GIT_EOSERR
,
"Failed to check index. off_t not big enough to access the whole pack"
);
}
}
p
->
index_version
=
version
;
p
->
num_objects
=
nr
;
return
GIT_SUCCESS
;
}
static
int
pack_index_open
(
struct
git_pack_file
*
p
)
{
char
*
idx_name
;
int
error
;
if
(
p
->
index_map
.
data
)
return
GIT_SUCCESS
;
idx_name
=
git__strdup
(
p
->
pack_name
);
strcpy
(
idx_name
+
strlen
(
idx_name
)
-
STRLEN
(
".pack"
),
".idx"
);
error
=
pack_index_check
(
idx_name
,
p
);
free
(
idx_name
);
return
error
==
GIT_SUCCESS
?
GIT_SUCCESS
:
git__rethrow
(
error
,
"Failed to open index"
);
}
static
unsigned
char
*
pack_window_open
(
struct
git_pack_file
*
p
,
git_mwindow
**
w_cursor
,
off_t
offset
,
unsigned
int
*
left
)
...
...
@@ -109,9 +282,9 @@ int git_packfile_unpack_header(
return
GIT_SUCCESS
;
}
int
packfile_unpack_delta
(
static
int
packfile_unpack_delta
(
git_rawobj
*
obj
,
struct
pack_file
*
p
,
struct
git_
pack_file
*
p
,
git_mwindow
**
w_curs
,
off_t
curpos
,
size_t
delta_size
,
...
...
@@ -127,7 +300,7 @@ int packfile_unpack_delta(
return
git__throw
(
GIT_EOBJCORRUPTED
,
"Delta offset is zero"
);
git_mwindow_close
(
w_curs
);
error
=
packfile_unpack
(
&
base
,
p
,
base_offset
);
error
=
git_
packfile_unpack
(
&
base
,
p
,
base_offset
);
/*
* TODO: git.git tries to load the base from other packfiles
...
...
@@ -157,9 +330,9 @@ int packfile_unpack_delta(
return
error
;
/* error set by git__delta_apply */
}
int
packfile_unpack
(
int
git_
packfile_unpack
(
git_rawobj
*
obj
,
struct
pack_file
*
p
,
struct
git_
pack_file
*
p
,
off_t
obj_offset
)
{
git_mwindow
*
w_curs
=
NULL
;
...
...
@@ -209,7 +382,7 @@ int packfile_unpack(
int
packfile_unpack_compressed
(
git_rawobj
*
obj
,
struct
pack_file
*
p
,
struct
git_
pack_file
*
p
,
git_mwindow
**
w_curs
,
off_t
curpos
,
size_t
size
,
...
...
@@ -257,7 +430,7 @@ int packfile_unpack_compressed(
}
off_t
get_delta_base
(
struct
pack_file
*
p
,
struct
git_
pack_file
*
p
,
git_mwindow
**
w_curs
,
off_t
*
curpos
,
git_otype
type
,
...
...
@@ -298,3 +471,311 @@ off_t get_delta_base(
return
base_offset
;
}
/***********************************************************
*
* PACKFILE METHODS
*
***********************************************************/
static
struct
git_pack_file
*
packfile_alloc
(
int
extra
)
{
struct
git_pack_file
*
p
=
git__malloc
(
sizeof
(
*
p
)
+
extra
);
memset
(
p
,
0
,
sizeof
(
*
p
));
p
->
mwf
.
fd
=
-
1
;
return
p
;
}
void
packfile_free
(
struct
git_pack_file
*
p
)
{
assert
(
p
);
/* clear_delta_base_cache(); */
git_mwindow_free_all
(
&
p
->
mwf
);
if
(
p
->
mwf
.
fd
!=
-
1
)
p_close
(
p
->
mwf
.
fd
);
pack_index_free
(
p
);
free
(
p
->
bad_object_sha1
);
free
(
p
);
}
static
int
packfile_open
(
struct
git_pack_file
*
p
)
{
struct
stat
st
;
struct
git_pack_header
hdr
;
git_oid
sha1
;
unsigned
char
*
idx_sha1
;
if
(
!
p
->
index_map
.
data
&&
pack_index_open
(
p
)
<
GIT_SUCCESS
)
return
git__throw
(
GIT_ENOTFOUND
,
"Failed to open packfile. File not found"
);
/* TODO: open with noatime */
p
->
mwf
.
fd
=
p_open
(
p
->
pack_name
,
O_RDONLY
);
if
(
p
->
mwf
.
fd
<
0
||
p_fstat
(
p
->
mwf
.
fd
,
&
st
)
<
GIT_SUCCESS
)
return
git__throw
(
GIT_EOSERR
,
"Failed to open packfile. File appears to be corrupted"
);
if
(
git_mwindow_file_register
(
&
p
->
mwf
)
<
GIT_SUCCESS
)
{
p_close
(
p
->
mwf
.
fd
);
return
git__throw
(
GIT_ERROR
,
"Failed to register packfile windows"
);
}
/* If we created the struct before we had the pack we lack size. */
if
(
!
p
->
mwf
.
size
)
{
if
(
!
S_ISREG
(
st
.
st_mode
))
goto
cleanup
;
p
->
mwf
.
size
=
(
off_t
)
st
.
st_size
;
}
else
if
(
p
->
mwf
.
size
!=
st
.
st_size
)
goto
cleanup
;
#if 0
/* We leave these file descriptors open with sliding mmap;
* there is no point keeping them open across exec(), though.
*/
fd_flag = fcntl(p->mwf.fd, F_GETFD, 0);
if (fd_flag < 0)
return error("cannot determine file descriptor flags");
fd_flag |= FD_CLOEXEC;
if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1)
return GIT_EOSERR;
#endif
/* Verify we recognize this pack file format. */
if
(
p_read
(
p
->
mwf
.
fd
,
&
hdr
,
sizeof
(
hdr
))
<
GIT_SUCCESS
)
goto
cleanup
;
if
(
hdr
.
hdr_signature
!=
htonl
(
PACK_SIGNATURE
))
goto
cleanup
;
if
(
!
pack_version_ok
(
hdr
.
hdr_version
))
goto
cleanup
;
/* Verify the pack matches its index. */
if
(
p
->
num_objects
!=
ntohl
(
hdr
.
hdr_entries
))
goto
cleanup
;
if
(
p_lseek
(
p
->
mwf
.
fd
,
p
->
mwf
.
size
-
GIT_OID_RAWSZ
,
SEEK_SET
)
==
-
1
)
goto
cleanup
;
if
(
p_read
(
p
->
mwf
.
fd
,
sha1
.
id
,
GIT_OID_RAWSZ
)
<
GIT_SUCCESS
)
goto
cleanup
;
idx_sha1
=
((
unsigned
char
*
)
p
->
index_map
.
data
)
+
p
->
index_map
.
len
-
40
;
if
(
git_oid_cmp
(
&
sha1
,
(
git_oid
*
)
idx_sha1
)
!=
0
)
goto
cleanup
;
return
GIT_SUCCESS
;
cleanup:
p_close
(
p
->
mwf
.
fd
);
p
->
mwf
.
fd
=
-
1
;
return
git__throw
(
GIT_EPACKCORRUPTED
,
"Failed to open packfile. Pack is corrupted"
);
}
int
git_packfile_check
(
struct
git_pack_file
**
pack_out
,
const
char
*
path
)
{
struct
stat
st
;
struct
git_pack_file
*
p
;
size_t
path_len
;
*
pack_out
=
NULL
;
path_len
=
strlen
(
path
);
p
=
packfile_alloc
(
path_len
+
2
);
/*
* Make sure a corresponding .pack file exists and that
* the index looks sane.
*/
path_len
-=
STRLEN
(
".idx"
);
if
(
path_len
<
1
)
{
free
(
p
);
return
git__throw
(
GIT_ENOTFOUND
,
"Failed to check packfile. Wrong path name"
);
}
memcpy
(
p
->
pack_name
,
path
,
path_len
);
strcpy
(
p
->
pack_name
+
path_len
,
".keep"
);
if
(
git_futils_exists
(
p
->
pack_name
)
==
GIT_SUCCESS
)
p
->
pack_keep
=
1
;
strcpy
(
p
->
pack_name
+
path_len
,
".pack"
);
if
(
p_stat
(
p
->
pack_name
,
&
st
)
<
GIT_SUCCESS
||
!
S_ISREG
(
st
.
st_mode
))
{
free
(
p
);
return
git__throw
(
GIT_ENOTFOUND
,
"Failed to check packfile. File not found"
);
}
/* ok, it looks sane as far as we can check without
* actually mapping the pack file.
*/
p
->
mwf
.
size
=
(
off_t
)
st
.
st_size
;
p
->
pack_local
=
1
;
p
->
mtime
=
(
git_time_t
)
st
.
st_mtime
;
/* see if we can parse the sha1 oid in the packfile name */
if
(
path_len
<
40
||
git_oid_fromstr
(
&
p
->
sha1
,
path
+
path_len
-
GIT_OID_HEXSZ
)
<
GIT_SUCCESS
)
memset
(
&
p
->
sha1
,
0x0
,
GIT_OID_RAWSZ
);
*
pack_out
=
p
;
return
GIT_SUCCESS
;
}
/***********************************************************
*
* PACKFILE ENTRY SEARCH INTERNALS
*
***********************************************************/
static
off_t
nth_packed_object_offset
(
const
struct
git_pack_file
*
p
,
uint32_t
n
)
{
const
unsigned
char
*
index
=
p
->
index_map
.
data
;
index
+=
4
*
256
;
if
(
p
->
index_version
==
1
)
{
return
ntohl
(
*
((
uint32_t
*
)(
index
+
24
*
n
)));
}
else
{
uint32_t
off
;
index
+=
8
+
p
->
num_objects
*
(
20
+
4
);
off
=
ntohl
(
*
((
uint32_t
*
)(
index
+
4
*
n
)));
if
(
!
(
off
&
0x80000000
))
return
off
;
index
+=
p
->
num_objects
*
4
+
(
off
&
0x7fffffff
)
*
8
;
return
(((
uint64_t
)
ntohl
(
*
((
uint32_t
*
)(
index
+
0
))))
<<
32
)
|
ntohl
(
*
((
uint32_t
*
)(
index
+
4
)));
}
}
static
int
pack_entry_find_offset
(
off_t
*
offset_out
,
git_oid
*
found_oid
,
struct
git_pack_file
*
p
,
const
git_oid
*
short_oid
,
unsigned
int
len
)
{
const
uint32_t
*
level1_ofs
=
p
->
index_map
.
data
;
const
unsigned
char
*
index
=
p
->
index_map
.
data
;
unsigned
hi
,
lo
,
stride
;
int
pos
,
found
=
0
;
const
unsigned
char
*
current
=
0
;
*
offset_out
=
0
;
if
(
index
==
NULL
)
{
int
error
;
if
((
error
=
pack_index_open
(
p
))
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to find offset for pack entry"
);
assert
(
p
->
index_map
.
data
);
index
=
p
->
index_map
.
data
;
level1_ofs
=
p
->
index_map
.
data
;
}
if
(
p
->
index_version
>
1
)
{
level1_ofs
+=
2
;
index
+=
8
;
}
index
+=
4
*
256
;
hi
=
ntohl
(
level1_ofs
[(
int
)
short_oid
->
id
[
0
]]);
lo
=
((
short_oid
->
id
[
0
]
==
0x0
)
?
0
:
ntohl
(
level1_ofs
[(
int
)
short_oid
->
id
[
0
]
-
1
]));
if
(
p
->
index_version
>
1
)
{
stride
=
20
;
}
else
{
stride
=
24
;
index
+=
4
;
}
#ifdef INDEX_DEBUG_LOOKUP
printf
(
"%02x%02x%02x... lo %u hi %u nr %d
\n
"
,
short_oid
->
id
[
0
],
short_oid
->
id
[
1
],
short_oid
->
id
[
2
],
lo
,
hi
,
p
->
num_objects
);
#endif
/* Use git.git lookup code */
pos
=
sha1_entry_pos
(
index
,
stride
,
0
,
lo
,
hi
,
p
->
num_objects
,
short_oid
->
id
);
if
(
pos
>=
0
)
{
/* An object matching exactly the oid was found */
found
=
1
;
current
=
index
+
pos
*
stride
;
}
else
{
/* No object was found */
/* pos refers to the object with the "closest" oid to short_oid */
pos
=
-
1
-
pos
;
if
(
pos
<
(
int
)
p
->
num_objects
)
{
current
=
index
+
pos
*
stride
;
if
(
!
git_oid_ncmp
(
short_oid
,
(
const
git_oid
*
)
current
,
len
))
{
found
=
1
;
}
}
}
if
(
found
&&
pos
+
1
<
(
int
)
p
->
num_objects
)
{
/* Check for ambiguousity */
const
unsigned
char
*
next
=
current
+
stride
;
if
(
!
git_oid_ncmp
(
short_oid
,
(
const
git_oid
*
)
next
,
len
))
{
found
=
2
;
}
}
if
(
!
found
)
{
return
git__throw
(
GIT_ENOTFOUND
,
"Failed to find offset for pack entry. Entry not found"
);
}
else
if
(
found
>
1
)
{
return
git__throw
(
GIT_EAMBIGUOUSOIDPREFIX
,
"Failed to find offset for pack entry. Ambiguous sha1 prefix within pack"
);
}
else
{
*
offset_out
=
nth_packed_object_offset
(
p
,
pos
);
git_oid_fromraw
(
found_oid
,
current
);
#ifdef INDEX_DEBUG_LOOKUP
unsigned
char
hex_sha1
[
GIT_OID_HEXSZ
+
1
];
git_oid_fmt
(
hex_sha1
,
found_oid
);
hex_sha1
[
GIT_OID_HEXSZ
]
=
'\0'
;
printf
(
"found lo=%d %s
\n
"
,
lo
,
hex_sha1
);
#endif
return
GIT_SUCCESS
;
}
}
int
git_pack_entry_find
(
struct
git_pack_entry
*
e
,
struct
git_pack_file
*
p
,
const
git_oid
*
short_oid
,
unsigned
int
len
)
{
off_t
offset
;
git_oid
found_oid
;
int
error
;
assert
(
p
);
if
(
len
==
GIT_OID_HEXSZ
&&
p
->
num_bad_objects
)
{
unsigned
i
;
for
(
i
=
0
;
i
<
p
->
num_bad_objects
;
i
++
)
if
(
git_oid_cmp
(
short_oid
,
&
p
->
bad_object_sha1
[
i
])
==
0
)
return
git__throw
(
GIT_ERROR
,
"Failed to find pack entry. Bad object found"
);
}
error
=
pack_entry_find_offset
(
&
offset
,
&
found_oid
,
p
,
short_oid
,
len
);
if
(
error
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to find pack entry. Couldn't find offset"
);
/* we found a unique entry in the index;
* make sure the packfile backing the index
* still exists on disk */
if
(
p
->
mwf
.
fd
==
-
1
&&
packfile_open
(
p
)
<
GIT_SUCCESS
)
return
git__throw
(
GIT_EOSERR
,
"Failed to find pack entry. Packfile doesn't exist on disk"
);
e
->
offset
=
offset
;
e
->
p
=
p
;
git_oid_cpy
(
&
e
->
sha1
,
&
found_oid
);
return
GIT_SUCCESS
;
}
src/pack.h
View file @
a070f152
...
...
@@ -36,7 +36,7 @@
#define PACK_SIGNATURE 0x5041434b
/* "PACK" */
#define PACK_VERSION 2
#define pack_version_ok(v) ((v) == htonl(2) || (v) == htonl(3))
struct
pack_header
{
struct
git_
pack_header
{
uint32_t
hdr_signature
;
uint32_t
hdr_version
;
uint32_t
hdr_entries
;
...
...
@@ -62,12 +62,12 @@ struct pack_header {
#define PACK_IDX_SIGNATURE 0xff744f63
/* "\377tOc" */
struct
pack_idx_header
{
struct
git_
pack_idx_header
{
uint32_t
idx_signature
;
uint32_t
idx_version
;
};
struct
pack_file
{
struct
git_
pack_file
{
git_mwindow_file
mwf
;
git_map
index_map
;
...
...
@@ -84,15 +84,12 @@ struct pack_file {
char
pack_name
[
GIT_FLEX_ARRAY
];
/* more */
};
struct
pack_entry
{
struct
git_
pack_entry
{
off_t
offset
;
git_oid
sha1
;
struct
pack_file
*
p
;
struct
git_
pack_file
*
p
;
};
static
unsigned
char
*
pack_window_open
(
struct
pack_file
*
p
,
git_mwindow
**
w_cursor
,
off_t
offset
,
unsigned
int
*
left
);
int
git_packfile_unpack_header
(
size_t
*
size_p
,
git_otype
*
type_p
,
...
...
@@ -100,19 +97,18 @@ int git_packfile_unpack_header(
git_mwindow
**
w_curs
,
off_t
*
curpos
);
int
packfile_unpack_delta
(
git_rawobj
*
obj
,
struct
pack_file
*
p
,
git_mwindow
**
w_curs
,
off_t
curpos
,
size_t
delta_size
,
git_otype
delta_type
,
off_t
obj_offset
);
int
packfile_unpack
(
git_rawobj
*
obj
,
struct
pack_file
*
p
,
off_t
obj_offset
);
int
git_packfile_unpack
(
git_rawobj
*
obj
,
struct
git_pack_file
*
p
,
off_t
obj_offset
);
off_t
get_delta_base
(
struct
pack_file
*
p
,
git_mwindow
**
w_curs
,
off_t
get_delta_base
(
struct
git_
pack_file
*
p
,
git_mwindow
**
w_curs
,
off_t
*
curpos
,
git_otype
type
,
off_t
delta_obj_offset
);
void
packfile_free
(
struct
git_pack_file
*
p
);
int
git_packfile_check
(
struct
git_pack_file
**
pack_out
,
const
char
*
path
);
int
git_pack_entry_find
(
struct
git_pack_entry
*
e
,
struct
git_pack_file
*
p
,
const
git_oid
*
short_oid
,
unsigned
int
len
);
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment