mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-31 06:21:11 +00:00 
			
		
		
		
	* Update blevesearch v0.8.1 -> v1.0.7 * make vendor Co-authored-by: zeripath <art27@cantab.net>
		
			
				
	
	
		
			153 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			153 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| // Copyright 2011 Evan Shaw. 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 (
 | |
| 	"errors"
 | |
| 	"os"
 | |
| 	"sync"
 | |
| 
 | |
| 	"golang.org/x/sys/windows"
 | |
| )
 | |
| 
 | |
| // mmap on Windows is a two-step process.
 | |
| // First, we call CreateFileMapping to get a handle.
 | |
| // Then, we call MapviewToFile to get an actual pointer into memory.
 | |
| // Because we want to emulate a POSIX-style mmap, we don't want to expose
 | |
| // the handle -- only the pointer. We also want to return only a byte slice,
 | |
| // not a struct, so it's convenient to manipulate.
 | |
| 
 | |
| // We keep this map so that we can get back the original handle from the memory address.
 | |
| 
 | |
| type addrinfo struct {
 | |
| 	file     windows.Handle
 | |
| 	mapview  windows.Handle
 | |
| 	writable bool
 | |
| }
 | |
| 
 | |
| var handleLock sync.Mutex
 | |
| var handleMap = map[uintptr]*addrinfo{}
 | |
| 
 | |
| func mmap(len int, prot, flags, hfile uintptr, off int64) ([]byte, error) {
 | |
| 	flProtect := uint32(windows.PAGE_READONLY)
 | |
| 	dwDesiredAccess := uint32(windows.FILE_MAP_READ)
 | |
| 	writable := false
 | |
| 	switch {
 | |
| 	case prot© != 0:
 | |
| 		flProtect = windows.PAGE_WRITECOPY
 | |
| 		dwDesiredAccess = windows.FILE_MAP_COPY
 | |
| 		writable = true
 | |
| 	case prot&RDWR != 0:
 | |
| 		flProtect = windows.PAGE_READWRITE
 | |
| 		dwDesiredAccess = windows.FILE_MAP_WRITE
 | |
| 		writable = true
 | |
| 	}
 | |
| 	if prot&EXEC != 0 {
 | |
| 		flProtect <<= 4
 | |
| 		dwDesiredAccess |= windows.FILE_MAP_EXECUTE
 | |
| 	}
 | |
| 
 | |
| 	// The maximum size is the area of the file, starting from 0,
 | |
| 	// that we wish to allow to be mappable. It is the sum of
 | |
| 	// the length the user requested, plus the offset where that length
 | |
| 	// is starting from. This does not map the data into memory.
 | |
| 	maxSizeHigh := uint32((off + int64(len)) >> 32)
 | |
| 	maxSizeLow := uint32((off + int64(len)) & 0xFFFFFFFF)
 | |
| 	// TODO: Do we need to set some security attributes? It might help portability.
 | |
| 	h, errno := windows.CreateFileMapping(windows.Handle(hfile), nil, flProtect, maxSizeHigh, maxSizeLow, nil)
 | |
| 	if h == 0 {
 | |
| 		return nil, os.NewSyscallError("CreateFileMapping", errno)
 | |
| 	}
 | |
| 
 | |
| 	// Actually map a view of the data into memory. The view's size
 | |
| 	// is the length the user requested.
 | |
| 	fileOffsetHigh := uint32(off >> 32)
 | |
| 	fileOffsetLow := uint32(off & 0xFFFFFFFF)
 | |
| 	addr, errno := windows.MapViewOfFile(h, dwDesiredAccess, fileOffsetHigh, fileOffsetLow, uintptr(len))
 | |
| 	if addr == 0 {
 | |
| 		return nil, os.NewSyscallError("MapViewOfFile", errno)
 | |
| 	}
 | |
| 	handleLock.Lock()
 | |
| 	handleMap[addr] = &addrinfo{
 | |
| 		file:     windows.Handle(hfile),
 | |
| 		mapview:  h,
 | |
| 		writable: writable,
 | |
| 	}
 | |
| 	handleLock.Unlock()
 | |
| 
 | |
| 	m := MMap{}
 | |
| 	dh := m.header()
 | |
| 	dh.Data = addr
 | |
| 	dh.Len = len
 | |
| 	dh.Cap = dh.Len
 | |
| 
 | |
| 	return m, nil
 | |
| }
 | |
| 
 | |
| func (m MMap) flush() error {
 | |
| 	addr, len := m.addrLen()
 | |
| 	errno := windows.FlushViewOfFile(addr, len)
 | |
| 	if errno != nil {
 | |
| 		return os.NewSyscallError("FlushViewOfFile", errno)
 | |
| 	}
 | |
| 
 | |
| 	handleLock.Lock()
 | |
| 	defer handleLock.Unlock()
 | |
| 	handle, ok := handleMap[addr]
 | |
| 	if !ok {
 | |
| 		// should be impossible; we would've errored above
 | |
| 		return errors.New("unknown base address")
 | |
| 	}
 | |
| 
 | |
| 	if handle.writable {
 | |
| 		if err := windows.FlushFileBuffers(handle.file); err != nil {
 | |
| 			return os.NewSyscallError("FlushFileBuffers", err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (m MMap) lock() error {
 | |
| 	addr, len := m.addrLen()
 | |
| 	errno := windows.VirtualLock(addr, len)
 | |
| 	return os.NewSyscallError("VirtualLock", errno)
 | |
| }
 | |
| 
 | |
| func (m MMap) unlock() error {
 | |
| 	addr, len := m.addrLen()
 | |
| 	errno := windows.VirtualUnlock(addr, len)
 | |
| 	return os.NewSyscallError("VirtualUnlock", errno)
 | |
| }
 | |
| 
 | |
| func (m MMap) unmap() error {
 | |
| 	err := m.flush()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	addr := m.header().Data
 | |
| 	// Lock the UnmapViewOfFile along with the handleMap deletion.
 | |
| 	// As soon as we unmap the view, the OS is free to give the
 | |
| 	// same addr to another new map. We don't want another goroutine
 | |
| 	// to insert and remove the same addr into handleMap while
 | |
| 	// we're trying to remove our old addr/handle pair.
 | |
| 	handleLock.Lock()
 | |
| 	defer handleLock.Unlock()
 | |
| 	err = windows.UnmapViewOfFile(addr)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	handle, ok := handleMap[addr]
 | |
| 	if !ok {
 | |
| 		// should be impossible; we would've errored above
 | |
| 		return errors.New("unknown base address")
 | |
| 	}
 | |
| 	delete(handleMap, addr)
 | |
| 
 | |
| 	e := windows.CloseHandle(windows.Handle(handle.mapview))
 | |
| 	return os.NewSyscallError("CloseHandle", e)
 | |
| }
 |