pagr

A 'static site generator', built using dati.
Log | Files | Refs | Atom

commit abfbca08f68bb71ab01d50755b54460e0684834e
parent 98b71a76f774959bc123b708dd769fdd4eaa2f62
Author: gearsix <gearsix@tuta.io>
Date:   Fri, 29 Jul 2022 17:11:47 +0100

bugfix(copy.go): improved reliability & portability.

Added back in the old golang copy code to handle files larger than
2GB (the limit on the count that `fseek` can return).

Diffstat:
Mcopy.go | 60++++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 40 insertions(+), 20 deletions(-)

diff --git a/copy.go b/copy.go @@ -6,32 +6,29 @@ package main // copyf copies data from file at `src` to the file at `dst` // in 4kb chunks`. -// any existing file @ `dst` will be overwritten. +// The file @ `src` *must* be **less than 2GB**. This is a +// limitation of libc (staying portable). +// Any existing file @ `dst` will be overwritten. // returns EXIT_SUCCESS or EXIT_FAILURE. int copyf(const char *src, const char *dst) { int ret = EXIT_FAILURE; - FILE *srcf, *dstf; - if ((!(srcf = fopen(src, "rb"))) || - (!(dstf = fopen(dst, "wb")))) - goto ABORT; + FILE *srcf = fopen(src, "rb"), *dstf = fopen(dst, "wb"); + if (!src || !dst) goto ABORT; fseek(srcf, 0, SEEK_END); - size_t siz = ftell(srcf); + size_t siz = ftell(srcf); // 2GB limit, returns long int rewind(srcf); char buf[4096]; // 4kb chunks size_t r, w, total = 0; - do { - r = fread(buf, sizeof(char), sizeof(buf), srcf); + while ((r = fread(buf, sizeof(char), sizeof(buf), srcf)) > 0) { if (ferror(srcf)) goto ABORT; - else { - w = fwrite(buf, sizeof(char), r, dstf); - if (ferror(dstf)) goto ABORT; - total += w; - } - } while (!feof(srcf)); + w = fwrite(buf, sizeof(char), r, dstf); + if (ferror(dstf)) goto ABORT; + total += w; + } if (total == siz) ret = EXIT_SUCCESS; @@ -44,11 +41,29 @@ ABORT: import "C" import ( "fmt" + "io" "os" "path/filepath" "unsafe" ) +func copyFile(src, dst string) (err error) { + var srcf, dstf *os.File + if srcf, err = os.Open(src); err != nil { + return err + } + defer srcf.Close() + if dstf, err = os.OpenFile(dst, os.O_RDWR|os.O_CREATE, 0644); err != nil { + return err + } + defer dstf.Close() + + if _, err = io.Copy(dstf, srcf); err != nil { + return err + } + return dstf.Sync() +} + func CopyFile(src, dst string) (err error) { var srcfi, dstfi os.FileInfo @@ -73,15 +88,20 @@ func CopyFile(src, dst string) (err error) { } // only copy if dst doesnt exist or has different name/size/modtime + // and has a size less than 2GB (libc limit) if dstfi == nil || srcfi.Name() != dstfi.Name() || srcfi.Size() != dstfi.Size() || srcfi.ModTime() != dstfi.ModTime() { - cSrc := C.CString(src) - cDst := C.CString(dst) - if uint32(C.copyf(cSrc, cDst)) != 0 { - err = fmt.Errorf("copyf failed ('%s' -> '%s')", src, dst) + if srcfi.Size() > 2000000000 { + copyFile(src, dst) + } else { + cSrc := C.CString(src) + cDst := C.CString(dst) + if uint32(C.copyf(cSrc, cDst)) != 0 { + err = fmt.Errorf("copyf failed ('%s' -> '%s')", src, dst) + } + C.free(unsafe.Pointer(cSrc)) + C.free(unsafe.Pointer(cDst)) } - C.free(unsafe.Pointer(cSrc)) - C.free(unsafe.Pointer(cDst)) } return