// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package mmap import ( "fmt" "os" "syscall" "unsafe" "golang.org/x/sys/windows" ) func mmapFile(f *os.File) (*Data, error) { st, err := f.Stat() if err != nil { return nil, err } size := st.Size() if size == 0 { return &Data{f, nil, nil}, nil } // set the min and max sizes to zero to map the whole file, as described in // https://learn.microsoft.com/en-us/windows/win32/memory/creating-a-file-mapping-object#file-mapping-size h, err := windows.CreateFileMapping(windows.Handle(f.Fd()), nil, syscall.PAGE_READWRITE, 0, 0, nil) if err != nil { return nil, fmt.Errorf("CreateFileMapping %s: %w", f.Name(), err) } // the mapping extends from zero to the end of the file mapping // https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-mapviewoffile addr, err := windows.MapViewOfFile(h, syscall.FILE_MAP_READ|syscall.FILE_MAP_WRITE, 0, 0, 0) if err != nil { return nil, fmt.Errorf("MapViewOfFile %s: %w", f.Name(), err) } // Note: previously, we called windows.VirtualQuery here to get the exact // size of the memory mapped region, but VirtualQuery reported sizes smaller // than the actual file size (hypothesis: VirtualQuery only reports pages in // a certain state, and newly written pages may not be counted). return &Data{f, unsafe.Slice((*byte)(unsafe.Pointer(addr)), size), h}, nil } func munmapFile(d *Data) error { err := windows.UnmapViewOfFile(uintptr(unsafe.Pointer(&d.Data[0]))) x, ok := d.Windows.(windows.Handle) if ok { windows.CloseHandle(x) } d.f.Close() return err }