github.com/rigado/snapd@v2.42.5-go-mod+incompatible/osutil/cmp.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2014-2015 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package osutil
    21  
    22  import (
    23  	"bytes"
    24  	"io"
    25  	"os"
    26  )
    27  
    28  const defaultBufsz = 16 * 1024
    29  
    30  var bufsz = defaultBufsz
    31  
    32  // FilesAreEqual compares the two files' contents and returns whether
    33  // they are the same.
    34  func FilesAreEqual(a, b string) bool {
    35  	fa, err := os.Open(a)
    36  	if err != nil {
    37  		return false
    38  	}
    39  	defer fa.Close()
    40  
    41  	fb, err := os.Open(b)
    42  	if err != nil {
    43  		return false
    44  	}
    45  	defer fb.Close()
    46  
    47  	fia, err := fa.Stat()
    48  	if err != nil {
    49  		return false
    50  	}
    51  
    52  	fib, err := fb.Stat()
    53  	if err != nil {
    54  		return false
    55  	}
    56  
    57  	if fia.Size() != fib.Size() {
    58  		return false
    59  	}
    60  
    61  	return StreamsEqual(fa, fb)
    62  }
    63  
    64  // StreamsEqual compares two streams and returns true if both
    65  // have the same content.
    66  func StreamsEqual(a, b io.Reader) bool {
    67  	bufa := make([]byte, bufsz)
    68  	bufb := make([]byte, bufsz)
    69  	for {
    70  		ra, erra := io.ReadAtLeast(a, bufa, bufsz)
    71  		rb, errb := io.ReadAtLeast(b, bufb, bufsz)
    72  		if erra == io.EOF && errb == io.EOF {
    73  			return true
    74  		}
    75  		if erra != nil || errb != nil {
    76  			// if both files finished in the middle of a
    77  			// ReadAtLeast, (returning io.ErrUnexpectedEOF), then we
    78  			// still need to check what was read to know whether
    79  			// they're equal.  Otherwise, we know they're not equal
    80  			// (because we count any read error as a being non-equal
    81  			// also).
    82  			tailMightBeEqual := erra == io.ErrUnexpectedEOF && errb == io.ErrUnexpectedEOF
    83  			if !tailMightBeEqual {
    84  				return false
    85  			}
    86  		}
    87  		if !bytes.Equal(bufa[:ra], bufb[:rb]) {
    88  			return false
    89  		}
    90  	}
    91  }