Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 75a0ccf

Browse files
committed
Merge pull request libgit2#3170 from CmdrMoozy/nsec_fix
git_index_entry__init_from_stat: set nsec fields in entry stats
2 parents 2c26c86 + 28659e5 commit 75a0ccf

File tree

16 files changed

+175
-50
lines changed

16 files changed

+175
-50
lines changed

CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Mo
2020

2121
INCLUDE(CheckLibraryExists)
2222
INCLUDE(CheckFunctionExists)
23+
INCLUDE(CheckStructHasMember)
2324
INCLUDE(AddCFlagIfSupported)
2425
INCLUDE(FindPkgConfig)
2526

@@ -85,6 +86,12 @@ IF (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
8586
OPTION( USE_OPENSSL "Link with and use openssl library" ON )
8687
ENDIF()
8788

89+
CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtim.tv_nsec sys/stat.h
90+
HAVE_STRUCT_STAT_NSEC LANGUAGE C)
91+
IF(HAVE_STRUCT_STAT_NSEC OR WIN32)
92+
OPTION( USE_NSEC "Care about sub-second file mtimes and ctimes" OFF )
93+
ENDIF()
94+
8895
# This variable will contain the libraries we need to put into
8996
# libgit2.pc's Requires.private. That is, what we're linking to or
9097
# what someone who's statically linking us needs to link to.
@@ -516,6 +523,10 @@ IF (THREADSAFE)
516523
ADD_DEFINITIONS(-DGIT_THREADS)
517524
ENDIF()
518525

526+
IF (USE_NSEC)
527+
ADD_DEFINITIONS(-DGIT_USE_NSEC)
528+
ENDIF()
529+
519530
ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64)
520531

521532
# Collect sourcefiles

include/git2/common.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,9 @@ GIT_EXTERN(void) git_libgit2_version(int *major, int *minor, int *rev);
101101
*/
102102
typedef enum {
103103
GIT_FEATURE_THREADS = (1 << 0),
104-
GIT_FEATURE_HTTPS = (1 << 1),
105-
GIT_FEATURE_SSH = (1 << 2),
104+
GIT_FEATURE_HTTPS = (1 << 1),
105+
GIT_FEATURE_SSH = (1 << 2),
106+
GIT_FEATURE_NSEC = (1 << 3),
106107
} git_feature_t;
107108

108109
/**

src/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
# include <ws2tcpip.h>
4242
# include "win32/msvc-compat.h"
4343
# include "win32/mingw-compat.h"
44+
# include "win32/win32-compat.h"
4445
# include "win32/error.h"
4546
# include "win32/version.h"
4647
# ifdef GIT_THREADS

src/diff.c

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ static bool diff_pathspec_match(
7979
git_diff *diff,
8080
const git_index_entry *entry)
8181
{
82-
bool disable_pathspec_match =
82+
bool disable_pathspec_match =
8383
DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH);
8484

8585
/* If we're disabling fnmatch, then the iterator has already applied
@@ -131,7 +131,7 @@ static int diff_delta__from_one(
131131
if (status == GIT_DELTA_UNTRACKED &&
132132
DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNTRACKED))
133133
return 0;
134-
134+
135135
if (status == GIT_DELTA_UNREADABLE &&
136136
DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNREADABLE))
137137
return 0;
@@ -706,6 +706,31 @@ static bool diff_time_eq(
706706
(!use_nanos || a->nanoseconds == b->nanoseconds);
707707
}
708708

709+
/*
710+
* Test if the given index time is newer than the given existing index entry.
711+
* If the timestamps are exactly equivalent, then the given index time is
712+
* considered "racily newer" than the existing index entry.
713+
*/
714+
static bool diff_newer_than_index(
715+
const git_index_time *a, const git_index *b, bool use_nanos)
716+
{
717+
bool is_newer = false;
718+
719+
if(!b)
720+
return false;
721+
722+
is_newer = is_newer || (a->seconds > (int32_t) b->stamp.mtime.tv_sec);
723+
is_newer = is_newer || (!use_nanos &&
724+
(a->seconds == (int32_t) b->stamp.mtime.tv_sec));
725+
if(use_nanos)
726+
{
727+
is_newer = is_newer || ((a->seconds == (int32_t) b->stamp.mtime.tv_sec) &&
728+
(a->nanoseconds >= (uint32_t) b->stamp.mtime.tv_nsec));
729+
}
730+
731+
return is_newer;
732+
}
733+
709734
typedef struct {
710735
git_repository *repo;
711736
git_iterator *old_iter;
@@ -838,7 +863,11 @@ static int maybe_modified(
838863
*/
839864
} else if (git_oid_iszero(&nitem->id) && new_is_workdir) {
840865
bool use_ctime = ((diff->diffcaps & GIT_DIFFCAPS_TRUST_CTIME) != 0);
866+
#ifdef GIT_USE_NSEC
841867
bool use_nanos = ((diff->diffcaps & GIT_DIFFCAPS_TRUST_NANOSECS) != 0);
868+
#else
869+
bool use_nanos = false;
870+
#endif
842871
git_index *index;
843872
git_iterator_index(&index, info->new_iter);
844873

@@ -863,7 +892,7 @@ static int maybe_modified(
863892
oitem->ino != nitem->ino ||
864893
oitem->uid != nitem->uid ||
865894
oitem->gid != nitem->gid ||
866-
(index && nitem->mtime.seconds >= index->stamp.mtime))
895+
diff_newer_than_index(&nitem->mtime, index, use_nanos))
867896
{
868897
status = GIT_DELTA_MODIFIED;
869898
modified_uncertain = true;

src/fileops.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ GIT_INLINE(int) mkdir_validate_mode(
366366

367367
return 0;
368368
}
369-
369+
370370
GIT_INLINE(int) mkdir_canonicalize(
371371
git_buf *path,
372372
uint32_t flags)
@@ -1034,6 +1034,11 @@ int git_futils_filestamp_check(
10341034
git_futils_filestamp *stamp, const char *path)
10351035
{
10361036
struct stat st;
1037+
#if defined(__APPLE__)
1038+
const struct timespec *statmtime = &st.st_mtimespec;
1039+
#else
1040+
const struct timespec *statmtime = &st.st_mtim;
1041+
#endif
10371042

10381043
/* if the stamp is NULL, then always reload */
10391044
if (stamp == NULL)
@@ -1042,12 +1047,18 @@ int git_futils_filestamp_check(
10421047
if (p_stat(path, &st) < 0)
10431048
return GIT_ENOTFOUND;
10441049

1045-
if (stamp->mtime == (git_time_t)st.st_mtime &&
1050+
if (stamp->mtime.tv_sec == statmtime->tv_sec &&
1051+
#if defined(GIT_USE_NSEC)
1052+
stamp->mtime.tv_nsec == statmtime->tv_nsec &&
1053+
#endif
10461054
stamp->size == (git_off_t)st.st_size &&
10471055
stamp->ino == (unsigned int)st.st_ino)
10481056
return 0;
10491057

1050-
stamp->mtime = (git_time_t)st.st_mtime;
1058+
stamp->mtime.tv_sec = statmtime->tv_sec;
1059+
#if defined(GIT_USE_NSEC)
1060+
stamp->mtime.tv_nsec = statmtime->tv_nsec;
1061+
#endif
10511062
stamp->size = (git_off_t)st.st_size;
10521063
stamp->ino = (unsigned int)st.st_ino;
10531064

@@ -1069,8 +1080,17 @@ void git_futils_filestamp_set(
10691080
void git_futils_filestamp_set_from_stat(
10701081
git_futils_filestamp *stamp, struct stat *st)
10711082
{
1083+
#if defined(__APPLE__)
1084+
const struct timespec *statmtime = &st->st_mtimespec;
1085+
#else
1086+
const struct timespec *statmtime = &st->st_mtim;
1087+
#endif
1088+
10721089
if (st) {
1073-
stamp->mtime = (git_time_t)st->st_mtime;
1090+
stamp->mtime = *statmtime;
1091+
#if !defined(GIT_USE_NSEC)
1092+
stamp->mtime.tv_nsec = 0;
1093+
#endif
10741094
stamp->size = (git_off_t)st->st_size;
10751095
stamp->ino = (unsigned int)st->st_ino;
10761096
} else {

src/fileops.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ extern int git_futils_fake_symlink(const char *new, const char *old);
310310
* versions could be implemented in the future.
311311
*/
312312
typedef struct {
313-
git_time_t mtime;
313+
struct timespec mtime;
314314
git_off_t size;
315315
unsigned int ino;
316316
} git_futils_filestamp;

src/index.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -719,18 +719,27 @@ int git_index__changed_relative_to(
719719
return !!git_oid_cmp(&index->checksum, checksum);
720720
}
721721

722-
static bool is_racy_timestamp(git_time_t stamp, git_index_entry *entry)
722+
static bool is_racy_timestamp(const struct timespec *stamp, git_index_entry *entry)
723723
{
724724
/* Git special-cases submodules in the check */
725725
if (S_ISGITLINK(entry->mode))
726726
return false;
727727

728728
/* If we never read the index, we can't have this race either */
729-
if (stamp == 0)
729+
if(stamp->tv_sec == 0)
730730
return false;
731731

732732
/* If the timestamp is the same or newer than the index, it's racy */
733-
return ((int32_t) stamp) <= entry->mtime.seconds;
733+
#if defined(GIT_USE_NSEC)
734+
if((int32_t) stamp->tv_sec < entry->mtime.seconds)
735+
return true;
736+
else if((int32_t) stamp->tv_sec > entry->mtime.seconds)
737+
return false;
738+
else
739+
return (uint32_t) stamp->tv_nsec <= entry->mtime.nanoseconds;
740+
#else
741+
return ((int32_t) stamp->tv_sec) <= entry->mtime.seconds;
742+
#endif
734743
}
735744

736745
/*
@@ -742,7 +751,6 @@ static int truncate_racily_clean(git_index *index)
742751
size_t i;
743752
int error;
744753
git_index_entry *entry;
745-
git_time_t ts = index->stamp.mtime;
746754
git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
747755
git_diff *diff;
748756

@@ -756,7 +764,7 @@ static int truncate_racily_clean(git_index *index)
756764

757765
diff_opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_DISABLE_PATHSPEC_MATCH;
758766
git_vector_foreach(&index->entries, i, entry) {
759-
if (!is_racy_timestamp(ts, entry))
767+
if (!is_racy_timestamp(&index->stamp.mtime, entry))
760768
continue;
761769

762770
/* TODO: use the (non-fnmatching) filelist iterator */
@@ -858,8 +866,10 @@ void git_index_entry__init_from_stat(
858866
{
859867
entry->ctime.seconds = (git_time_t)st->st_ctime;
860868
entry->mtime.seconds = (git_time_t)st->st_mtime;
861-
/* entry->mtime.nanoseconds = st->st_mtimensec; */
862-
/* entry->ctime.nanoseconds = st->st_ctimensec; */
869+
#if defined(GIT_USE_NSEC)
870+
entry->mtime.nanoseconds = st->st_mtim.tv_nsec;
871+
entry->ctime.nanoseconds = st->st_ctim.tv_nsec;
872+
#endif
863873
entry->dev = st->st_rdev;
864874
entry->ino = st->st_ino;
865875
entry->mode = (!trust_mode && S_ISREG(st->st_mode)) ?
@@ -2924,9 +2934,9 @@ int git_index_read_index(
29242934
(error = git_iterator_for_index(&new_iterator, (git_index *)new_index, &opts)) < 0)
29252935
goto done;
29262936

2927-
if (((error = git_iterator_current(&old_entry, index_iterator)) < 0 &&
2937+
if (((error = git_iterator_current(&old_entry, index_iterator)) < 0 &&
29282938
error != GIT_ITEROVER) ||
2929-
((error = git_iterator_current(&new_entry, new_iterator)) < 0 &&
2939+
((error = git_iterator_current(&new_entry, new_iterator)) < 0 &&
29302940
error != GIT_ITEROVER))
29312941
goto done;
29322942

src/settings.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ int git_libgit2_features()
3333
#endif
3434
#if defined(GIT_SSH)
3535
| GIT_FEATURE_SSH
36+
#endif
37+
#if defined(GIT_USE_NSEC)
38+
| GIT_FEATURE_NSEC
3639
#endif
3740
;
3841
}

src/win32/mingw-compat.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@
1111

1212
#undef stat
1313

14-
#if _WIN32_WINNT >= 0x0601
15-
#define stat __stat64
16-
#else
17-
#define stat _stati64
18-
#endif
19-
2014
#if _WIN32_WINNT < 0x0600 && !defined(__MINGW64_VERSION_MAJOR)
2115
#undef MemoryBarrier
2216
void __mingworg_MemoryBarrier(void);

src/win32/msvc-compat.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99

1010
#if defined(_MSC_VER)
1111

12-
/* 64-bit stat information, regardless of USE_32BIT_TIME_T define */
13-
#define stat __stat64
14-
1512
typedef unsigned short mode_t;
1613
typedef SSIZE_T ssize_t;
1714

src/win32/w32_util.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,23 @@ size_t git_win32__path_trim_end(wchar_t *str, size_t len);
7676
size_t git_win32__canonicalize_path(wchar_t *str, size_t len);
7777

7878
/**
79-
* Converts a FILETIME structure to a time_t.
79+
* Converts a FILETIME structure to a struct timespec.
8080
*
8181
* @param FILETIME A pointer to a FILETIME
82-
* @return A time_t containing the same time
82+
* @param ts A pointer to the timespec structure to fill in
8383
*/
84-
GIT_INLINE(time_t) git_win32__filetime_to_time_t(const FILETIME *ft)
84+
GIT_INLINE(void) git_win32__filetime_to_timespec(
85+
const FILETIME *ft,
86+
struct timespec *ts)
8587
{
8688
long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
8789
winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
88-
winTime /= 10000000; /* Nano to seconds resolution */
89-
return (time_t)winTime;
90+
ts->tv_sec = (time_t)(winTime / 10000000);
91+
#ifdef GIT_USE_NSEC
92+
ts->tv_nsec = (winTime % 10000000) * 100;
93+
#else
94+
ts->tv_nsec = 0;
95+
#endif
9096
}
9197

9298
GIT_INLINE(void) git_win32__timeval_to_filetime(
@@ -122,9 +128,9 @@ GIT_INLINE(int) git_win32__file_attribute_to_stat(
122128
st->st_size = ((git_off_t)attrdata->nFileSizeHigh << 32) + attrdata->nFileSizeLow;
123129
st->st_dev = _getdrive() - 1;
124130
st->st_rdev = st->st_dev;
125-
st->st_atime = git_win32__filetime_to_time_t(&(attrdata->ftLastAccessTime));
126-
st->st_mtime = git_win32__filetime_to_time_t(&(attrdata->ftLastWriteTime));
127-
st->st_ctime = git_win32__filetime_to_time_t(&(attrdata->ftCreationTime));
131+
git_win32__filetime_to_timespec(&(attrdata->ftLastAccessTime), &(st->st_atim));
132+
git_win32__filetime_to_timespec(&(attrdata->ftLastWriteTime), &(st->st_mtim));
133+
git_win32__filetime_to_timespec(&(attrdata->ftCreationTime), &(st->st_ctim));
128134

129135
if (attrdata->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && path) {
130136
git_win32_path target;

src/win32/win32-compat.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
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.
6+
*/
7+
#ifndef INCLUDE_win32_compat__
8+
#define INCLUDE_win32_compat__
9+
10+
#include <stdint.h>
11+
#include <time.h>
12+
#include <wchar.h>
13+
#include <sys/stat.h>
14+
#include <sys/types.h>
15+
16+
struct p_timespec {
17+
time_t tv_sec;
18+
long tv_nsec;
19+
};
20+
21+
#define timespec p_timespec
22+
23+
struct p_stat {
24+
_dev_t st_dev;
25+
_ino_t st_ino;
26+
mode_t st_mode;
27+
short st_nlink;
28+
short st_uid;
29+
short st_gid;
30+
_dev_t st_rdev;
31+
uint64_t st_size;
32+
struct timespec st_atim;
33+
struct timespec st_mtim;
34+
struct timespec st_ctim;
35+
#define st_atime st_atim.tv_sec
36+
#define st_mtime st_mtim.tv_sec
37+
#define st_ctime st_ctim.tv_sec
38+
};
39+
40+
#define stat p_stat
41+
42+
#endif /* INCLUDE_win32_compat__ */

0 commit comments

Comments
 (0)