github.com/scottcagno/storage@v1.8.0/pkg/mmap/mmfile.go (about) 1 package mmap 2 3 import ( 4 "os" 5 "path/filepath" 6 "reflect" 7 "unsafe" 8 ) 9 10 // OpenMappedFile prepares a file, calls the initializer if file was just created 11 // and returns a new mapping of the prepared file into the memory. 12 func OpenFileMapping(name string, perm os.FileMode, size uintptr, flags Flag, init func(mf *Mapping) error) (*Mapping, error) { 13 mf, created, err := func() (*Mapping, bool, error) { 14 created := false 15 if _, err := os.Stat(name); err != nil && os.IsNotExist(err) { 16 created = true 17 } 18 f, err := os.OpenFile(name, os.O_CREATE|os.O_RDWR, perm) 19 if err != nil { 20 return nil, false, err 21 } 22 defer func() { 23 if f != nil { 24 _ = f.Close() 25 } 26 }() 27 onFailure := func() { 28 _ = f.Close() 29 f = nil 30 if created { 31 _ = os.Remove(name) 32 } 33 } 34 if err := f.Truncate(int64(size)); err != nil { 35 onFailure() 36 return nil, false, err 37 } 38 mf, err := Open(f.Fd(), 0, size, ModeReadWrite, flags) 39 if err != nil { 40 onFailure() 41 return nil, false, err 42 } 43 return mf, created, nil 44 }() 45 if err != nil { 46 return nil, err 47 } 48 if created && init != nil { 49 if err := init(mf); err != nil { 50 _ = mf.Close() 51 _ = os.Remove(name) 52 return nil, err 53 } 54 } 55 return mf, nil 56 } 57 58 func OpenFile(path string) (*os.File, error) { 59 _, err := os.Stat(path) 60 if os.IsNotExist(err) { 61 dir, file := filepath.Split(path) 62 err = os.MkdirAll(dir, os.ModeDir) 63 if err != nil { 64 return nil, err 65 } 66 fd, err := os.Create(dir + file) 67 if err != nil { 68 return nil, err 69 } 70 err = fd.Close() 71 if err != nil { 72 return fd, err 73 } 74 } 75 fd, err := os.OpenFile(path, os.O_RDWR, os.ModeSticky) 76 if err != nil { 77 return nil, err 78 } 79 return fd, nil 80 } 81 82 // UnsafeBytesToString converts bytes to string saving allocations 83 func UnsafeBytesToString(bytes []byte) string { 84 sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&bytes)) 85 86 return *(*string)(unsafe.Pointer(&reflect.StringHeader{ 87 Data: sliceHeader.Data, 88 Len: sliceHeader.Len, 89 })) 90 } 91 92 // UnsafeStringToBytes converts bytes to string saving allocations by re-using 93 func UnsafeStringToBytes(s string) []byte { 94 stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s)) 95 return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ 96 Data: stringHeader.Data, 97 Len: stringHeader.Len, 98 Cap: stringHeader.Len, 99 })) 100 }