]> code.delx.au - gnu-emacs/blobdiff - lib/timespec-add.c
Fix an error in Tramp for rsync
[gnu-emacs] / lib / timespec-add.c
index 4e5c641ac12aee8d187a4ea657e6ecbea0f22294..b09394677c5189c8a8b33f05c0f6bba33d356aa4 100644 (file)
@@ -1,6 +1,6 @@
 /* Add two struct timespec values.
 
-   Copyright (C) 2011-2012 Free Software Foundation, Inc.
+   Copyright (C) 2011-2016 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
 /* Written by Paul Eggert.  */
 
 /* Return the sum of two timespec values A and B.  On overflow, return
-   an extremal value.  This assumes 0 <= tv_nsec <= 999999999.  */
+   an extremal value.  This assumes 0 <= tv_nsec < TIMESPEC_RESOLUTION.  */
 
 #include <config.h>
 #include "timespec.h"
 struct timespec
 timespec_add (struct timespec a, struct timespec b)
 {
-  struct timespec r;
   time_t rs = a.tv_sec;
   time_t bs = b.tv_sec;
   int ns = a.tv_nsec + b.tv_nsec;
-  int nsd = ns - 1000000000;
+  int nsd = ns - TIMESPEC_RESOLUTION;
   int rns = ns;
+  time_t tmin = TYPE_MINIMUM (time_t);
+  time_t tmax = TYPE_MAXIMUM (time_t);
 
   if (0 <= nsd)
     {
       rns = nsd;
-      if (rs == TYPE_MAXIMUM (time_t))
-        {
-          if (0 <= bs)
-            goto high_overflow;
-          bs++;
-        }
-      else
+      if (bs < tmax)
+        bs++;
+      else if (rs < 0)
         rs++;
+      else
+        goto high_overflow;
     }
 
-  if (INT_ADD_OVERFLOW (rs, bs))
+  /* INT_ADD_WRAPV is not appropriate since time_t might be unsigned.
+     In theory time_t might be narrower than int, so plain
+     INT_ADD_OVERFLOW does not suffice.  */
+  if (! INT_ADD_OVERFLOW (rs, bs) && tmin <= rs + bs && rs + bs <= tmax)
+    rs += bs;
+  else
     {
       if (rs < 0)
         {
-          rs = TYPE_MINIMUM (time_t);
+          rs = tmin;
           rns = 0;
         }
       else
         {
         high_overflow:
-          rs = TYPE_MAXIMUM (time_t);
-          rns = 999999999;
+          rs = tmax;
+          rns = TIMESPEC_RESOLUTION - 1;
         }
     }
-  else
-    rs += bs;
 
-  r.tv_sec = rs;
-  r.tv_nsec = rns;
-  return r;
+  return make_timespec (rs, rns);
 }