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
45d387ac
Commit
45d387ac
authored
Feb 15, 2012
by
Vicent Martí
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refs: Error handling rework. WIP
parent
60bc2d20
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
258 additions
and
283 deletions
+258
-283
include/git2/errors.h
+3
-0
src/path.c
+16
-11
src/refs.c
+239
-272
No files found.
include/git2/errors.h
View file @
45d387ac
...
...
@@ -122,9 +122,12 @@ typedef struct {
typedef
enum
{
GITERR_NOMEMORY
,
GITERR_REFERENCE
,
}
git_error_class
;
#define GITERR_CHECK_ALLOC(ptr, error) if (ptr == NULL) { giterr_set_oom(error); return -1 }
GIT_EXTERN
(
void
)
giterr_set
(
git_error
**
error_out
,
int
error_class
,
const
char
*
string
,
...);
GIT_EXTERN
(
void
)
giterr_set_oom
(
git_error
**
error
);
GIT_EXTERN
(
void
)
giterr_free
(
git_error
*
error
);
...
...
src/path.c
View file @
45d387ac
...
...
@@ -486,20 +486,23 @@ GIT_INLINE(int) is_dot_or_dotdot(const char *name)
int
git_path_direach
(
git_buf
*
path
,
int
(
*
fn
)(
void
*
,
git_buf
*
),
void
*
arg
)
int
(
*
fn
)(
void
*
,
git_buf
*
,
git_error
**
),
void
*
arg
,
git_error
**
error
)
{
ssize_t
wd_len
;
DIR
*
dir
;
struct
dirent
de_buf
,
*
de
;
if
(
git_path_to_dir
(
path
)
<
GIT_SUCCESS
)
return
git_buf_lasterror
(
path
)
;
if
(
git_path_to_dir
(
path
,
error
)
<
0
)
return
-
1
;
wd_len
=
path
->
size
;
dir
=
opendir
(
path
->
ptr
);
if
(
!
dir
)
return
git__throw
(
GIT_EOSERR
,
"Failed to process `%s` tree structure. An error occured while opening the directory"
,
path
->
ptr
);
if
(
!
dir
)
{
giterr_set
(
error
,
GITERR_OS
,
"Failed to `opendir` %s: %s"
,
path
->
ptr
,
strerror
(
errno
));
return
-
1
;
}
while
(
p_readdir_r
(
dir
,
&
de_buf
,
&
de
)
==
0
&&
de
!=
NULL
)
{
int
result
;
...
...
@@ -507,16 +510,18 @@ int git_path_direach(
if
(
is_dot_or_dotdot
(
de
->
d_name
))
continue
;
if
(
git_buf_puts
(
path
,
de
->
d_name
)
<
GIT_SUCCESS
)
return
git_buf_lasterror
(
path
);
if
(
git_buf_puts
(
path
,
de
->
d_name
)
<
0
)
{
giterr_set_oom
(
error
);
return
-
1
;
}
result
=
fn
(
arg
,
path
);
result
=
fn
(
arg
,
path
,
error
);
git_buf_truncate
(
path
,
wd_len
);
/* restore path */
if
(
result
!=
GIT_SUCCESS
)
{
if
(
result
<
0
)
{
closedir
(
dir
);
return
result
;
/* The callee is reponsible for setting the correct error message */
return
-
1
;
}
}
...
...
src/refs.c
View file @
45d387ac
...
...
@@ -62,7 +62,7 @@ static int packed_write(git_repository *repo);
/* internal helpers */
static
int
reference_available
(
git_repository
*
repo
,
const
char
*
ref
,
const
char
*
old_ref
);
const
char
*
ref
,
const
char
*
old_ref
,
git_error
**
error
);
static
int
reference_delete
(
git_reference
*
ref
);
static
int
reference_lookup
(
git_reference
*
ref
);
...
...
@@ -521,7 +521,7 @@ struct dirent_list_data {
void
*
callback_payload
;
};
static
int
_dirent_loose_listall
(
void
*
_data
,
git_buf
*
full_path
)
static
int
_dirent_loose_listall
(
void
*
_data
,
git_buf
*
full_path
,
git_error
**
error
)
{
struct
dirent_list_data
*
data
=
(
struct
dirent_list_data
*
)
_data
;
const
char
*
file_path
=
full_path
->
ptr
+
data
->
repo_path_len
;
...
...
@@ -844,49 +844,55 @@ cleanup:
return
error
;
}
struct
reference_available_t
{
const
char
*
new_ref
;
const
char
*
old_ref
;
int
available
;
};
static
int
_reference_available_cb
(
const
char
*
ref
,
void
*
data
)
{
const
char
*
new
,
*
old
;
const
char
**
refs
;
struct
reference_available_t
*
d
;
assert
(
ref
&&
data
);
d
=
(
reference_available_t
*
)
data
;
refs
=
(
const
char
**
)
data
;
new
=
(
const
char
*
)
refs
[
0
];
old
=
(
const
char
*
)
refs
[
1
];
if
(
!
old
||
strcmp
(
old
,
ref
))
{
if
(
!
d
->
old_ref
||
strcmp
(
d
->
old_ref
,
ref
))
{
int
reflen
=
strlen
(
ref
);
int
newlen
=
strlen
(
new
);
int
newlen
=
strlen
(
d
->
new_ref
);
int
cmplen
=
reflen
<
newlen
?
reflen
:
newlen
;
const
char
*
lead
=
reflen
<
newlen
?
new
:
ref
;
const
char
*
lead
=
reflen
<
newlen
?
d
->
new_ref
:
ref
;
if
(
!
strncmp
(
new
,
ref
,
cmplen
)
&&
lead
[
cmplen
]
==
'/'
)
return
GIT_EEXISTS
;
if
(
!
strncmp
(
d
->
new_ref
,
ref
,
cmplen
)
&&
lead
[
cmplen
]
==
'/'
)
{
d
->
available
=
0
;
return
-
1
;
}
}
return
GIT_SUCCESS
;
return
0
;
}
static
int
reference_available
(
int
*
available
,
git_repository
*
repo
,
const
char
*
ref
,
const
char
*
old_ref
)
const
char
*
old_ref
,
git_error
**
error
)
{
const
char
*
refs
[
2
]
;
struct
reference_available_t
data
;
refs
[
0
]
=
ref
;
refs
[
1
]
=
old_ref
;
data
.
new_ref
=
ref
;
data
.
old_ref
=
old_ref
;
data
.
available
=
1
;
if
(
git_reference_foreach
(
repo
,
GIT_REF_LISTALL
,
_reference_available_cb
,
(
void
*
)
refs
)
<
0
)
{
return
git__throw
(
GIT_EEXISTS
,
"Reference name `%s` conflicts with existing reference"
,
ref
);
}
_reference_available_cb
,
(
void
*
)
&
data
,
error
)
<
0
)
return
-
1
;
return
GIT_SUCCESS
;
*
available
=
data
.
available
;
return
0
;
}
static
int
reference_exists
(
int
*
exists
,
git_repository
*
repo
,
const
char
*
ref_name
)
...
...
@@ -946,17 +952,17 @@ static int packed_lookup(git_reference *ref)
return
GIT_SUCCESS
;
}
static
int
reference_lookup
(
git_reference
*
ref
)
static
int
reference_lookup
(
git_reference
*
ref
,
git_error
**
error
)
{
int
error_loose
,
error_packed
;
int
result
;
error_loose
=
loose_lookup
(
ref
);
if
(
error_loose
==
GIT_SUCCESS
)
return
GIT_SUCCESS
;
result
=
loose_lookup
(
ref
,
error
);
if
(
result
!=
GIT_ENOTFOUND
)
return
result
;
error_packed
=
packed_lookup
(
ref
);
if
(
error_packed
==
GIT_SUCCESS
)
return
GIT_SUCCESS
;
result
=
packed_lookup
(
ref
,
error
);
if
(
result
!=
GIT_ENOTFOUND
)
return
result
;
git_reference_free
(
ref
);
...
...
@@ -974,9 +980,9 @@ static int reference_lookup(git_reference *ref)
* This is an internal method; the reference is removed
* from disk or the packfile, but the pointer is not freed
*/
static
int
reference_delete
(
git_reference
*
ref
)
static
int
reference_delete
(
git_reference
*
ref
,
git_error
**
error
)
{
int
error
;
int
result
;
assert
(
ref
);
...
...
@@ -986,15 +992,19 @@ static int reference_delete(git_reference *ref)
if
(
ref
->
flags
&
GIT_REF_PACKED
)
{
struct
packref
*
packref
;
/* load the existing packfile */
if
(
(
error
=
packed_load
(
ref
->
owner
))
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to delete reference"
)
;
if
(
packed_load
(
ref
->
owner
,
error
)
<
0
)
return
-
1
;
if
(
git_hashtable_remove2
(
ref
->
owner
->
references
.
packfile
,
ref
->
name
,
(
void
**
)
&
packref
)
<
GIT_SUCCESS
)
return
git__throw
(
GIT_ENOTFOUND
,
"Reference not found"
);
ref
->
name
,
(
void
**
)
&
packref
)
<
0
)
{
giterr_set
(
error
,
GITERR_REFERENCE
,
"Reference %s stopped existing in the packfile"
,
ref
->
name
);
return
-
1
;
}
git__free
(
packref
);
error
=
packed_write
(
ref
->
owner
);
git__free
(
packref
);
if
(
packed_write
(
ref
->
owner
,
error
)
<
0
)
return
-
1
;
/* If the reference is loose, we can just remove the reference
* from the filesystem */
...
...
@@ -1002,66 +1012,55 @@ static int reference_delete(git_reference *ref)
git_reference
*
ref_in_pack
;
git_buf
full_path
=
GIT_BUF_INIT
;
error
=
git_buf_joinpath
(
&
full_path
,
ref
->
owner
->
path_repository
,
ref
->
name
);
if
(
error
<
GIT_SUCCESS
)
goto
cleanup
;
if
(
git_buf_joinpath
(
&
full_path
,
ref
->
owner
->
path_repository
,
ref
->
name
)
<
0
)
{
giterr_set_oom
(
error
);
return
-
1
;
}
error
=
p_unlink
(
full_path
.
ptr
);
result
=
p_unlink
(
full_path
.
ptr
);
git_buf_free
(
&
full_path
);
/* done with path at this point */
if
(
error
<
GIT_SUCCESS
)
goto
cleanup
;
if
(
result
<
0
)
{
giterr_set
(
error
,
GITERR_OS
,
"Failed to unlink '%s': %s"
,
full_path
.
ptr
,
strerror
(
errno
));
return
-
1
;
}
/* When deleting a loose reference, we have to ensure that an older
* packed version of it doesn't exist */
if
(
git_reference_lookup
(
&
ref_in_pack
,
ref
->
owner
,
ref
->
name
)
==
GIT_SUCCESS
)
{
if
(
git_reference_lookup
(
&
ref_in_pack
,
ref
->
owner
,
ref
->
name
,
NULL
)
==
GIT_SUCCESS
)
{
assert
((
ref_in_pack
->
flags
&
GIT_REF_PACKED
)
!=
0
);
error
=
git_reference_delete
(
ref_in_pack
);
return
git_reference_delete
(
ref_in_pack
,
error
);
}
}
cleanup:
return
error
==
GIT_SUCCESS
?
GIT_SUCCESS
:
git__rethrow
(
error
,
"Failed to delete reference"
);
return
0
;
}
int
git_reference_delete
(
git_reference
*
ref
)
int
git_reference_delete
(
git_reference
*
ref
,
git_error
**
error
)
{
int
error
=
reference_delete
(
ref
);
if
(
error
<
GIT_SUCCESS
)
return
error
;
int
result
=
reference_delete
(
ref
,
error
);
git_reference_free
(
ref
);
return
GIT_SUCCESS
;
return
result
;
}
int
git_reference_lookup
(
git_reference
**
ref_out
,
git_repository
*
repo
,
const
char
*
name
)
git_repository
*
repo
,
const
char
*
name
,
git_error
**
error
)
{
int
error
;
char
normalized_name
[
GIT_REFNAME_MAX
];
git_reference
*
ref
=
NULL
;
assert
(
ref_out
&&
repo
&&
name
);
*
ref_out
=
NULL
;
if
(
normalize_name
(
normalized_name
,
sizeof
(
normalized_name
),
name
,
0
,
error
)
<
0
)
return
-
1
;
error
=
normalize_name
(
normalized_name
,
sizeof
(
normalized_name
),
name
,
0
);
if
(
error
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to lookup reference"
);
error
=
reference_alloc
(
&
ref
,
repo
,
normalized_name
);
if
(
error
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to lookup reference"
);
error
=
reference_lookup
(
ref
);
if
(
error
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to lookup reference"
);
if
(
reference_alloc
(
&
ref
,
repo
,
normalized_name
,
error
)
<
0
)
return
-
1
;
*
ref_out
=
ref
;
return
GIT_SUCCESS
;
return
reference_lookup
(
ref
,
error
)
;
}
/**
...
...
@@ -1123,46 +1122,43 @@ int git_reference_create_symbolic(
git_repository
*
repo
,
const
char
*
name
,
const
char
*
target
,
int
force
)
int
force
,
git_error
**
error
)
{
char
normalized
[
GIT_REFNAME_MAX
];
int
ref_exists
,
error
=
GIT_SUCCESS
;
int
exists
;
git_reference
*
ref
=
NULL
;
error
=
normalize_name
(
normalized
,
sizeof
(
normalized
),
name
,
0
);
if
(
error
<
GIT_SUCCESS
)
goto
cleanup
;
if
(
normalize_name
(
normalized
,
sizeof
(
normalized
),
name
,
0
,
error
)
<
0
)
return
-
1
;
if
(
(
error
=
reference_exists
(
&
ref_exists
,
repo
,
normalized
)
<
GIT_SUCCESS
)
)
return
git__rethrow
(
error
,
"Failed to create symbolic reference"
)
;
if
(
reference_exists
(
&
exists
,
repo
,
normalized
,
error
)
<
0
)
return
-
1
;
if
(
ref_exists
&&
!
force
)
return
git__throw
(
GIT_EEXISTS
,
"Failed to create symbolic reference. Reference already exists"
);
if
(
exists
&&
!
force
)
{
giterr_set
(
error
,
GITERR_REFERENCE
,
"A reference with that name (%s) already exists"
);
return
GIT_EEXISTS
;
}
error
=
reference_alloc
(
&
ref
,
repo
,
normalized
);
if
(
error
<
GIT_SUCCESS
)
goto
cleanup
;
if
(
reference_alloc
(
&
ref
,
repo
,
normalized
,
error
)
<
0
)
return
-
1
;
ref
->
flags
|=
GIT_REF_SYMBOLIC
;
/* set the target; this will normalize the name automatically
* and write the reference on disk */
error
=
git_reference_set_target
(
ref
,
target
);
if
(
error
<
GIT_SUCCESS
)
goto
cleanup
;
if
(
git_reference_set_target
(
ref
,
target
,
error
)
<
0
)
{
git_reference_free
(
ref
);
return
-
1
;
}
if
(
ref_out
==
NULL
)
{
git_reference_free
(
ref
);
}
else
{
*
ref_out
=
ref
;
}
return
GIT_SUCCESS
;
cleanup:
git_reference_free
(
ref
);
return
git__rethrow
(
error
,
"Failed to create symbolic reference"
);
return
0
;
}
int
git_reference_create_oid
(
...
...
@@ -1170,36 +1166,35 @@ int git_reference_create_oid(
git_repository
*
repo
,
const
char
*
name
,
const
git_oid
*
id
,
int
force
)
int
force
,
git_error
**
error
)
{
int
e
rror
=
GIT_SUCCESS
,
ref_e
xists
;
int
exists
;
git_reference
*
ref
=
NULL
;
char
normalized
[
GIT_REFNAME_MAX
];
error
=
normalize_name
(
normalized
,
sizeof
(
normalized
),
name
,
1
);
if
(
error
<
GIT_SUCCESS
)
goto
cleanup
;
if
((
error
=
reference_exists
(
&
ref_exists
,
repo
,
normalized
)
<
GIT_SUCCESS
))
return
git__rethrow
(
error
,
"Failed to create OID reference"
);
if
(
normalize_name
(
normalized
,
sizeof
(
normalized
),
name
,
1
,
error
)
<
0
)
return
-
1
;
if
(
ref_exists
&&
!
force
)
return
git__throw
(
GIT_EEXISTS
,
"Failed to create OID reference. Reference already exists"
);
if
(
reference_exists
(
&
exists
,
repo
,
normalized
,
error
)
<
0
)
return
-
1
;
if
((
error
=
reference_available
(
repo
,
name
,
NULL
))
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to create reference"
);
if
(
exists
&&
!
force
)
{
giterr_set
(
error
,
GITERR_REFERENCE
,
"A reference with that name (%s) already exists"
);
return
GIT_EEXISTS
;
}
error
=
reference_alloc
(
&
ref
,
repo
,
name
);
if
(
error
<
GIT_SUCCESS
)
goto
cleanup
;
if
(
reference_alloc
(
&
ref
,
repo
,
name
,
error
)
<
0
)
return
-
1
;
ref
->
flags
|=
GIT_REF_OID
;
/* set the oid; this will write the reference on disk */
error
=
git_reference_set_oid
(
ref
,
id
);
if
(
error
<
GIT_SUCCESS
)
goto
cleanup
;
if
(
git_reference_set_oid
(
ref
,
id
,
error
)
<
0
)
{
git_reference_free
(
ref
);
return
-
1
;
}
if
(
ref_out
==
NULL
)
{
git_reference_free
(
ref
);
...
...
@@ -1207,13 +1202,8 @@ int git_reference_create_oid(
*
ref_out
=
ref
;
}
return
GIT_SUCCESS
;
cleanup:
git_reference_free
(
ref
);
return
git__rethrow
(
error
,
"Failed to create reference OID"
);
return
0
;
}
/*
* Change the OID target of a reference.
*
...
...
@@ -1223,40 +1213,34 @@ cleanup:
* We do not repack packed references because of performance
* reasons.
*/
int
git_reference_set_oid
(
git_reference
*
ref
,
const
git_oid
*
id
)
int
git_reference_set_oid
(
git_reference
*
ref
,
const
git_oid
*
id
,
git_error
**
error
)
{
int
error
=
GIT_SUCCESS
,
exists
;
git_odb
*
odb
=
NULL
;
if
((
ref
->
flags
&
GIT_REF_OID
)
==
0
)
return
git__throw
(
GIT_EINVALIDREFSTATE
,
"Failed to set OID target of reference. Not an OID reference"
);
if
((
ref
->
flags
&
GIT_REF_OID
)
==
0
)
{
giterr_set
(
error
,
GITERR_REFERENCE
,
"Cannot set OID on symbolic reference"
);
return
-
1
;
}
assert
(
ref
->
owner
);
error
=
git_repository_odb__weakptr
(
&
odb
,
ref
->
owner
);
if
(
error
<
GIT_SUCCESS
)
return
error
;
exists
=
git_odb_exists
(
odb
,
id
);
git_odb_free
(
odb
);
if
(
git_repository_odb__weakptr
(
&
odb
,
ref
->
owner
,
error
)
<
0
)
return
-
1
;
/* Don't let the user create references to OIDs that
* don't exist in the ODB */
if
(
!
exists
)
return
git__throw
(
GIT_ENOTFOUND
,
"Failed to set OID target of reference. OID doesn't exist in ODB"
);
if
(
!
git_odb_exists
(
odb
,
id
))
{
giterr_set
(
error
,
GITERR_REFERENCE
,
"Target OID for the reference doesn't exist on the repository"
);
return
-
1
;
}
/* Update the OID value on `ref` */
git_oid_cpy
(
&
ref
->
target
.
oid
,
id
);
/* Write back to disk */
error
=
loose_write
(
ref
);
if
(
error
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to set OID target of reference"
);
return
GIT_SUCCESS
;
return
loose_write
(
ref
,
error
);
}
/*
...
...
@@ -1266,84 +1250,72 @@ int git_reference_set_oid(git_reference *ref, const git_oid *id)
* a pack. We just change the target in memory
* and overwrite the file on disk.
*/
int
git_reference_set_target
(
git_reference
*
ref
,
const
char
*
target
)
int
git_reference_set_target
(
git_reference
*
ref
,
const
char
*
target
,
git_error
**
error
)
{
int
error
;
char
normalized
[
GIT_REFNAME_MAX
];
if
((
ref
->
flags
&
GIT_REF_SYMBOLIC
)
==
0
)
return
git__throw
(
GIT_EINVALIDREFSTATE
,
"Failed to set reference target. Not a symbolic reference"
);
if
((
ref
->
flags
&
GIT_REF_SYMBOLIC
)
==
0
)
{
giterr_set
(
error
,
GITERR_REFERENCE
,
"Cannot set symbolic target on a direct reference"
);
return
-
1
;
}
error
=
normalize_name
(
normalized
,
sizeof
(
normalized
),
target
,
0
);
if
(
error
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to set reference target. Invalid target name"
);
if
(
normalize_name
(
normalized
,
sizeof
(
normalized
),
target
,
0
,
error
))
return
-
1
;
git__free
(
ref
->
target
.
symbolic
);
ref
->
target
.
symbolic
=
git__strdup
(
normalized
);
if
(
ref
->
target
.
symbolic
==
NULL
)
return
GIT_ENOMEM
;
GITERR_CHECK_ALLOC
(
ref
->
target
.
symbolic
,
error
);
return
loose_write
(
ref
);
return
loose_write
(
ref
,
error
);
}
int
git_reference_rename
(
git_reference
*
ref
,
const
char
*
new_name
,
int
force
)
int
git_reference_rename
(
git_reference
*
ref
,
const
char
*
new_name
,
int
force
,
git_error
**
error
)
{
int
error
;
int
result
,
ref_available
;
git_buf
aux_path
=
GIT_BUF_INIT
;
char
normalized
[
GIT_REFNAME_MAX
];
const
char
*
head_target
=
NULL
;
git_reference
*
existing_ref
=
NULL
,
*
head
=
NULL
;
error
=
normalize_name
(
normalized
,
sizeof
(
normalized
),
new_name
,
ref
->
flags
&
GIT_REF_OID
);
if
(
error
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to rename reference. Invalid name"
);
if
(
normalize_name
(
normalized
,
sizeof
(
normalized
),
new_name
,
ref
->
flags
&
GIT_REF_OID
,
error
)
<
0
)
return
-
1
;
new_name
=
normalized
;
/* If we are forcing the rename, try to lookup a reference with the
* new one. If the lookup succeeds, we need to delete that ref
* before the renaming can proceed */
if
(
force
)
{
error
=
git_reference_lookup
(
&
existing_ref
,
ref
->
owner
,
new_name
);
if
(
error
==
GIT_SUCCESS
)
{
error
=
git_reference_delete
(
existing_ref
);
if
(
error
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to rename reference. "
"The existing reference cannot be deleted"
);
}
else
if
(
error
!=
GIT_ENOTFOUND
)
goto
cleanup
;
/* If we're not forcing the rename, check if the reference exists.
* If it does, renaming cannot continue */
}
else
{
int
exists
;
/* see if the reference already exists */
if
(
reference_available
(
&
ref_available
,
ref
->
owner
,
new_name
,
ref
->
name
,
error
)
<
0
)
return
-
1
;
error
=
reference_exists
(
&
exists
,
ref
->
owner
,
normalized
);
if
(
error
<
GIT_SUCCESS
)
goto
cleanup
;
if
(
exists
)
return
git__throw
(
GIT_EEXISTS
,
"Failed to rename reference. Reference already exists"
);
/* We cannot proceed if the reference already exists and we're not forcing
* the rename; the existing one would be overwritten */
if
(
!
force
&&
!
ref_available
)
{
giterr_set
(
error
,
GITERR_REFERENCE
,
"A reference with the same name (%s) already exists"
,
normalized
);
return
GIT_EEXISTS
;
}
if
((
error
=
reference_available
(
ref
->
owner
,
new_name
,
ref
->
name
))
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to rename reference. Reference already exists"
);
/* FIXME: if the reference exists and we are forcing, do we really need to
* remove the reference first?
*
* Two cases:
*
* - the reference already exists and is loose: not a problem, the file
* gets overwritten on disk
*
* - the reference already exists and is packed: we write a new one as
* loose, which by all means renders the packed one useless
*/
/* Initialize path now so we won't get an allocation failure once
* we actually start removing things.
*/
error
=
git_buf_joinpath
(
&
aux_path
,
ref
->
owner
->
path_repository
,
new_name
);
if
(
error
<
GIT_SUCCESS
)
goto
cleanup
;
if
(
git_buf_joinpath
(
&
aux_path
,
ref
->
owner
->
path_repository
,
new_name
)
<
0
)
{
giterr_set_oom
(
error
);
return
-
1
;
}
/*
* Now delete the old ref and remove an possibly existing directory
...
...
@@ -1351,12 +1323,12 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
* method deletes the ref from disk but doesn't free the pointer, so
* we can still access the ref's attributes for creating the new one
*/
if
(
(
error
=
reference_delete
(
ref
))
<
GIT_SUCCESS
)
if
(
reference_delete
(
ref
,
error
)
<
0
)
goto
cleanup
;
if
(
git_path_exists
(
aux_path
.
ptr
)
==
GIT_SUCCESS
)
{
if
(
git_path_isdir
(
aux_path
.
ptr
)
==
GIT_SUCCESS
)
{
if
(
(
error
=
git_futils_rmdir_r
(
aux_path
.
ptr
,
0
))
<
GIT_SUCCESS
)
if
(
git_futils_rmdir_r
(
aux_path
.
ptr
,
0
,
error
)
<
0
)
goto
rollback
;
}
else
goto
rollback
;
}
...
...
@@ -1365,43 +1337,48 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
* Finally we can create the new reference.
*/
if
(
ref
->
flags
&
GIT_REF_SYMBOLIC
)
{
error
=
git_reference_create_symbolic
(
NULL
,
ref
->
owner
,
new_name
,
ref
->
target
.
symbolic
,
0
);
result
=
git_reference_create_symbolic
(
NULL
,
ref
->
owner
,
new_name
,
ref
->
target
.
symbolic
,
force
,
error
);
}
else
{
error
=
git_reference_create_oid
(
NULL
,
ref
->
owner
,
new_name
,
&
ref
->
target
.
oid
,
0
);
result
=
git_reference_create_oid
(
NULL
,
ref
->
owner
,
new_name
,
&
ref
->
target
.
oid
,
force
,
error
);
}
if
(
error
<
GIT_SUCCESS
)
if
(
result
<
0
)
goto
rollback
;
/*
* Check if we have to update HEAD.
*/
error
=
git_reference_lookup
(
&
head
,
ref
->
owner
,
GIT_HEAD_FILE
);
if
(
error
<
GIT_SUCCESS
)
if
(
git_reference_lookup
(
&
head
,
ref
->
owner
,
GIT_HEAD_FILE
,
NULL
)
<
0
)
{
giterr_set
(
error
,
GITERR_REFERENCE
,
"Failed to update HEAD after renaming reference"
);
goto
cleanup
;
}
head_target
=
git_reference_target
(
head
);
if
(
head_target
&&
!
strcmp
(
head_target
,
ref
->
name
))
{
error
=
git_reference_create_symbolic
(
&
head
,
ref
->
owner
,
"HEAD"
,
new_name
,
1
);
if
(
error
<
GIT_SUCCESS
)
if
(
git_reference_create_symbolic
(
&
head
,
ref
->
owner
,
"HEAD"
,
new_name
,
1
,
NULL
)
<
0
)
{
giterr_set
(
error
,
GITERR_REFERENCE
,
"Failed to update HEAD after renaming reference"
);
goto
cleanup
;
}
}
/*
* Rename the reflog file.
*/
error
=
git_buf_join_n
(
&
aux_path
,
'/'
,
3
,
ref
->
owner
->
path_repository
,
GIT_REFLOG_DIR
,
ref
->
name
)
;
if
(
error
<
GIT_SUCCESS
)
if
(
git_buf_join_n
(
&
aux_path
,
'/'
,
3
,
ref
->
owner
->
path_repository
,
GIT_REFLOG_DIR
,
ref
->
name
)
<
0
)
{
giterr_set_oom
(
error
);
goto
cleanup
;
}
if
(
git_path_exists
(
aux_path
.
ptr
)
==
GIT_SUCCESS
)
error
=
git_reflog_rename
(
ref
,
new_name
);
if
(
git_path_exists
(
aux_path
.
ptr
)
==
0
)
{
if
(
git_reflog_rename
(
ref
,
new_name
,
error
)
<
0
)
goto
cleanup
;
}
/*
* Change the name of the reference given by the user.
...
...
@@ -1412,38 +1389,37 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
/* The reference is no longer packed */
ref
->
flags
&=
~
GIT_REF_PACKED
;
git_reference_free
(
head
);
git_buf_free
(
&
aux_path
);
return
0
;
cleanup:
/* We no longer need the newly created reference nor the head */
git_reference_free
(
head
);
git_buf_free
(
&
aux_path
);
return
error
==
GIT_SUCCESS
?
GIT_SUCCESS
:
git__rethrow
(
error
,
"Failed to rename reference"
);
return
-
1
;
rollback:
/*
* Try to create the old reference again
.
* Try to create the old reference again
, ignore failures
*/
if
(
ref
->
flags
&
GIT_REF_SYMBOLIC
)
error
=
git_reference_create_symbolic
(
NULL
,
ref
->
owner
,
ref
->
name
,
ref
->
target
.
symbolic
,
0
);
git_reference_create_symbolic
(
NULL
,
ref
->
owner
,
ref
->
name
,
ref
->
target
.
symbolic
,
0
,
NULL
);
else
error
=
git_reference_create_oid
(
NULL
,
ref
->
owner
,
ref
->
name
,
&
ref
->
target
.
oid
,
0
);
git_reference_create_oid
(
NULL
,
ref
->
owner
,
ref
->
name
,
&
ref
->
target
.
oid
,
0
.
NULL
);
/* The reference is no longer packed */
ref
->
flags
&=
~
GIT_REF_PACKED
;
git_buf_free
(
&
aux_path
);
return
error
==
GIT_SUCCESS
?
git__rethrow
(
GIT_ERROR
,
"Failed to rename reference. Did rollback"
)
:
git__rethrow
(
error
,
"Failed to rename reference. Failed to rollback"
);
return
-
1
;
}
int
git_reference_resolve
(
git_reference
**
ref_out
,
git_reference
*
ref
)
int
git_reference_resolve
(
git_reference
**
ref_out
,
git_reference
*
ref
,
git_error
**
error
)
{
int
error
,
i
=
0
;
int
result
,
i
=
0
;
git_repository
*
repo
;
assert
(
ref
);
...
...
@@ -1455,15 +1431,15 @@ int git_reference_resolve(git_reference **ref_out, git_reference *ref)
* copy. Instead of duplicating `ref`, we look it up again to
* ensure the copy is out to date */
if
(
ref
->
flags
&
GIT_REF_OID
)
return
git_reference_lookup
(
ref_out
,
ref
->
owner
,
ref
->
name
);
return
git_reference_lookup
(
ref_out
,
ref
->
owner
,
ref
->
name
,
error
);
/* Otherwise, keep iterating until the reference is resolved */
for
(
i
=
0
;
i
<
MAX_NESTING_LEVEL
;
++
i
)
{
git_reference
*
new_ref
;
error
=
git_reference_lookup
(
&
new_ref
,
repo
,
ref
->
target
.
symbolic
);
if
(
error
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to resolve reference"
)
;
result
=
git_reference_lookup
(
&
new_ref
,
repo
,
ref
->
target
.
symbolic
,
error
);
if
(
result
<
0
)
return
result
;
/* Free intermediate references, except for the original one
* we've received */
...
...
@@ -1480,33 +1456,30 @@ int git_reference_resolve(git_reference **ref_out, git_reference *ref)
}
}
return
git__throw
(
GIT_ENOMEM
,
"Failed to resolve reference. Reference is too nested"
);
giterr_set
(
error
,
GITERR_REFERENCE
,
"Symbolic reference too nested (%d levels deep)"
,
MAX_NESTING_LEVEL
);
return
-
1
;
}
int
git_reference_packall
(
git_repository
*
repo
)
int
git_reference_packall
(
git_repository
*
repo
,
git_error
**
error
)
{
int
error
;
/* load the existing packfile */
if
((
error
=
packed_load
(
repo
))
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to pack references"
);
if
(
packed_load
(
repo
,
error
)
<
0
||
/* load the existing packfile */
packed_loadloose
(
repo
,
error
)
<
0
||
/* add all the loose refs */
packed_write
(
repo
,
error
)
<
0
)
/* write back to disk */
return
-
1
;
/* update it in-memory with all the loose references */
if
((
error
=
packed_loadloose
(
repo
))
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to pack references"
);
/* write it back to disk */
return
packed_write
(
repo
);
return
0
;
}
int
git_reference_foreach
(
git_repository
*
repo
,
unsigned
int
list_flags
,
int
(
*
callback
)(
const
char
*
,
void
*
),
void
*
payload
)
void
*
payload
,
git_error
**
error
)
{
int
error
;
int
result
;
struct
dirent_list_data
data
;
git_buf
refs_path
=
GIT_BUF_INIT
;
...
...
@@ -1514,13 +1487,12 @@ int git_reference_foreach(
if
(
list_flags
&
GIT_REF_PACKED
)
{
const
char
*
ref_name
;
if
(
(
error
=
packed_load
(
repo
))
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to list references"
)
;
if
(
packed_load
(
repo
,
error
)
<
0
)
return
-
1
;
GIT_HASHTABLE_FOREACH_KEY
(
repo
->
references
.
packfile
,
ref_name
,
if
((
error
=
callback
(
ref_name
,
payload
))
<
GIT_SUCCESS
)
return
git__throw
(
error
,
"Failed to list references. User callback failed"
);
GIT_HASHTABLE_FOREACH
(
repo
->
references
.
packfile
,
ref_name
,
_unused
,
if
(
callback
(
ref_name
,
payload
)
<
0
)
return
0
;
);
}
...
...
@@ -1533,15 +1505,15 @@ int git_reference_foreach(
data
.
callback
=
callback
;
data
.
callback_payload
=
payload
;
if
((
error
=
git_buf_joinpath
(
&
refs_path
,
repo
->
path_repository
,
GIT_REFS_DIR
))
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to alloc space for references"
);
error
=
git_path_direach
(
&
refs_path
,
_dirent_loose_listall
,
&
data
);
if
(
git_buf_joinpath
(
&
refs_path
,
repo
->
path_repository
,
GIT_REFS_DIR
)
<
0
)
{
giterr_set_oom
(
error
);
return
-
1
;
}
result
=
git_path_direach
(
&
refs_path
,
_dirent_loose_listall
,
&
data
,
error
);
git_buf_free
(
&
refs_path
);
return
error
;
return
result
;
}
static
int
cb__reflist_add
(
const
char
*
ref
,
void
*
data
)
...
...
@@ -1552,9 +1524,10 @@ static int cb__reflist_add(const char *ref, void *data)
int
git_reference_listall
(
git_strarray
*
array
,
git_repository
*
repo
,
unsigned
int
list_flags
)
unsigned
int
list_flags
,
git_error
**
error
)
{
int
error
;
int
result
;
git_vector
ref_list
;
assert
(
array
&&
repo
);
...
...
@@ -1562,15 +1535,15 @@ int git_reference_listall(
array
->
strings
=
NULL
;
array
->
count
=
0
;
if
(
git_vector_init
(
&
ref_list
,
8
,
NULL
)
<
GIT_SUCCESS
)
return
GIT_ENOMEM
;
error
=
git_reference_foreach
(
repo
,
list_flags
,
&
cb__reflist_add
,
(
void
*
)
&
ref_list
);
if
(
git_vector_init
(
&
ref_list
,
8
,
NULL
)
<
GIT_SUCCESS
)
{
giterr_set_oom
(
error
);
return
-
1
;
}
if
(
error
<
GIT_SUCCESS
)
{
if
(
git_reference_foreach
(
repo
,
list_flags
,
&
cb__reflist_add
,
(
void
*
)
&
ref_list
,
error
)
<
0
)
{
git_vector_free
(
&
ref_list
);
return
error
;
return
-
1
;
}
array
->
strings
=
(
char
**
)
ref_list
.
contents
;
...
...
@@ -1578,17 +1551,11 @@ int git_reference_listall(
return
GIT_SUCCESS
;
}
int
git_reference_reload
(
git_reference
*
ref
)
int
git_reference_reload
(
git_reference
*
ref
,
git_error
**
error
)
{
int
error
=
reference_lookup
(
ref
);
if
(
error
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to reload reference"
);
return
GIT_SUCCESS
;
return
reference_lookup
(
ref
,
error
);
}
void
git_repository__refcache_free
(
git_refcache
*
refs
)
{
assert
(
refs
);
...
...
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