mirror of https://github.com/go-gitea/gitea.git
93 lines
2.3 KiB
Go
93 lines
2.3 KiB
Go
// +build linux darwin dragonfly freebsd netbsd openbsd
|
|
// +build !appengine
|
|
|
|
package msgp
|
|
|
|
import (
|
|
"os"
|
|
"syscall"
|
|
)
|
|
|
|
// ReadFile reads a file into 'dst' using
|
|
// a read-only memory mapping. Consequently,
|
|
// the file must be mmap-able, and the
|
|
// Unmarshaler should never write to
|
|
// the source memory. (Methods generated
|
|
// by the msgp tool obey that constraint, but
|
|
// user-defined implementations may not.)
|
|
//
|
|
// Reading and writing through file mappings
|
|
// is only efficient for large files; small
|
|
// files are best read and written using
|
|
// the ordinary streaming interfaces.
|
|
//
|
|
func ReadFile(dst Unmarshaler, file *os.File) error {
|
|
stat, err := file.Stat()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
data, err := syscall.Mmap(int(file.Fd()), 0, int(stat.Size()), syscall.PROT_READ, syscall.MAP_SHARED)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
adviseRead(data)
|
|
_, err = dst.UnmarshalMsg(data)
|
|
uerr := syscall.Munmap(data)
|
|
if err == nil {
|
|
err = uerr
|
|
}
|
|
return err
|
|
}
|
|
|
|
// MarshalSizer is the combination
|
|
// of the Marshaler and Sizer
|
|
// interfaces.
|
|
type MarshalSizer interface {
|
|
Marshaler
|
|
Sizer
|
|
}
|
|
|
|
// WriteFile writes a file from 'src' using
|
|
// memory mapping. It overwrites the entire
|
|
// contents of the previous file.
|
|
// The mapping size is calculated
|
|
// using the `Msgsize()` method
|
|
// of 'src', so it must produce a result
|
|
// equal to or greater than the actual encoded
|
|
// size of the object. Otherwise,
|
|
// a fault (SIGBUS) will occur.
|
|
//
|
|
// Reading and writing through file mappings
|
|
// is only efficient for large files; small
|
|
// files are best read and written using
|
|
// the ordinary streaming interfaces.
|
|
//
|
|
// NOTE: The performance of this call
|
|
// is highly OS- and filesystem-dependent.
|
|
// Users should take care to test that this
|
|
// performs as expected in a production environment.
|
|
// (Linux users should run a kernel and filesystem
|
|
// that support fallocate(2) for the best results.)
|
|
func WriteFile(src MarshalSizer, file *os.File) error {
|
|
sz := src.Msgsize()
|
|
err := fallocate(file, int64(sz))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
data, err := syscall.Mmap(int(file.Fd()), 0, sz, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
adviseWrite(data)
|
|
chunk := data[:0]
|
|
chunk, err = src.MarshalMsg(chunk)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
uerr := syscall.Munmap(data)
|
|
if uerr != nil {
|
|
return uerr
|
|
}
|
|
return file.Truncate(int64(len(chunk)))
|
|
}
|