Package: fakeroot
Version: 1.2.2
Severity: wishlist
Here is a patch to do something possibly useful with settimeofday()
and related functions. Why? For testing schedule-oriented systems,
Y2038 testing, and other relativistic excursions.
Please tell me whether this feature is appropriate for Fakeroot.
Otherwise, I must assume that it won't be accepted, and I will cease
work on things that I don't personally need, such as save-file
support, backwards compatibility, etc.
Best regards,
-John
orig = fakeroot--main--0.0--patch-48
--- orig/communicate.c
+++ mod/communicate.c
@@ -86,6 +86,12 @@
f->st.gid =st->st_gid ;
f->st.dev =st->st_dev ;
f->st.rdev =st->st_rdev;
+ f->st.atim.sec =st->st_atime;
+ f->st.mtim.sec =st->st_mtime;
+ f->st.ctim.sec =st->st_ctime;
+ f->st.atim.nsec=STAT_ATIMENSEC(st);
+ f->st.mtim.nsec=STAT_MTIMENSEC(st);
+ f->st.ctim.nsec=STAT_CTIMENSEC(st);
/* DO copy the nlink count. Although the system knows this
one better, we need it for unlink().
@@ -106,6 +112,12 @@
st->st_gid =f->st.gid ;
st->st_dev =f->st.dev ;
st->st_rdev =f->st.rdev;
+ st->st_atime=f->st.atim.sec;
+ st->st_mtime=f->st.mtim.sec;
+ st->st_ctime=f->st.ctim.sec;
+ STAT_SET_ATIMENSEC(st, f->st.atim.nsec);
+ STAT_SET_MTIMENSEC(st, f->st.mtim.nsec);
+ STAT_SET_CTIMENSEC(st, f->st.ctim.nsec);
/* DON'T copy the nlink count! The system always knows
this one better! */
/* st->st_nlink=f->st.nlink;*/
@@ -122,6 +134,12 @@
f->st.gid =st->st_gid ;
f->st.dev =st->st_dev ;
f->st.rdev =st->st_rdev;
+ f->st.atim.sec =st->st_atime;
+ f->st.mtim.sec =st->st_mtime;
+ f->st.ctim.sec =st->st_ctime;
+ f->st.atim.nsec=STAT_ATIMENSEC(st);
+ f->st.mtim.nsec=STAT_MTIMENSEC(st);
+ f->st.ctim.nsec=STAT_CTIMENSEC(st);
/* DO copy the nlink count. Although the system knows this
one better, we need it for unlink().
@@ -141,6 +159,12 @@
st->st_gid =f->st.gid ;
st->st_dev =f->st.dev ;
st->st_rdev =f->st.rdev;
+ st->st_atime=f->st.atim.sec;
+ st->st_mtime=f->st.mtim.sec;
+ st->st_ctime=f->st.ctim.sec;
+ STAT_SET_ATIMENSEC(st, f->st.atim.nsec);
+ STAT_SET_MTIMENSEC(st, f->st.mtim.nsec);
+ STAT_SET_CTIMENSEC(st, f->st.ctim.nsec);
/* DON'T copy the nlink count! The system always knows
this one better! */
/* st->st_nlink=f->st.nlink;*/
@@ -156,6 +180,9 @@
dest->gid =source->gid ;
dest->dev =source->dev ;
dest->rdev =source->rdev;
+ dest->atim =source->atim;
+ dest->mtim =source->mtim;
+ dest->ctim =source->ctim;
/* DON'T copy the nlink count! The system always knows
this one better! */
/* dest->nlink=source->nlink;*/
@@ -181,6 +208,9 @@
s64->st_atime = s32->st_atime;
s64->st_mtime = s32->st_mtime;
s64->st_ctime = s32->st_ctime;
+ STAT_SET_ATIMENSEC(s64, STAT_ATIMENSEC(s32));
+ STAT_SET_MTIMENSEC(s64, STAT_MTIMENSEC(s32));
+ STAT_SET_CTIMENSEC(s64, STAT_CTIMENSEC(s32));
}
/* This assumes that the 64 bit structure is actually filled in and does not
@@ -200,6 +230,9 @@
s32->st_atime = s64->st_atime;
s32->st_mtime = s64->st_mtime;
s32->st_ctime = s64->st_ctime;
+ STAT_SET_ATIMENSEC(s32, STAT_ATIMENSEC(s64));
+ STAT_SET_MTIMENSEC(s32, STAT_MTIMENSEC(s64));
+ STAT_SET_CTIMENSEC(s32, STAT_CTIMENSEC(s64));
}
#endif
@@ -444,6 +477,12 @@
fm.st.rdev = htonll(buf->st.rdev);
fm.st.mode = htonl(buf->st.mode);
fm.st.nlink = htonl(buf->st.nlink);
+ fm.st.atim.sec = htonll(buf->st.atim.sec);
+ fm.st.mtim.sec = htonll(buf->st.mtim.sec);
+ fm.st.ctim.sec = htonll(buf->st.ctim.sec);
+ fm.st.atim.nsec = htonl(buf->st.atim.nsec);
+ fm.st.mtim.nsec = htonl(buf->st.mtim.nsec);
+ fm.st.ctim.nsec = htonl(buf->st.ctim.nsec);
fm.remote = htonl(0);
while (1) {
@@ -500,6 +539,12 @@
buf->st.rdev = ntohll(buf->st.rdev);
buf->st.mode = ntohl(buf->st.mode);
buf->st.nlink = ntohl(buf->st.nlink);
+ buf->st.atim.sec = ntohll(buf->st.atim.sec);
+ buf->st.mtim.sec = ntohll(buf->st.mtim.sec);
+ buf->st.ctim.sec = ntohll(buf->st.ctim.sec);
+ buf->st.atim.nsec = ntohl(buf->st.atim.nsec);
+ buf->st.mtim.nsec = ntohl(buf->st.mtim.nsec);
+ buf->st.ctim.nsec = ntohl(buf->st.ctim.nsec);
buf->remote = ntohl(buf->remote);
}
--- orig/faked.c
+++ mod/faked.c
@@ -44,6 +44,9 @@
mkdir(),
lstat(), fstat(), stat() (actually, __xlstat, ...)
unlink(), remove(), rmdir(), rename()
+ stime(), settimeofday(), clock_settime(),
+ time(), gettimeofday(), clock_gettime()
+ utime(), utimes(), futimes(), lutimes()
comments:
I need to wrap unlink because of the following:
@@ -131,6 +134,9 @@
void process_mknod(struct fake_msg *buf);
void process_stat(struct fake_msg *buf);
void process_unlink(struct fake_msg *buf);
+void process_settime(struct fake_msg *buf);
+void process_gettime(struct fake_msg *buf);
+void process_utimes(struct fake_msg *buf);
#ifdef FAKEROOT_FAKENET
static int get_fakem(struct fake_msg *buf);
@@ -143,9 +149,12 @@
process_mknod,
process_stat,
process_unlink,
+ process_settime,
+ process_gettime,
+ process_utimes,
};
-unsigned int highest_funcid = sizeof(func_arr)/sizeof(func_arr[0]);
+int highest_funcid = sizeof(func_arr)/sizeof(func_arr[0]) - 1;
#ifndef FAKEROOT_FAKENET
key_t msg_key=0;
@@ -206,8 +215,8 @@
return n;
}
-static void data_insert(const struct fakestat *buf,
- const uint32_t remote)
+static data_node_t* data_insert(const struct fakestat *buf,
+ const uint32_t remote)
{
data_node_t *n, *last = NULL;
@@ -226,6 +235,7 @@
memcpy(&n->buf, buf, sizeof (struct fakestat));
n->remote = (uint32_t) remote;
+ return n;
}
static data_node_t *data_erase(data_node_t *pos)
@@ -285,6 +295,104 @@
#define data_end() (NULL)
+/* Time map. */
+/* What is "remote" for? Do I have to use "remote"? */
+
+typedef struct time_shift_s {
+ struct fake_timespec real;
+ struct fake_timespec fake;
+} time_shift_t;
+
+static time_shift_t *time_map;
+static size_t time_map_alloc;
+static size_t time_map_fill;
+
+static int timespec_compare(const struct fake_timespec *left,
+ const struct fake_timespec *right)
+{
+ if (left->sec < right->sec) return -1;
+ if (left->sec > right->sec) return 1;
+ if (left->nsec < right->nsec) return -1;
+ if (left->nsec > right->nsec) return 1;
+ return 0;
+}
+
+static time_shift_t *time_shift_find(const struct fake_timespec *real)
+{
+ time_shift_t *lo, *hi;
+
+ if (time_map == NULL)
+ return NULL;
+ lo = time_map;
+ hi = time_map + time_map_fill - 1;
+ if (timespec_compare(real, &lo->real) < 0)
+ return NULL;
+ if (timespec_compare(real, &hi->real) >= 0)
+ return hi;
+ while (1) {
+ time_shift_t *mid = lo + (hi - lo) / 2;
+
+ if (mid == lo)
+ return lo;
+ int cmp = timespec_compare(real, &mid->real);
+ if (cmp == 0)
+ return mid;
+ if (cmp < 0)
+ hi = mid;
+ else
+ lo = mid;
+ }
+}
+
+static void time_shift_insert(const struct fake_timespec *real,
+ const struct fake_timespec *fake)
+{
+ time_shift_t *entry;
+
+ if (time_map == NULL) {
+ time_map_alloc = 4;
+ time_map = (time_shift_t*)malloc(time_map_alloc * sizeof time_map[0]);
+ time_map_fill = 1;
+ entry = time_map;
+ }
+ else {
+ entry = time_shift_find(real);
+ if (entry == NULL)
+ entry = time_map;
+ else if (!timespec_compare(real, &entry->real))
+ entry++;
+ time_map_fill = (entry - time_map) + 1;
+ if (time_map_fill > time_map_alloc) {
+ time_map_alloc *= 2;
+ time_map = (time_shift_t*)realloc(time_map, time_map_alloc
+ * sizeof time_map[0]);
+ }
+ }
+ entry->real = *real;
+ entry->fake = *fake;
+}
+
+static void time_shift(struct fake_timespec *ts){
+ time_shift_t *shift;
+
+ shift = time_shift_find(ts);
+ if (shift != NULL) {
+ fake_time_t sec = ts->sec + shift->fake.sec - shift->real.sec;
+ int32_t nsec = ts->nsec + shift->fake.nsec - shift->real.nsec;
+ if (nsec < 0) {
+ nsec += 1000000000;
+ sec -= 1;
+ }
+ else if (nsec > 999999999) {
+ nsec -= 1000000000;
+ sec += 1;
+ }
+ ts->sec = sec;
+ ts->nsec = nsec;
+ }
+}
+
+
#ifdef FAKEROOT_FAKENET
static struct {
unsigned int capacity;
@@ -337,6 +445,12 @@
fm.st.dev = htonll(buf->st.dev);
fm.st.rdev = htonll(buf->st.rdev);
fm.st.mode = htonl(buf->st.mode);
+ fm.st.atim.sec = htonll(buf->st.atim.sec);
+ fm.st.mtim.sec = htonll(buf->st.mtim.sec);
+ fm.st.ctim.sec = htonll(buf->st.ctim.sec);
+ fm.st.atim.nsec = htonl(buf->st.atim.nsec);
+ fm.st.mtim.nsec = htonl(buf->st.mtim.nsec);
+ fm.st.ctim.nsec = htonl(buf->st.ctim.nsec);
fm.st.nlink = htonl(buf->st.nlink);
fm.remote = htonl(buf->remote);
@@ -482,6 +596,8 @@
#endif
}
+ /* XXX times */
+
return fclose(f);
}
@@ -531,6 +647,9 @@
st.rdev = strdev;
data_insert(&st, remote);
}
+
+ /* XXX times */
+
if(!r||r==EOF)
return 1;
else
@@ -553,20 +672,25 @@
st->rdev);
}
-void insert_or_overwrite(struct fakestat *st,
- const uint32_t remote){
+static struct fakestat *find_stat(struct fake_msg *buf){
data_node_t *i;
-
- i = data_find(st, remote);
- if (i == data_end()) {
- if(debug){
- fprintf(stderr,"FAKEROOT: insert_or_overwrite unknown stat:\n");
- debug_stat(st);
- }
- data_insert(st, remote);
+
+ i = data_find(&buf->st, buf->remote);
+ if (i != data_end())
+ return data_node_get(i);
+
+ if (debug)
+ fprintf(stderr,"FAKEROOT: (previously unknown)\n");
+
+ if (!unknown_is_real) {
+ buf->st.uid=0;
+ buf->st.gid=0;
+ time_shift(&buf->st.atim);
+ time_shift(&buf->st.mtim);
+ time_shift(&buf->st.ctim);
}
- else
- memcpy(data_node_get(i), st, sizeof (struct fakestat));
+ i = data_insert(&buf->st, buf->remote);
+ return data_node_get(i);
}
/*******************************************/
@@ -577,115 +701,72 @@
void process_chown(struct fake_msg *buf){
- struct fakestat *stptr;
- struct fakestat st;
- data_node_t *i;
+ struct fakestat *st;
if(debug){
fprintf(stderr,"FAKEROOT: chown ");
debug_stat(&buf->st);
}
- i = data_find(&buf->st, buf->remote);
- if (i != data_end()) {
- stptr = data_node_get(i);
- /* From chown(2): If the owner or group is specified as -1,
- then that ID is not changed.
- Cannot put that test in libtricks, as at that point it isn't
- known what the fake user/group is (so cannot specify `unchanged')
-
- I typecast to (uint32_t), as st.uid may be bigger than uid_t.
- In that case, the msb in st.uid should be discarded.
- I don't typecaset to (uid_t), as the size of uid_t may vary
- depending on what libc (headers) were used to compile. So,
- different clients might actually use different uid_t's
- concurrently. Yes, this does seem farfeched, but was
- actually the case with the libc5/6 transition.
- */
- if ((uint32_t)buf->st.uid != (uint32_t)-1)
- stptr->uid=buf->st.uid;
- if ((uint32_t)buf->st.gid != (uint32_t)-1)
- stptr->gid=buf->st.gid;
- }
- else{
- st=buf->st;
- /* See comment above. We pretend that unknown files are owned
- by root.root, so we have to maintain that pretense when the
- caller asks to leave an id unchanged. */
- if ((uint32_t)st.uid == (uint32_t)-1)
- st.uid = 0;
- if ((uint32_t)st.gid == (uint32_t)-1)
- st.gid = 0;
- insert_or_overwrite(&st, buf->remote);
- }
+ st = find_stat(buf);
+
+ /* From chown(2): If the owner or group is specified as -1,
+ then that ID is not changed.
+ Cannot put that test in libtricks, as at that point it isn't
+ known what the fake user/group is (so cannot specify `unchanged')
+
+ I typecast to (uint32_t), as st.uid may be bigger than uid_t.
+ In that case, the msb in st.uid should be discarded.
+ I don't typecaset to (uid_t), as the size of uid_t may vary
+ depending on what libc (headers) were used to compile. So,
+ different clients might actually use different uid_t's
+ concurrently. Yes, this does seem farfeched, but was
+ actually the case with the libc5/6 transition.
+ */
+ if ((uint32_t)buf->st.uid != (uint32_t)-1)
+ st->uid=buf->st.uid;
+ if ((uint32_t)buf->st.gid != (uint32_t)-1)
+ st->gid=buf->st.gid;
+
+ /* See comment above. We pretend that unknown files are owned
+ by root.root, so we have to maintain that pretense when the
+ caller asks to leave an id unchanged. */
+ if ((uint32_t)st->uid == (uint32_t)-1)
+ st->uid = 0;
+ if ((uint32_t)st->gid == (uint32_t)-1)
+ st->gid = 0;
}
void process_chmod(struct fake_msg *buf){
struct fakestat *st;
- data_node_t *i;
-
+
if(debug)
fprintf(stderr,"FAKEROOT: chmod, mode=%lo\n",
buf->st.mode);
-
- i = data_find(&buf->st, buf->remote);
- if (i != data_end()) {
- st = data_node_get(i);
- st->mode = (buf->st.mode&~S_IFMT) | (st->mode&S_IFMT);
- }
- else{
- st=&buf->st;
- st->uid=0;
- st->gid=0;
- }
- insert_or_overwrite(st, buf->remote);
+
+ st = find_stat(buf);
+ st->mode = (buf->st.mode&~S_IFMT) | (st->mode&S_IFMT);
}
void process_mknod(struct fake_msg *buf){
struct fakestat *st;
- data_node_t *i;
if(debug)
- fprintf(stderr,"FAKEROOT: chmod, mode=%lo\n",
- buf->st.mode);
+ fprintf(stderr,"FAKEROOT: mknod\n");
- i = data_find(&buf->st, buf->remote);
- if (i != data_end()) {
- st = data_node_get(i);
- st->mode = buf->st.mode;
- st->rdev = buf->st.rdev;
- }
- else{
- st=&buf->st;
- st->uid=0;
- st->gid=0;
- }
- insert_or_overwrite(st, buf->remote);
+ st = find_stat(buf);
+ st->mode = buf->st.mode;
+ st->rdev = buf->st.rdev;
}
void process_stat(struct fake_msg *buf){
- data_node_t *i;
+ struct fakestat *st;
- i = data_find(&buf->st, buf->remote);
+ st = find_stat(buf);
if(debug){
fprintf(stderr,"FAKEROOT: process stat oldstate=");
- debug_stat(&buf->st);
- }
- if (i == data_end()) {
- if (debug)
- fprintf(stderr,"FAKEROOT: (previously unknown)\n");
- if (!unknown_is_real) {
- buf->st.uid=0;
- buf->st.gid=0;
- }
- }
- else{
- cpyfakefake(&buf->st, data_node_get(i));
- if(debug){
- fprintf(stderr,"FAKEROOT: (previously known): fake=");
- debug_stat(&buf->st);
- }
-
+ debug_stat(st);
}
+ cpyfakefake(&buf->st, st);
faked_send_fakem(buf);
}
//void process_fstat(struct fake_msg *buf){
@@ -711,6 +792,36 @@
}
}
+static void debug_time_shift(const time_shift_t* shift){
+ if (shift == NULL)
+ fprintf(stderr, "FAKEROOT: shift NULL\n");
+ else
+ fprintf(stderr, "FAKEROOT: shift %ld.%09ld -> %ld.%09ld\n",
(long)shift->real.sec,
+ (long)shift->real.nsec, (long)shift->fake.sec,
(long)shift->fake.nsec);
+}
+
+void process_settime(struct fake_msg *buf){
+ /* I use atim for real and mtim for fake. */
+ time_shift_insert(&buf->st.atim, &buf->st.mtim);
+}
+
+void process_gettime(struct fake_msg *buf){
+ /* I use atim for the current time. */
+ time_shift(&buf->st.atim);
+ faked_send_fakem(buf);
+}
+
+void process_utimes(struct fake_msg *buf){
+ struct fakestat *st;
+
+ if(debug)
+ fprintf(stderr,"FAKEROOT: utimes\n");
+
+ st = find_stat(buf);
+ st->atim = buf->st.atim;
+ st->mtim = buf->st.mtim;
+}
+
void debugdata(int dummy UNUSED){
int stored_errno = errno;
data_node_t *i;
@@ -927,6 +1038,12 @@
buf->st.dev = ntohll(buf->st.dev);
buf->st.rdev = ntohll(buf->st.rdev);
buf->st.mode = ntohl(buf->st.mode);
+ buf->st.atim.sec = ntohll(buf->st.atim.sec);
+ buf->st.mtim.sec = ntohll(buf->st.mtim.sec);
+ buf->st.ctim.sec = ntohll(buf->st.ctim.sec);
+ buf->st.atim.nsec = ntohl(buf->st.atim.nsec);
+ buf->st.mtim.nsec = ntohl(buf->st.mtim.nsec);
+ buf->st.ctim.nsec = ntohl(buf->st.ctim.nsec);
buf->st.nlink = ntohl(buf->st.nlink);
buf->remote = ntohl(buf->remote);
--- orig/libfakeroot.c
+++ mod/libfakeroot.c
@@ -730,8 +730,10 @@
umask(old_mask);
/*Don't bother to mknod the file, that probably doesn't work.
- just create it as normal file, and leave the premissions
+ just create it as normal file, and leave the permissions
to the fakemode.*/
+
+ /* XXX should be O_EXCL since mknod can fail with EEXIST */
fd=open(pathname, O_WRONLY|O_CREAT|O_TRUNC, 00644);
@@ -892,6 +894,210 @@
return 0;
}
+static void set_time(fake_time_t real_sec, int32_t real_nsec,
+ fake_time_t fake_sec, int32_t fake_nsec){
+ struct fake_msg buf;
+ memset(&buf, 0, sizeof buf);
+ buf.st.atim.sec = real_sec;
+ buf.st.atim.nsec = real_nsec;
+ buf.st.mtim.sec = fake_sec;
+ buf.st.mtim.nsec = fake_nsec;
+ buf.id = settime_func;
+ send_fakem(&buf);
+}
+
+static void get_time(fake_time_t real_sec, int32_t real_nsec,
+ fake_time_t *fake_sec, int32_t *fake_nsec){
+ struct fake_msg buf;
+ memset(&buf, 0, sizeof buf);
+ buf.st.atim.sec = real_sec;
+ buf.st.atim.nsec = real_nsec;
+ buf.id = gettime_func;
+ send_get_fakem(&buf);
+ *fake_sec = buf.st.atim.sec;
+ *fake_nsec = buf.st.atim.nsec;
+}
+
+int stime(const time_t *newtime){
+ /* Is the ability to call the real version useful? */
+ if (fakeroot_disabled)
+ return next_stime(newtime);
+
+ set_time(next_time(NULL), 0, *newtime, 0);
+ return 0;
+}
+
+int settimeofday(const struct timeval *tp, const struct timezone *tzp){
+ struct timeval tmp;
+ /* Is the ability to call the real version useful? */
+ if (fakeroot_disabled)
+ return next_settimeofday(tp, tzp);
+
+ if (!tp)
+ return 0; /* ignore the timezone thing */
+ if (next_gettimeofday(&tmp, NULL))
+ return -1;
+ set_time(tmp.tv_sec, tmp.tv_usec * 1000, tp->tv_sec, tp->tv_usec * 1000);
+ return 0;
+}
+
+#ifdef HAVE_CLOCK_SETTIME
+int clock_settime(clockid_t clk_id, const struct timespec *tp){
+ struct timespec tmp;
+ /* Is the ability to call the real version useful? */
+ if (fakeroot_disabled)
+ return next_clock_settime(clk_id, tp);
+ if (clk_id != CLOCK_REALTIME)
+ return next_clock_settime(clk_id, tp);
+ if (next_clock_gettime(clk_id, &tmp))
+ return -1;
+ set_time(tmp.tv_sec, tmp.tv_nsec, tp->tv_sec, tp->tv_nsec);
+ return 0;
+}
+#endif /* HAVE_CLOCK_SETTIME */
+
+time_t time(time_t *result){
+ time_t tmp;
+ fake_time_t sec;
+ int32_t nsec;
+ tmp = next_time(NULL);
+ if (tmp == (time_t)-1)
+ return tmp;
+ get_time(tmp, 0, &sec, &nsec);
+ if (result)
+ *result = (time_t)sec;
+ return (time_t)sec;
+}
+
+int gettimeofday(struct timeval *tp, struct timezone *tzp){
+ struct timeval tmp;
+ fake_time_t sec;
+ int32_t nsec;
+ if (!tp)
+ return next_gettimeofday(tp, tzp);
+ if (next_gettimeofday(&tmp, tzp))
+ return -1;
+ get_time(tmp.tv_sec, tmp.tv_usec * 1000, &sec, &nsec);
+ tp->tv_sec = sec;
+ tp->tv_usec = nsec / 1000;
+ return 0;
+}
+
+#ifdef HAVE_CLOCK_GETTIME
+int clock_gettime(clockid_t clk_id, struct timespec *tp){
+ struct timespec tmp;
+ fake_time_t sec;
+ int32_t nsec;
+ if (clk_id != CLOCK_REALTIME)
+ return next_clock_gettime(clk_id, tp);
+ if (next_clock_gettime(clk_id, &tmp))
+ return -1;
+ get_time(tmp.tv_sec, tmp.tv_nsec, &sec, &nsec);
+ tp->tv_sec = sec;
+ tp->tv_nsec = nsec;
+ return 0;
+}
+#endif /* HAVE_CLOCK_GETTIME */
+
+static void utime_current(struct stat *st){
+ struct timeval tv;
+#if HAVE_CLOCK_GETTIME
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
+ st->st_atime = ts.tv_sec; STAT_SET_ATIMENSEC(st, ts.tv_nsec);
+ st->st_mtime = ts.tv_sec; STAT_SET_MTIMENSEC(st, ts.tv_nsec);
+ return;
+ }
+#endif
+ if (gettimeofday(&tv, NULL) == 0) {
+ st->st_atime = tv.tv_sec; STAT_SET_ATIMENSEC(st, tv.tv_usec * 1000);
+ st->st_mtime = tv.tv_sec; STAT_SET_MTIMENSEC(st, tv.tv_usec * 1000);
+ return;
+ }
+ st->st_atime = next_time(NULL); STAT_SET_ATIMENSEC(st, 0);
+ st->st_mtime = st->st_atime; STAT_SET_MTIMENSEC(st, 0);
+}
+
+int utime(const char *filename, const struct utimbuf *times){
+ struct stat st;
+ int r;
+
+ r=next_utime(filename, times);
+ if(r&&(errno!=EPERM))
+ return r;
+ r=NEXT_STAT(_STAT_VER, filename, &st);
+ if(r)
+ return r;
+
+ if (times) {
+ st.st_atime = times->actime; STAT_SET_ATIMENSEC(&st, 0);
+ st.st_mtime = times->modtime; STAT_SET_MTIMENSEC(&st, 0);
+ }
+ else
+ utime_current(&st);
+
+ send_stat(&st,utimes_func);
+ return 0;
+}
+
+static void copy_utimes(struct stat *st, const struct timeval tvp[2]){
+ if (tvp) {
+ st->st_atime=tvp[0].tv_sec; STAT_SET_ATIMENSEC(st,tvp[0].tv_usec*1000);
+ st->st_mtime=tvp[1].tv_sec; STAT_SET_MTIMENSEC(st,tvp[1].tv_usec*1000);
+ }
+ else
+ utime_current(st);
+}
+
+int utimes(const char *filename, const struct timeval tvp[2]){
+ struct stat st;
+ int r;
+
+ r = next_utimes(filename, tvp);
+ if(r&&(errno!=EPERM))
+ return r;
+ r=NEXT_STAT(_STAT_VER, filename, &st);
+ if(r)
+ return r;
+
+ copy_utimes(&st, tvp);
+ send_stat(&st,utimes_func);
+ return 0;
+}
+
+int lutimes(const char *filename, const struct timeval tvp[2]){
+ struct stat st;
+ int r;
+
+ r = next_lutimes(filename, tvp);
+ if(r&&(errno!=EPERM))
+ return r;
+ r=NEXT_LSTAT(_STAT_VER, filename, &st);
+ if(r)
+ return r;
+
+ copy_utimes(&st, tvp);
+ send_stat(&st,utimes_func);
+ return 0;
+}
+
+int futimes(int fd, const struct timeval tvp[2]){
+ struct stat st;
+ int r;
+
+ r = next_futimes(fd, tvp);
+ if(r&&(errno!=EPERM))
+ return r;
+ r=NEXT_FSTAT(_STAT_VER, fd, &st);
+ if(r)
+ return r;
+
+ copy_utimes(&st, tvp);
+ send_stat(&st,utimes_func);
+ return 0;
+}
+
#ifdef FAKEROOT_FAKENET
pid_t fork(void)
{
--- orig/message.h
+++ mod/message.h
@@ -29,6 +29,12 @@
typedef uint32_t fake_gid_t;
typedef uint32_t fake_mode_t;
typedef uint32_t fake_nlink_t;
+typedef int64_t fake_time_t;
+
+struct fake_timespec {
+ fake_time_t sec;
+ int32_t nsec;
+} FAKEROOT_ATTR(packed);
struct fakestat {
fake_uid_t uid;
@@ -38,6 +44,9 @@
fake_dev_t rdev;
fake_mode_t mode;
fake_nlink_t nlink;
+ struct fake_timespec atim;
+ struct fake_timespec mtim;
+ struct fake_timespec ctim;
} FAKEROOT_ATTR(packed);
struct fake_msg {
--- orig/communicate.h
+++ mod/communicate.h
@@ -57,6 +57,19 @@
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+#ifdef HAVE_UTIME_H
+# include <utime.h>
+#endif
#ifndef FAKEROOT_FAKENET
# define FAKEROOTKEY_ENV "FAKEROOTKEY"
@@ -95,6 +108,25 @@
# define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)/* 07777 */
#endif
+#define CAT2(x, y) CAT2x(x, y)
+#define CAT2x(x, y) x ## y
+
+#ifdef STAT_NSEC_END
+# define STAT_ATIMENSEC(st) ((st)->CAT2(st_a, STAT_NSEC_END))
+# define STAT_MTIMENSEC(st) ((st)->CAT2(st_m, STAT_NSEC_END))
+# define STAT_CTIMENSEC(st) ((st)->CAT2(st_c, STAT_NSEC_END))
+# define STAT_SET_ATIMENSEC(st, ns) (STAT_ATIMENSEC(st) = (ns))
+# define STAT_SET_MTIMENSEC(st, ns) (STAT_MTIMENSEC(st) = (ns))
+# define STAT_SET_CTIMENSEC(st, ns) (STAT_CTIMENSEC(st) = (ns))
+#else
+# define STAT_ATIMENSEC(st) (0)
+# define STAT_MTIMENSEC(st) (0)
+# define STAT_CTIMENSEC(st) (0)
+# define STAT_SET_ATIMENSEC(st, ns)
+# define STAT_SET_MTIMENSEC(st, ns)
+# define STAT_SET_CTIMENSEC(st, ns)
+#endif
+
/* Define big enough _constant size_ types for the various types of the
stat struct. I cannot (or rather, shouldn't) use struct stat itself
in the communication between the fake-daemon and the client (libfake),
@@ -111,6 +143,9 @@
/*3*/ mknod_func,
stat_func,
/*5*/ unlink_func,
+ settime_func,
+ gettime_func,
+ utimes_func,
debugdata_func,
reqoptions_func,
last_func};
@@ -121,6 +156,7 @@
extern void send_stat(const struct stat *st, func_id_t f);
extern void send_fakem(const struct fake_msg *buf);
extern void send_get_stat(struct stat *buf);
+extern void send_get_fakem(struct fake_msg *buf);
extern void cpyfakefake (struct fakestat *b1, const struct fakestat *b2);
extern void cpystatfakem(struct stat *st, const struct fake_msg *buf);
--- orig/wrapfunc.inp
+++ mod/wrapfunc.inp
@@ -87,3 +87,18 @@
#endif /* HAVE_SETFSGID */
initgroups;int;(const char *user, INITGROUPS_SECOND_ARG group);(user, group)
setgroups;int;(SETGROUPS_SIZE_TYPE size, const gid_t *list);(size, list)
+
+stime;int;(const time_t *newtime);(newtime)
+settimeofday;int;(const struct timeval *tp, const struct timezone *tzp);(tp,
tzp)
+#ifdef HAVE_CLOCK_SETTIME
+clock_settime;int;(clockid_t clk_id, const struct timespec *tp);(clk_id, tp)
+#endif /* HAVE_CLOCK_SETTIME */
+time;time_t;(time_t *result);(result)
+gettimeofday;int;(struct timeval *tp, struct timezone *tzp);(tp, tzp)
+#ifdef HAVE_CLOCK_GETTIME
+clock_gettime;int;(clockid_t clk_id, struct timespec *tp);(clk_id, tp)
+#endif /* HAVE_CLOCK_GETTIME */
+utime;int;(const char *filename, const struct utimbuf *times);(filename, times)
+utimes;int;(const char *filename, const struct timeval tvp[2]);(filename, tvp)
+lutimes;int;(const char *filename, const struct timeval tvp[2]);(filename, tvp)
+futimes;int;(int fd, const struct timeval tvp[2]);(fd, tvp)
--- orig/configure.ac
+++ mod/configure.ac
@@ -4,7 +4,7 @@
AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE
AM_MAINTAINER_MODE
-AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_HEADERS(config.h)
AC_PROG_MAKE_SET
AM_PROG_LIBTOOL
AC_PROG_CC
@@ -39,6 +39,7 @@
dnl Checks for libraries.
dnl Replace `main' with a function in -ldl:
AC_CHECK_LIB(dl, dlopen)
+AC_CHECK_LIB(rt, clock_gettime)
AH_TEMPLATE([FAKEROOT_FAKENET], [use TCP instead of SysV IPC])
if test $ac_cv_use_ipc = "tcp"; then
AC_DEFINE_UNQUOTED(FAKEROOT_FAKENET, [TCP])
@@ -49,7 +50,8 @@
dnl Checks for header files.
AC_HEADER_DIRENT
AC_HEADER_STDC
-AC_CHECK_HEADERS(fcntl.h unistd.h features.h sys/feature_tests.h pthread.h
stdint.h inttypes.h grp.h endian.h sys/sysmacros.h sys/socket.h)
+AC_HEADER_TIME
+AC_CHECK_HEADERS(fcntl.h unistd.h features.h sys/feature_tests.h pthread.h
stdint.h inttypes.h grp.h endian.h sys/sysmacros.h sys/socket.h utime.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
@@ -287,6 +289,14 @@
done
done
+NSEC_END=
+AC_CHECK_MEMBER(struct stat.st_atim.tv_nsec, NSEC_END=tim.tv_nsec,
+ AC_CHECK_MEMBER(struct stat.st_atimensec, NSEC_END=timensec,
+ AC_CHECK_MEMBER(struct stat.st_atimespec.tv_nsec,
NSEC_END=timespec.tv_nsec)))
+if test -n "$NSEC_END"; then
+ AC_DEFINE_UNQUOTED(STAT_NSEC_END, $NSEC_END, [Last part of nanoseconds stat
member])
+fi
+
if test -r fakerootconfig.h
then
if test "`diff fakerootconfig.h fakerootconfig.h.tmp`" = ""
@@ -344,6 +354,7 @@
dnl Checks for library functions.
AC_CHECK_FUNCS(strdup strstr getresuid setresuid getresgid setresgid setfsuid
setfsgid)
+AC_CHECK_FUNCS(clock_gettime clock_settime)
dnl kludge
AH_VERBATIM([WRAP_STAT],
End of patch.
--
John Tobey <[EMAIL PROTECTED]>
\____^-^
/\ /\
--
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]