]>
git.proxmox.com Git - libgit2.git/blob - src/reflog.c
2 * Copyright (C) 2009-2012 the libgit2 contributors
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
9 #include "repository.h"
11 #include "signature.h"
13 static int reflog_init(git_reflog
**reflog
, git_reference
*ref
)
19 log
= git__malloc(sizeof(git_reflog
));
23 memset(log
, 0x0, sizeof(git_reflog
));
25 log
->ref_name
= git__strdup(ref
->name
);
27 if (git_vector_init(&log
->entries
, 0, NULL
) < 0) {
28 git__free(log
->ref_name
);
38 static int reflog_write(const char *log_path
, const char *oid_old
,
39 const char *oid_new
, const git_signature
*committer
,
43 git_buf log
= GIT_BUF_INIT
;
44 git_filebuf fbuf
= GIT_FILEBUF_INIT
;
46 assert(log_path
&& oid_old
&& oid_new
&& committer
);
48 git_buf_puts(&log
, oid_old
);
49 git_buf_putc(&log
, ' ');
51 git_buf_puts(&log
, oid_new
);
53 git_signature__writebuf(&log
, " ", committer
);
54 git_buf_truncate(&log
, log
.size
- 1); /* drop LF */
57 if (strchr(msg
, '\n')) {
59 return git__throw(GIT_ERROR
, "Reflog message cannot contain newline");
62 git_buf_putc(&log
, '\t');
63 git_buf_puts(&log
, msg
);
66 git_buf_putc(&log
, '\n');
68 if ((error
= git_buf_lasterror(&log
)) < GIT_SUCCESS
) {
70 return git__rethrow(error
, "Failed to write reflog. Memory allocation failure");
73 if ((error
= git_filebuf_open(&fbuf
, log_path
, GIT_FILEBUF_APPEND
)) < GIT_SUCCESS
) {
75 return git__rethrow(error
, "Failed to write reflog. Cannot open reflog `%s`", log_path
);
78 git_filebuf_write(&fbuf
, log
.ptr
, log
.size
);
79 error
= git_filebuf_commit(&fbuf
, GIT_REFLOG_FILE_MODE
);
83 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to write reflog");
86 static int reflog_parse(git_reflog
*log
, const char *buf
, size_t buf_size
)
88 int error
= GIT_SUCCESS
;
90 git_reflog_entry
*entry
;
92 #define seek_forward(_increase) { \
93 if (_increase >= buf_size) { \
94 if (entry->committer) \
95 git__free(entry->committer); \
97 return git__throw(GIT_ERROR, "Failed to seek forward. Buffer size exceeded"); \
100 buf_size -= _increase; \
103 while (buf_size
> GIT_REFLOG_SIZE_MIN
) {
104 entry
= git__malloc(sizeof(git_reflog_entry
));
107 entry
->committer
= NULL
;
109 if (git_oid_fromstrn(&entry
->oid_old
, buf
, GIT_OID_HEXSZ
) < GIT_SUCCESS
) {
113 seek_forward(GIT_OID_HEXSZ
+ 1);
115 if (git_oid_fromstrn(&entry
->oid_cur
, buf
, GIT_OID_HEXSZ
) < GIT_SUCCESS
) {
119 seek_forward(GIT_OID_HEXSZ
+ 1);
123 /* Seek forward to the end of the signature. */
124 while (*buf
&& *buf
!= '\t' && *buf
!= '\n')
127 entry
->committer
= git__malloc(sizeof(git_signature
));
128 if (entry
->committer
== NULL
) {
133 if ((error
= git_signature__parse(entry
->committer
, &ptr
, buf
+ 1, NULL
, *buf
)) < GIT_SUCCESS
) {
134 git__free(entry
->committer
);
136 return git__rethrow(error
, "Failed to parse reflog. Could not parse signature");
140 /* We got a message. Read everything till we reach LF. */
144 while (*buf
&& *buf
!= '\n')
147 entry
->msg
= git__strndup(ptr
, buf
- ptr
);
151 while (*buf
&& *buf
== '\n' && buf_size
> 1)
154 if ((error
= git_vector_insert(&log
->entries
, entry
)) < GIT_SUCCESS
)
155 return git__rethrow(error
, "Failed to parse reflog. Could not add new entry");
160 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to parse reflog");
163 void git_reflog_free(git_reflog
*reflog
)
166 git_reflog_entry
*entry
;
168 for (i
=0; i
< reflog
->entries
.length
; i
++) {
169 entry
= git_vector_get(&reflog
->entries
, i
);
171 git_signature_free(entry
->committer
);
173 git__free(entry
->msg
);
177 git_vector_free(&reflog
->entries
);
178 git__free(reflog
->ref_name
);
182 int git_reflog_read(git_reflog
**reflog
, git_reference
*ref
)
185 git_buf log_path
= GIT_BUF_INIT
;
186 git_fbuffer log_file
= GIT_FBUFFER_INIT
;
187 git_reflog
*log
= NULL
;
191 if ((error
= reflog_init(&log
, ref
)) < GIT_SUCCESS
)
192 return git__rethrow(error
, "Failed to read reflog. Cannot init reflog");
194 error
= git_buf_join_n(&log_path
, '/', 3,
195 ref
->owner
->path_repository
, GIT_REFLOG_DIR
, ref
->name
);
196 if (error
< GIT_SUCCESS
)
199 if ((error
= git_futils_readbuffer(&log_file
, log_path
.ptr
)) < GIT_SUCCESS
) {
200 git__rethrow(error
, "Failed to read reflog. Cannot read file `%s`", log_path
.ptr
);
204 if ((error
= reflog_parse(log
, log_file
.data
, log_file
.len
)) < GIT_SUCCESS
)
205 git__rethrow(error
, "Failed to read reflog");
210 if (error
!= GIT_SUCCESS
&& log
!= NULL
)
211 git_reflog_free(log
);
212 git_futils_freebuffer(&log_file
);
213 git_buf_free(&log_path
);
218 int git_reflog_write(git_reference
*ref
, const git_oid
*oid_old
,
219 const git_signature
*committer
, const char *msg
)
222 char old
[GIT_OID_HEXSZ
+1];
223 char new[GIT_OID_HEXSZ
+1];
224 git_buf log_path
= GIT_BUF_INIT
;
228 if ((error
= git_reference_resolve(&r
, ref
)) < GIT_SUCCESS
)
229 return git__rethrow(error
,
230 "Failed to write reflog. Cannot resolve reference `%s`", ref
->name
);
232 oid
= git_reference_oid(r
);
234 error
= git__throw(GIT_ERROR
,
235 "Failed to write reflog. Cannot resolve reference `%s`", r
->name
);
236 git_reference_free(r
);
240 git_oid_to_string(new, GIT_OID_HEXSZ
+1, oid
);
242 git_reference_free(r
);
244 error
= git_buf_join_n(&log_path
, '/', 3,
245 ref
->owner
->path_repository
, GIT_REFLOG_DIR
, ref
->name
);
246 if (error
< GIT_SUCCESS
)
249 if (git_path_exists(log_path
.ptr
)) {
250 error
= git_futils_mkpath2file(log_path
.ptr
, GIT_REFLOG_DIR_MODE
);
251 if (error
< GIT_SUCCESS
)
253 "Failed to write reflog. Cannot create reflog directory");
254 } else if (git_path_isfile(log_path
.ptr
)) {
255 error
= git__throw(GIT_ERROR
,
256 "Failed to write reflog. `%s` is directory", log_path
.ptr
);
257 } else if (oid_old
== NULL
) {
258 error
= git__throw(GIT_ERROR
,
259 "Failed to write reflog. Old OID cannot be NULL for existing reference");
262 if (error
< GIT_SUCCESS
)
266 git_oid_to_string(old
, sizeof(old
), oid_old
);
268 p_snprintf(old
, sizeof(old
), "%0*d", GIT_OID_HEXSZ
, 0);
270 error
= reflog_write(log_path
.ptr
, old
, new, committer
, msg
);
273 git_buf_free(&log_path
);
277 int git_reflog_rename(git_reference
*ref
, const char *new_name
)
280 git_buf old_path
= GIT_BUF_INIT
;
281 git_buf new_path
= GIT_BUF_INIT
;
283 if (git_buf_join_n(&old_path
, '/', 3, ref
->owner
->path_repository
,
284 GIT_REFLOG_DIR
, ref
->name
) &&
285 git_buf_join_n(&new_path
, '/', 3, ref
->owner
->path_repository
,
286 GIT_REFLOG_DIR
, new_name
))
287 error
= p_rename(git_buf_cstr(&old_path
), git_buf_cstr(&new_path
));
291 git_buf_free(&old_path
);
292 git_buf_free(&new_path
);
297 int git_reflog_delete(git_reference
*ref
)
299 int error
= GIT_SUCCESS
;
300 git_buf path
= GIT_BUF_INIT
;
302 error
= git_buf_join_n(&path
, '/', 3,
303 ref
->owner
->path_repository
, GIT_REFLOG_DIR
, ref
->name
);
305 if (error
== GIT_SUCCESS
&& git_path_exists(path
.ptr
) == 0)
306 error
= p_unlink(path
.ptr
);
313 unsigned int git_reflog_entrycount(git_reflog
*reflog
)
316 return reflog
->entries
.length
;
319 const git_reflog_entry
* git_reflog_entry_byindex(git_reflog
*reflog
, unsigned int idx
)
322 return git_vector_get(&reflog
->entries
, idx
);
325 const git_oid
* git_reflog_entry_oidold(const git_reflog_entry
*entry
)
328 return &entry
->oid_old
;
331 const git_oid
* git_reflog_entry_oidnew(const git_reflog_entry
*entry
)
334 return &entry
->oid_cur
;
337 git_signature
* git_reflog_entry_committer(const git_reflog_entry
*entry
)
340 return entry
->committer
;
343 char * git_reflog_entry_msg(const git_reflog_entry
*entry
)