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]