mmap_windows.go (1712B)
1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package mmap 6 7 import ( 8 "fmt" 9 "os" 10 "syscall" 11 "unsafe" 12 13 "golang.org/x/sys/windows" 14 ) 15 16 func mmapFile(f *os.File) (*Data, error) { 17 st, err := f.Stat() 18 if err != nil { 19 return nil, err 20 } 21 size := st.Size() 22 if size == 0 { 23 return &Data{f, nil, nil}, nil 24 } 25 // set the min and max sizes to zero to map the whole file, as described in 26 // https://learn.microsoft.com/en-us/windows/win32/memory/creating-a-file-mapping-object#file-mapping-size 27 h, err := windows.CreateFileMapping(windows.Handle(f.Fd()), nil, syscall.PAGE_READWRITE, 0, 0, nil) 28 if err != nil { 29 return nil, fmt.Errorf("CreateFileMapping %s: %w", f.Name(), err) 30 } 31 // the mapping extends from zero to the end of the file mapping 32 // https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-mapviewoffile 33 addr, err := windows.MapViewOfFile(h, syscall.FILE_MAP_READ|syscall.FILE_MAP_WRITE, 0, 0, 0) 34 if err != nil { 35 return nil, fmt.Errorf("MapViewOfFile %s: %w", f.Name(), err) 36 } 37 // Note: previously, we called windows.VirtualQuery here to get the exact 38 // size of the memory mapped region, but VirtualQuery reported sizes smaller 39 // than the actual file size (hypothesis: VirtualQuery only reports pages in 40 // a certain state, and newly written pages may not be counted). 41 return &Data{f, unsafe.Slice((*byte)(unsafe.Pointer(addr)), size), h}, nil 42 } 43 44 func munmapFile(d *Data) error { 45 err := windows.UnmapViewOfFile(uintptr(unsafe.Pointer(&d.Data[0]))) 46 x, ok := d.Windows.(windows.Handle) 47 if ok { 48 windows.CloseHandle(x) 49 } 50 d.f.Close() 51 return err 52 }