Skip to content

Commit e54c347

Browse files
mhaggergitster
authored andcommitted
create_bundle(): duplicate file descriptor to avoid closing it twice
write_pack_data() passes bundle_fd to start_command() to be used as the stdout of pack-objects. But start_command() closes its stdout if it is > 1. This is a problem if bundle_fd is the fd of a lock_file, because commit_lock_file() will also try to close the fd. So the old code suppressed commit_lock_file()'s usual behavior of closing the file descriptor by setting the lock_file object's fd field to -1. But this is not really kosher. Code here shouldn't be mutating fields within the lock_file object. Instead, duplicate the file descriptor before passing it to write_pack_data(). Then that function can close its copy without closing the copy held in the lock_file object. Signed-off-by: Michael Haggerty <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 2db69de commit e54c347

File tree

1 file changed

+16
-10
lines changed

1 file changed

+16
-10
lines changed

bundle.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,9 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)
235235
return result;
236236
}
237237

238-
static int write_pack_data(int bundle_fd, struct lock_file *lock, struct rev_info *revs)
238+
239+
/* Write the pack data to bundle_fd, then close it if it is > 1. */
240+
static int write_pack_data(int bundle_fd, struct rev_info *revs)
239241
{
240242
struct child_process pack_objects = CHILD_PROCESS_INIT;
241243
int i;
@@ -250,13 +252,6 @@ static int write_pack_data(int bundle_fd, struct lock_file *lock, struct rev_inf
250252
if (start_command(&pack_objects))
251253
return error(_("Could not spawn pack-objects"));
252254

253-
/*
254-
* start_command closed bundle_fd if it was > 1
255-
* so set the lock fd to -1 so commit_lock_file()
256-
* won't fail trying to close it.
257-
*/
258-
lock->fd = -1;
259-
260255
for (i = 0; i < revs->pending.nr; i++) {
261256
struct object *object = revs->pending.objects[i].item;
262257
if (object->flags & UNINTERESTING)
@@ -416,10 +411,21 @@ int create_bundle(struct bundle_header *header, const char *path,
416411
bundle_to_stdout = !strcmp(path, "-");
417412
if (bundle_to_stdout)
418413
bundle_fd = 1;
419-
else
414+
else {
420415
bundle_fd = hold_lock_file_for_update(&lock, path,
421416
LOCK_DIE_ON_ERROR);
422417

418+
/*
419+
* write_pack_data() will close the fd passed to it,
420+
* but commit_lock_file() will also try to close the
421+
* lockfile's fd. So make a copy of the file
422+
* descriptor to avoid trying to close it twice.
423+
*/
424+
bundle_fd = dup(bundle_fd);
425+
if (bundle_fd < 0)
426+
die_errno("unable to dup file descriptor");
427+
}
428+
423429
/* write signature */
424430
write_or_die(bundle_fd, bundle_signature, strlen(bundle_signature));
425431

@@ -445,7 +451,7 @@ int create_bundle(struct bundle_header *header, const char *path,
445451
return -1;
446452

447453
/* write pack */
448-
if (write_pack_data(bundle_fd, &lock, &revs))
454+
if (write_pack_data(bundle_fd, &revs))
449455
return -1;
450456

451457
if (!bundle_to_stdout) {

0 commit comments

Comments
 (0)