diff --git a/ioctl_linux.go b/ioctl_linux.go index 6abe030..206584e 100644 --- a/ioctl_linux.go +++ b/ioctl_linux.go @@ -14,6 +14,9 @@ import ( "github.com/pkg/errors" ) +// BLKGETSIZE64 ioctl +const blkGetSize64 = 0x80081272 + // FICLONERANGE ioctl const fiCloneRange = 0x4020940d @@ -56,6 +59,31 @@ func CloneRange(dst, src *os.File, srcOffset, srcLength, dstOffset uint64) error return errors.Wrapf(err, "failure cloning blocks from %s to %s", src.Name(), dst.Name()) } +// GetFileSize determines the size, in Bytes, of the file located at the given +// fileName. +func GetFileSize(fileName string) (size uint64, err error) { + info, err := os.Stat(fileName) + if err != nil { + return 0, err + } + fm := info.Mode() + if isDevice(fm) { + // When we are working with block devices, we can't simply use `Size()`, because it + // will return zero instead of the expected device size. + f, err := os.Open(fileName) + if err != nil { + return 0, err + } + err = ioctl(f.Fd(), blkGetSize64, uintptr(unsafe.Pointer(&size))) + if err != nil { + return 0, err + } + return size, nil + } else { + return uint64(info.Size()), nil + } +} + func ioctl(fd, operation, argp uintptr) error { _, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, operation, argp) if e != 0 { diff --git a/ioctl_nonlinux.go b/ioctl_nonlinux.go index bb7200f..b6392b3 100644 --- a/ioctl_nonlinux.go +++ b/ioctl_nonlinux.go @@ -14,3 +14,17 @@ func CanClone(dstFile string, srcFile string) bool { func CloneRange(dst, src *os.File, srcOffset, srcLength, dstOffset uint64) error { return errors.New("Not available on this platform") } + +// GetFileSize determines the size, in Bytes, of the file located at the given +// fileName. +func GetFileSize(fileName string) (size uint64, err error) { + info, err := os.Stat(fileName) + if err != nil { + return 0, err + } + fm := info.Mode() + if isDevice(fm) { + // TODO we probably should do something platform specific here to get the correct size + } + return uint64(info.Size()), nil +} diff --git a/make.go b/make.go index 54c2e2d..8b5566b 100644 --- a/make.go +++ b/make.go @@ -60,21 +60,21 @@ func IndexFromFile(ctx context.Context, } f.Close() - // Adjust n if it's a small file that doesn't have n*max bytes - info, err := os.Stat(name) + size, err := GetFileSize(name) if err != nil { return index, stats, err } - nn := int(info.Size()/int64(max)) + 1 - if nn < n { - n = nn + + // Adjust n if it's a small file that doesn't have n*max bytes + nn := size/max + 1 + if nn < uint64(n) { + n = int(nn) } - size := uint64(info.Size()) span := size / uint64(n) // initial spacing between chunkers // Setup and start the progressbar if any if pb != nil { - pb.SetTotal(int(info.Size())) + pb.SetTotal(int(size)) pb.Start() defer pb.Finish() }