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]

Reply via email to