equalfile.go
func (c *Cmp) CompareFile(path1, path2 string) (bool, error) {

	if c.Opt.MaxSize < 0 {
		return false, fmt.Errorf("negative MaxSize")
	}

	r1, openErr1 := os.Open(path1)
	if openErr1 != nil {
		return false, openErr1
	}
	defer r1.Close()
	info1, statErr1 := r1.Stat()
	if statErr1 != nil {
		return false, statErr1
	}

	r2, openErr2 := os.Open(path2)
	if openErr2 != nil {
		return false, openErr2
	}
	defer r2.Close()
	info2, statErr2 := r2.Stat()
	if statErr2 != nil {
		return false, statErr2
	}

	if !c.Opt.ForceFileRead {
		// shortcut: ask the filesystem: are these files the same? (link, pathname, etc)
		if os.SameFile(info1, info2) {
			c.debugf("CompareFile(%s,%s): os reported same file\n", path1, path2)
			return true, nil
		}
	}

	if info1.Mode().IsRegular() && info2.Mode().IsRegular() {
		if info1.Size() != info2.Size() {
			c.debugf("CompareFile(%s,%s): distinct file sizes\n", path1, path2)
			return false, nil
		}
	}

	// If Opt.MaxSize not initialized, set maxSize to an appropriate value
	// for comparing regular files or streams (pipes, devices), etc.
	// Pass maxSize to getHash to ensure the hash is computed only up to
	// the user specified MaxSize amount.
	maxSize := c.Opt.MaxSize
	if maxSize == 0 {
		// If comparing regular to non-regular file, sizes may not
		// agree...  Use the larger value.
		maxSize = info1.Size()
		if maxSize < info2.Size() {
			maxSize = info2.Size()
		}
		if maxSize == 0 { // possible non-regular files
			maxSize = defaultMaxSize
		}
	}

	if c.multipleMode() {
		h1, err1 := c.getHash(path1, maxSize)
		if err1 != nil {
			return false, err1
		}
		h2, err2 := c.getHash(path2, maxSize)
		if err2 != nil {
			return false, err2
		}
		if !bytes.Equal(h1, h2) {
			return false, nil // hashes mismatch
		}
		// hashes match
		if !c.hashMatchCompare {
			return true, nil // accept hash match without byte-by-byte comparison
		}
		// do byte-by-byte comparison
		c.debugf("CompareFile(%s,%s): hash match, will compare bytes\n", path1, path2)
	}

	// Use our maxSize to avoid triggering the defaultMaxSize for files.
	// We still need to preserve the error returning properties of the
	// input amount exceeding MaxSize, so we can't use LimitedReader.
	c.resetDebugging()

	eq, err := c.compareReader(r1, r2, maxSize)

	c.printDebugCompareReader()

	return eq, err
}
func (c *Cmp) CompareFile(path1, path2 string) (bool, error) {

	if c.Opt.MaxSize < 0 {
		return false, fmt.Errorf("negative MaxSize")
	}

	r1, openErr1 := os.Open(path1)
	if openErr1 != nil {
		return false, openErr1
	}
	defer r1.Close()
	info1, statErr1 := r1.Stat()
	if statErr1 != nil {
		return false, statErr1
	}

	r2, openErr2 := os.Open(path2)
	if openErr2 != nil {
		return false, openErr2
	}
	defer r2.Close()
	info2, statErr2 := r2.Stat()
	if statErr2 != nil {
		return false, statErr2
	}

	if !c.Opt.ForceFileRead {
		// shortcut: ask the filesystem: are these files the same? (link, pathname, etc)
		if os.SameFile(info1, info2) {
			c.debugf("CompareFile(%s,%s): os reported same file\n", path1, path2)
			return true, nil
		}
	}

	if info1.Mode().IsRegular() && info2.Mode().IsRegular() {
		if info1.Size() != info2.Size() {
			c.debugf("CompareFile(%s,%s): distinct file sizes\n", path1, path2)
			return false, nil
		}
	}

	// If Opt.MaxSize not initialized, set maxSize to an appropriate value
	// for comparing regular files or streams (pipes, devices), etc.
	// Pass maxSize to getHash to ensure the hash is computed only up to
	// the user specified MaxSize amount.
	maxSize := c.Opt.MaxSize
	if maxSize == 0 {
		// If comparing regular to non-regular file, sizes may not
		// agree...  Use the larger value.
		maxSize = info1.Size()
		if maxSize < info2.Size() {
			maxSize = info2.Size()
		}
		if maxSize == 0 { // possible non-regular files
			maxSize = defaultMaxSize
		}
	}

	if c.multipleMode() {
		h1, err1 := c.getHash(path1, maxSize)
		if err1 != nil {
			return false, err1
		}
		h2, err2 := c.getHash(path2, maxSize)
		if err2 != nil {
			return false, err2
		}
		if !bytes.Equal(h1, h2) {
			return false, nil // hashes mismatch
		}
		// hashes match
		if !c.hashMatchCompare {
			return true, nil // accept hash match without byte-by-byte comparison
		}
		// do byte-by-byte comparison
		c.debugf("CompareFile(%s,%s): hash match, will compare bytes\n", path1, path2)
	}

	// Use our maxSize to avoid triggering the defaultMaxSize for files.
	// We still need to preserve the error returning properties of the
	// input amount exceeding MaxSize, so we can't use LimitedReader.
	c.resetDebugging()

	eq, err := c.compareReader(r1, r2, maxSize)

	c.printDebugCompareReader()

	return eq, err
}
// CompareFile verifies that files with names path1, path2 have same contents.