1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright (c) 1995 Sun Microsystems, Inc. All Rights Reserved 24*7c478bd9Sstevel@tonic-gate * 25*7c478bd9Sstevel@tonic-gate * module: 26*7c478bd9Sstevel@tonic-gate * recon.c 27*7c478bd9Sstevel@tonic-gate * 28*7c478bd9Sstevel@tonic-gate * purpose: 29*7c478bd9Sstevel@tonic-gate * process the reconciliation list, figure out exactly what the 30*7c478bd9Sstevel@tonic-gate * changes were, and what we should do about them. 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * contents: 33*7c478bd9Sstevel@tonic-gate * reconcile ... (top level) process the reconciliation list 34*7c478bd9Sstevel@tonic-gate * samedata .... (static) do two files have the same contents 35*7c478bd9Sstevel@tonic-gate * samestuff ... (static) do two files have the same ownership/protection 36*7c478bd9Sstevel@tonic-gate * samecompare . (static) actually read and compare the contents 37*7c478bd9Sstevel@tonic-gate * samelink .... (static) do two symlinks have the same contents 38*7c478bd9Sstevel@tonic-gate * truncated ... (static) was one of the two copies truncted 39*7c478bd9Sstevel@tonic-gate * older ....... (static) which copy is older 40*7c478bd9Sstevel@tonic-gate * newer ....... (static) which copy is newer 41*7c478bd9Sstevel@tonic-gate * full_name ... generate a full path name for a file 42*7c478bd9Sstevel@tonic-gate * 43*7c478bd9Sstevel@tonic-gate * notes: 44*7c478bd9Sstevel@tonic-gate * If you only study one routine in this whole program, reconcile 45*7c478bd9Sstevel@tonic-gate * is that routine. Everything else is just book keeping. 46*7c478bd9Sstevel@tonic-gate * 47*7c478bd9Sstevel@tonic-gate * things were put onto the reconciliation list because analyze 48*7c478bd9Sstevel@tonic-gate * thought that they might have changed ... but up until now 49*7c478bd9Sstevel@tonic-gate * nobody has figured out what the changes really were, or even 50*7c478bd9Sstevel@tonic-gate * if there really were any changes. 51*7c478bd9Sstevel@tonic-gate * 52*7c478bd9Sstevel@tonic-gate * queue_file has ordered the reconciliation list with directory 53*7c478bd9Sstevel@tonic-gate * creations first (depth ordered) and deletions last (inversely 54*7c478bd9Sstevel@tonic-gate * depth ordered). all other changes have been ordered by mod time. 55*7c478bd9Sstevel@tonic-gate */ 56*7c478bd9Sstevel@tonic-gate #ident "%W% %E% SMI" 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate #include <stdio.h> 59*7c478bd9Sstevel@tonic-gate #include <unistd.h> 60*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 61*7c478bd9Sstevel@tonic-gate #include <string.h> 62*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate #include "filesync.h" 65*7c478bd9Sstevel@tonic-gate #include "database.h" 66*7c478bd9Sstevel@tonic-gate #include "messages.h" 67*7c478bd9Sstevel@tonic-gate #include "debug.h" 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate /* 70*7c478bd9Sstevel@tonic-gate * local routines to figure out how the files really differ 71*7c478bd9Sstevel@tonic-gate */ 72*7c478bd9Sstevel@tonic-gate static bool_t samedata(struct file *); 73*7c478bd9Sstevel@tonic-gate static bool_t samestuff(struct file *); 74*7c478bd9Sstevel@tonic-gate static bool_t samecompare(struct file *); 75*7c478bd9Sstevel@tonic-gate static bool_t truncated(struct file *); 76*7c478bd9Sstevel@tonic-gate static bool_t samelink(); 77*7c478bd9Sstevel@tonic-gate static side_t newer(struct file *); 78*7c478bd9Sstevel@tonic-gate static side_t older(struct file *); 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate /* 81*7c478bd9Sstevel@tonic-gate * globals 82*7c478bd9Sstevel@tonic-gate */ 83*7c478bd9Sstevel@tonic-gate char *srcname; /* file we are emulating */ 84*7c478bd9Sstevel@tonic-gate char *dstname; /* file we are updating */ 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate /* 87*7c478bd9Sstevel@tonic-gate * routine: 88*7c478bd9Sstevel@tonic-gate * reconcile 89*7c478bd9Sstevel@tonic-gate * 90*7c478bd9Sstevel@tonic-gate * purpose: 91*7c478bd9Sstevel@tonic-gate * to perform the reconciliation action associated with a file 92*7c478bd9Sstevel@tonic-gate * 93*7c478bd9Sstevel@tonic-gate * parameters: 94*7c478bd9Sstevel@tonic-gate * file pointer 95*7c478bd9Sstevel@tonic-gate * 96*7c478bd9Sstevel@tonic-gate * returns: 97*7c478bd9Sstevel@tonic-gate * built up error mask 98*7c478bd9Sstevel@tonic-gate * updated statistics 99*7c478bd9Sstevel@tonic-gate * 100*7c478bd9Sstevel@tonic-gate * notes: 101*7c478bd9Sstevel@tonic-gate * The switch statement handles the obvious stuff. 102*7c478bd9Sstevel@tonic-gate * The TRUE side of the samedata test handles minor differences. 103*7c478bd9Sstevel@tonic-gate * The interesting stuff is in the FALSE side of the samedata test. 104*7c478bd9Sstevel@tonic-gate * 105*7c478bd9Sstevel@tonic-gate * The desparation heuristics (in the diffmask&CONTENTS test) are 106*7c478bd9Sstevel@tonic-gate * not rigorously correct ... but they always try do the right thing 107*7c478bd9Sstevel@tonic-gate * with data, and only lose mode/ownership changes in relatively 108*7c478bd9Sstevel@tonic-gate * pathological cases. But I claim that the benefits outweigh the 109*7c478bd9Sstevel@tonic-gate * risks, and most users will be pleased with the resulting decisions. 110*7c478bd9Sstevel@tonic-gate * 111*7c478bd9Sstevel@tonic-gate * Another trick is in the deletion cases of the switch. We 112*7c478bd9Sstevel@tonic-gate * normally won't allow an unlink that conflicts with data 113*7c478bd9Sstevel@tonic-gate * changes. If there are multiple links to the file, however, 114*7c478bd9Sstevel@tonic-gate * we can make the changes and do the deletion. 115*7c478bd9Sstevel@tonic-gate * 116*7c478bd9Sstevel@tonic-gate * The action routines do_{remove,rename,like,copy} handle all 117*7c478bd9Sstevel@tonic-gate * of their own statistics and status updating. This routine 118*7c478bd9Sstevel@tonic-gate * only has to handle its own reconciliation failures (when we 119*7c478bd9Sstevel@tonic-gate * can't decide what to do). 120*7c478bd9Sstevel@tonic-gate */ 121*7c478bd9Sstevel@tonic-gate errmask_t 122*7c478bd9Sstevel@tonic-gate reconcile(struct file *fp) 123*7c478bd9Sstevel@tonic-gate { errmask_t errs = 0; 124*7c478bd9Sstevel@tonic-gate diffmask_t diffmask; 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate if (opt_debug & DBG_RECON) 127*7c478bd9Sstevel@tonic-gate fprintf(stderr, "RECO: %s flgs=%s, mtime=%08lx.%08lx\n", 128*7c478bd9Sstevel@tonic-gate fp->f_fullname, 129*7c478bd9Sstevel@tonic-gate showflags(fileflags, fp->f_flags), 130*7c478bd9Sstevel@tonic-gate fp->f_modtime, fp->f_modns); 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate /* 133*7c478bd9Sstevel@tonic-gate * form the fully qualified names for both files 134*7c478bd9Sstevel@tonic-gate */ 135*7c478bd9Sstevel@tonic-gate srcname = full_name(fp, OPT_SRC, OPT_SRC); 136*7c478bd9Sstevel@tonic-gate dstname = full_name(fp, OPT_DST, OPT_DST); 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate /* 139*7c478bd9Sstevel@tonic-gate * because they are so expensive to read and so troublesome 140*7c478bd9Sstevel@tonic-gate * to set, we try to put off reading ACLs as long as possible. 141*7c478bd9Sstevel@tonic-gate * If we haven't read them yet, we must read them now (so that 142*7c478bd9Sstevel@tonic-gate * samestuff can compare them). 143*7c478bd9Sstevel@tonic-gate */ 144*7c478bd9Sstevel@tonic-gate if (opt_acls == 0 && fp->f_info[ OPT_BASE ].f_numacls == 0) { 145*7c478bd9Sstevel@tonic-gate if (get_acls(srcname, &fp->f_info[ OPT_SRC ])) 146*7c478bd9Sstevel@tonic-gate fp->f_srcdiffs |= D_FACLS; 147*7c478bd9Sstevel@tonic-gate if (get_acls(dstname, &fp->f_info[ OPT_DST ])) 148*7c478bd9Sstevel@tonic-gate fp->f_dstdiffs |= D_FACLS; 149*7c478bd9Sstevel@tonic-gate } 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate /* 152*7c478bd9Sstevel@tonic-gate * If a rename has been detected, we don't have to figure 153*7c478bd9Sstevel@tonic-gate * it out, since both the rename-to and rename-from files 154*7c478bd9Sstevel@tonic-gate * have already been designated. When we encounter a rename-to 155*7c478bd9Sstevel@tonic-gate * we should carry it out. When we encounter a rename-from 156*7c478bd9Sstevel@tonic-gate * we can ignore it, since it should be dealt with as a side 157*7c478bd9Sstevel@tonic-gate * effect of processing the rename-to. 158*7c478bd9Sstevel@tonic-gate */ 159*7c478bd9Sstevel@tonic-gate if ((fp->f_srcdiffs|fp->f_dstdiffs) & D_RENAME_FROM) 160*7c478bd9Sstevel@tonic-gate return (0); 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate if ((fp->f_srcdiffs|fp->f_dstdiffs) & D_RENAME_TO) { 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate if (opt_verbose) 165*7c478bd9Sstevel@tonic-gate fprintf(stdout, gettext(V_renamed), 166*7c478bd9Sstevel@tonic-gate fp->f_previous->f_fullname, fp->f_name); 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate if (fp->f_srcdiffs & D_RENAME_TO) { 169*7c478bd9Sstevel@tonic-gate errs = do_rename(fp, OPT_DST); 170*7c478bd9Sstevel@tonic-gate fp->f_srcdiffs &= D_MTIME | D_SIZE; 171*7c478bd9Sstevel@tonic-gate } else if (fp->f_dstdiffs & D_RENAME_TO) { 172*7c478bd9Sstevel@tonic-gate errs = do_rename(fp, OPT_SRC); 173*7c478bd9Sstevel@tonic-gate fp->f_dstdiffs &= D_MTIME | D_SIZE; 174*7c478bd9Sstevel@tonic-gate } 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate if (errs != ERR_RESOLVABLE) 177*7c478bd9Sstevel@tonic-gate goto done; 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate /* 180*7c478bd9Sstevel@tonic-gate * if any differences remain, then we may be dealing 181*7c478bd9Sstevel@tonic-gate * with contents changes in addition to a rename 182*7c478bd9Sstevel@tonic-gate */ 183*7c478bd9Sstevel@tonic-gate if ((fp->f_srcdiffs | fp->f_dstdiffs) == 0) 184*7c478bd9Sstevel@tonic-gate goto done; 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate /* 187*7c478bd9Sstevel@tonic-gate * fall through to reconcile the data changes 188*7c478bd9Sstevel@tonic-gate */ 189*7c478bd9Sstevel@tonic-gate } 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate /* 192*7c478bd9Sstevel@tonic-gate * pull of the easy cases (non-conflict creations & deletions) 193*7c478bd9Sstevel@tonic-gate */ 194*7c478bd9Sstevel@tonic-gate switch (fp->f_flags & (F_WHEREFOUND)) { 195*7c478bd9Sstevel@tonic-gate case F_IN_BASELINE: /* only exists in baseline */ 196*7c478bd9Sstevel@tonic-gate case 0: /* only exists in rules */ 197*7c478bd9Sstevel@tonic-gate if (opt_verbose) 198*7c478bd9Sstevel@tonic-gate fprintf(stdout, gettext(V_nomore), 199*7c478bd9Sstevel@tonic-gate fp->f_fullname); 200*7c478bd9Sstevel@tonic-gate fp->f_flags |= F_REMOVE; /* fix baseline */ 201*7c478bd9Sstevel@tonic-gate return (0); 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate case F_IN_BASELINE|F_IN_SOURCE: /* deleted from dest */ 204*7c478bd9Sstevel@tonic-gate /* 205*7c478bd9Sstevel@tonic-gate * the basic principle here is that we are willing 206*7c478bd9Sstevel@tonic-gate * to do the deletion if: 207*7c478bd9Sstevel@tonic-gate * no changes were made on the other side 208*7c478bd9Sstevel@tonic-gate * OR 209*7c478bd9Sstevel@tonic-gate * we have been told to force in this direction 210*7c478bd9Sstevel@tonic-gate * 211*7c478bd9Sstevel@tonic-gate * we do, however, make an exception for files that 212*7c478bd9Sstevel@tonic-gate * will still have other links. In this case, the 213*7c478bd9Sstevel@tonic-gate * (changed) data will still be accessable through 214*7c478bd9Sstevel@tonic-gate * another link and so we are willing to do the unlink 215*7c478bd9Sstevel@tonic-gate * inspite of conflicting changes (which may well 216*7c478bd9Sstevel@tonic-gate * have been introduced through another link. 217*7c478bd9Sstevel@tonic-gate * 218*7c478bd9Sstevel@tonic-gate * The jury is still out on this one 219*7c478bd9Sstevel@tonic-gate */ 220*7c478bd9Sstevel@tonic-gate if (((fp->f_srcdiffs&D_IMPORTANT) == 0) || 221*7c478bd9Sstevel@tonic-gate (opt_force == OPT_DST) || 222*7c478bd9Sstevel@tonic-gate has_other_links(fp, OPT_SRC)) { 223*7c478bd9Sstevel@tonic-gate if (opt_verbose) 224*7c478bd9Sstevel@tonic-gate fprintf(stdout, gettext(V_deleted), 225*7c478bd9Sstevel@tonic-gate fp->f_fullname, "dst"); 226*7c478bd9Sstevel@tonic-gate errs = do_remove(fp, OPT_SRC); 227*7c478bd9Sstevel@tonic-gate goto done; 228*7c478bd9Sstevel@tonic-gate } 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate /* a deletion combined with changes */ 231*7c478bd9Sstevel@tonic-gate if (opt_verbose) 232*7c478bd9Sstevel@tonic-gate fprintf(stdout, gettext(V_delconf), 233*7c478bd9Sstevel@tonic-gate fp->f_fullname); 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate /* if we are to resolve in favor of source */ 236*7c478bd9Sstevel@tonic-gate if (opt_force == OPT_SRC) { 237*7c478bd9Sstevel@tonic-gate errs = do_copy(fp, OPT_DST); 238*7c478bd9Sstevel@tonic-gate goto done; 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate fp->f_problem = gettext(PROB_del_change); 242*7c478bd9Sstevel@tonic-gate goto cant; 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate case F_IN_BASELINE|F_IN_DEST: /* deleted from src */ 245*7c478bd9Sstevel@tonic-gate /* just like previous case, w/sides reversed */ 246*7c478bd9Sstevel@tonic-gate if (((fp->f_dstdiffs&D_IMPORTANT) == 0) || 247*7c478bd9Sstevel@tonic-gate (opt_force == OPT_SRC) || 248*7c478bd9Sstevel@tonic-gate has_other_links(fp, OPT_DST)) { 249*7c478bd9Sstevel@tonic-gate if (opt_verbose) 250*7c478bd9Sstevel@tonic-gate fprintf(stdout, gettext(V_deleted), 251*7c478bd9Sstevel@tonic-gate fp->f_fullname, "src"); 252*7c478bd9Sstevel@tonic-gate errs = do_remove(fp, OPT_DST); 253*7c478bd9Sstevel@tonic-gate goto done; 254*7c478bd9Sstevel@tonic-gate } 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate /* a deletion combined with changes */ 257*7c478bd9Sstevel@tonic-gate if (opt_verbose) 258*7c478bd9Sstevel@tonic-gate fprintf(stdout, gettext(V_delconf), 259*7c478bd9Sstevel@tonic-gate fp->f_fullname); 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate /* if we are to resolve in favor of destination */ 262*7c478bd9Sstevel@tonic-gate if (opt_force == OPT_DST) { 263*7c478bd9Sstevel@tonic-gate errs = do_copy(fp, OPT_SRC); 264*7c478bd9Sstevel@tonic-gate goto done; 265*7c478bd9Sstevel@tonic-gate } 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate fp->f_problem = gettext(PROB_del_change); 268*7c478bd9Sstevel@tonic-gate goto cant; 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate /* 271*7c478bd9Sstevel@tonic-gate * if something new shows up, and for some reason we cannot 272*7c478bd9Sstevel@tonic-gate * propagate it to the other side, we should suppress the 273*7c478bd9Sstevel@tonic-gate * file from the baseline, so it will show up as a new 274*7c478bd9Sstevel@tonic-gate * creation next time too. 275*7c478bd9Sstevel@tonic-gate */ 276*7c478bd9Sstevel@tonic-gate case F_IN_SOURCE: /* created in src */ 277*7c478bd9Sstevel@tonic-gate if (opt_verbose) 278*7c478bd9Sstevel@tonic-gate fprintf(stdout, gettext(V_created), 279*7c478bd9Sstevel@tonic-gate fp->f_fullname, "src"); 280*7c478bd9Sstevel@tonic-gate errs = do_copy(fp, OPT_DST); 281*7c478bd9Sstevel@tonic-gate goto done; 282*7c478bd9Sstevel@tonic-gate 283*7c478bd9Sstevel@tonic-gate case F_IN_DEST: /* created in dest */ 284*7c478bd9Sstevel@tonic-gate if (opt_verbose) 285*7c478bd9Sstevel@tonic-gate fprintf(stdout, gettext(V_created), 286*7c478bd9Sstevel@tonic-gate fp->f_fullname, "dst"); 287*7c478bd9Sstevel@tonic-gate errs = do_copy(fp, OPT_SRC); 288*7c478bd9Sstevel@tonic-gate goto done; 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate case F_IN_SOURCE|F_IN_DEST: /* not in baseline */ 291*7c478bd9Sstevel@tonic-gate /* 292*7c478bd9Sstevel@tonic-gate * since we don't have a baseline, we cannot 293*7c478bd9Sstevel@tonic-gate * know which of the two copies should prevail 294*7c478bd9Sstevel@tonic-gate */ 295*7c478bd9Sstevel@tonic-gate break; 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate case F_IN_BASELINE|F_IN_SOURCE|F_IN_DEST: 298*7c478bd9Sstevel@tonic-gate /* 299*7c478bd9Sstevel@tonic-gate * we have a baseline where the two copies agreed, 300*7c478bd9Sstevel@tonic-gate * so maybe we can determine that only one of the 301*7c478bd9Sstevel@tonic-gate * two copies have changed ... but before we decide 302*7c478bd9Sstevel@tonic-gate * who should be the winner we should determine 303*7c478bd9Sstevel@tonic-gate * that the two copies are actually different. 304*7c478bd9Sstevel@tonic-gate */ 305*7c478bd9Sstevel@tonic-gate break; 306*7c478bd9Sstevel@tonic-gate } 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate /* 309*7c478bd9Sstevel@tonic-gate * if we have fallen out of the case statement, it is because 310*7c478bd9Sstevel@tonic-gate * we have discovered a non-obvious situation where potentially 311*7c478bd9Sstevel@tonic-gate * changed versions of the file exist on both sides. 312*7c478bd9Sstevel@tonic-gate * 313*7c478bd9Sstevel@tonic-gate * if the two copies turn out to be identical, this is simple 314*7c478bd9Sstevel@tonic-gate */ 315*7c478bd9Sstevel@tonic-gate if (samedata(fp)) { 316*7c478bd9Sstevel@tonic-gate if (samestuff(fp)) { 317*7c478bd9Sstevel@tonic-gate /* files are identical, just update baseline */ 318*7c478bd9Sstevel@tonic-gate if (opt_verbose) 319*7c478bd9Sstevel@tonic-gate fprintf(stdout, gettext(V_unchanged), 320*7c478bd9Sstevel@tonic-gate fp->f_fullname); 321*7c478bd9Sstevel@tonic-gate update_info(fp, OPT_SRC); 322*7c478bd9Sstevel@tonic-gate goto done; 323*7c478bd9Sstevel@tonic-gate } else { 324*7c478bd9Sstevel@tonic-gate /* 325*7c478bd9Sstevel@tonic-gate * contents agree but ownership/protection does 326*7c478bd9Sstevel@tonic-gate * not agree, so we have to bring these into 327*7c478bd9Sstevel@tonic-gate * agreement. We can pick a winner if one 328*7c478bd9Sstevel@tonic-gate * side hasn't changed, or if the user has 329*7c478bd9Sstevel@tonic-gate * specified a force flag. 330*7c478bd9Sstevel@tonic-gate */ 331*7c478bd9Sstevel@tonic-gate if (opt_verbose) 332*7c478bd9Sstevel@tonic-gate fprintf(stdout, gettext(V_modes), 333*7c478bd9Sstevel@tonic-gate fp->f_fullname); 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate if (((fp->f_srcdiffs & D_ADMIN) == 0) || 336*7c478bd9Sstevel@tonic-gate (opt_force == OPT_DST)) { 337*7c478bd9Sstevel@tonic-gate errs = do_like(fp, OPT_SRC, TRUE); 338*7c478bd9Sstevel@tonic-gate goto done; 339*7c478bd9Sstevel@tonic-gate } 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate if (((fp->f_dstdiffs & D_ADMIN) == 0) || 342*7c478bd9Sstevel@tonic-gate (opt_force == OPT_SRC)) { 343*7c478bd9Sstevel@tonic-gate errs = do_like(fp, OPT_DST, TRUE); 344*7c478bd9Sstevel@tonic-gate goto done; 345*7c478bd9Sstevel@tonic-gate } 346*7c478bd9Sstevel@tonic-gate } 347*7c478bd9Sstevel@tonic-gate /* falls down to cant */ 348*7c478bd9Sstevel@tonic-gate } else { 349*7c478bd9Sstevel@tonic-gate /* 350*7c478bd9Sstevel@tonic-gate * The two files have different contents, so we have 351*7c478bd9Sstevel@tonic-gate * a potential conflict here. If we know that only one 352*7c478bd9Sstevel@tonic-gate * side has changed, we go with that side. 353*7c478bd9Sstevel@tonic-gate */ 354*7c478bd9Sstevel@tonic-gate if (fp->f_dstdiffs == 0 || fp->f_srcdiffs == 0) { 355*7c478bd9Sstevel@tonic-gate if (opt_verbose) 356*7c478bd9Sstevel@tonic-gate fprintf(stdout, gettext(V_changed), 357*7c478bd9Sstevel@tonic-gate fp->f_fullname); 358*7c478bd9Sstevel@tonic-gate errs = do_copy(fp, fp->f_srcdiffs ? OPT_DST : OPT_SRC); 359*7c478bd9Sstevel@tonic-gate goto done; 360*7c478bd9Sstevel@tonic-gate } 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate /* 363*7c478bd9Sstevel@tonic-gate * Both sides have changed, so we have a real conflict. 364*7c478bd9Sstevel@tonic-gate */ 365*7c478bd9Sstevel@tonic-gate if (opt_verbose) 366*7c478bd9Sstevel@tonic-gate fprintf(stdout, 367*7c478bd9Sstevel@tonic-gate gettext(truncated(fp) ? 368*7c478bd9Sstevel@tonic-gate V_trunconf : V_different), 369*7c478bd9Sstevel@tonic-gate fp->f_fullname); 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate /* 372*7c478bd9Sstevel@tonic-gate * See if the user has given us explicit instructions 373*7c478bd9Sstevel@tonic-gate * on how to resolve conflicts. We may have been told 374*7c478bd9Sstevel@tonic-gate * to favor the older, the newer, the source, or the 375*7c478bd9Sstevel@tonic-gate * destination ... but the default is to leave the 376*7c478bd9Sstevel@tonic-gate * conflict unresolved. 377*7c478bd9Sstevel@tonic-gate */ 378*7c478bd9Sstevel@tonic-gate if (opt_force == OPT_OLD) { 379*7c478bd9Sstevel@tonic-gate errs = do_copy(fp, newer(fp)); 380*7c478bd9Sstevel@tonic-gate goto done; 381*7c478bd9Sstevel@tonic-gate } 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate if (opt_force == OPT_NEW) { 384*7c478bd9Sstevel@tonic-gate errs = do_copy(fp, older(fp)); 385*7c478bd9Sstevel@tonic-gate goto done; 386*7c478bd9Sstevel@tonic-gate } 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate if (opt_force != 0) { 389*7c478bd9Sstevel@tonic-gate errs = do_copy(fp, (opt_force == OPT_SRC) ? 390*7c478bd9Sstevel@tonic-gate OPT_DST : OPT_SRC); 391*7c478bd9Sstevel@tonic-gate goto done; 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate /* 396*7c478bd9Sstevel@tonic-gate * This is our last chance before giving up. 397*7c478bd9Sstevel@tonic-gate * 398*7c478bd9Sstevel@tonic-gate * We know that the files have different contents and 399*7c478bd9Sstevel@tonic-gate * that there were changes on both sides. The only way 400*7c478bd9Sstevel@tonic-gate * we can safely handle this is if there were pure contents 401*7c478bd9Sstevel@tonic-gate * changes on one side and pure ownership changes on the 402*7c478bd9Sstevel@tonic-gate * other side. In this case we can propagate the ownership 403*7c478bd9Sstevel@tonic-gate * one way and the contents the other way. 404*7c478bd9Sstevel@tonic-gate * 405*7c478bd9Sstevel@tonic-gate * We decide whether or not this is possible by ANDing 406*7c478bd9Sstevel@tonic-gate * together the changes on the two sides, and seeing 407*7c478bd9Sstevel@tonic-gate * if the changes were all orthogonal (none of the same 408*7c478bd9Sstevel@tonic-gate * things changed on both sides). 409*7c478bd9Sstevel@tonic-gate */ 410*7c478bd9Sstevel@tonic-gate diffmask = fp->f_srcdiffs & fp->f_dstdiffs; 411*7c478bd9Sstevel@tonic-gate if ((diffmask & D_CONTENTS) == 0) { 412*7c478bd9Sstevel@tonic-gate /* 413*7c478bd9Sstevel@tonic-gate * if ownership changes were only made on one side 414*7c478bd9Sstevel@tonic-gate * (presumably the side that didn't have data changes) 415*7c478bd9Sstevel@tonic-gate * we can handle them separately. In this case, 416*7c478bd9Sstevel@tonic-gate * ownership changes must be fixed first, because 417*7c478bd9Sstevel@tonic-gate * the subsequent do_copy will overwrite them. 418*7c478bd9Sstevel@tonic-gate */ 419*7c478bd9Sstevel@tonic-gate if ((diffmask & D_ADMIN) == 0) 420*7c478bd9Sstevel@tonic-gate errs |= do_like(fp, (fp->f_srcdiffs&D_ADMIN) ? 421*7c478bd9Sstevel@tonic-gate OPT_DST : OPT_SRC, 422*7c478bd9Sstevel@tonic-gate TRUE); 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate /* 425*7c478bd9Sstevel@tonic-gate * Now we can deal with the propagation of the data 426*7c478bd9Sstevel@tonic-gate * changes. Note that any ownership/protection 427*7c478bd9Sstevel@tonic-gate * changes (from the other side) that have not been 428*7c478bd9Sstevel@tonic-gate * propagated yet are about to be lost. The cases 429*7c478bd9Sstevel@tonic-gate * in which this might happen are all pathological 430*7c478bd9Sstevel@tonic-gate * and the consequences of losing the protection 431*7c478bd9Sstevel@tonic-gate * changes are (IMHO) minor when compared to the 432*7c478bd9Sstevel@tonic-gate * obviously correct data propagation. 433*7c478bd9Sstevel@tonic-gate */ 434*7c478bd9Sstevel@tonic-gate errs |= do_copy(fp, (fp->f_srcdiffs&D_CONTENTS) ? 435*7c478bd9Sstevel@tonic-gate OPT_DST : OPT_SRC); 436*7c478bd9Sstevel@tonic-gate goto done; 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate /* 440*7c478bd9Sstevel@tonic-gate * there are conflicting changes, nobody has told us how to 441*7c478bd9Sstevel@tonic-gate * resolve conflicts, and we cannot figure out how to merge 442*7c478bd9Sstevel@tonic-gate * the differences. 443*7c478bd9Sstevel@tonic-gate */ 444*7c478bd9Sstevel@tonic-gate fp->f_problem = gettext(PROB_different); 445*7c478bd9Sstevel@tonic-gate } 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate cant: 448*7c478bd9Sstevel@tonic-gate /* 449*7c478bd9Sstevel@tonic-gate * I'm not smart enough to resolve this conflict automatically, 450*7c478bd9Sstevel@tonic-gate * so I have no choice but to bounce it back to the user. 451*7c478bd9Sstevel@tonic-gate */ 452*7c478bd9Sstevel@tonic-gate fp->f_flags |= F_CONFLICT; 453*7c478bd9Sstevel@tonic-gate fp->f_base->b_unresolved++; 454*7c478bd9Sstevel@tonic-gate errs |= ERR_UNRESOLVED; 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate done: 457*7c478bd9Sstevel@tonic-gate /* 458*7c478bd9Sstevel@tonic-gate * if we have a conflict and the file is not in the baseline, 459*7c478bd9Sstevel@tonic-gate * then there was never any point at which the two copies were 460*7c478bd9Sstevel@tonic-gate * in agreement, and we want to preserve the conflict for future 461*7c478bd9Sstevel@tonic-gate * resolution. 462*7c478bd9Sstevel@tonic-gate */ 463*7c478bd9Sstevel@tonic-gate if ((errs&ERR_UNRESOLVED) && (fp->f_flags & F_IN_BASELINE) == 0) 464*7c478bd9Sstevel@tonic-gate if (fp->f_files == 0) 465*7c478bd9Sstevel@tonic-gate /* 466*7c478bd9Sstevel@tonic-gate * in most cases, this is most easily done by just 467*7c478bd9Sstevel@tonic-gate * excluding the file in question from the baseline 468*7c478bd9Sstevel@tonic-gate */ 469*7c478bd9Sstevel@tonic-gate fp->f_flags |= F_REMOVE; 470*7c478bd9Sstevel@tonic-gate else 471*7c478bd9Sstevel@tonic-gate /* 472*7c478bd9Sstevel@tonic-gate * but ... if the file in question is a directory 473*7c478bd9Sstevel@tonic-gate * with children, excluding it from the baseline 474*7c478bd9Sstevel@tonic-gate * would keep all of its children (even those with 475*7c478bd9Sstevel@tonic-gate * no conflicts) out of the baseline as well. In 476*7c478bd9Sstevel@tonic-gate * This case, it is better to tell a lie and to 477*7c478bd9Sstevel@tonic-gate * manufacture a point of imaginary agreement 478*7c478bd9Sstevel@tonic-gate * in the baseline ... but one that is absurd enough 479*7c478bd9Sstevel@tonic-gate * that we will still see conflicts each time we run. 480*7c478bd9Sstevel@tonic-gate * 481*7c478bd9Sstevel@tonic-gate * recording a type of directory, and everything 482*7c478bd9Sstevel@tonic-gate * else as zero should be absurd enough. 483*7c478bd9Sstevel@tonic-gate */ 484*7c478bd9Sstevel@tonic-gate fp->f_info[ OPT_BASE ].f_type = S_IFDIR; 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate if (opt_debug & DBG_MISC) 487*7c478bd9Sstevel@tonic-gate fprintf(stderr, "MISC: %s ERRS=%s\n", fp->f_fullname, 488*7c478bd9Sstevel@tonic-gate showflags(errmap, errs)); 489*7c478bd9Sstevel@tonic-gate 490*7c478bd9Sstevel@tonic-gate return (errs); 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate /* 494*7c478bd9Sstevel@tonic-gate * routine: 495*7c478bd9Sstevel@tonic-gate * newer 496*7c478bd9Sstevel@tonic-gate * 497*7c478bd9Sstevel@tonic-gate * purpose: 498*7c478bd9Sstevel@tonic-gate * determine which of two files is newer 499*7c478bd9Sstevel@tonic-gate * 500*7c478bd9Sstevel@tonic-gate * parameters: 501*7c478bd9Sstevel@tonic-gate * struct file 502*7c478bd9Sstevel@tonic-gate * 503*7c478bd9Sstevel@tonic-gate * returns: 504*7c478bd9Sstevel@tonic-gate * side_t (src/dest) 505*7c478bd9Sstevel@tonic-gate */ 506*7c478bd9Sstevel@tonic-gate static side_t 507*7c478bd9Sstevel@tonic-gate newer(struct file *fp) 508*7c478bd9Sstevel@tonic-gate { 509*7c478bd9Sstevel@tonic-gate struct fileinfo *sp, *dp; 510*7c478bd9Sstevel@tonic-gate 511*7c478bd9Sstevel@tonic-gate sp = &fp->f_info[OPT_SRC]; 512*7c478bd9Sstevel@tonic-gate dp = &fp->f_info[OPT_DST]; 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate if (sp->f_modtime > dp->f_modtime) 515*7c478bd9Sstevel@tonic-gate return (OPT_SRC); 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate if (sp->f_modtime < dp->f_modtime) 518*7c478bd9Sstevel@tonic-gate return (OPT_DST); 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate if (sp->f_modns >= dp->f_modns) 521*7c478bd9Sstevel@tonic-gate return (OPT_SRC); 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate return (OPT_DST); 524*7c478bd9Sstevel@tonic-gate } 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate /* 527*7c478bd9Sstevel@tonic-gate * routine: 528*7c478bd9Sstevel@tonic-gate * older 529*7c478bd9Sstevel@tonic-gate * 530*7c478bd9Sstevel@tonic-gate * purpose: 531*7c478bd9Sstevel@tonic-gate * determine which of two files is older 532*7c478bd9Sstevel@tonic-gate * 533*7c478bd9Sstevel@tonic-gate * parameters: 534*7c478bd9Sstevel@tonic-gate * struct file 535*7c478bd9Sstevel@tonic-gate * 536*7c478bd9Sstevel@tonic-gate * returns: 537*7c478bd9Sstevel@tonic-gate * side_t (src/dest) 538*7c478bd9Sstevel@tonic-gate */ 539*7c478bd9Sstevel@tonic-gate static side_t 540*7c478bd9Sstevel@tonic-gate older(struct file *fp) 541*7c478bd9Sstevel@tonic-gate { 542*7c478bd9Sstevel@tonic-gate struct fileinfo *sp, *dp; 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate sp = &fp->f_info[OPT_SRC]; 545*7c478bd9Sstevel@tonic-gate dp = &fp->f_info[OPT_DST]; 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate if (sp->f_modtime < dp->f_modtime) 548*7c478bd9Sstevel@tonic-gate return (OPT_SRC); 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate if (sp->f_modtime > dp->f_modtime) 551*7c478bd9Sstevel@tonic-gate return (OPT_DST); 552*7c478bd9Sstevel@tonic-gate 553*7c478bd9Sstevel@tonic-gate if (sp->f_modns <= dp->f_modns) 554*7c478bd9Sstevel@tonic-gate return (OPT_SRC); 555*7c478bd9Sstevel@tonic-gate 556*7c478bd9Sstevel@tonic-gate return (OPT_DST); 557*7c478bd9Sstevel@tonic-gate } 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate /* 560*7c478bd9Sstevel@tonic-gate * routine: 561*7c478bd9Sstevel@tonic-gate * samedata 562*7c478bd9Sstevel@tonic-gate * 563*7c478bd9Sstevel@tonic-gate * purpose: 564*7c478bd9Sstevel@tonic-gate * determine whether or not two files contain the same data 565*7c478bd9Sstevel@tonic-gate * 566*7c478bd9Sstevel@tonic-gate * parameters: 567*7c478bd9Sstevel@tonic-gate * struct file 568*7c478bd9Sstevel@tonic-gate * 569*7c478bd9Sstevel@tonic-gate * returns: 570*7c478bd9Sstevel@tonic-gate * bool_t (true/false) 571*7c478bd9Sstevel@tonic-gate */ 572*7c478bd9Sstevel@tonic-gate static bool_t 573*7c478bd9Sstevel@tonic-gate samedata(struct file *fp) 574*7c478bd9Sstevel@tonic-gate { 575*7c478bd9Sstevel@tonic-gate struct fileinfo *sp, *dp; 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate sp = &fp->f_info[OPT_SRC]; 578*7c478bd9Sstevel@tonic-gate dp = &fp->f_info[OPT_DST]; 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate /* cheap test: types are different */ 581*7c478bd9Sstevel@tonic-gate if (sp->f_type != dp->f_type) 582*7c478bd9Sstevel@tonic-gate return (FALSE); 583*7c478bd9Sstevel@tonic-gate 584*7c478bd9Sstevel@tonic-gate /* cheap test: directories have same contents */ 585*7c478bd9Sstevel@tonic-gate if (sp->f_type == S_IFDIR) 586*7c478bd9Sstevel@tonic-gate return (TRUE); 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate /* special files are compared via their maj/min */ 589*7c478bd9Sstevel@tonic-gate if ((sp->f_type == S_IFBLK) || (sp->f_type == S_IFCHR)) { 590*7c478bd9Sstevel@tonic-gate if (sp->f_rd_maj != dp->f_rd_maj) 591*7c478bd9Sstevel@tonic-gate return (FALSE); 592*7c478bd9Sstevel@tonic-gate if (sp->f_rd_min != dp->f_rd_min) 593*7c478bd9Sstevel@tonic-gate return (FALSE); 594*7c478bd9Sstevel@tonic-gate return (TRUE); 595*7c478bd9Sstevel@tonic-gate } 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate /* symlinks are the same if their contents are the same */ 598*7c478bd9Sstevel@tonic-gate if (sp->f_type == S_IFLNK) 599*7c478bd9Sstevel@tonic-gate return (samelink()); 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate /* cheap test: sizes are different */ 602*7c478bd9Sstevel@tonic-gate if (fp->f_info[OPT_SRC].f_size != fp->f_info[OPT_DST].f_size) 603*7c478bd9Sstevel@tonic-gate return (FALSE); 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate /* expensive test: byte for byte comparison */ 606*7c478bd9Sstevel@tonic-gate if (samecompare(fp) == 0) 607*7c478bd9Sstevel@tonic-gate return (FALSE); 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate return (TRUE); 610*7c478bd9Sstevel@tonic-gate } 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate /* 613*7c478bd9Sstevel@tonic-gate * routine: 614*7c478bd9Sstevel@tonic-gate * samestuff 615*7c478bd9Sstevel@tonic-gate * 616*7c478bd9Sstevel@tonic-gate * purpose: 617*7c478bd9Sstevel@tonic-gate * determine whether or not two files have same owner/protection 618*7c478bd9Sstevel@tonic-gate * 619*7c478bd9Sstevel@tonic-gate * parameters: 620*7c478bd9Sstevel@tonic-gate * struct file 621*7c478bd9Sstevel@tonic-gate * 622*7c478bd9Sstevel@tonic-gate * returns: 623*7c478bd9Sstevel@tonic-gate * bool_t (true/false) 624*7c478bd9Sstevel@tonic-gate */ 625*7c478bd9Sstevel@tonic-gate static bool_t 626*7c478bd9Sstevel@tonic-gate samestuff(struct file *fp) 627*7c478bd9Sstevel@tonic-gate { int same_mode, same_uid, same_gid, same_acl; 628*7c478bd9Sstevel@tonic-gate struct fileinfo *sp, *dp; 629*7c478bd9Sstevel@tonic-gate 630*7c478bd9Sstevel@tonic-gate sp = &fp->f_info[OPT_SRC]; 631*7c478bd9Sstevel@tonic-gate dp = &fp->f_info[OPT_DST]; 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate same_mode = (sp->f_mode == dp->f_mode); 634*7c478bd9Sstevel@tonic-gate same_uid = (sp->f_uid == dp->f_uid); 635*7c478bd9Sstevel@tonic-gate same_gid = (sp->f_gid == dp->f_gid); 636*7c478bd9Sstevel@tonic-gate same_acl = cmp_acls(sp, dp); 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate /* if the are all the same, it is easy to tell the truth */ 639*7c478bd9Sstevel@tonic-gate if (same_uid && same_gid && same_mode && same_acl) 640*7c478bd9Sstevel@tonic-gate return (TRUE); 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate /* note the nature of the conflict */ 643*7c478bd9Sstevel@tonic-gate if (!same_uid || !same_gid || !same_acl) 644*7c478bd9Sstevel@tonic-gate fp->f_problem = gettext(PROB_ownership); 645*7c478bd9Sstevel@tonic-gate else 646*7c478bd9Sstevel@tonic-gate fp->f_problem = gettext(PROB_protection); 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate return (FALSE); 649*7c478bd9Sstevel@tonic-gate } 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate /* 652*7c478bd9Sstevel@tonic-gate * routine: 653*7c478bd9Sstevel@tonic-gate * samecompare 654*7c478bd9Sstevel@tonic-gate * 655*7c478bd9Sstevel@tonic-gate * purpose: 656*7c478bd9Sstevel@tonic-gate * do a byte-for-byte comparison of two files 657*7c478bd9Sstevel@tonic-gate * 658*7c478bd9Sstevel@tonic-gate * parameters: 659*7c478bd9Sstevel@tonic-gate * struct file 660*7c478bd9Sstevel@tonic-gate * 661*7c478bd9Sstevel@tonic-gate * returns: 662*7c478bd9Sstevel@tonic-gate * bool_t (true/false) 663*7c478bd9Sstevel@tonic-gate */ 664*7c478bd9Sstevel@tonic-gate static bool_t 665*7c478bd9Sstevel@tonic-gate samecompare(struct file *fp) 666*7c478bd9Sstevel@tonic-gate { int sfd, dfd; 667*7c478bd9Sstevel@tonic-gate int i, count; 668*7c478bd9Sstevel@tonic-gate char srcbuf[ COPY_BSIZE ], dstbuf[ COPY_BSIZE ]; 669*7c478bd9Sstevel@tonic-gate bool_t same = TRUE; 670*7c478bd9Sstevel@tonic-gate 671*7c478bd9Sstevel@tonic-gate 672*7c478bd9Sstevel@tonic-gate sfd = open(srcname, 0); 673*7c478bd9Sstevel@tonic-gate if (sfd < 0) 674*7c478bd9Sstevel@tonic-gate return (FALSE); 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate dfd = open(dstname, 0); 677*7c478bd9Sstevel@tonic-gate if (dfd < 0) { 678*7c478bd9Sstevel@tonic-gate close(sfd); 679*7c478bd9Sstevel@tonic-gate return (FALSE); 680*7c478bd9Sstevel@tonic-gate } 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate for ( 683*7c478bd9Sstevel@tonic-gate count = read(sfd, srcbuf, COPY_BSIZE); 684*7c478bd9Sstevel@tonic-gate count > 0; 685*7c478bd9Sstevel@tonic-gate count = read(sfd, srcbuf, COPY_BSIZE)) { 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate /* do a matching read */ 688*7c478bd9Sstevel@tonic-gate if (read(dfd, dstbuf, COPY_BSIZE) != count) { 689*7c478bd9Sstevel@tonic-gate same = FALSE; 690*7c478bd9Sstevel@tonic-gate goto done; 691*7c478bd9Sstevel@tonic-gate } 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate /* do the comparison for this block */ 694*7c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 695*7c478bd9Sstevel@tonic-gate if (srcbuf[i] != dstbuf[i]) { 696*7c478bd9Sstevel@tonic-gate same = FALSE; 697*7c478bd9Sstevel@tonic-gate goto done; 698*7c478bd9Sstevel@tonic-gate } 699*7c478bd9Sstevel@tonic-gate } 700*7c478bd9Sstevel@tonic-gate } 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate done: 703*7c478bd9Sstevel@tonic-gate if (opt_debug & DBG_ANAL) 704*7c478bd9Sstevel@tonic-gate fprintf(stderr, "ANAL: SAME=%d %s\n", same, fp->f_fullname); 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate close(sfd); 707*7c478bd9Sstevel@tonic-gate close(dfd); 708*7c478bd9Sstevel@tonic-gate return (same); 709*7c478bd9Sstevel@tonic-gate } 710*7c478bd9Sstevel@tonic-gate 711*7c478bd9Sstevel@tonic-gate /* 712*7c478bd9Sstevel@tonic-gate * routine: 713*7c478bd9Sstevel@tonic-gate * truncated 714*7c478bd9Sstevel@tonic-gate * 715*7c478bd9Sstevel@tonic-gate * purpose: 716*7c478bd9Sstevel@tonic-gate * to determine whether or not a file has been truncated 717*7c478bd9Sstevel@tonic-gate * 718*7c478bd9Sstevel@tonic-gate * parameters: 719*7c478bd9Sstevel@tonic-gate * pointer to file structure 720*7c478bd9Sstevel@tonic-gate * 721*7c478bd9Sstevel@tonic-gate * returns: 722*7c478bd9Sstevel@tonic-gate * true/false 723*7c478bd9Sstevel@tonic-gate */ 724*7c478bd9Sstevel@tonic-gate static bool_t 725*7c478bd9Sstevel@tonic-gate truncated(struct file *fp) 726*7c478bd9Sstevel@tonic-gate { 727*7c478bd9Sstevel@tonic-gate /* either source or destination must now be zero length */ 728*7c478bd9Sstevel@tonic-gate if (fp->f_info[OPT_SRC].f_size && fp->f_info[OPT_DST].f_size) 729*7c478bd9Sstevel@tonic-gate return (FALSE); 730*7c478bd9Sstevel@tonic-gate 731*7c478bd9Sstevel@tonic-gate /* file must have originally had a non-zero length */ 732*7c478bd9Sstevel@tonic-gate if (fp->f_info[OPT_BASE].f_size == 0) 733*7c478bd9Sstevel@tonic-gate return (FALSE); 734*7c478bd9Sstevel@tonic-gate 735*7c478bd9Sstevel@tonic-gate /* file type must "normal" all around */ 736*7c478bd9Sstevel@tonic-gate if (fp->f_info[OPT_BASE].f_type != S_IFREG) 737*7c478bd9Sstevel@tonic-gate return (FALSE); 738*7c478bd9Sstevel@tonic-gate if (fp->f_info[OPT_SRC].f_type != S_IFREG) 739*7c478bd9Sstevel@tonic-gate return (FALSE); 740*7c478bd9Sstevel@tonic-gate if (fp->f_info[OPT_DST].f_type != S_IFREG) 741*7c478bd9Sstevel@tonic-gate return (FALSE); 742*7c478bd9Sstevel@tonic-gate 743*7c478bd9Sstevel@tonic-gate 744*7c478bd9Sstevel@tonic-gate return (TRUE); 745*7c478bd9Sstevel@tonic-gate } 746*7c478bd9Sstevel@tonic-gate 747*7c478bd9Sstevel@tonic-gate /* 748*7c478bd9Sstevel@tonic-gate * routine: 749*7c478bd9Sstevel@tonic-gate * samelink 750*7c478bd9Sstevel@tonic-gate * 751*7c478bd9Sstevel@tonic-gate * purpose: 752*7c478bd9Sstevel@tonic-gate * to determine whether or not two symbolic links agree 753*7c478bd9Sstevel@tonic-gate * 754*7c478bd9Sstevel@tonic-gate * parameters: 755*7c478bd9Sstevel@tonic-gate * pointer to file structure 756*7c478bd9Sstevel@tonic-gate * 757*7c478bd9Sstevel@tonic-gate * returns: 758*7c478bd9Sstevel@tonic-gate * true/false 759*7c478bd9Sstevel@tonic-gate */ 760*7c478bd9Sstevel@tonic-gate static bool_t 761*7c478bd9Sstevel@tonic-gate samelink() 762*7c478bd9Sstevel@tonic-gate { int i, srclen, dstlen; 763*7c478bd9Sstevel@tonic-gate char srcbuf[ MAX_PATH ], dstbuf[ MAX_PATH ]; 764*7c478bd9Sstevel@tonic-gate 765*7c478bd9Sstevel@tonic-gate 766*7c478bd9Sstevel@tonic-gate /* read both copies of the link */ 767*7c478bd9Sstevel@tonic-gate srclen = readlink(srcname, srcbuf, sizeof (srcbuf)); 768*7c478bd9Sstevel@tonic-gate dstlen = readlink(dstname, dstbuf, sizeof (dstbuf)); 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate /* if they aren't the same length, they disagree */ 771*7c478bd9Sstevel@tonic-gate if (srclen < 0 || dstlen < 0 || srclen != dstlen) 772*7c478bd9Sstevel@tonic-gate return (FALSE); 773*7c478bd9Sstevel@tonic-gate 774*7c478bd9Sstevel@tonic-gate /* look for differences in contents */ 775*7c478bd9Sstevel@tonic-gate for (i = 0; i < srclen; i++) 776*7c478bd9Sstevel@tonic-gate if (srcbuf[i] != dstbuf[i]) 777*7c478bd9Sstevel@tonic-gate return (FALSE); 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate return (TRUE); 780*7c478bd9Sstevel@tonic-gate } 781*7c478bd9Sstevel@tonic-gate 782*7c478bd9Sstevel@tonic-gate /* 783*7c478bd9Sstevel@tonic-gate * routine: 784*7c478bd9Sstevel@tonic-gate * full_name 785*7c478bd9Sstevel@tonic-gate * 786*7c478bd9Sstevel@tonic-gate * purpose: 787*7c478bd9Sstevel@tonic-gate * to figure out the fully qualified path name to a file on the 788*7c478bd9Sstevel@tonic-gate * reconciliation list. 789*7c478bd9Sstevel@tonic-gate * 790*7c478bd9Sstevel@tonic-gate * parameters: 791*7c478bd9Sstevel@tonic-gate * pointer to the file structure 792*7c478bd9Sstevel@tonic-gate * side indication for which base to use 793*7c478bd9Sstevel@tonic-gate * side indication for which buffer to use 794*7c478bd9Sstevel@tonic-gate * 795*7c478bd9Sstevel@tonic-gate * returns: 796*7c478bd9Sstevel@tonic-gate * pointer to a clobberable buffer 797*7c478bd9Sstevel@tonic-gate * 798*7c478bd9Sstevel@tonic-gate * notes: 799*7c478bd9Sstevel@tonic-gate * the zero'th buffer is used for renames and links, where 800*7c478bd9Sstevel@tonic-gate * we need the name of another file on the same side. 801*7c478bd9Sstevel@tonic-gate */ 802*7c478bd9Sstevel@tonic-gate char * 803*7c478bd9Sstevel@tonic-gate full_name(struct file *fp, side_t srcdst, side_t whichbuf) 804*7c478bd9Sstevel@tonic-gate { static char *buffers[3]; 805*7c478bd9Sstevel@tonic-gate static int buflen = 0; 806*7c478bd9Sstevel@tonic-gate char *p, *b; 807*7c478bd9Sstevel@tonic-gate int l; 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate /* see if the existing buffer is long enough */ 810*7c478bd9Sstevel@tonic-gate b = (srcdst == OPT_SRC) ? fp->f_base->b_src_name 811*7c478bd9Sstevel@tonic-gate : fp->f_base->b_dst_name; 812*7c478bd9Sstevel@tonic-gate 813*7c478bd9Sstevel@tonic-gate /* see if the allocated buffer is long enough */ 814*7c478bd9Sstevel@tonic-gate l = strlen(b) + strlen(fp->f_fullname) + 2; 815*7c478bd9Sstevel@tonic-gate if (l > buflen) { 816*7c478bd9Sstevel@tonic-gate /* figure out the next "nice" size to use */ 817*7c478bd9Sstevel@tonic-gate for (buflen = MAX_PATH; buflen < l; buflen += MAX_NAME); 818*7c478bd9Sstevel@tonic-gate 819*7c478bd9Sstevel@tonic-gate /* reallocate all buffers to this size */ 820*7c478bd9Sstevel@tonic-gate for (l = 0; l < 3; l++) { 821*7c478bd9Sstevel@tonic-gate buffers[l] = (char *) realloc(buffers[l], buflen); 822*7c478bd9Sstevel@tonic-gate if (buffers[l] == 0) 823*7c478bd9Sstevel@tonic-gate nomem("full name"); 824*7c478bd9Sstevel@tonic-gate } 825*7c478bd9Sstevel@tonic-gate } 826*7c478bd9Sstevel@tonic-gate 827*7c478bd9Sstevel@tonic-gate /* assemble the name in the buffer and reurn it */ 828*7c478bd9Sstevel@tonic-gate p = buffers[whichbuf]; 829*7c478bd9Sstevel@tonic-gate strcpy(p, b); 830*7c478bd9Sstevel@tonic-gate strcat(p, "/"); 831*7c478bd9Sstevel@tonic-gate strcat(p, fp->f_fullname); 832*7c478bd9Sstevel@tonic-gate return (p); 833*7c478bd9Sstevel@tonic-gate } 834