release-avoid-negative-time-20060124
[openafs.git] / src / volser / vsprocs.c
index c1d0cca..331c90b 100644 (file)
@@ -56,6 +56,7 @@ RCSID
 #include <errno.h>
 #define ERRCODE_RANGE 8                /* from error_table.h */
 #define        CLOCKSKEW   2           /* not really skew, but resolution */
+#define CLOCKADJ(x) (((x) < CLOCKSKEW) ? 0 : (x) - CLOCKSKEW)
 
 /* for UV_MoveVolume() recovery */
 
@@ -68,7 +69,8 @@ struct ubik_client *cstruct;
 int verbose = 0;
 
 struct release {
-    afs_int32 time;
+    afs_int32 crtime;
+    afs_int32 uptime;
     afs_int32 vldbEntryIndex;
 };
 
@@ -162,12 +164,11 @@ static int DelVol(struct rx_connection *conn, afs_int32 vid, afs_int32 part,
                  afs_int32 flags);
 static int GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
                    struct rx_connection **connPtr, afs_int32 * transPtr,
-                   afs_int32 * timePtr);
+                   afs_int32 * crtimePtr, afs_int32 * uptimePtr);
 static int SimulateForwardMultiple(struct rx_connection *fromconn,
                                   afs_int32 fromtid, afs_int32 fromdate,
                                   manyDests * tr, afs_int32 flags,
                                   void *cookie, manyResults * results);
-static int rel_compar(struct release *r1, struct release *r2);
 static afs_int32 CheckVolume(volintInfo * volumeinfo, afs_int32 aserver,
                             afs_int32 apart, afs_int32 * modentry,
                             afs_uint32 * maxvolid);
@@ -406,6 +407,19 @@ PrintError(char *msg, afs_int32 errcode)
     return 0;
 }
 
+void init_volintInfo(struct volintInfo *vinfo) {
+    memset(vinfo, 0, sizeof(struct volintInfo));
+
+    vinfo->maxquota = -1;
+    vinfo->dayUse = -1;
+    vinfo->creationDate = -1;
+    vinfo->updateDate = -1;
+    vinfo->flags = -1;
+    vinfo->spare0 = -1;
+    vinfo->spare1 = -1;
+    vinfo->spare2 = -1;
+    vinfo->spare3 = -1;
+}
 
 static struct rx_securityClass *uvclass = 0;
 static int uvindex = -1;
@@ -624,8 +638,8 @@ UV_CreateVolume2(afs_int32 aserver, afs_int32 apart, char *aname,
     tid = 0;
     aconn = (struct rx_connection *)0;
     error = 0;
-    memset(&tstatus, 0, sizeof(struct volintInfo));
-    tstatus.dayUse = -1;
+
+    init_volintInfo(&tstatus);
     tstatus.maxquota = aquota;
 
     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
@@ -1316,7 +1330,7 @@ UV_MoveVolume2(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
               newVol);
        VDONE;
 
-       fromDate = tstatus.creationDate - CLOCKSKEW;
+       fromDate = CLOCKADJ(tstatus.creationDate);
     } else {
        /* With RV_NOCLONE, just do a full copy from the source */
        fromDate = 0;
@@ -1338,6 +1352,8 @@ UV_MoveVolume2(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
 
     infop = (volintInfo *) volumeInfo.volEntries_val;
     infop->maxquota = -1;      /* Else it will replace the default quota */
+    infop->creationDate = -1;  /* Else it will use the source creation date */
+    infop->updateDate = -1;    /* Else it will use the source update date */
 #endif
 
     /* create a volume on the target machine */
@@ -2147,7 +2163,7 @@ UV_CopyVolume2(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
               cloneVol);
        VDONE;
 
-       fromDate = tstatus.creationDate - CLOCKSKEW;
+       fromDate = CLOCKADJ(tstatus.creationDate);
     } else {
        fromDate = 0;
     }
@@ -2165,7 +2181,7 @@ UV_CopyVolume2(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart,
            VDONE;
 
            /* Using the update date should be OK here, but add some fudge */
-           cloneFromDate = tstatus.updateDate - CLOCKSKEW;
+           cloneFromDate = CLOCKADJ(tstatus.updateDate);
            if ((flags & RV_NOCLONE))
                fromDate = cloneFromDate;
 
@@ -2991,15 +3007,16 @@ DelVol(struct rx_connection *conn, afs_int32 vid, afs_int32 part,
 static int
 GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
         struct rx_connection **connPtr, afs_int32 * transPtr,
-        afs_int32 * timePtr)
+        afs_int32 * crtimePtr, afs_int32 * uptimePtr)
 {
     afs_int32 volid;
     struct volser_status tstatus;
     int code, rcode, tcode;
 
     *connPtr = (struct rx_connection *)0;
-    *timePtr = 0;
     *transPtr = 0;
+    *crtimePtr = 0;
+    *uptimePtr = 0;
 
     /* get connection to the replication site */
     *connPtr = UV_Bind(vldbEntryPtr->serverNumber[index], AFSCONF_VOLUMEPORT);
@@ -3071,7 +3088,8 @@ GetTrans(struct nvldbentry *vldbEntryPtr, afs_int32 index,
                       code);
            goto fail;
        }
-       *timePtr = tstatus.creationDate - CLOCKSKEW;
+       *crtimePtr = CLOCKADJ(tstatus.creationDate);
+       *uptimePtr = CLOCKADJ(tstatus.updateDate);
     }
 
     return 0;
@@ -3106,12 +3124,6 @@ SimulateForwardMultiple(struct rx_connection *fromconn, afs_int32 fromtid,
 }
 
 
-static int
-rel_compar(struct release *r1, struct release *r2)
-{
-    return (r1->time - r2->time);
-}
-
 /* UV_ReleaseVolume()
  *    Release volume <afromvol> on <afromserver> <afrompart> to all
  *    its RO sites (full release). Unless the previous release was
@@ -3151,10 +3163,10 @@ UV_ReleaseVolume(afs_int32 afromvol, afs_int32 afromserver,
     manyDests tr;
     manyResults results;
     int rwindex, roindex, roclone, roexists;
-    afs_int32 rwcrdate, clcrdate;
+    afs_int32 rwcrdate, rwupdate, clcrdate;
     struct rtime {
        int validtime;
-       afs_uint32 time;
+       afs_uint32 uptime;
     } remembertime[NMAXNSERVERS];
     int releasecount = 0;
     struct volser_status volstatus;
@@ -3251,6 +3263,7 @@ UV_ReleaseVolume(afs_int32 afromvol, afs_int32 afromserver,
            ONERROR(code, afromvol,
                    "Failed to get the status of RW volume %u\n");
            rwcrdate = volstatus.creationDate;
+           rwupdate = volstatus.updateDate;
 
            /* End transaction on RW */
            code = AFSVolEndTrans(fromconn, fromtid, &rcode);
@@ -3271,11 +3284,11 @@ UV_ReleaseVolume(afs_int32 afromvol, afs_int32 afromserver,
                    "Failed to get the status of RW clone %u\n");
            clcrdate = volstatus.creationDate;
 
-           /* End transaction on RW */
+           /* End transaction on clone */
            code = AFSVolEndTrans(fromconn, clonetid, &rcode);
            clonetid = 0;
            ONERROR((code ? code : rcode), cloneVolId,
-                   "Failed to end transaction on RW volume %u\n");
+                   "Failed to end transaction on RW clone %u\n");
 
            if (rwcrdate > clcrdate)
                fullrelease = 2;/* Do a full release if RO clone older than RW */
@@ -3339,10 +3352,10 @@ UV_ReleaseVolume(afs_int32 afromvol, afs_int32 afromserver,
            if (roclone) {
                strcpy(vname, entry.name);
                strcat(vname, ".readonly");
-               VPRINT("Cloning RW volume %u to permanent RO...");
+               VPRINT1("Cloning RW volume %u to permanent RO...", afromvol);
            } else {
                strcpy(vname, "readonly-clone-temp");
-               VPRINT("Cloning RW volume %u to temporary RO...");
+               VPRINT1("Cloning RW volume %u to temporary RO...", afromvol);
            }
            code =
                AFSVolClone(fromconn, clonetid, 0, readonlyVolume, vname,
@@ -3352,18 +3365,19 @@ UV_ReleaseVolume(afs_int32 afromvol, afs_int32 afromserver,
        }
 
        /* Get the time the RW was created for future information */
-       VPRINT1("Getting status of RW volume %u...", cloneVolId);
+       VPRINT1("Getting status of RW volume %u...", afromvol);
        code = AFSVolGetStatus(fromconn, clonetid, &volstatus);
-       ONERROR(code, cloneVolId,
+       ONERROR(code, afromvol,
                "Failed to get the status of the RW volume %u\n");
        VDONE;
        rwcrdate = volstatus.creationDate;
+       rwupdate = volstatus.updateDate;
 
        /* End the transaction on the RW volume */
-       VPRINT1("Ending cloning transaction on RW volume %u...", cloneVolId);
+       VPRINT1("Ending cloning transaction on RW volume %u...", afromvol);
        code = AFSVolEndTrans(fromconn, clonetid, &rcode);
        clonetid = 0;
-       ONERROR((code ? code : rcode), cloneVolId,
+       ONERROR((code ? code : rcode), afromvol,
                "Failed to end cloning transaction on RW %u\n");
        VDONE;
 
@@ -3505,13 +3519,14 @@ UV_ReleaseVolume(afs_int32 afromvol, afs_int32 afromserver,
            code =
                GetTrans(&entry, vldbindex, &(toconns[volcount]),
                         &(replicas[volcount].trans),
-                        &(times[volcount].time));
+                        &(times[volcount].crtime),
+                        &(times[volcount].uptime));
            if (code)
                continue;
 
            /* Thisdate is the date from which we want to pick up all changes */
            if (forceflag || !fullrelease
-               || (rwcrdate > times[volcount].time)) {
+               || (rwcrdate > times[volcount].crtime)) {
                /* If the forceflag is set, then we want to do a full dump.
                 * If it's not a full release, we can't be sure that the creation
                 *  date is good (so we also do a full dump).
@@ -3526,14 +3541,14 @@ UV_ReleaseVolume(afs_int32 afromvol, afs_int32 afromserver,
                 * case time[volcount].time would be now instead of 0.
                 */
                thisdate =
-                   (remembertime[vldbindex].time <
-                    times[volcount].time) ? remembertime[vldbindex].
-                   time : times[volcount].time;
+                   (remembertime[vldbindex].uptime < times[volcount].uptime)
+                       ? remembertime[vldbindex].uptime
+                       : times[volcount].uptime;
            } else {
-               thisdate = times[volcount].time;
+               thisdate = times[volcount].uptime;
            }
            remembertime[vldbindex].validtime = 1;
-           remembertime[vldbindex].time = thisdate;
+           remembertime[vldbindex].uptime = thisdate;
 
            if (volcount == 0) {
                fromdate = thisdate;
@@ -3571,6 +3586,8 @@ UV_ReleaseVolume(afs_int32 afromvol, afs_int32 afromserver,
 
            if (fromdate == 0)
                fprintf(STDOUT, " (full release)");
+           else
+               fprintf(STDOUT, " (as of %.24s)", ctime((time_t *)&fromdate));
            fprintf(STDOUT, ".\n");
            fflush(STDOUT);
        }
@@ -4031,17 +4048,18 @@ UV_DumpClonedVolume(afs_int32 afromvol, afs_int32 afromserver,
  * after extracting params from the rock 
  */
 int
-UV_RestoreVolume(afs_int32 toserver, afs_int32 topart, afs_int32 tovolid,
-                char tovolname[], int flags, afs_int32(*WriteData) (),
-                char *rock)
+UV_RestoreVolume2(afs_int32 toserver, afs_int32 topart, afs_int32 tovolid,
+                 afs_int32 toparentid, char tovolname[], int flags,
+                 afs_int32(*WriteData) (), char *rock)
 {
     struct rx_connection *toconn, *tempconn;
     struct rx_call *tocall;
     afs_int32 totid, code, rcode, vcode, terror = 0;
     afs_int32 rxError = 0;
     struct volser_status tstatus;
+    struct volintInfo vinfo;
     char partName[10];
-    afs_int32 pvolid;
+    afs_int32 pvolid, pparentid;
     afs_int32 temptid;
     int success;
     struct nvldbentry entry, storeEntry;
@@ -4049,7 +4067,8 @@ UV_RestoreVolume(afs_int32 toserver, afs_int32 topart, afs_int32 tovolid,
     int islocked;
     struct restoreCookie cookie;
     int reuseID;
-    afs_int32 newDate, volflag, voltype, volsertype;
+    afs_int32 volflag, voltype, volsertype;
+    afs_int32 oldCreateDate, oldUpdateDate, newCreateDate, newUpdateDate;
     int index, same, errcode;
     char apartName[10];
 
@@ -4074,6 +4093,7 @@ UV_RestoreVolume(afs_int32 toserver, afs_int32 topart, afs_int32 tovolid,
     }
 
     pvolid = tovolid;
+    pparentid = toparentid;
     toconn = UV_Bind(toserver, AFSCONF_VOLUMEPORT);
     if (pvolid == 0) {         /*alot a new id if needed */
        vcode = VLDB_GetEntryByName(tovolname, &entry);
@@ -4102,10 +4122,13 @@ UV_RestoreVolume(afs_int32 toserver, afs_int32 topart, afs_int32 tovolid,
                goto refail;
            }
            pvolid = entry.volumeId[ROVOL];
+           pparentid = entry.volumeId[RWVOL];
        } else {
            pvolid = entry.volumeId[RWVOL];
+           pparentid = entry.volumeId[RWVOL];
        }
     }
+    if (!pparentid) pparentid = pvolid;
     /* at this point we have a volume id to use/reuse for the volume to be restored */
     if (strlen(tovolname) > (VOLSER_OLDMAXVOLNAME - 1)) {
        EGOTO1(refail, VOLSERBADOP,
@@ -4118,7 +4141,7 @@ UV_RestoreVolume(afs_int32 toserver, afs_int32 topart, afs_int32 tovolid,
            hostutil_GetNameByINet(toserver), partName);
     fflush(STDOUT);
     code =
-       AFSVolCreateVolume(toconn, topart, tovolname, volsertype, 0, &pvolid,
+       AFSVolCreateVolume(toconn, topart, tovolname, volsertype, pparentid, &pvolid,
                           &totid);
     if (code) {
        if (flags & RV_FULLRST) {       /* full restore: delete then create anew */
@@ -4129,6 +4152,13 @@ UV_RestoreVolume(afs_int32 toserver, afs_int32 topart, afs_int32 tovolid,
            EGOTO1(refail, code, "Failed to start transaction on %u\n",
                   pvolid);
 
+           code = AFSVolGetStatus(toconn, totid, &tstatus);
+           EGOTO1(refail, code, "Could not get timestamp from volume %u\n",
+                  pvolid);
+
+           oldCreateDate = tstatus.creationDate;
+           oldUpdateDate = tstatus.updateDate;
+
            code =
                AFSVolSetFlags(toconn, totid,
                               VTDeleteOnSalvage | VTOutOfService);
@@ -4147,11 +4177,9 @@ UV_RestoreVolume(afs_int32 toserver, afs_int32 topart, afs_int32 tovolid,
            VDONE;
 
            code =
-               AFSVolCreateVolume(toconn, topart, tovolname, volsertype, 0,
+               AFSVolCreateVolume(toconn, topart, tovolname, volsertype, pparentid,
                                   &pvolid, &totid);
            EGOTO1(refail, code, "Could not create new volume %u\n", pvolid);
-
-           newDate = 0;
        } else {
            code =
                AFSVolTransCreate(toconn, pvolid, topart, ITOffline, &totid);
@@ -4161,10 +4189,16 @@ UV_RestoreVolume(afs_int32 toserver, afs_int32 topart, afs_int32 tovolid,
            code = AFSVolGetStatus(toconn, totid, &tstatus);
            EGOTO1(refail, code, "Could not get timestamp from volume %u\n",
                   pvolid);
-           newDate = tstatus.creationDate;
+
+           oldCreateDate = tstatus.creationDate;
+           oldUpdateDate = tstatus.updateDate;
        }
+    } else {
+       oldCreateDate = 0;
+       oldUpdateDate = 0;
     }
-    cookie.parent = pvolid;
+
+    cookie.parent = pparentid;
     cookie.type = voltype;
     cookie.clone = 0;
     strncpy(cookie.name, tovolname, VOLSER_OLDMAXVOLNAME);
@@ -4197,19 +4231,40 @@ UV_RestoreVolume(afs_int32 toserver, afs_int32 topart, afs_int32 tovolid,
        error = code;
        goto refail;
     }
-    code = AFSVolSetIdsTypes(toconn, totid, tovolname, voltype, pvolid, 0, 0);
+    code = AFSVolSetIdsTypes(toconn, totid, tovolname, voltype, pparentid, 0, 0);
     if (code) {
        fprintf(STDERR, "Could not set the right type and ID on %lu\n",
                (unsigned long)pvolid);
        error = code;
        goto refail;
     }
-    if (!newDate)
-       newDate = time(0);
-    code = AFSVolSetDate(toconn, totid, newDate);
+
+    if (flags & RV_CRDUMP)
+       newCreateDate = tstatus.creationDate;
+    else if (flags & RV_CRKEEP && oldCreateDate != 0)
+       newCreateDate = oldCreateDate;
+    else
+       newCreateDate = time(0);
+    if (flags & RV_LUDUMP)
+       newUpdateDate = tstatus.updateDate;
+    else if (flags & RV_LUKEEP)
+       newUpdateDate = oldUpdateDate;
+    else
+       newUpdateDate = time(0);
+    code = AFSVolSetDate(toconn,totid, newCreateDate);
     if (code) {
-       fprintf(STDERR, "Could not set the date on %lu\n",
-               (unsigned long)pvolid);
+       fprintf(STDERR, "Could not set the 'creation' date on %u\n", pvolid);
+       error = code;
+       goto refail;
+    }
+
+    init_volintInfo(&vinfo);
+    vinfo.creationDate = newCreateDate;
+    vinfo.updateDate = newUpdateDate;
+    code = AFSVolSetInfo(toconn, totid, &vinfo);
+    if (code) {
+       fprintf(STDERR, "Could not set the 'last updated' date on %u\n",
+               pvolid);
        error = code;
        goto refail;
     }
@@ -4266,7 +4321,7 @@ UV_RestoreVolume(afs_int32 toserver, afs_int32 topart, afs_int32 tovolid,
                entry.volumeId[ROVOL] = tstatus.cloneID;        /*this should come from status info on the volume if non zero */
            } else
                entry.volumeId[ROVOL] = INVALID_BID;
-           entry.volumeId[RWVOL] = pvolid;
+           entry.volumeId[RWVOL] = pparentid;
            entry.cloneId = 0;
            if (tstatus.backupID != 0) {
                entry.volumeId[BACKVOL] = tstatus.backupID;
@@ -4452,6 +4507,15 @@ UV_RestoreVolume(afs_int32 toserver, afs_int32 topart, afs_int32 tovolid,
     return error;
 }
 
+int
+UV_RestoreVolume(afs_int32 toserver, afs_int32 topart, afs_int32 tovolid,
+                char tovolname[], int flags, afs_int32(*WriteData) (),
+                char *rock)
+{
+    return UV_RestoreVolume2(toserver, topart, tovolid, 0, tovolname, flags,
+                            WriteData, rock);
+}
+
 
 /*unlocks the vldb entry associated with <volid> */
 int