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
577cd8ae
Commit
577cd8ae
authored
Jul 30, 2012
by
Vicent Martí
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #840 from carlosmn/remote-unify
Unify the transport code
parents
50364dd8
0048372a
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
540 additions
and
782 deletions
+540
-782
examples/network/fetch.c
+8
-4
examples/network/git2.c
+3
-2
examples/network/index-pack.c
+10
-37
examples/network/ls-remote.c
+6
-3
src/common.h
+3
-0
src/fetch.c
+198
-22
src/fetch.h
+1
-2
src/netops.c
+37
-33
src/netops.h
+6
-3
src/pkt.c
+30
-8
src/protocol.c
+58
-28
src/protocol.h
+3
-9
src/remote.c
+20
-1
src/transport.h
+13
-9
src/transports/git.c
+25
-257
src/transports/http.c
+84
-332
src/transports/local.c
+35
-32
No files found.
examples/network/fetch.c
View file @
577cd8ae
...
@@ -40,9 +40,8 @@ exit:
...
@@ -40,9 +40,8 @@ exit:
pthread_exit
(
&
data
->
ret
);
pthread_exit
(
&
data
->
ret
);
}
}
int
update_cb
(
const
char
*
refname
,
const
git_oid
*
a
,
const
git_oid
*
b
,
void
*
data
)
static
int
update_cb
(
const
char
*
refname
,
const
git_oid
*
a
,
const
git_oid
*
b
,
void
*
data
)
{
{
const
char
*
action
;
char
a_str
[
GIT_OID_HEXSZ
+
1
],
b_str
[
GIT_OID_HEXSZ
+
1
];
char
a_str
[
GIT_OID_HEXSZ
+
1
],
b_str
[
GIT_OID_HEXSZ
+
1
];
git_oid_fmt
(
b_str
,
b
);
git_oid_fmt
(
b_str
,
b
);
...
@@ -68,6 +67,7 @@ int fetch(git_repository *repo, int argc, char **argv)
...
@@ -68,6 +67,7 @@ int fetch(git_repository *repo, int argc, char **argv)
struct
dl_data
data
;
struct
dl_data
data
;
git_remote_callbacks
callbacks
;
git_remote_callbacks
callbacks
;
argc
=
argc
;
// Figure out whether it's a named remote or a URL
// Figure out whether it's a named remote or a URL
printf
(
"Fetching %s
\n
"
,
argv
[
1
]);
printf
(
"Fetching %s
\n
"
,
argv
[
1
]);
if
(
git_remote_load
(
&
remote
,
repo
,
argv
[
1
])
<
0
)
{
if
(
git_remote_load
(
&
remote
,
repo
,
argv
[
1
])
<
0
)
{
...
@@ -96,10 +96,14 @@ int fetch(git_repository *repo, int argc, char **argv)
...
@@ -96,10 +96,14 @@ int fetch(git_repository *repo, int argc, char **argv)
// the download rate.
// the download rate.
do
{
do
{
usleep
(
10000
);
usleep
(
10000
);
printf
(
"
\r
Received %d/%d objects in %
d
bytes"
,
stats
.
processed
,
stats
.
total
,
bytes
);
printf
(
"
\r
Received %d/%d objects in %
zu
bytes"
,
stats
.
processed
,
stats
.
total
,
bytes
);
}
while
(
!
data
.
finished
);
}
while
(
!
data
.
finished
);
printf
(
"
\r
Received %d/%d objects in %d bytes
\n
"
,
stats
.
processed
,
stats
.
total
,
bytes
);
if
(
data
.
ret
<
0
)
goto
on_error
;
pthread_join
(
worker
,
NULL
);
printf
(
"
\r
Received %d/%d objects in %zu bytes
\n
"
,
stats
.
processed
,
stats
.
total
,
bytes
);
// Disconnect the underlying connection to prevent from idling.
// Disconnect the underlying connection to prevent from idling.
git_remote_disconnect
(
remote
);
git_remote_disconnect
(
remote
);
...
...
examples/network/git2.c
View file @
577cd8ae
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "common.h"
...
@@ -16,7 +17,7 @@ struct {
...
@@ -16,7 +17,7 @@ struct {
{
NULL
,
NULL
}
{
NULL
,
NULL
}
};
};
int
run_command
(
git_cb
fn
,
int
argc
,
char
**
argv
)
static
int
run_command
(
git_cb
fn
,
int
argc
,
char
**
argv
)
{
{
int
error
;
int
error
;
git_repository
*
repo
;
git_repository
*
repo
;
...
@@ -45,7 +46,7 @@ int run_command(git_cb fn, int argc, char **argv)
...
@@ -45,7 +46,7 @@ int run_command(git_cb fn, int argc, char **argv)
int
main
(
int
argc
,
char
**
argv
)
int
main
(
int
argc
,
char
**
argv
)
{
{
int
i
,
error
;
int
i
;
if
(
argc
<
2
)
{
if
(
argc
<
2
)
{
fprintf
(
stderr
,
"usage: %s <cmd> [repo]
\n
"
,
argv
[
0
]);
fprintf
(
stderr
,
"usage: %s <cmd> [repo]
\n
"
,
argv
[
0
]);
...
...
examples/network/index-pack.c
View file @
577cd8ae
...
@@ -2,13 +2,20 @@
...
@@ -2,13 +2,20 @@
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "common.h"
#include "common.h"
// This could be run in the main loop whilst the application waits for
// This could be run in the main loop whilst the application waits for
// the indexing to finish in a worker thread
// the indexing to finish in a worker thread
int
index_cb
(
const
git_indexer_stats
*
stats
,
void
*
data
)
static
int
index_cb
(
const
git_indexer_stats
*
stats
,
void
*
data
)
{
{
data
=
data
;
printf
(
"
\r
Processing %d of %d"
,
stats
->
processed
,
stats
->
total
);
printf
(
"
\r
Processing %d of %d"
,
stats
->
processed
,
stats
->
total
);
return
0
;
}
}
int
index_pack
(
git_repository
*
repo
,
int
argc
,
char
**
argv
)
int
index_pack
(
git_repository
*
repo
,
int
argc
,
char
**
argv
)
...
@@ -20,6 +27,7 @@ int index_pack(git_repository *repo, int argc, char **argv)
...
@@ -20,6 +27,7 @@ int index_pack(git_repository *repo, int argc, char **argv)
ssize_t
read_bytes
;
ssize_t
read_bytes
;
char
buf
[
512
];
char
buf
[
512
];
repo
=
repo
;
if
(
argc
<
2
)
{
if
(
argc
<
2
)
{
fprintf
(
stderr
,
"I need a packfile
\n
"
);
fprintf
(
stderr
,
"I need a packfile
\n
"
);
return
EXIT_FAILURE
;
return
EXIT_FAILURE
;
...
@@ -43,7 +51,7 @@ int index_pack(git_repository *repo, int argc, char **argv)
...
@@ -43,7 +51,7 @@ int index_pack(git_repository *repo, int argc, char **argv)
if
((
error
=
git_indexer_stream_add
(
idx
,
buf
,
read_bytes
,
&
stats
))
<
0
)
if
((
error
=
git_indexer_stream_add
(
idx
,
buf
,
read_bytes
,
&
stats
))
<
0
)
goto
cleanup
;
goto
cleanup
;
printf
(
"
\r
Indexing %d of %d"
,
stats
.
processed
,
stats
.
total
);
index_cb
(
&
stats
,
NULL
);
}
while
(
read_bytes
>
0
);
}
while
(
read_bytes
>
0
);
if
(
read_bytes
<
0
)
{
if
(
read_bytes
<
0
)
{
...
@@ -65,38 +73,3 @@ int index_pack(git_repository *repo, int argc, char **argv)
...
@@ -65,38 +73,3 @@ int index_pack(git_repository *repo, int argc, char **argv)
git_indexer_stream_free
(
idx
);
git_indexer_stream_free
(
idx
);
return
error
;
return
error
;
}
}
int
index_pack_old
(
git_repository
*
repo
,
int
argc
,
char
**
argv
)
{
git_indexer
*
indexer
;
git_indexer_stats
stats
;
int
error
;
char
hash
[
GIT_OID_HEXSZ
+
1
]
=
{
0
};
if
(
argc
<
2
)
{
fprintf
(
stderr
,
"I need a packfile
\n
"
);
return
EXIT_FAILURE
;
}
// Create a new indexer
error
=
git_indexer_new
(
&
indexer
,
argv
[
1
]);
if
(
error
<
0
)
return
error
;
// Index the packfile. This function can take a very long time and
// should be run in a worker thread.
error
=
git_indexer_run
(
indexer
,
&
stats
);
if
(
error
<
0
)
return
error
;
// Write the information out to an index file
error
=
git_indexer_write
(
indexer
);
// Get the packfile's hash (which should become it's filename)
git_oid_fmt
(
hash
,
git_indexer_hash
(
indexer
));
puts
(
hash
);
git_indexer_free
(
indexer
);
return
0
;
}
examples/network/ls-remote.c
View file @
577cd8ae
...
@@ -7,12 +7,14 @@
...
@@ -7,12 +7,14 @@
static
int
show_ref__cb
(
git_remote_head
*
head
,
void
*
payload
)
static
int
show_ref__cb
(
git_remote_head
*
head
,
void
*
payload
)
{
{
char
oid
[
GIT_OID_HEXSZ
+
1
]
=
{
0
};
char
oid
[
GIT_OID_HEXSZ
+
1
]
=
{
0
};
payload
=
payload
;
git_oid_fmt
(
oid
,
&
head
->
oid
);
git_oid_fmt
(
oid
,
&
head
->
oid
);
printf
(
"%s
\t
%s
\n
"
,
oid
,
head
->
name
);
printf
(
"%s
\t
%s
\n
"
,
oid
,
head
->
name
);
return
0
;
return
0
;
}
}
int
use_unnamed
(
git_repository
*
repo
,
const
char
*
url
)
static
int
use_unnamed
(
git_repository
*
repo
,
const
char
*
url
)
{
{
git_remote
*
remote
=
NULL
;
git_remote
*
remote
=
NULL
;
int
error
;
int
error
;
...
@@ -37,7 +39,7 @@ cleanup:
...
@@ -37,7 +39,7 @@ cleanup:
return
error
;
return
error
;
}
}
int
use_remote
(
git_repository
*
repo
,
char
*
name
)
static
int
use_remote
(
git_repository
*
repo
,
char
*
name
)
{
{
git_remote
*
remote
=
NULL
;
git_remote
*
remote
=
NULL
;
int
error
;
int
error
;
...
@@ -63,8 +65,9 @@ cleanup:
...
@@ -63,8 +65,9 @@ cleanup:
int
ls_remote
(
git_repository
*
repo
,
int
argc
,
char
**
argv
)
int
ls_remote
(
git_repository
*
repo
,
int
argc
,
char
**
argv
)
{
{
int
error
,
i
;
int
error
;
argc
=
argc
;
/* If there's a ':' in the name, assume it's an URL */
/* If there's a ':' in the name, assume it's an URL */
if
(
strchr
(
argv
[
1
],
':'
)
!=
NULL
)
{
if
(
strchr
(
argv
[
1
],
':'
)
!=
NULL
)
{
error
=
use_unnamed
(
repo
,
argv
[
1
]);
error
=
use_unnamed
(
repo
,
argv
[
1
]);
...
...
src/common.h
View file @
577cd8ae
...
@@ -59,4 +59,7 @@ void giterr_set_regex(const regex_t *regex, int error_code);
...
@@ -59,4 +59,7 @@ void giterr_set_regex(const regex_t *regex, int error_code);
#include "util.h"
#include "util.h"
typedef
struct
git_transport
git_transport
;
typedef
struct
gitno_buffer
gitno_buffer
;
#endif
/* INCLUDE_common_h__ */
#endif
/* INCLUDE_common_h__ */
src/fetch.c
View file @
577cd8ae
...
@@ -18,6 +18,7 @@
...
@@ -18,6 +18,7 @@
#include "pack.h"
#include "pack.h"
#include "fetch.h"
#include "fetch.h"
#include "netops.h"
#include "netops.h"
#include "pkt.h"
struct
filter_payload
{
struct
filter_payload
{
git_remote
*
remote
;
git_remote
*
remote
;
...
@@ -70,7 +71,62 @@ static int filter_wants(git_remote *remote)
...
@@ -70,7 +71,62 @@ static int filter_wants(git_remote *remote)
if
(
git_repository_odb__weakptr
(
&
p
.
odb
,
remote
->
repo
)
<
0
)
if
(
git_repository_odb__weakptr
(
&
p
.
odb
,
remote
->
repo
)
<
0
)
return
-
1
;
return
-
1
;
return
remote
->
transport
->
ls
(
remote
->
transport
,
&
filter_ref__cb
,
&
p
);
return
git_remote_ls
(
remote
,
filter_ref__cb
,
&
p
);
}
/* Wait until we get an ack from the */
static
int
recv_pkt
(
git_pkt
**
out
,
gitno_buffer
*
buf
)
{
const
char
*
ptr
=
buf
->
data
,
*
line_end
=
ptr
;
git_pkt
*
pkt
;
int
pkt_type
,
error
=
0
,
ret
;
do
{
if
(
buf
->
offset
>
0
)
error
=
git_pkt_parse_line
(
&
pkt
,
ptr
,
&
line_end
,
buf
->
offset
);
else
error
=
GIT_EBUFS
;
if
(
error
==
0
)
break
;
/* return the pkt */
if
(
error
<
0
&&
error
!=
GIT_EBUFS
)
return
-
1
;
if
((
ret
=
gitno_recv
(
buf
))
<
0
)
return
-
1
;
}
while
(
error
);
gitno_consume
(
buf
,
line_end
);
pkt_type
=
pkt
->
type
;
if
(
out
!=
NULL
)
*
out
=
pkt
;
else
git__free
(
pkt
);
return
pkt_type
;
}
static
int
store_common
(
git_transport
*
t
)
{
git_pkt
*
pkt
=
NULL
;
gitno_buffer
*
buf
=
&
t
->
buffer
;
do
{
if
(
recv_pkt
(
&
pkt
,
buf
)
<
0
)
return
-
1
;
if
(
pkt
->
type
==
GIT_PKT_ACK
)
{
if
(
git_vector_insert
(
&
t
->
common
,
pkt
)
<
0
)
return
-
1
;
}
else
{
git__free
(
pkt
);
return
0
;
}
}
while
(
1
);
return
0
;
}
}
/*
/*
...
@@ -81,6 +137,12 @@ static int filter_wants(git_remote *remote)
...
@@ -81,6 +137,12 @@ static int filter_wants(git_remote *remote)
int
git_fetch_negotiate
(
git_remote
*
remote
)
int
git_fetch_negotiate
(
git_remote
*
remote
)
{
{
git_transport
*
t
=
remote
->
transport
;
git_transport
*
t
=
remote
->
transport
;
gitno_buffer
*
buf
=
&
t
->
buffer
;
git_buf
data
=
GIT_BUF_INIT
;
git_revwalk
*
walk
=
NULL
;
int
error
,
pkt_type
;
unsigned
int
i
;
git_oid
oid
;
if
(
filter_wants
(
remote
)
<
0
)
{
if
(
filter_wants
(
remote
)
<
0
)
{
giterr_set
(
GITERR_NET
,
"Failed to filter the reference list for wants"
);
giterr_set
(
GITERR_NET
,
"Failed to filter the reference list for wants"
);
...
@@ -92,60 +154,174 @@ int git_fetch_negotiate(git_remote *remote)
...
@@ -92,60 +154,174 @@ int git_fetch_negotiate(git_remote *remote)
return
0
;
return
0
;
/*
/*
* Now we have everything set up so we can start tell the server
* Now we have everything set up so we can start tell the
* what we want and what we have.
* server what we want and what we have. Call the function if
* the transport has its own logic. This is transitional and
* will be removed once this function can support git and http.
*/
*/
if
(
t
->
own_logic
)
return
t
->
negotiate_fetch
(
t
,
remote
->
repo
,
&
remote
->
refs
);
return
t
->
negotiate_fetch
(
t
,
remote
->
repo
,
&
remote
->
refs
);
/* No own logic, do our thing */
if
(
git_pkt_buffer_wants
(
&
remote
->
refs
,
&
t
->
caps
,
&
data
)
<
0
)
return
-
1
;
if
(
git_fetch_setup_walk
(
&
walk
,
remote
->
repo
)
<
0
)
goto
on_error
;
/*
* We don't support any kind of ACK extensions, so the negotiation
* boils down to sending what we have and listening for an ACK
* every once in a while.
*/
i
=
0
;
while
((
error
=
git_revwalk_next
(
&
oid
,
walk
))
==
0
)
{
git_pkt_buffer_have
(
&
oid
,
&
data
);
i
++
;
if
(
i
%
20
==
0
)
{
git_pkt_buffer_flush
(
&
data
);
if
(
git_buf_oom
(
&
data
))
goto
on_error
;
if
(
t
->
negotiation_step
(
t
,
data
.
ptr
,
data
.
size
)
<
0
)
goto
on_error
;
git_buf_clear
(
&
data
);
if
(
t
->
caps
.
multi_ack
)
{
if
(
store_common
(
t
)
<
0
)
goto
on_error
;
}
else
{
pkt_type
=
recv_pkt
(
NULL
,
buf
);
if
(
pkt_type
==
GIT_PKT_ACK
)
{
break
;
}
else
if
(
pkt_type
==
GIT_PKT_NAK
)
{
continue
;
}
else
{
giterr_set
(
GITERR_NET
,
"Unexpected pkt type"
);
goto
on_error
;
}
}
}
if
(
t
->
common
.
length
>
0
)
break
;
if
(
i
%
20
==
0
&&
t
->
rpc
)
{
git_pkt_ack
*
pkt
;
unsigned
int
i
;
if
(
git_pkt_buffer_wants
(
&
remote
->
refs
,
&
t
->
caps
,
&
data
)
<
0
)
goto
on_error
;
git_vector_foreach
(
&
t
->
common
,
i
,
pkt
)
{
git_pkt_buffer_have
(
&
pkt
->
oid
,
&
data
);
}
if
(
git_buf_oom
(
&
data
))
goto
on_error
;
}
}
if
(
error
<
0
&&
error
!=
GIT_REVWALKOVER
)
goto
on_error
;
/* Tell the other end that we're done negotiating */
if
(
t
->
rpc
&&
t
->
common
.
length
>
0
)
{
git_pkt_ack
*
pkt
;
unsigned
int
i
;
if
(
git_pkt_buffer_wants
(
&
remote
->
refs
,
&
t
->
caps
,
&
data
)
<
0
)
goto
on_error
;
git_vector_foreach
(
&
t
->
common
,
i
,
pkt
)
{
git_pkt_buffer_have
(
&
pkt
->
oid
,
&
data
);
}
if
(
git_buf_oom
(
&
data
))
goto
on_error
;
}
git_pkt_buffer_done
(
&
data
);
if
(
t
->
negotiation_step
(
t
,
data
.
ptr
,
data
.
size
)
<
0
)
goto
on_error
;
git_buf_free
(
&
data
);
git_revwalk_free
(
walk
);
/* Now let's eat up whatever the server gives us */
if
(
!
t
->
caps
.
multi_ack
)
{
pkt_type
=
recv_pkt
(
NULL
,
buf
);
if
(
pkt_type
!=
GIT_PKT_ACK
&&
pkt_type
!=
GIT_PKT_NAK
)
{
giterr_set
(
GITERR_NET
,
"Unexpected pkt type"
);
return
-
1
;
}
}
else
{
git_pkt_ack
*
pkt
;
do
{
if
(
recv_pkt
((
git_pkt
**
)
&
pkt
,
buf
)
<
0
)
return
-
1
;
if
(
pkt
->
type
==
GIT_PKT_NAK
||
(
pkt
->
type
==
GIT_PKT_ACK
&&
pkt
->
status
!=
GIT_ACK_CONTINUE
))
{
git__free
(
pkt
);
break
;
}
git__free
(
pkt
);
}
while
(
1
);
}
return
0
;
on_error:
git_revwalk_free
(
walk
);
git_buf_free
(
&
data
);
return
-
1
;
}
}
int
git_fetch_download_pack
(
git_remote
*
remote
,
git_off_t
*
bytes
,
git_indexer_stats
*
stats
)
int
git_fetch_download_pack
(
git_remote
*
remote
,
git_off_t
*
bytes
,
git_indexer_stats
*
stats
)
{
{
git_transport
*
t
=
remote
->
transport
;
if
(
!
remote
->
need_pack
)
if
(
!
remote
->
need_pack
)
return
0
;
return
0
;
return
remote
->
transport
->
download_pack
(
remote
->
transport
,
remote
->
repo
,
bytes
,
stats
);
if
(
t
->
own_logic
)
return
t
->
download_pack
(
t
,
remote
->
repo
,
bytes
,
stats
);
return
git_fetch__download_pack
(
t
,
remote
->
repo
,
bytes
,
stats
);
}
}
/* Receiving data from a socket and storing it is pretty much the same for git and HTTP */
/* Receiving data from a socket and storing it is pretty much the same for git and HTTP */
int
git_fetch__download_pack
(
int
git_fetch__download_pack
(
const
char
*
buffered
,
size_t
buffered_size
,
git_transport
*
t
,
git_transport
*
t
,
git_repository
*
repo
,
git_repository
*
repo
,
git_off_t
*
bytes
,
git_off_t
*
bytes
,
git_indexer_stats
*
stats
)
git_indexer_stats
*
stats
)
{
{
int
recvd
;
int
recvd
;
char
buff
[
1024
];
gitno_buffer
buf
;
git_buf
path
=
GIT_BUF_INIT
;
git_buf
path
=
GIT_BUF_INIT
;
gitno_buffer
*
buf
=
&
t
->
buffer
;
git_indexer_stream
*
idx
=
NULL
;
git_indexer_stream
*
idx
=
NULL
;
gitno_buffer_setup
(
t
,
&
buf
,
buff
,
sizeof
(
buff
));
if
(
memcmp
(
buffered
,
"PACK"
,
strlen
(
"PACK"
)))
{
giterr_set
(
GITERR_NET
,
"The pack doesn't start with the signature"
);
return
-
1
;
}
if
(
git_buf_joinpath
(
&
path
,
git_repository_path
(
repo
),
"objects/pack"
)
<
0
)
if
(
git_buf_joinpath
(
&
path
,
git_repository_path
(
repo
),
"objects/pack"
)
<
0
)
return
-
1
;
return
-
1
;
if
(
git_indexer_stream_new
(
&
idx
,
git_buf_cstr
(
&
path
))
<
0
)
if
(
git_indexer_stream_new
(
&
idx
,
git_buf_cstr
(
&
path
))
<
0
)
goto
on_error
;
goto
on_error
;
git_buf_free
(
&
path
);
memset
(
stats
,
0
,
sizeof
(
git_indexer_stats
));
memset
(
stats
,
0
,
sizeof
(
git_indexer_stats
));
if
(
git_indexer_stream_add
(
idx
,
buffered
,
buffered_size
,
stats
)
<
0
)
*
bytes
=
0
;
goto
on_error
;
*
bytes
=
buffered_size
;
do
{
do
{
if
(
git_indexer_stream_add
(
idx
,
buf
.
data
,
buf
.
offset
,
stats
)
<
0
)
if
(
git_indexer_stream_add
(
idx
,
buf
->
data
,
buf
->
offset
,
stats
)
<
0
)
goto
on_error
;
goto
on_error
;
gitno_consume_n
(
&
buf
,
buf
.
offset
);
gitno_consume_n
(
buf
,
buf
->
offset
);
if
((
recvd
=
gitno_recv
(
&
buf
))
<
0
)
if
((
recvd
=
gitno_recv
(
buf
))
<
0
)
goto
on_error
;
goto
on_error
;
*
bytes
+=
recvd
;
*
bytes
+=
recvd
;
...
...
src/fetch.h
View file @
577cd8ae
...
@@ -12,8 +12,7 @@
...
@@ -12,8 +12,7 @@
int
git_fetch_negotiate
(
git_remote
*
remote
);
int
git_fetch_negotiate
(
git_remote
*
remote
);
int
git_fetch_download_pack
(
git_remote
*
remote
,
git_off_t
*
bytes
,
git_indexer_stats
*
stats
);
int
git_fetch_download_pack
(
git_remote
*
remote
,
git_off_t
*
bytes
,
git_indexer_stats
*
stats
);
int
git_fetch__download_pack
(
const
char
*
buffered
,
size_t
buffered_size
,
git_transport
*
t
,
int
git_fetch__download_pack
(
git_transport
*
t
,
git_repository
*
repo
,
git_off_t
*
bytes
,
git_indexer_stats
*
stats
);
git_repository
*
repo
,
git_off_t
*
bytes
,
git_indexer_stats
*
stats
);
int
git_fetch_setup_walk
(
git_revwalk
**
out
,
git_repository
*
repo
);
int
git_fetch_setup_walk
(
git_revwalk
**
out
,
git_repository
*
repo
);
#endif
#endif
src/netops.c
View file @
577cd8ae
...
@@ -61,63 +61,67 @@ static int ssl_set_error(gitno_ssl *ssl, int error)
...
@@ -61,63 +61,67 @@ static int ssl_set_error(gitno_ssl *ssl, int error)
}
}
#endif
#endif
void
gitno_buffer_setup
(
git_transport
*
t
,
gitno_buffer
*
buf
,
char
*
data
,
unsigned
int
len
)
int
gitno_recv
(
gitno_buffer
*
buf
)
{
{
memset
(
buf
,
0x0
,
sizeof
(
gitno_buffer
));
return
buf
->
recv
(
buf
);
memset
(
data
,
0x0
,
len
);
buf
->
data
=
data
;
buf
->
len
=
len
;
buf
->
offset
=
0
;
buf
->
fd
=
t
->
socket
;
#ifdef GIT_SSL
if
(
t
->
encrypt
)
buf
->
ssl
=
&
t
->
ssl
;
#endif
}
}
#ifdef GIT_SSL
#ifdef GIT_SSL
static
int
ssl_recv
(
gitno_ssl
*
ssl
,
void
*
data
,
size_t
len
)
static
int
gitno__recv_ssl
(
gitno_buffer
*
buf
)
{
{
int
ret
;
int
ret
;
do
{
do
{
ret
=
SSL_read
(
ssl
->
ssl
,
data
,
len
);
ret
=
SSL_read
(
buf
->
ssl
->
ssl
,
buf
->
data
+
buf
->
offset
,
buf
->
len
-
buf
->
offset
);
}
while
(
SSL_get_error
(
ssl
->
ssl
,
ret
)
==
SSL_ERROR_WANT_READ
);
}
while
(
SSL_get_error
(
buf
->
ssl
->
ssl
,
ret
)
==
SSL_ERROR_WANT_READ
);
if
(
ret
<
0
)
if
(
ret
<
0
)
{
return
ssl_set_error
(
ssl
,
ret
);
net_set_error
(
"Error receiving socket data"
);
return
-
1
;
}
buf
->
offset
+=
ret
;
return
ret
;
return
ret
;
}
}
#endif
#endif
int
gitno_recv
(
gitno_buffer
*
buf
)
int
gitno_
_
recv
(
gitno_buffer
*
buf
)
{
{
int
ret
;
int
ret
;
#ifdef GIT_SSL
if
(
buf
->
ssl
!=
NULL
)
{
if
((
ret
=
ssl_recv
(
buf
->
ssl
,
buf
->
data
+
buf
->
offset
,
buf
->
len
-
buf
->
offset
))
<
0
)
return
-
1
;
}
else
{
ret
=
p_recv
(
buf
->
fd
,
buf
->
data
+
buf
->
offset
,
buf
->
len
-
buf
->
offset
,
0
);
if
(
ret
<
0
)
{
net_set_error
(
"Error receiving socket data"
);
return
-
1
;
}
}
#else
ret
=
p_recv
(
buf
->
fd
,
buf
->
data
+
buf
->
offset
,
buf
->
len
-
buf
->
offset
,
0
);
ret
=
p_recv
(
buf
->
fd
,
buf
->
data
+
buf
->
offset
,
buf
->
len
-
buf
->
offset
,
0
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
net_set_error
(
"Error receiving socket data"
);
net_set_error
(
"Error receiving socket data"
);
return
-
1
;
return
-
1
;
}
}
#endif
buf
->
offset
+=
ret
;
buf
->
offset
+=
ret
;
return
ret
;
return
ret
;
}
}
void
gitno_buffer_setup_callback
(
git_transport
*
t
,
gitno_buffer
*
buf
,
char
*
data
,
unsigned
int
len
,
int
(
*
recv
)(
gitno_buffer
*
buf
),
void
*
cb_data
)
{
memset
(
buf
,
0x0
,
sizeof
(
gitno_buffer
));
memset
(
data
,
0x0
,
len
);
buf
->
data
=
data
;
buf
->
len
=
len
;
buf
->
offset
=
0
;
buf
->
fd
=
t
->
socket
;
buf
->
recv
=
recv
;
buf
->
cb_data
=
cb_data
;
}
void
gitno_buffer_setup
(
git_transport
*
t
,
gitno_buffer
*
buf
,
char
*
data
,
unsigned
int
len
)
{
#ifdef GIT_SSL
if
(
t
->
use_ssl
)
{
gitno_buffer_setup_callback
(
t
,
buf
,
data
,
len
,
gitno__recv_ssl
,
NULL
);
buf
->
ssl
=
&
t
->
ssl
;
}
else
#endif
gitno_buffer_setup_callback
(
t
,
buf
,
data
,
len
,
gitno__recv
,
NULL
);
}
/* Consume up to ptr and move the rest of the buffer to the beginning */
/* Consume up to ptr and move the rest of the buffer to the beginning */
void
gitno_consume
(
gitno_buffer
*
buf
,
const
char
*
ptr
)
void
gitno_consume
(
gitno_buffer
*
buf
,
const
char
*
ptr
)
{
{
...
@@ -147,7 +151,7 @@ int gitno_ssl_teardown(git_transport *t)
...
@@ -147,7 +151,7 @@ int gitno_ssl_teardown(git_transport *t)
int
ret
;
int
ret
;
#endif
#endif
if
(
!
t
->
encrypt
)
if
(
!
t
->
use_ssl
)
return
0
;
return
0
;
#ifdef GIT_SSL
#ifdef GIT_SSL
...
@@ -415,7 +419,7 @@ int gitno_connect(git_transport *t, const char *host, const char *port)
...
@@ -415,7 +419,7 @@ int gitno_connect(git_transport *t, const char *host, const char *port)
t
->
socket
=
s
;
t
->
socket
=
s
;
p_freeaddrinfo
(
info
);
p_freeaddrinfo
(
info
);
if
(
t
->
encrypt
&&
ssl_setup
(
t
,
host
)
<
0
)
if
(
t
->
use_ssl
&&
ssl_setup
(
t
,
host
)
<
0
)
return
-
1
;
return
-
1
;
return
0
;
return
0
;
...
@@ -445,7 +449,7 @@ int gitno_send(git_transport *t, const char *msg, size_t len, int flags)
...
@@ -445,7 +449,7 @@ int gitno_send(git_transport *t, const char *msg, size_t len, int flags)
size_t
off
=
0
;
size_t
off
=
0
;
#ifdef GIT_SSL
#ifdef GIT_SSL
if
(
t
->
encrypt
)
if
(
t
->
use_ssl
)
return
send_ssl
(
&
t
->
ssl
,
msg
,
len
);
return
send_ssl
(
&
t
->
ssl
,
msg
,
len
);
#endif
#endif
...
...
src/netops.h
View file @
577cd8ae
...
@@ -8,10 +8,9 @@
...
@@ -8,10 +8,9 @@
#define INCLUDE_netops_h__
#define INCLUDE_netops_h__
#include "posix.h"
#include "posix.h"
#include "transport.h"
#include "common.h"
#include "common.h"
typedef
struct
gitno_buffer
{
struct
gitno_buffer
{
char
*
data
;
char
*
data
;
size_t
len
;
size_t
len
;
size_t
offset
;
size_t
offset
;
...
@@ -19,10 +18,14 @@ typedef struct gitno_buffer {
...
@@ -19,10 +18,14 @@ typedef struct gitno_buffer {
#ifdef GIT_SSL
#ifdef GIT_SSL
struct
gitno_ssl
*
ssl
;
struct
gitno_ssl
*
ssl
;
#endif
#endif
}
gitno_buffer
;
int
(
*
recv
)(
gitno_buffer
*
buffer
);
void
*
cb_data
;
};
void
gitno_buffer_setup
(
git_transport
*
t
,
gitno_buffer
*
buf
,
char
*
data
,
unsigned
int
len
);
void
gitno_buffer_setup
(
git_transport
*
t
,
gitno_buffer
*
buf
,
char
*
data
,
unsigned
int
len
);
void
gitno_buffer_setup_callback
(
git_transport
*
t
,
gitno_buffer
*
buf
,
char
*
data
,
unsigned
int
len
,
int
(
*
recv
)(
gitno_buffer
*
buf
),
void
*
cb_data
);
int
gitno_recv
(
gitno_buffer
*
buf
);
int
gitno_recv
(
gitno_buffer
*
buf
);
int
gitno__recv
(
gitno_buffer
*
buf
);
void
gitno_consume
(
gitno_buffer
*
buf
,
const
char
*
ptr
);
void
gitno_consume
(
gitno_buffer
*
buf
,
const
char
*
ptr
);
void
gitno_consume_n
(
gitno_buffer
*
buf
,
size_t
cons
);
void
gitno_consume_n
(
gitno_buffer
*
buf
,
size_t
cons
);
...
...
src/pkt.c
View file @
577cd8ae
...
@@ -42,15 +42,29 @@ static int flush_pkt(git_pkt **out)
...
@@ -42,15 +42,29 @@ static int flush_pkt(git_pkt **out)
/* the rest of the line will be useful for multi_ack */
/* the rest of the line will be useful for multi_ack */
static
int
ack_pkt
(
git_pkt
**
out
,
const
char
*
line
,
size_t
len
)
static
int
ack_pkt
(
git_pkt
**
out
,
const
char
*
line
,
size_t
len
)
{
{
git_pkt
*
pkt
;
git_pkt
_ack
*
pkt
;
GIT_UNUSED
(
line
);
GIT_UNUSED
(
line
);
GIT_UNUSED
(
len
);
GIT_UNUSED
(
len
);
pkt
=
git__
malloc
(
sizeof
(
git_pkt
));
pkt
=
git__
calloc
(
1
,
sizeof
(
git_pkt_ack
));
GITERR_CHECK_ALLOC
(
pkt
);
GITERR_CHECK_ALLOC
(
pkt
);
pkt
->
type
=
GIT_PKT_ACK
;
pkt
->
type
=
GIT_PKT_ACK
;
*
out
=
pkt
;
line
+=
3
;
len
-=
3
;
if
(
len
>=
GIT_OID_HEXSZ
)
{
git_oid_fromstr
(
&
pkt
->
oid
,
line
+
1
);
line
+=
GIT_OID_HEXSZ
+
1
;
len
-=
GIT_OID_HEXSZ
+
1
;
}
if
(
len
>=
7
)
{
if
(
!
git__prefixcmp
(
line
+
1
,
"continue"
))
pkt
->
status
=
GIT_ACK_CONTINUE
;
}
*
out
=
(
git_pkt
*
)
pkt
;
return
0
;
return
0
;
}
}
...
@@ -283,20 +297,28 @@ int git_pkt_buffer_flush(git_buf *buf)
...
@@ -283,20 +297,28 @@ int git_pkt_buffer_flush(git_buf *buf)
static
int
buffer_want_with_caps
(
git_remote_head
*
head
,
git_transport_caps
*
caps
,
git_buf
*
buf
)
static
int
buffer_want_with_caps
(
git_remote_head
*
head
,
git_transport_caps
*
caps
,
git_buf
*
buf
)
{
{
char
capstr
[
20
]
;
git_buf
str
=
GIT_BUF_INIT
;
char
oid
[
GIT_OID_HEXSZ
+
1
]
=
{
0
};
char
oid
[
GIT_OID_HEXSZ
+
1
]
=
{
0
};
unsigned
int
len
;
unsigned
int
len
;
if
(
caps
->
ofs_delta
)
if
(
caps
->
ofs_delta
)
strncpy
(
capstr
,
GIT_CAP_OFS_DELTA
,
sizeof
(
capstr
));
git_buf_puts
(
&
str
,
GIT_CAP_OFS_DELTA
" "
);
if
(
caps
->
multi_ack
)
git_buf_puts
(
&
str
,
GIT_CAP_MULTI_ACK
" "
);
if
(
git_buf_oom
(
&
str
))
return
-
1
;
len
=
(
unsigned
int
)
len
=
(
unsigned
int
)
(
strlen
(
"XXXXwant "
)
+
GIT_OID_HEXSZ
+
1
/* NUL */
+
(
strlen
(
"XXXXwant "
)
+
GIT_OID_HEXSZ
+
1
/* NUL */
+
strlen
(
cap
str
)
+
1
/* LF */
);
git_buf_len
(
&
str
)
+
1
/* LF */
);
git_buf_grow
(
buf
,
git_buf_len
(
buf
)
+
len
);
git_buf_grow
(
buf
,
git_buf_len
(
buf
)
+
len
);
git_oid_fmt
(
oid
,
&
head
->
oid
);
git_oid_fmt
(
oid
,
&
head
->
oid
);
return
git_buf_printf
(
buf
,
"%04xwant %s %s
\n
"
,
len
,
oid
,
capstr
);
git_buf_printf
(
buf
,
"%04xwant %s %s
\n
"
,
len
,
oid
,
git_buf_cstr
(
&
str
));
git_buf_free
(
&
str
);
return
git_buf_oom
(
buf
);
}
}
/*
/*
...
...
src/protocol.c
View file @
577cd8ae
...
@@ -9,38 +9,36 @@
...
@@ -9,38 +9,36 @@
#include "pkt.h"
#include "pkt.h"
#include "buffer.h"
#include "buffer.h"
int
git_protocol_store_refs
(
git_
protocol
*
p
,
const
char
*
data
,
size_t
len
)
int
git_protocol_store_refs
(
git_
transport
*
t
,
int
flushes
)
{
{
git_buf
*
buf
=
&
p
->
buf
;
gitno_buffer
*
buf
=
&
t
->
buffer
;
git_vector
*
refs
=
p
->
refs
;
git_vector
*
refs
=
&
t
->
refs
;
int
error
;
int
error
,
flush
=
0
,
recvd
;
const
char
*
line_end
,
*
ptr
;
const
char
*
line_end
;
if
(
len
==
0
)
{
/* EOF */
if
(
git_buf_len
(
buf
)
!=
0
)
{
giterr_set
(
GITERR_NET
,
"Unexpected EOF"
);
return
p
->
error
=
-
1
;
}
else
{
return
0
;
}
}
git_buf_put
(
buf
,
data
,
len
);
ptr
=
buf
->
ptr
;
while
(
1
)
{
git_pkt
*
pkt
;
git_pkt
*
pkt
;
if
(
git_buf_len
(
buf
)
==
0
)
do
{
return
0
;
if
(
buf
->
offset
>
0
)
error
=
git_pkt_parse_line
(
&
pkt
,
buf
->
data
,
&
line_end
,
buf
->
offset
);
else
error
=
GIT_EBUFS
;
error
=
git_pkt_parse_line
(
&
pkt
,
ptr
,
&
line_end
,
git_buf_len
(
buf
));
if
(
error
<
0
&&
error
!=
GIT_EBUFS
)
if
(
error
==
GIT_EBUFS
)
return
-
1
;
return
0
;
/* Ask for more */
if
(
error
<
0
)
return
p
->
error
=
-
1
;
git_buf_consume
(
buf
,
line_end
);
if
(
error
==
GIT_EBUFS
)
{
if
((
recvd
=
gitno_recv
(
buf
))
<
0
)
return
-
1
;
if
(
recvd
==
0
&&
!
flush
)
{
giterr_set
(
GITERR_NET
,
"Early EOF"
);
return
-
1
;
}
continue
;
}
gitno_consume
(
buf
,
line_end
);
if
(
pkt
->
type
==
GIT_PKT_ERR
)
{
if
(
pkt
->
type
==
GIT_PKT_ERR
)
{
giterr_set
(
GITERR_NET
,
"Remote error: %s"
,
((
git_pkt_err
*
)
pkt
)
->
error
);
giterr_set
(
GITERR_NET
,
"Remote error: %s"
,
((
git_pkt_err
*
)
pkt
)
->
error
);
git__free
(
pkt
);
git__free
(
pkt
);
...
@@ -48,10 +46,42 @@ int git_protocol_store_refs(git_protocol *p, const char *data, size_t len)
...
@@ -48,10 +46,42 @@ int git_protocol_store_refs(git_protocol *p, const char *data, size_t len)
}
}
if
(
git_vector_insert
(
refs
,
pkt
)
<
0
)
if
(
git_vector_insert
(
refs
,
pkt
)
<
0
)
return
p
->
error
=
-
1
;
return
-
1
;
if
(
pkt
->
type
==
GIT_PKT_FLUSH
)
if
(
pkt
->
type
==
GIT_PKT_FLUSH
)
p
->
flush
=
1
;
flush
++
;
}
while
(
flush
<
flushes
);
return
flush
;
}
int
git_protocol_detect_caps
(
git_pkt_ref
*
pkt
,
git_transport_caps
*
caps
)
{
const
char
*
ptr
;
/* No refs or capabilites, odd but not a problem */
if
(
pkt
==
NULL
||
pkt
->
capabilities
==
NULL
)
return
0
;
ptr
=
pkt
->
capabilities
;
while
(
ptr
!=
NULL
&&
*
ptr
!=
'\0'
)
{
if
(
*
ptr
==
' '
)
ptr
++
;
if
(
!
git__prefixcmp
(
ptr
,
GIT_CAP_OFS_DELTA
))
{
caps
->
common
=
caps
->
ofs_delta
=
1
;
ptr
+=
strlen
(
GIT_CAP_OFS_DELTA
);
continue
;
}
if
(
!
git__prefixcmp
(
ptr
,
GIT_CAP_MULTI_ACK
))
{
caps
->
common
=
caps
->
multi_ack
=
1
;
ptr
+=
strlen
(
GIT_CAP_MULTI_ACK
);
continue
;
}
/* We don't know this capability, so skip it */
ptr
=
strchr
(
ptr
,
' '
);
}
}
return
0
;
return
0
;
...
...
src/protocol.h
View file @
577cd8ae
...
@@ -9,15 +9,9 @@
...
@@ -9,15 +9,9 @@
#include "transport.h"
#include "transport.h"
#include "buffer.h"
#include "buffer.h"
#include "pkt.h"
typedef
struct
{
int
git_protocol_store_refs
(
git_transport
*
t
,
int
flushes
);
git_transport
*
transport
;
int
git_protocol_detect_caps
(
git_pkt_ref
*
pkt
,
git_transport_caps
*
caps
);
git_vector
*
refs
;
git_buf
buf
;
int
error
;
unsigned
int
flush
:
1
;
}
git_protocol
;
int
git_protocol_store_refs
(
git_protocol
*
p
,
const
char
*
data
,
size_t
len
);
#endif
#endif
src/remote.c
View file @
577cd8ae
...
@@ -14,6 +14,7 @@
...
@@ -14,6 +14,7 @@
#include "remote.h"
#include "remote.h"
#include "fetch.h"
#include "fetch.h"
#include "refs.h"
#include "refs.h"
#include "pkt.h"
#include <regex.h>
#include <regex.h>
...
@@ -401,6 +402,10 @@ on_error:
...
@@ -401,6 +402,10 @@ on_error:
int
git_remote_ls
(
git_remote
*
remote
,
git_headlist_cb
list_cb
,
void
*
payload
)
int
git_remote_ls
(
git_remote
*
remote
,
git_headlist_cb
list_cb
,
void
*
payload
)
{
{
git_vector
*
refs
=
&
remote
->
transport
->
refs
;
unsigned
int
i
;
git_pkt
*
p
=
NULL
;
assert
(
remote
);
assert
(
remote
);
if
(
!
remote
->
transport
||
!
remote
->
transport
->
connected
)
{
if
(
!
remote
->
transport
||
!
remote
->
transport
->
connected
)
{
...
@@ -408,7 +413,21 @@ int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
...
@@ -408,7 +413,21 @@ int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
return
-
1
;
return
-
1
;
}
}
return
remote
->
transport
->
ls
(
remote
->
transport
,
list_cb
,
payload
);
git_vector_foreach
(
refs
,
i
,
p
)
{
git_pkt_ref
*
pkt
=
NULL
;
if
(
p
->
type
!=
GIT_PKT_REF
)
continue
;
pkt
=
(
git_pkt_ref
*
)
p
;
if
(
list_cb
(
&
pkt
->
head
,
payload
)
<
0
)
{
giterr_set
(
GITERR_NET
,
"User callback returned error"
);
return
-
1
;
}
}
return
0
;
}
}
int
git_remote_download
(
git_remote
*
remote
,
git_off_t
*
bytes
,
git_indexer_stats
*
stats
)
int
git_remote_download
(
git_remote
*
remote
,
git_off_t
*
bytes
,
git_indexer_stats
*
stats
)
...
...
src/transport.h
View file @
577cd8ae
...
@@ -12,6 +12,7 @@
...
@@ -12,6 +12,7 @@
#include "vector.h"
#include "vector.h"
#include "posix.h"
#include "posix.h"
#include "common.h"
#include "common.h"
#include "netops.h"
#ifdef GIT_SSL
#ifdef GIT_SSL
# include <openssl/ssl.h>
# include <openssl/ssl.h>
# include <openssl/err.h>
# include <openssl/err.h>
...
@@ -19,10 +20,12 @@
...
@@ -19,10 +20,12 @@
#define GIT_CAP_OFS_DELTA "ofs-delta"
#define GIT_CAP_OFS_DELTA "ofs-delta"
#define GIT_CAP_MULTI_ACK "multi_ack"
typedef
struct
git_transport_caps
{
typedef
struct
git_transport_caps
{
int
common
:
1
,
int
common
:
1
,
ofs_delta
:
1
;
ofs_delta
:
1
,
multi_ack
:
1
;
}
git_transport_caps
;
}
git_transport_caps
;
#ifdef GIT_SSL
#ifdef GIT_SSL
...
@@ -70,19 +73,25 @@ struct git_transport {
...
@@ -70,19 +73,25 @@ struct git_transport {
int
direction
:
1
,
/* 0 fetch, 1 push */
int
direction
:
1
,
/* 0 fetch, 1 push */
connected
:
1
,
connected
:
1
,
check_cert
:
1
,
check_cert
:
1
,
encrypt
:
1
;
use_ssl
:
1
,
own_logic
:
1
,
/* transitional */
rpc
:
1
;
/* git-speak for the HTTP transport */
#ifdef GIT_SSL
#ifdef GIT_SSL
struct
gitno_ssl
ssl
;
struct
gitno_ssl
ssl
;
#endif
#endif
git_vector
refs
;
git_vector
common
;
gitno_buffer
buffer
;
GIT_SOCKET
socket
;
GIT_SOCKET
socket
;
git_transport_caps
caps
;
/**
/**
* Connect and store the remote heads
* Connect and store the remote heads
*/
*/
int
(
*
connect
)(
struct
git_transport
*
transport
,
int
dir
);
int
(
*
connect
)(
struct
git_transport
*
transport
,
int
dir
);
/**
/**
*
Give a list of references, useful for ls-remote
*
Send our side of a negotiation
*/
*/
int
(
*
ls
)(
struct
git_transport
*
transport
,
git_headlist_cb
list_cb
,
void
*
opaque
);
int
(
*
negotiation_step
)(
struct
git_transport
*
transport
,
void
*
data
,
size_t
len
);
/**
/**
* Push the changes over
* Push the changes over
*/
*/
...
@@ -97,10 +106,6 @@ struct git_transport {
...
@@ -97,10 +106,6 @@ struct git_transport {
*/
*/
int
(
*
download_pack
)(
struct
git_transport
*
transport
,
git_repository
*
repo
,
git_off_t
*
bytes
,
git_indexer_stats
*
stats
);
int
(
*
download_pack
)(
struct
git_transport
*
transport
,
git_repository
*
repo
,
git_off_t
*
bytes
,
git_indexer_stats
*
stats
);
/**
/**
* Fetch the changes
*/
int
(
*
fetch
)(
struct
git_transport
*
transport
);
/**
* Close the connection
* Close the connection
*/
*/
int
(
*
close
)(
struct
git_transport
*
transport
);
int
(
*
close
)(
struct
git_transport
*
transport
);
...
@@ -124,7 +129,6 @@ int git_transport_dummy(struct git_transport **transport);
...
@@ -124,7 +129,6 @@ int git_transport_dummy(struct git_transport **transport);
*/
*/
int
git_transport_valid_url
(
const
char
*
url
);
int
git_transport_valid_url
(
const
char
*
url
);
typedef
struct
git_transport
git_transport
;
typedef
int
(
*
git_transport_cb
)(
git_transport
**
transport
);
typedef
int
(
*
git_transport_cb
)(
git_transport
**
transport
);
#endif
#endif
src/transports/git.c
View file @
577cd8ae
...
@@ -24,12 +24,7 @@
...
@@ -24,12 +24,7 @@
typedef
struct
{
typedef
struct
{
git_transport
parent
;
git_transport
parent
;
git_protocol
proto
;
git_vector
refs
;
git_remote_head
**
heads
;
git_transport_caps
caps
;
char
buff
[
1024
];
char
buff
[
1024
];
gitno_buffer
buf
;
#ifdef GIT_WIN32
#ifdef GIT_WIN32
WSADATA
wsd
;
WSADATA
wsd
;
#endif
#endif
...
@@ -127,68 +122,6 @@ on_error:
...
@@ -127,68 +122,6 @@ on_error:
}
}
/*
/*
* Read from the socket and store the references in the vector
*/
static
int
store_refs
(
transport_git
*
t
)
{
gitno_buffer
*
buf
=
&
t
->
buf
;
int
ret
=
0
;
while
(
1
)
{
if
((
ret
=
gitno_recv
(
buf
))
<
0
)
return
-
1
;
if
(
ret
==
0
)
/* Orderly shutdown, so exit */
return
0
;
ret
=
git_protocol_store_refs
(
&
t
->
proto
,
buf
->
data
,
buf
->
offset
);
if
(
ret
==
GIT_EBUFS
)
{
gitno_consume_n
(
buf
,
buf
->
len
);
continue
;
}
if
(
ret
<
0
)
return
ret
;
gitno_consume_n
(
buf
,
buf
->
offset
);
if
(
t
->
proto
.
flush
)
{
/* No more refs */
t
->
proto
.
flush
=
0
;
return
0
;
}
}
}
static
int
detect_caps
(
transport_git
*
t
)
{
git_vector
*
refs
=
&
t
->
refs
;
git_pkt_ref
*
pkt
;
git_transport_caps
*
caps
=
&
t
->
caps
;
const
char
*
ptr
;
pkt
=
git_vector_get
(
refs
,
0
);
/* No refs or capabilites, odd but not a problem */
if
(
pkt
==
NULL
||
pkt
->
capabilities
==
NULL
)
return
0
;
ptr
=
pkt
->
capabilities
;
while
(
ptr
!=
NULL
&&
*
ptr
!=
'\0'
)
{
if
(
*
ptr
==
' '
)
ptr
++
;
if
(
!
git__prefixcmp
(
ptr
,
GIT_CAP_OFS_DELTA
))
{
caps
->
common
=
caps
->
ofs_delta
=
1
;
ptr
+=
strlen
(
GIT_CAP_OFS_DELTA
);
continue
;
}
/* We don't know this capability, so skip it */
ptr
=
strchr
(
ptr
,
' '
);
}
return
0
;
}
/*
* Since this is a network connection, we need to parse and store the
* Since this is a network connection, we need to parse and store the
* pkt-lines at this stage and keep them there.
* pkt-lines at this stage and keep them there.
*/
*/
...
@@ -202,202 +135,26 @@ static int git_connect(git_transport *transport, int direction)
...
@@ -202,202 +135,26 @@ static int git_connect(git_transport *transport, int direction)
}
}
t
->
parent
.
direction
=
direction
;
t
->
parent
.
direction
=
direction
;
if
(
git_vector_init
(
&
t
->
refs
,
16
,
NULL
)
<
0
)
return
-
1
;
/* Connect and ask for the refs */
/* Connect and ask for the refs */
if
(
do_connect
(
t
,
transport
->
url
)
<
0
)
if
(
do_connect
(
t
,
transport
->
url
)
<
0
)
goto
cleanup
;
gitno_buffer_setup
(
transport
,
&
t
->
buf
,
t
->
buff
,
sizeof
(
t
->
buff
));
t
->
parent
.
connected
=
1
;
if
(
store_refs
(
t
)
<
0
)
goto
cleanup
;
if
(
detect_caps
(
t
)
<
0
)
goto
cleanup
;
return
0
;
cleanup:
git_vector_free
(
&
t
->
refs
);
return
-
1
;
}
static
int
git_ls
(
git_transport
*
transport
,
git_headlist_cb
list_cb
,
void
*
opaque
)
{
transport_git
*
t
=
(
transport_git
*
)
transport
;
git_vector
*
refs
=
&
t
->
refs
;
unsigned
int
i
;
git_pkt
*
p
=
NULL
;
git_vector_foreach
(
refs
,
i
,
p
)
{
git_pkt_ref
*
pkt
=
NULL
;
if
(
p
->
type
!=
GIT_PKT_REF
)
continue
;
pkt
=
(
git_pkt_ref
*
)
p
;
if
(
list_cb
(
&
pkt
->
head
,
opaque
)
<
0
)
{
giterr_set
(
GITERR_NET
,
"User callback returned error"
);
return
-
1
;
return
-
1
;
}
}
return
0
;
}
/* Wait until we get an ack from the */
gitno_buffer_setup
(
transport
,
&
transport
->
buffer
,
t
->
buff
,
sizeof
(
t
->
buff
));
static
int
recv_pkt
(
gitno_buffer
*
buf
)
{
const
char
*
ptr
=
buf
->
data
,
*
line_end
;
git_pkt
*
pkt
;
int
pkt_type
,
error
;
do
{
/* Wait for max. 1 second */
if
((
error
=
gitno_select_in
(
buf
,
1
,
0
))
<
0
)
{
return
-
1
;
}
else
if
(
error
==
0
)
{
/*
* Some servers don't respond immediately, so if this
* happens, we keep sending information until it
* answers. Pretend we received a NAK to convince higher
* layers to do so.
*/
return
GIT_PKT_NAK
;
}
if
((
error
=
gitno_recv
(
buf
))
<
0
)
return
-
1
;
error
=
git_pkt_parse_line
(
&
pkt
,
ptr
,
&
line_end
,
buf
->
offset
);
t
->
parent
.
connected
=
1
;
if
(
error
==
GIT_EBUFS
)
if
(
git_protocol_store_refs
(
transport
,
1
)
<
0
)
continue
;
if
(
error
<
0
)
return
-
1
;
return
-
1
;
}
while
(
error
);
gitno_consume
(
buf
,
line_end
);
pkt_type
=
pkt
->
type
;
git__free
(
pkt
);
return
pkt_type
;
}
static
int
git_negotiate_fetch
(
git_transport
*
transport
,
git_repository
*
repo
,
const
git_vector
*
wants
)
if
(
git_protocol_detect_caps
(
git_vector_get
(
&
transport
->
refs
,
0
),
&
transport
->
caps
)
<
0
)
{
transport_git
*
t
=
(
transport_git
*
)
transport
;
git_revwalk
*
walk
;
git_oid
oid
;
int
error
;
unsigned
int
i
;
git_buf
data
=
GIT_BUF_INIT
;
gitno_buffer
*
buf
=
&
t
->
buf
;
if
(
git_pkt_buffer_wants
(
wants
,
&
t
->
caps
,
&
data
)
<
0
)
return
-
1
;
return
-
1
;
if
(
git_fetch_setup_walk
(
&
walk
,
repo
)
<
0
)
goto
on_error
;
if
(
gitno_send
(
transport
,
data
.
ptr
,
data
.
size
,
0
)
<
0
)
goto
on_error
;
git_buf_clear
(
&
data
);
/*
* We don't support any kind of ACK extensions, so the negotiation
* boils down to sending what we have and listening for an ACK
* every once in a while.
*/
i
=
0
;
while
((
error
=
git_revwalk_next
(
&
oid
,
walk
))
==
0
)
{
git_pkt_buffer_have
(
&
oid
,
&
data
);
i
++
;
if
(
i
%
20
==
0
)
{
int
pkt_type
;
git_pkt_buffer_flush
(
&
data
);
if
(
git_buf_oom
(
&
data
))
goto
on_error
;
if
(
gitno_send
(
transport
,
data
.
ptr
,
data
.
size
,
0
)
<
0
)
goto
on_error
;
pkt_type
=
recv_pkt
(
buf
);
if
(
pkt_type
==
GIT_PKT_ACK
)
{
break
;
}
else
if
(
pkt_type
==
GIT_PKT_NAK
)
{
continue
;
}
else
{
giterr_set
(
GITERR_NET
,
"Unexpected pkt type"
);
goto
on_error
;
}
}
}
if
(
error
<
0
&&
error
!=
GIT_REVWALKOVER
)
goto
on_error
;
/* Tell the other end that we're done negotiating */
git_buf_clear
(
&
data
);
git_pkt_buffer_flush
(
&
data
);
git_pkt_buffer_done
(
&
data
);
if
(
gitno_send
(
transport
,
data
.
ptr
,
data
.
size
,
0
)
<
0
)
goto
on_error
;
git_buf_free
(
&
data
);
git_revwalk_free
(
walk
);
return
0
;
return
0
;
on_error:
git_buf_free
(
&
data
);
git_revwalk_free
(
walk
);
return
-
1
;
}
}
static
int
git_
download_pack
(
git_transport
*
transport
,
git_repository
*
repo
,
git_off_t
*
bytes
,
git_indexer_stats
*
stats
)
static
int
git_
negotiation_step
(
struct
git_transport
*
transport
,
void
*
data
,
size_t
len
)
{
{
transport_git
*
t
=
(
transport_git
*
)
transport
;
return
gitno_send
(
transport
,
data
,
len
,
0
);
int
error
=
0
,
read_bytes
;
gitno_buffer
*
buf
=
&
t
->
buf
;
git_pkt
*
pkt
;
const
char
*
line_end
,
*
ptr
;
/*
* For now, we ignore everything and wait for the pack
*/
do
{
ptr
=
buf
->
data
;
/* Whilst we're searching for the pack */
while
(
1
)
{
if
(
buf
->
offset
==
0
)
{
break
;
}
error
=
git_pkt_parse_line
(
&
pkt
,
ptr
,
&
line_end
,
buf
->
offset
);
if
(
error
==
GIT_EBUFS
)
break
;
if
(
error
<
0
)
return
error
;
if
(
pkt
->
type
==
GIT_PKT_PACK
)
{
git__free
(
pkt
);
return
git_fetch__download_pack
(
buf
->
data
,
buf
->
offset
,
transport
,
repo
,
bytes
,
stats
);
}
/* For now we don't care about anything */
git__free
(
pkt
);
gitno_consume
(
buf
,
line_end
);
}
read_bytes
=
gitno_recv
(
buf
);
}
while
(
read_bytes
);
return
read_bytes
;
}
}
static
int
git_close
(
git_transport
*
t
)
static
int
git_close
(
git_transport
*
t
)
...
@@ -408,6 +165,7 @@ static int git_close(git_transport *t)
...
@@ -408,6 +165,7 @@ static int git_close(git_transport *t)
return
-
1
;
return
-
1
;
/* Can't do anything if there's an error, so don't bother checking */
/* Can't do anything if there's an error, so don't bother checking */
gitno_send
(
t
,
buf
.
ptr
,
buf
.
size
,
0
);
gitno_send
(
t
,
buf
.
ptr
,
buf
.
size
,
0
);
git_buf_free
(
&
buf
);
if
(
gitno_close
(
t
->
socket
)
<
0
)
{
if
(
gitno_close
(
t
->
socket
)
<
0
)
{
giterr_set
(
GITERR_NET
,
"Failed to close socket"
);
giterr_set
(
GITERR_NET
,
"Failed to close socket"
);
...
@@ -426,17 +184,22 @@ static int git_close(git_transport *t)
...
@@ -426,17 +184,22 @@ static int git_close(git_transport *t)
static
void
git_free
(
git_transport
*
transport
)
static
void
git_free
(
git_transport
*
transport
)
{
{
transport_git
*
t
=
(
transport_git
*
)
transport
;
transport_git
*
t
=
(
transport_git
*
)
transport
;
git_vector
*
refs
=
&
t
->
refs
;
git_vector
*
refs
=
&
t
ransport
->
refs
;
unsigned
int
i
;
unsigned
int
i
;
for
(
i
=
0
;
i
<
refs
->
length
;
++
i
)
{
for
(
i
=
0
;
i
<
refs
->
length
;
++
i
)
{
git_pkt
*
p
=
git_vector_get
(
refs
,
i
);
git_pkt
*
p
=
git_vector_get
(
refs
,
i
);
git_pkt_free
(
p
);
git_pkt_free
(
p
);
}
}
git_vector_free
(
refs
);
refs
=
&
transport
->
common
;
for
(
i
=
0
;
i
<
refs
->
length
;
++
i
)
{
git_pkt
*
p
=
git_vector_get
(
refs
,
i
);
git_pkt_free
(
p
);
}
git_vector_free
(
refs
);
git_vector_free
(
refs
);
git__free
(
t
->
heads
);
git_buf_free
(
&
t
->
proto
.
buf
);
git__free
(
t
->
parent
.
url
);
git__free
(
t
->
parent
.
url
);
git__free
(
t
);
git__free
(
t
);
}
}
...
@@ -452,15 +215,16 @@ int git_transport_git(git_transport **out)
...
@@ -452,15 +215,16 @@ int git_transport_git(git_transport **out)
GITERR_CHECK_ALLOC
(
t
);
GITERR_CHECK_ALLOC
(
t
);
memset
(
t
,
0x0
,
sizeof
(
transport_git
));
memset
(
t
,
0x0
,
sizeof
(
transport_git
));
if
(
git_vector_init
(
&
t
->
parent
.
common
,
8
,
NULL
))
goto
on_error
;
if
(
git_vector_init
(
&
t
->
parent
.
refs
,
16
,
NULL
)
<
0
)
goto
on_error
;
t
->
parent
.
connect
=
git_connect
;
t
->
parent
.
connect
=
git_connect
;
t
->
parent
.
ls
=
git_ls
;
t
->
parent
.
negotiation_step
=
git_negotiation_step
;
t
->
parent
.
negotiate_fetch
=
git_negotiate_fetch
;
t
->
parent
.
download_pack
=
git_download_pack
;
t
->
parent
.
close
=
git_close
;
t
->
parent
.
close
=
git_close
;
t
->
parent
.
free
=
git_free
;
t
->
parent
.
free
=
git_free
;
t
->
proto
.
refs
=
&
t
->
refs
;
t
->
proto
.
transport
=
(
git_transport
*
)
t
;
*
out
=
(
git_transport
*
)
t
;
*
out
=
(
git_transport
*
)
t
;
...
@@ -474,4 +238,8 @@ int git_transport_git(git_transport **out)
...
@@ -474,4 +238,8 @@ int git_transport_git(git_transport **out)
#endif
#endif
return
0
;
return
0
;
on_error:
git__free
(
t
);
return
-
1
;
}
}
src/transports/http.c
View file @
577cd8ae
...
@@ -29,11 +29,8 @@ enum last_cb {
...
@@ -29,11 +29,8 @@ enum last_cb {
typedef
struct
{
typedef
struct
{
git_transport
parent
;
git_transport
parent
;
git_protocol
proto
;
http_parser_settings
settings
;
git_vector
refs
;
git_vector
common
;
git_buf
buf
;
git_buf
buf
;
git_remote_head
**
heads
;
int
error
;
int
error
;
int
transfer_finished
:
1
,
int
transfer_finished
:
1
,
ct_found
:
1
,
ct_found
:
1
,
...
@@ -46,7 +43,7 @@ typedef struct {
...
@@ -46,7 +43,7 @@ typedef struct {
char
*
host
;
char
*
host
;
char
*
port
;
char
*
port
;
char
*
service
;
char
*
service
;
git_transport_caps
caps
;
char
buffer
[
4096
]
;
#ifdef GIT_WIN32
#ifdef GIT_WIN32
WSADATA
wsd
;
WSADATA
wsd
;
#endif
#endif
...
@@ -183,76 +180,78 @@ static int on_headers_complete(http_parser *parser)
...
@@ -183,76 +180,78 @@ static int on_headers_complete(http_parser *parser)
return
0
;
return
0
;
}
}
static
int
on_
body_store_refs
(
http_parser
*
parser
,
const
char
*
str
,
size_t
len
)
static
int
on_
message_complete
(
http_parser
*
parser
)
{
{
transport_http
*
t
=
(
transport_http
*
)
parser
->
data
;
transport_http
*
t
=
(
transport_http
*
)
parser
->
data
;
t
->
transfer_finished
=
1
;
if
(
parser
->
status_code
==
404
)
{
if
(
parser
->
status_code
==
404
)
{
return
git_buf_put
(
&
t
->
buf
,
str
,
len
);
giterr_set
(
GITERR_NET
,
"Remote error: %s"
,
git_buf_cstr
(
&
t
->
buf
));
t
->
error
=
-
1
;
}
}
return
git_protocol_store_refs
(
&
t
->
proto
,
str
,
len
)
;
return
0
;
}
}
static
int
on_
message_complete
(
http_parser
*
parser
)
static
int
on_
body_fill_buffer
(
http_parser
*
parser
,
const
char
*
str
,
size_t
len
)
{
{
git_transport
*
transport
=
(
git_transport
*
)
parser
->
data
;
transport_http
*
t
=
(
transport_http
*
)
parser
->
data
;
transport_http
*
t
=
(
transport_http
*
)
parser
->
data
;
gitno_buffer
*
buf
=
&
transport
->
buffer
;
t
->
transfer_finished
=
1
;
if
(
buf
->
len
-
buf
->
offset
<
len
)
{
giterr_set
(
GITERR_NET
,
"Can't fit data in the buffer"
);
if
(
parser
->
status_code
==
404
)
{
return
t
->
error
=
-
1
;
giterr_set
(
GITERR_NET
,
"Remote error: %s"
,
git_buf_cstr
(
&
t
->
buf
));
t
->
error
=
-
1
;
}
}
memcpy
(
buf
->
data
+
buf
->
offset
,
str
,
len
);
buf
->
offset
+=
len
;
return
0
;
return
0
;
}
}
static
int
store_refs
(
transport_http
*
t
)
static
int
http_recv_cb
(
gitno_buffer
*
buf
)
{
{
http_parser_settings
settings
;
git_transport
*
transport
=
(
git_transport
*
)
buf
->
cb_data
;
char
buffer
[
1024
];
transport_http
*
t
=
(
transport_http
*
)
transport
;
gitno_buffer
buf
;
size_t
old_len
;
git_pkt
*
pkt
;
gitno_buffer
inner
;
int
ret
;
char
buffer
[
2048
];
int
error
;
http_parser_init
(
&
t
->
parser
,
HTTP_RESPONSE
);
t
->
parser
.
data
=
t
;
memset
(
&
settings
,
0x0
,
sizeof
(
http_parser_settings
));
settings
.
on_header_field
=
on_header_field
;
settings
.
on_header_value
=
on_header_value
;
settings
.
on_headers_complete
=
on_headers_complete
;
settings
.
on_body
=
on_body_store_refs
;
settings
.
on_message_complete
=
on_message_complete
;
gitno_buffer_setup
((
git_transport
*
)
t
,
&
buf
,
buffer
,
sizeof
(
buffer
));
if
(
t
->
transfer_finished
)
return
0
;
while
(
1
)
{
gitno_buffer_setup
(
transport
,
&
inner
,
buffer
,
sizeof
(
buffer
));
size_t
parsed
;
if
((
ret
=
gitno_recv
(
&
buf
))
<
0
)
if
((
error
=
gitno_recv
(
&
inner
))
<
0
)
return
-
1
;
return
-
1
;
parsed
=
http_parser_execute
(
&
t
->
parser
,
&
settings
,
buf
.
data
,
buf
.
offset
)
;
old_len
=
buf
->
offset
;
/* Both should happen at the same time */
http_parser_execute
(
&
t
->
parser
,
&
t
->
settings
,
inner
.
data
,
inner
.
offset
);
if
(
parsed
!=
buf
.
offset
||
t
->
error
<
0
)
if
(
t
->
error
<
0
)
return
t
->
error
;
return
t
->
error
;
gitno_consume_n
(
&
buf
,
parsed
);
return
buf
->
offset
-
old_len
;
}
if
(
ret
==
0
||
t
->
transfer_finished
)
return
0
;
}
pkt
=
git_vector_get
(
&
t
->
refs
,
0
);
/* Set up the gitno_buffer so calling gitno_recv() grabs data from the HTTP response */
if
(
pkt
==
NULL
||
pkt
->
type
!=
GIT_PKT_COMMENT
)
{
static
void
setup_gitno_buffer
(
git_transport
*
transport
)
giterr_set
(
GITERR_NET
,
"Invalid HTTP response"
);
{
return
t
->
error
=
-
1
;
transport_http
*
t
=
(
transport_http
*
)
transport
;
}
else
{
git_vector_remove
(
&
t
->
refs
,
0
);
}
return
0
;
http_parser_init
(
&
t
->
parser
,
HTTP_RESPONSE
);
t
->
parser
.
data
=
t
;
t
->
transfer_finished
=
0
;
memset
(
&
t
->
settings
,
0x0
,
sizeof
(
http_parser_settings
));
t
->
settings
.
on_header_field
=
on_header_field
;
t
->
settings
.
on_header_value
=
on_header_value
;
t
->
settings
.
on_headers_complete
=
on_headers_complete
;
t
->
settings
.
on_body
=
on_body_fill_buffer
;
t
->
settings
.
on_message_complete
=
on_message_complete
;
gitno_buffer_setup_callback
(
transport
,
&
transport
->
buffer
,
t
->
buffer
,
sizeof
(
t
->
buffer
),
http_recv_cb
,
t
);
}
}
static
int
http_connect
(
git_transport
*
transport
,
int
direction
)
static
int
http_connect
(
git_transport
*
transport
,
int
direction
)
...
@@ -263,6 +262,7 @@ static int http_connect(git_transport *transport, int direction)
...
@@ -263,6 +262,7 @@ static int http_connect(git_transport *transport, int direction)
const
char
*
service
=
"upload-pack"
;
const
char
*
service
=
"upload-pack"
;
const
char
*
url
=
t
->
parent
.
url
,
*
prefix_http
=
"http://"
,
*
prefix_https
=
"https://"
;
const
char
*
url
=
t
->
parent
.
url
,
*
prefix_http
=
"http://"
,
*
prefix_https
=
"https://"
;
const
char
*
default_port
;
const
char
*
default_port
;
git_pkt
*
pkt
;
if
(
direction
==
GIT_DIR_PUSH
)
{
if
(
direction
==
GIT_DIR_PUSH
)
{
giterr_set
(
GITERR_NET
,
"Pushing over HTTP is not implemented"
);
giterr_set
(
GITERR_NET
,
"Pushing over HTTP is not implemented"
);
...
@@ -270,8 +270,6 @@ static int http_connect(git_transport *transport, int direction)
...
@@ -270,8 +270,6 @@ static int http_connect(git_transport *transport, int direction)
}
}
t
->
parent
.
direction
=
direction
;
t
->
parent
.
direction
=
direction
;
if
(
git_vector_init
(
&
t
->
refs
,
16
,
NULL
)
<
0
)
return
-
1
;
if
(
!
git__prefixcmp
(
url
,
prefix_http
))
{
if
(
!
git__prefixcmp
(
url
,
prefix_http
))
{
url
=
t
->
parent
.
url
+
strlen
(
prefix_http
);
url
=
t
->
parent
.
url
+
strlen
(
prefix_http
);
...
@@ -304,307 +302,61 @@ static int http_connect(git_transport *transport, int direction)
...
@@ -304,307 +302,61 @@ static int http_connect(git_transport *transport, int direction)
if
(
gitno_send
(
transport
,
request
.
ptr
,
request
.
size
,
0
)
<
0
)
if
(
gitno_send
(
transport
,
request
.
ptr
,
request
.
size
,
0
)
<
0
)
goto
cleanup
;
goto
cleanup
;
ret
=
store_refs
(
t
);
setup_gitno_buffer
(
transport
);
if
((
ret
=
git_protocol_store_refs
(
transport
,
2
))
<
0
)
cleanup:
goto
cleanup
;
git_buf_free
(
&
request
);
git_buf_clear
(
&
t
->
buf
);
return
ret
;
}
static
int
http_ls
(
git_transport
*
transport
,
git_headlist_cb
list_cb
,
void
*
opaque
)
{
transport_http
*
t
=
(
transport_http
*
)
transport
;
git_vector
*
refs
=
&
t
->
refs
;
unsigned
int
i
;
git_pkt_ref
*
p
;
git_vector_foreach
(
refs
,
i
,
p
)
{
if
(
p
->
type
!=
GIT_PKT_REF
)
continue
;
if
(
list_cb
(
&
p
->
head
,
opaque
)
<
0
)
{
giterr_set
(
GITERR_NET
,
"The user callback returned error"
);
return
-
1
;
}
}
return
0
;
}
static
int
on_body_parse_response
(
http_parser
*
parser
,
const
char
*
str
,
size_t
len
)
{
transport_http
*
t
=
(
transport_http
*
)
parser
->
data
;
git_buf
*
buf
=
&
t
->
buf
;
git_vector
*
common
=
&
t
->
common
;
int
error
;
const
char
*
line_end
,
*
ptr
;
if
(
len
==
0
)
{
/* EOF */
pkt
=
git_vector_get
(
&
transport
->
refs
,
0
);
if
(
git_buf_len
(
buf
)
!=
0
)
{
if
(
pkt
==
NULL
||
pkt
->
type
!=
GIT_PKT_COMMENT
)
{
giterr_set
(
GITERR_NET
,
"Unexpected EOF
"
);
giterr_set
(
GITERR_NET
,
"Invalid HTTP response
"
);
return
t
->
error
=
-
1
;
return
t
->
error
=
-
1
;
}
else
{
}
else
{
return
0
;
/* Remove the comment and flush pkts */
}
git_vector_remove
(
&
transport
->
refs
,
0
);
}
git_buf_put
(
buf
,
str
,
len
);
ptr
=
buf
->
ptr
;
while
(
1
)
{
git_pkt
*
pkt
;
if
(
git_buf_len
(
buf
)
==
0
)
return
0
;
error
=
git_pkt_parse_line
(
&
pkt
,
ptr
,
&
line_end
,
git_buf_len
(
buf
));
if
(
error
==
GIT_EBUFS
)
{
return
0
;
/* Ask for more */
}
if
(
error
<
0
)
return
t
->
error
=
-
1
;
git_buf_consume
(
buf
,
line_end
);
if
(
pkt
->
type
==
GIT_PKT_PACK
)
{
git__free
(
pkt
);
git__free
(
pkt
);
t
->
pack_ready
=
1
;
pkt
=
git_vector_get
(
&
transport
->
refs
,
0
);
return
0
;
git_vector_remove
(
&
transport
->
refs
,
0
);
}
if
(
pkt
->
type
==
GIT_PKT_NAK
)
{
git__free
(
pkt
);
return
0
;
}
if
(
pkt
->
type
!=
GIT_PKT_ACK
)
{
git__free
(
pkt
);
git__free
(
pkt
);
continue
;
}
}
if
(
git_vector_insert
(
common
,
pkt
)
<
0
)
if
(
git_protocol_detect_caps
(
git_vector_get
(
&
transport
->
refs
,
0
),
&
transport
->
caps
)
<
0
)
return
-
1
;
return
t
->
error
=
-
1
;
}
return
error
;
}
static
int
parse_response
(
transport_http
*
t
)
{
int
ret
=
0
;
http_parser_settings
settings
;
char
buffer
[
1024
];
gitno_buffer
buf
;
http_parser_init
(
&
t
->
parser
,
HTTP_RESPONSE
);
t
->
parser
.
data
=
t
;
t
->
transfer_finished
=
0
;
memset
(
&
settings
,
0x0
,
sizeof
(
http_parser_settings
));
settings
.
on_header_field
=
on_header_field
;
settings
.
on_header_value
=
on_header_value
;
settings
.
on_headers_complete
=
on_headers_complete
;
settings
.
on_body
=
on_body_parse_response
;
settings
.
on_message_complete
=
on_message_complete
;
gitno_buffer_setup
((
git_transport
*
)
t
,
&
buf
,
buffer
,
sizeof
(
buffer
));
while
(
1
)
{
size_t
parsed
;
if
((
ret
=
gitno_recv
(
&
buf
))
<
0
)
return
-
1
;
parsed
=
http_parser_execute
(
&
t
->
parser
,
&
settings
,
buf
.
data
,
buf
.
offset
);
/* Both should happen at the same time */
if
(
parsed
!=
buf
.
offset
||
t
->
error
<
0
)
return
t
->
error
;
gitno_consume_n
(
&
buf
,
parsed
);
if
(
ret
==
0
||
t
->
transfer_finished
||
t
->
pack_ready
)
{
cleanup:
return
0
;
git_buf_free
(
&
request
);
}
git_buf_clear
(
&
t
->
buf
);
}
return
ret
;
return
ret
;
}
}
static
int
http_negotiat
e_fetch
(
git_transport
*
transport
,
git_repository
*
repo
,
const
git_vector
*
wants
)
static
int
http_negotiat
ion_step
(
struct
git_transport
*
transport
,
void
*
data
,
size_t
len
)
{
{
transport_http
*
t
=
(
transport_http
*
)
transport
;
transport_http
*
t
=
(
transport_http
*
)
transport
;
git_buf
request
=
GIT_BUF_INIT
;
int
ret
;
int
ret
;
unsigned
int
i
;
char
buff
[
128
];
gitno_buffer
buf
;
git_revwalk
*
walk
=
NULL
;
git_oid
oid
;
git_pkt_ack
*
pkt
;
git_vector
*
common
=
&
t
->
common
;
git_buf
request
=
GIT_BUF_INIT
,
data
=
GIT_BUF_INIT
;
gitno_buffer_setup
(
transport
,
&
buf
,
buff
,
sizeof
(
buff
));
if
(
git_vector_init
(
common
,
16
,
NULL
)
<
0
)
return
-
1
;
if
(
git_fetch_setup_walk
(
&
walk
,
repo
)
<
0
)
return
-
1
;
do
{
/* First, send the data as a HTTP POST request */
if
((
ret
=
do_connect
(
t
,
t
->
host
,
t
->
port
))
<
0
)
if
((
ret
=
do_connect
(
t
,
t
->
host
,
t
->
port
))
<
0
)
goto
cleanup
;
if
((
ret
=
git_pkt_buffer_wants
(
wants
,
&
t
->
caps
,
&
data
))
<
0
)
goto
cleanup
;
/* We need to send these on each connection */
git_vector_foreach
(
common
,
i
,
pkt
)
{
if
((
ret
=
git_pkt_buffer_have
(
&
pkt
->
oid
,
&
data
))
<
0
)
goto
cleanup
;
}
i
=
0
;
while
((
i
<
20
)
&&
((
ret
=
git_revwalk_next
(
&
oid
,
walk
))
==
0
))
{
if
((
ret
=
git_pkt_buffer_have
(
&
oid
,
&
data
))
<
0
)
goto
cleanup
;
i
++
;
}
git_pkt_buffer_done
(
&
data
);
if
((
ret
=
gen_request
(
&
request
,
t
->
path
,
t
->
host
,
"POST"
,
"upload-pack"
,
data
.
size
,
0
))
<
0
)
goto
cleanup
;
if
((
ret
=
gitno_send
(
transport
,
request
.
ptr
,
request
.
size
,
0
))
<
0
)
goto
cleanup
;
if
((
ret
=
gitno_send
(
transport
,
data
.
ptr
,
data
.
size
,
0
))
<
0
)
goto
cleanup
;
git_buf_clear
(
&
request
);
git_buf_clear
(
&
data
);
if
(
ret
<
0
||
i
>=
256
)
break
;
if
((
ret
=
parse_response
(
t
))
<
0
)
goto
cleanup
;
if
(
t
->
pack_ready
)
{
ret
=
0
;
goto
cleanup
;
}
}
while
(
1
);
cleanup:
git_buf_free
(
&
request
);
git_buf_free
(
&
data
);
git_revwalk_free
(
walk
);
return
ret
;
}
typedef
struct
{
git_indexer_stream
*
idx
;
git_indexer_stats
*
stats
;
transport_http
*
transport
;
}
download_pack_cbdata
;
static
int
on_message_complete_download_pack
(
http_parser
*
parser
)
{
download_pack_cbdata
*
data
=
(
download_pack_cbdata
*
)
parser
->
data
;
data
->
transport
->
transfer_finished
=
1
;
return
0
;
}
static
int
on_body_download_pack
(
http_parser
*
parser
,
const
char
*
str
,
size_t
len
)
{
download_pack_cbdata
*
data
=
(
download_pack_cbdata
*
)
parser
->
data
;
transport_http
*
t
=
data
->
transport
;
git_indexer_stream
*
idx
=
data
->
idx
;
git_indexer_stats
*
stats
=
data
->
stats
;
return
t
->
error
=
git_indexer_stream_add
(
idx
,
str
,
len
,
stats
);
}
/*
* As the server is probably using Transfer-Encoding: chunked, we have
* to use the HTTP parser to download the pack instead of giving it to
* the simple downloader. Furthermore, we're using keep-alive
* connections, so the simple downloader would just hang.
*/
static
int
http_download_pack
(
git_transport
*
transport
,
git_repository
*
repo
,
git_off_t
*
bytes
,
git_indexer_stats
*
stats
)
{
transport_http
*
t
=
(
transport_http
*
)
transport
;
git_buf
*
oldbuf
=
&
t
->
buf
;
int
recvd
;
http_parser_settings
settings
;
char
buffer
[
1024
];
gitno_buffer
buf
;
git_buf
path
=
GIT_BUF_INIT
;
git_indexer_stream
*
idx
=
NULL
;
download_pack_cbdata
data
;
gitno_buffer_setup
(
transport
,
&
buf
,
buffer
,
sizeof
(
buffer
));
if
(
memcmp
(
oldbuf
->
ptr
,
"PACK"
,
strlen
(
"PACK"
)))
{
giterr_set
(
GITERR_NET
,
"The pack doesn't start with a pack signature"
);
return
-
1
;
}
if
(
git_buf_joinpath
(
&
path
,
git_repository_path
(
repo
),
"objects/pack"
)
<
0
)
return
-
1
;
if
(
git_indexer_stream_new
(
&
idx
,
git_buf_cstr
(
&
path
))
<
0
)
return
-
1
;
return
-
1
;
/*
if
((
ret
=
gen_request
(
&
request
,
t
->
path
,
t
->
host
,
"POST"
,
"upload-pack"
,
len
,
0
))
<
0
)
* This is part of the previous response, so we don't want to
* re-init the parser, just set these two callbacks.
*/
memset
(
stats
,
0
,
sizeof
(
git_indexer_stats
));
data
.
stats
=
stats
;
data
.
idx
=
idx
;
data
.
transport
=
t
;
t
->
parser
.
data
=
&
data
;
t
->
transfer_finished
=
0
;
memset
(
&
settings
,
0x0
,
sizeof
(
settings
));
settings
.
on_message_complete
=
on_message_complete_download_pack
;
settings
.
on_body
=
on_body_download_pack
;
*
bytes
=
git_buf_len
(
oldbuf
);
if
(
git_indexer_stream_add
(
idx
,
git_buf_cstr
(
oldbuf
),
git_buf_len
(
oldbuf
),
stats
)
<
0
)
goto
on_error
;
goto
on_error
;
gitno_buffer_setup
(
transport
,
&
buf
,
buffer
,
sizeof
(
buffer
));
if
((
ret
=
gitno_send
(
transport
,
request
.
ptr
,
request
.
size
,
0
))
<
0
)
do
{
size_t
parsed
;
if
((
recvd
=
gitno_recv
(
&
buf
))
<
0
)
goto
on_error
;
goto
on_error
;
parsed
=
http_parser_execute
(
&
t
->
parser
,
&
settings
,
buf
.
data
,
buf
.
offset
);
if
((
ret
=
gitno_send
(
transport
,
data
,
len
,
0
))
<
0
)
if
(
parsed
!=
buf
.
offset
||
t
->
error
<
0
)
goto
on_error
;
goto
on_error
;
*
bytes
+=
recvd
;
git_buf_free
(
&
request
);
gitno_consume_n
(
&
buf
,
parsed
);
}
while
(
recvd
>
0
&&
!
t
->
transfer_finished
);
if
(
git_indexer_stream_finalize
(
idx
,
stats
)
<
0
)
/* Then we need to set up the buffer to grab data from the HTTP response */
goto
on_error
;
setup_gitno_buffer
(
transport
)
;
git_indexer_stream_free
(
idx
);
return
0
;
return
0
;
on_error:
on_error:
git_indexer_stream_free
(
idx
);
git_buf_free
(
&
request
);
git_buf_free
(
&
path
);
return
-
1
;
return
-
1
;
}
}
...
@@ -627,8 +379,8 @@ static int http_close(git_transport *transport)
...
@@ -627,8 +379,8 @@ static int http_close(git_transport *transport)
static
void
http_free
(
git_transport
*
transport
)
static
void
http_free
(
git_transport
*
transport
)
{
{
transport_http
*
t
=
(
transport_http
*
)
transport
;
transport_http
*
t
=
(
transport_http
*
)
transport
;
git_vector
*
refs
=
&
t
->
refs
;
git_vector
*
refs
=
&
t
ransport
->
refs
;
git_vector
*
common
=
&
t
->
common
;
git_vector
*
common
=
&
t
ransport
->
common
;
unsigned
int
i
;
unsigned
int
i
;
git_pkt
*
p
;
git_pkt
*
p
;
...
@@ -649,8 +401,6 @@ static void http_free(git_transport *transport)
...
@@ -649,8 +401,6 @@ static void http_free(git_transport *transport)
}
}
git_vector_free
(
common
);
git_vector_free
(
common
);
git_buf_free
(
&
t
->
buf
);
git_buf_free
(
&
t
->
buf
);
git_buf_free
(
&
t
->
proto
.
buf
);
git__free
(
t
->
heads
);
git__free
(
t
->
content_type
);
git__free
(
t
->
content_type
);
git__free
(
t
->
host
);
git__free
(
t
->
host
);
git__free
(
t
->
port
);
git__free
(
t
->
port
);
...
@@ -669,13 +419,15 @@ int git_transport_http(git_transport **out)
...
@@ -669,13 +419,15 @@ int git_transport_http(git_transport **out)
memset
(
t
,
0x0
,
sizeof
(
transport_http
));
memset
(
t
,
0x0
,
sizeof
(
transport_http
));
t
->
parent
.
connect
=
http_connect
;
t
->
parent
.
connect
=
http_connect
;
t
->
parent
.
ls
=
http_ls
;
t
->
parent
.
negotiation_step
=
http_negotiation_step
;
t
->
parent
.
negotiate_fetch
=
http_negotiate_fetch
;
t
->
parent
.
download_pack
=
http_download_pack
;
t
->
parent
.
close
=
http_close
;
t
->
parent
.
close
=
http_close
;
t
->
parent
.
free
=
http_free
;
t
->
parent
.
free
=
http_free
;
t
->
proto
.
refs
=
&
t
->
refs
;
t
->
parent
.
rpc
=
1
;
t
->
proto
.
transport
=
(
git_transport
*
)
t
;
if
(
git_vector_init
(
&
t
->
parent
.
refs
,
16
,
NULL
)
<
0
)
{
git__free
(
t
);
return
-
1
;
}
#ifdef GIT_WIN32
#ifdef GIT_WIN32
/* on win32, the WSA context needs to be initialized
/* on win32, the WSA context needs to be initialized
...
@@ -698,7 +450,7 @@ int git_transport_https(git_transport **out)
...
@@ -698,7 +450,7 @@ int git_transport_https(git_transport **out)
if
(
git_transport_http
((
git_transport
**
)
&
t
)
<
0
)
if
(
git_transport_http
((
git_transport
**
)
&
t
)
<
0
)
return
-
1
;
return
-
1
;
t
->
parent
.
encrypt
=
1
;
t
->
parent
.
use_ssl
=
1
;
t
->
parent
.
check_cert
=
1
;
t
->
parent
.
check_cert
=
1
;
*
out
=
(
git_transport
*
)
t
;
*
out
=
(
git_transport
*
)
t
;
...
...
src/transports/local.c
View file @
577cd8ae
...
@@ -15,11 +15,11 @@
...
@@ -15,11 +15,11 @@
#include "posix.h"
#include "posix.h"
#include "path.h"
#include "path.h"
#include "buffer.h"
#include "buffer.h"
#include "pkt.h"
typedef
struct
{
typedef
struct
{
git_transport
parent
;
git_transport
parent
;
git_repository
*
repo
;
git_repository
*
repo
;
git_vector
refs
;
}
transport_local
;
}
transport_local
;
static
int
add_ref
(
transport_local
*
t
,
const
char
*
name
)
static
int
add_ref
(
transport_local
*
t
,
const
char
*
name
)
...
@@ -27,19 +27,32 @@ static int add_ref(transport_local *t, const char *name)
...
@@ -27,19 +27,32 @@ static int add_ref(transport_local *t, const char *name)
const
char
peeled
[]
=
"^{}"
;
const
char
peeled
[]
=
"^{}"
;
git_remote_head
*
head
;
git_remote_head
*
head
;
git_object
*
obj
=
NULL
,
*
target
=
NULL
;
git_object
*
obj
=
NULL
,
*
target
=
NULL
;
git_transport
*
transport
=
(
git_transport
*
)
t
;
git_buf
buf
=
GIT_BUF_INIT
;
git_buf
buf
=
GIT_BUF_INIT
;
git_pkt_ref
*
pkt
;
head
=
git__malloc
(
sizeof
(
git_remote_head
));
head
=
git__malloc
(
sizeof
(
git_remote_head
));
GITERR_CHECK_ALLOC
(
head
);
GITERR_CHECK_ALLOC
(
head
);
pkt
=
git__malloc
(
sizeof
(
git_pkt_ref
));
GITERR_CHECK_ALLOC
(
pkt
);
head
->
name
=
git__strdup
(
name
);
head
->
name
=
git__strdup
(
name
);
GITERR_CHECK_ALLOC
(
head
->
name
);
GITERR_CHECK_ALLOC
(
head
->
name
);
if
(
git_reference_name_to_oid
(
&
head
->
oid
,
t
->
repo
,
name
)
<
0
||
if
(
git_reference_name_to_oid
(
&
head
->
oid
,
t
->
repo
,
name
)
<
0
)
{
git_vector_insert
(
&
t
->
refs
,
head
)
<
0
)
{
git__free
(
head
->
name
);
git__free
(
head
);
git__free
(
head
);
git__free
(
pkt
->
head
.
name
);
git__free
(
pkt
);
}
pkt
->
type
=
GIT_PKT_REF
;
memcpy
(
&
pkt
->
head
,
head
,
sizeof
(
git_remote_head
));
git__free
(
head
);
if
(
git_vector_insert
(
&
transport
->
refs
,
pkt
)
<
0
)
{
git__free
(
pkt
->
head
.
name
);
git__free
(
pkt
);
return
-
1
;
return
-
1
;
}
}
...
@@ -47,7 +60,7 @@ static int add_ref(transport_local *t, const char *name)
...
@@ -47,7 +60,7 @@ static int add_ref(transport_local *t, const char *name)
if
(
git__prefixcmp
(
name
,
GIT_REFS_TAGS_DIR
))
if
(
git__prefixcmp
(
name
,
GIT_REFS_TAGS_DIR
))
return
0
;
return
0
;
if
(
git_object_lookup
(
&
obj
,
t
->
repo
,
&
head
->
oid
,
GIT_OBJ_ANY
)
<
0
)
if
(
git_object_lookup
(
&
obj
,
t
->
repo
,
&
pkt
->
head
.
oid
,
GIT_OBJ_ANY
)
<
0
)
return
-
1
;
return
-
1
;
head
=
NULL
;
head
=
NULL
;
...
@@ -66,14 +79,20 @@ static int add_ref(transport_local *t, const char *name)
...
@@ -66,14 +79,20 @@ static int add_ref(transport_local *t, const char *name)
head
->
name
=
git_buf_detach
(
&
buf
);
head
->
name
=
git_buf_detach
(
&
buf
);
pkt
=
git__malloc
(
sizeof
(
git_pkt_ref
));
GITERR_CHECK_ALLOC
(
pkt
);
pkt
->
type
=
GIT_PKT_REF
;
if
(
git_tag_peel
(
&
target
,
(
git_tag
*
)
obj
)
<
0
)
if
(
git_tag_peel
(
&
target
,
(
git_tag
*
)
obj
)
<
0
)
goto
on_error
;
goto
on_error
;
git_oid_cpy
(
&
head
->
oid
,
git_object_id
(
target
));
git_oid_cpy
(
&
head
->
oid
,
git_object_id
(
target
));
git_object_free
(
obj
);
git_object_free
(
obj
);
git_object_free
(
target
);
git_object_free
(
target
);
memcpy
(
&
pkt
->
head
,
head
,
sizeof
(
git_remote_head
));
git__free
(
head
);
if
(
git_vector_insert
(
&
t
->
refs
,
head
)
<
0
)
if
(
git_vector_insert
(
&
t
ransport
->
refs
,
pkt
)
<
0
)
return
-
1
;
return
-
1
;
return
0
;
return
0
;
...
@@ -88,11 +107,12 @@ static int store_refs(transport_local *t)
...
@@ -88,11 +107,12 @@ static int store_refs(transport_local *t)
{
{
unsigned
int
i
;
unsigned
int
i
;
git_strarray
ref_names
=
{
0
};
git_strarray
ref_names
=
{
0
};
git_transport
*
transport
=
(
git_transport
*
)
t
;
assert
(
t
);
assert
(
t
);
if
(
git_reference_list
(
&
ref_names
,
t
->
repo
,
GIT_REF_LISTALL
)
<
0
||
if
(
git_reference_list
(
&
ref_names
,
t
->
repo
,
GIT_REF_LISTALL
)
<
0
||
git_vector_init
(
&
t
->
refs
,
(
unsigned
int
)
ref_names
.
count
,
NULL
)
<
0
)
git_vector_init
(
&
t
ransport
->
refs
,
(
unsigned
int
)
ref_names
.
count
,
NULL
)
<
0
)
goto
on_error
;
goto
on_error
;
/* Sort the references first */
/* Sort the references first */
...
@@ -111,28 +131,11 @@ static int store_refs(transport_local *t)
...
@@ -111,28 +131,11 @@ static int store_refs(transport_local *t)
return
0
;
return
0
;
on_error:
on_error:
git_vector_free
(
&
t
->
refs
);
git_vector_free
(
&
t
ransport
->
refs
);
git_strarray_free
(
&
ref_names
);
git_strarray_free
(
&
ref_names
);
return
-
1
;
return
-
1
;
}
}
static
int
local_ls
(
git_transport
*
transport
,
git_headlist_cb
list_cb
,
void
*
payload
)
{
transport_local
*
t
=
(
transport_local
*
)
transport
;
git_vector
*
refs
=
&
t
->
refs
;
unsigned
int
i
;
git_remote_head
*
h
;
assert
(
transport
&&
transport
->
connected
);
git_vector_foreach
(
refs
,
i
,
h
)
{
if
(
list_cb
(
h
,
payload
)
<
0
)
return
-
1
;
}
return
0
;
}
/*
/*
* Try to open the url as a git directory. The direction doesn't
* Try to open the url as a git directory. The direction doesn't
* matter in this case because we're calulating the heads ourselves.
* matter in this case because we're calulating the heads ourselves.
...
@@ -201,14 +204,14 @@ static void local_free(git_transport *transport)
...
@@ -201,14 +204,14 @@ static void local_free(git_transport *transport)
{
{
unsigned
int
i
;
unsigned
int
i
;
transport_local
*
t
=
(
transport_local
*
)
transport
;
transport_local
*
t
=
(
transport_local
*
)
transport
;
git_vector
*
vec
=
&
t
->
refs
;
git_vector
*
vec
=
&
t
ransport
->
refs
;
git_
remote_head
*
h
;
git_
pkt_ref
*
pkt
;
assert
(
transport
);
assert
(
transport
);
git_vector_foreach
(
vec
,
i
,
h
)
{
git_vector_foreach
(
vec
,
i
,
pkt
)
{
git__free
(
h
->
name
);
git__free
(
pkt
->
head
.
name
);
git__free
(
h
);
git__free
(
pkt
);
}
}
git_vector_free
(
vec
);
git_vector_free
(
vec
);
...
@@ -229,8 +232,8 @@ int git_transport_local(git_transport **out)
...
@@ -229,8 +232,8 @@ int git_transport_local(git_transport **out)
memset
(
t
,
0x0
,
sizeof
(
transport_local
));
memset
(
t
,
0x0
,
sizeof
(
transport_local
));
t
->
parent
.
own_logic
=
1
;
t
->
parent
.
connect
=
local_connect
;
t
->
parent
.
connect
=
local_connect
;
t
->
parent
.
ls
=
local_ls
;
t
->
parent
.
negotiate_fetch
=
local_negotiate_fetch
;
t
->
parent
.
negotiate_fetch
=
local_negotiate_fetch
;
t
->
parent
.
close
=
local_close
;
t
->
parent
.
close
=
local_close
;
t
->
parent
.
free
=
local_free
;
t
->
parent
.
free
=
local_free
;
...
...
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