Coverage Report

Created: 2026-01-09 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/statinfo.c
Line
Count
Source
1
#define USE_THE_REPOSITORY_VARIABLE
2
3
#include "git-compat-util.h"
4
#include "environment.h"
5
#include "statinfo.h"
6
7
/*
8
 * Munge st_size into an unsigned int.
9
 */
10
0
static unsigned int munge_st_size(off_t st_size) {
11
0
  unsigned int sd_size = st_size;
12
13
  /*
14
   * If the file is an exact multiple of 4 GiB, modify the value so it
15
   * doesn't get marked as racily clean (zero).
16
   */
17
0
  if (!sd_size && st_size)
18
0
    return 0x80000000;
19
0
  else
20
0
    return sd_size;
21
0
}
22
23
void fill_stat_data(struct stat_data *sd, struct stat *st)
24
0
{
25
0
  sd->sd_ctime.sec = (unsigned int)st->st_ctime;
26
0
  sd->sd_mtime.sec = (unsigned int)st->st_mtime;
27
0
  sd->sd_ctime.nsec = ST_CTIME_NSEC(*st);
28
0
  sd->sd_mtime.nsec = ST_MTIME_NSEC(*st);
29
0
  sd->sd_dev = st->st_dev;
30
0
  sd->sd_ino = st->st_ino;
31
0
  sd->sd_uid = st->st_uid;
32
0
  sd->sd_gid = st->st_gid;
33
0
  sd->sd_size = munge_st_size(st->st_size);
34
0
}
35
36
static void set_times(struct stat *st, const struct stat_data *sd)
37
0
{
38
0
  st->st_ctime = sd->sd_ctime.sec;
39
0
  st->st_mtime = sd->sd_mtime.sec;
40
#ifdef NO_NSEC
41
  ; /* nothing */
42
#else
43
#ifdef USE_ST_TIMESPEC
44
  st->st_ctimespec.tv_nsec = sd->sd_ctime.nsec;
45
  st->st_mtimespec.tv_nsec = sd->sd_mtime.nsec;
46
#else
47
0
  st->st_ctim.tv_nsec = sd->sd_ctime.nsec;
48
0
  st->st_mtim.tv_nsec = sd->sd_mtime.nsec;
49
0
#endif
50
0
#endif
51
0
}
52
53
void fake_lstat_data(const struct stat_data *sd, struct stat *st)
54
0
{
55
0
  set_times(st, sd);
56
0
  st->st_dev = sd->sd_dev;
57
0
  st->st_ino = sd->sd_ino;
58
0
  st->st_uid = sd->sd_uid;
59
0
  st->st_gid = sd->sd_gid;
60
0
  st->st_size = sd->sd_size;
61
0
}
62
63
int match_stat_data(const struct stat_data *sd, struct stat *st)
64
0
{
65
0
  int changed = 0;
66
67
0
  if (sd->sd_mtime.sec != (unsigned int)st->st_mtime)
68
0
    changed |= MTIME_CHANGED;
69
0
  if (trust_ctime && check_stat &&
70
0
      sd->sd_ctime.sec != (unsigned int)st->st_ctime)
71
0
    changed |= CTIME_CHANGED;
72
73
#ifdef USE_NSEC
74
  if (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
75
    changed |= MTIME_CHANGED;
76
  if (trust_ctime && check_stat &&
77
      sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
78
    changed |= CTIME_CHANGED;
79
#endif
80
81
0
  if (check_stat) {
82
0
    if (sd->sd_uid != (unsigned int) st->st_uid ||
83
0
      sd->sd_gid != (unsigned int) st->st_gid)
84
0
      changed |= OWNER_CHANGED;
85
0
    if (sd->sd_ino != (unsigned int) st->st_ino)
86
0
      changed |= INODE_CHANGED;
87
0
  }
88
89
#ifdef USE_STDEV
90
  /*
91
   * st_dev breaks on network filesystems where different
92
   * clients will have different views of what "device"
93
   * the filesystem is on
94
   */
95
  if (check_stat && sd->sd_dev != (unsigned int) st->st_dev)
96
      changed |= INODE_CHANGED;
97
#endif
98
99
0
  if (sd->sd_size != munge_st_size(st->st_size))
100
0
    changed |= DATA_CHANGED;
101
102
0
  return changed;
103
0
}
104
105
void stat_validity_clear(struct stat_validity *sv)
106
0
{
107
0
  FREE_AND_NULL(sv->sd);
108
0
}
109
110
int stat_validity_check(struct stat_validity *sv, const char *path)
111
0
{
112
0
  struct stat st;
113
114
0
  if (stat(path, &st) < 0)
115
0
    return sv->sd == NULL;
116
0
  if (!sv->sd)
117
0
    return 0;
118
0
  return S_ISREG(st.st_mode) && !match_stat_data(sv->sd, &st);
119
0
}
120
121
void stat_validity_update(struct stat_validity *sv, int fd)
122
0
{
123
0
  struct stat st;
124
125
0
  if (fstat(fd, &st) < 0 || !S_ISREG(st.st_mode))
126
0
    stat_validity_clear(sv);
127
0
  else {
128
0
    if (!sv->sd)
129
0
      CALLOC_ARRAY(sv->sd, 1);
130
0
    fill_stat_data(sv->sd, &st);
131
0
  }
132
0
}