Git fork
at reftables-rust 132 lines 3.1 kB view raw
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 */ 10static unsigned int munge_st_size(off_t st_size) { 11 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 if (!sd_size && st_size) 18 return 0x80000000; 19 else 20 return sd_size; 21} 22 23void fill_stat_data(struct stat_data *sd, struct stat *st) 24{ 25 sd->sd_ctime.sec = (unsigned int)st->st_ctime; 26 sd->sd_mtime.sec = (unsigned int)st->st_mtime; 27 sd->sd_ctime.nsec = ST_CTIME_NSEC(*st); 28 sd->sd_mtime.nsec = ST_MTIME_NSEC(*st); 29 sd->sd_dev = st->st_dev; 30 sd->sd_ino = st->st_ino; 31 sd->sd_uid = st->st_uid; 32 sd->sd_gid = st->st_gid; 33 sd->sd_size = munge_st_size(st->st_size); 34} 35 36static void set_times(struct stat *st, const struct stat_data *sd) 37{ 38 st->st_ctime = sd->sd_ctime.sec; 39 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 st->st_ctim.tv_nsec = sd->sd_ctime.nsec; 48 st->st_mtim.tv_nsec = sd->sd_mtime.nsec; 49#endif 50#endif 51} 52 53void fake_lstat_data(const struct stat_data *sd, struct stat *st) 54{ 55 set_times(st, sd); 56 st->st_dev = sd->sd_dev; 57 st->st_ino = sd->sd_ino; 58 st->st_uid = sd->sd_uid; 59 st->st_gid = sd->sd_gid; 60 st->st_size = sd->sd_size; 61} 62 63int match_stat_data(const struct stat_data *sd, struct stat *st) 64{ 65 int changed = 0; 66 67 if (sd->sd_mtime.sec != (unsigned int)st->st_mtime) 68 changed |= MTIME_CHANGED; 69 if (trust_ctime && check_stat && 70 sd->sd_ctime.sec != (unsigned int)st->st_ctime) 71 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 if (check_stat) { 82 if (sd->sd_uid != (unsigned int) st->st_uid || 83 sd->sd_gid != (unsigned int) st->st_gid) 84 changed |= OWNER_CHANGED; 85 if (sd->sd_ino != (unsigned int) st->st_ino) 86 changed |= INODE_CHANGED; 87 } 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 if (sd->sd_size != munge_st_size(st->st_size)) 100 changed |= DATA_CHANGED; 101 102 return changed; 103} 104 105void stat_validity_clear(struct stat_validity *sv) 106{ 107 FREE_AND_NULL(sv->sd); 108} 109 110int stat_validity_check(struct stat_validity *sv, const char *path) 111{ 112 struct stat st; 113 114 if (stat(path, &st) < 0) 115 return sv->sd == NULL; 116 if (!sv->sd) 117 return 0; 118 return S_ISREG(st.st_mode) && !match_stat_data(sv->sd, &st); 119} 120 121void stat_validity_update(struct stat_validity *sv, int fd) 122{ 123 struct stat st; 124 125 if (fstat(fd, &st) < 0 || !S_ISREG(st.st_mode)) 126 stat_validity_clear(sv); 127 else { 128 if (!sv->sd) 129 CALLOC_ARRAY(sv->sd, 1); 130 fill_stat_data(sv->sd, &st); 131 } 132}