Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
467bb7a7
Commit
467bb7a7
authored
Apr 04, 2016
by
Felix Lange
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
rpc: use go-winio instead of vendoring a named pipe implementation
parent
3a2da31c
Changes
13
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
1849 additions
and
622 deletions
+1849
-622
Godeps.json
Godeps/Godeps.json
+6
-0
LICENSE
Godeps/_workspace/src/github.com/microsoft/go-winio/LICENSE
+22
-0
README.md
...ps/_workspace/src/github.com/microsoft/go-winio/README.md
+15
-0
backup.go
...ps/_workspace/src/github.com/microsoft/go-winio/backup.go
+266
-0
file.go
Godeps/_workspace/src/github.com/microsoft/go-winio/file.go
+219
-0
fileinfo.go
.../_workspace/src/github.com/microsoft/go-winio/fileinfo.go
+54
-0
pipe.go
Godeps/_workspace/src/github.com/microsoft/go-winio/pipe.go
+398
-0
privilege.go
..._workspace/src/github.com/microsoft/go-winio/privilege.go
+150
-0
reparse.go
...s/_workspace/src/github.com/microsoft/go-winio/reparse.go
+124
-0
sd.go
Godeps/_workspace/src/github.com/microsoft/go-winio/sd.go
+96
-0
syscall.go
...s/_workspace/src/github.com/microsoft/go-winio/syscall.go
+3
-0
zsyscall.go
.../_workspace/src/github.com/microsoft/go-winio/zsyscall.go
+492
-0
ipc_windows.go
rpc/ipc_windows.go
+4
-622
No files found.
Godeps/Godeps.json
View file @
467bb7a7
{
"ImportPath"
:
"github.com/ethereum/go-ethereum"
,
"GoVersion"
:
"go1.5.2"
,
"GodepVersion"
:
"v60"
,
"Packages"
:
[
"./..."
],
...
...
@@ -93,6 +94,11 @@
"Comment"
:
"travisish-44-ge882a96"
,
"Rev"
:
"e882a96ec18dd43fa283187b66af74497c9101c0"
},
{
"ImportPath"
:
"github.com/microsoft/go-winio"
,
"Comment"
:
"v0.2.0"
,
"Rev"
:
"9e2895e5f6c3f16473b91d37fae6e89990a4520c"
},
{
"ImportPath"
:
"github.com/nsf/termbox-go"
,
"Rev"
:
"362329b0aa6447eadd52edd8d660ec1dff470295"
...
...
Godeps/_workspace/src/github.com/microsoft/go-winio/LICENSE
0 → 100644
View file @
467bb7a7
The MIT License (MIT)
Copyright (c) 2015 Microsoft
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Godeps/_workspace/src/github.com/microsoft/go-winio/README.md
0 → 100644
View file @
467bb7a7
# go-winio
This repository contains utilities for efficiently performing Win32 IO operations in
Go. Currently, this is focused on accessing named pipes and other file handles, and
for using named pipes as a net transport.
This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go
to reuse the thread to schedule another goroutine. This limits support to Windows Vista and
newer operating systems. This is similar to the implementation of network sockets in Go's net
package.
Please see the LICENSE file for licensing information.
Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe
for another named pipe implementation.
Godeps/_workspace/src/github.com/microsoft/go-winio/backup.go
0 → 100644
View file @
467bb7a7
package
winio
import
(
"encoding/binary"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"runtime"
"syscall"
"unicode/utf16"
)
//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
const
(
BackupData
=
uint32
(
iota
+
1
)
BackupEaData
BackupSecurity
BackupAlternateData
BackupLink
BackupPropertyData
BackupObjectId
BackupReparseData
BackupSparseBlock
BackupTxfsData
)
const
(
StreamSparseAttributes
=
uint32
(
8
)
)
const
(
WRITE_DAC
=
0x40000
WRITE_OWNER
=
0x80000
ACCESS_SYSTEM_SECURITY
=
0x1000000
)
// BackupHeader represents a backup stream of a file.
type
BackupHeader
struct
{
Id
uint32
// The backup stream ID
Attributes
uint32
// Stream attributes
Size
int64
// The size of the stream in bytes
Name
string
// The name of the stream (for BackupAlternateData only).
Offset
int64
// The offset of the stream in the file (for BackupSparseBlock only).
}
type
win32StreamId
struct
{
StreamId
uint32
Attributes
uint32
Size
uint64
NameSize
uint32
}
// BackupStreamReader reads from a stream produced by the BackupRead Win32 API and produces a series
// of BackupHeader values.
type
BackupStreamReader
struct
{
r
io
.
Reader
bytesLeft
int64
}
// NewBackupStreamReader produces a BackupStreamReader from any io.Reader.
func
NewBackupStreamReader
(
r
io
.
Reader
)
*
BackupStreamReader
{
return
&
BackupStreamReader
{
r
,
0
}
}
// Next returns the next backup stream and prepares for calls to Write(). It skips the remainder of the current stream if
// it was not completely read.
func
(
r
*
BackupStreamReader
)
Next
()
(
*
BackupHeader
,
error
)
{
if
r
.
bytesLeft
>
0
{
if
_
,
err
:=
io
.
Copy
(
ioutil
.
Discard
,
r
);
err
!=
nil
{
return
nil
,
err
}
}
var
wsi
win32StreamId
if
err
:=
binary
.
Read
(
r
.
r
,
binary
.
LittleEndian
,
&
wsi
);
err
!=
nil
{
return
nil
,
err
}
hdr
:=
&
BackupHeader
{
Id
:
wsi
.
StreamId
,
Attributes
:
wsi
.
Attributes
,
Size
:
int64
(
wsi
.
Size
),
}
if
wsi
.
NameSize
!=
0
{
name
:=
make
([]
uint16
,
int
(
wsi
.
NameSize
/
2
))
if
err
:=
binary
.
Read
(
r
.
r
,
binary
.
LittleEndian
,
name
);
err
!=
nil
{
return
nil
,
err
}
hdr
.
Name
=
syscall
.
UTF16ToString
(
name
)
}
if
wsi
.
StreamId
==
BackupSparseBlock
{
if
err
:=
binary
.
Read
(
r
.
r
,
binary
.
LittleEndian
,
&
hdr
.
Offset
);
err
!=
nil
{
return
nil
,
err
}
hdr
.
Size
-=
8
}
r
.
bytesLeft
=
hdr
.
Size
return
hdr
,
nil
}
// Read reads from the current backup stream.
func
(
r
*
BackupStreamReader
)
Read
(
b
[]
byte
)
(
int
,
error
)
{
if
r
.
bytesLeft
==
0
{
return
0
,
io
.
EOF
}
if
int64
(
len
(
b
))
>
r
.
bytesLeft
{
b
=
b
[
:
r
.
bytesLeft
]
}
n
,
err
:=
r
.
r
.
Read
(
b
)
r
.
bytesLeft
-=
int64
(
n
)
if
err
==
io
.
EOF
{
err
=
io
.
ErrUnexpectedEOF
}
else
if
r
.
bytesLeft
==
0
&&
err
==
nil
{
err
=
io
.
EOF
}
return
n
,
err
}
// BackupStreamWriter writes a stream compatible with the BackupWrite Win32 API.
type
BackupStreamWriter
struct
{
w
io
.
Writer
bytesLeft
int64
}
// NewBackupStreamWriter produces a BackupStreamWriter on top of an io.Writer.
func
NewBackupStreamWriter
(
w
io
.
Writer
)
*
BackupStreamWriter
{
return
&
BackupStreamWriter
{
w
,
0
}
}
// WriteHeader writes the next backup stream header and prepares for calls to Write().
func
(
w
*
BackupStreamWriter
)
WriteHeader
(
hdr
*
BackupHeader
)
error
{
if
w
.
bytesLeft
!=
0
{
return
fmt
.
Errorf
(
"missing %d bytes"
,
w
.
bytesLeft
)
}
name
:=
utf16
.
Encode
([]
rune
(
hdr
.
Name
))
wsi
:=
win32StreamId
{
StreamId
:
hdr
.
Id
,
Attributes
:
hdr
.
Attributes
,
Size
:
uint64
(
hdr
.
Size
),
NameSize
:
uint32
(
len
(
name
)
*
2
),
}
if
hdr
.
Id
==
BackupSparseBlock
{
// Include space for the int64 block offset
wsi
.
Size
+=
8
}
if
err
:=
binary
.
Write
(
w
.
w
,
binary
.
LittleEndian
,
&
wsi
);
err
!=
nil
{
return
err
}
if
len
(
name
)
!=
0
{
if
err
:=
binary
.
Write
(
w
.
w
,
binary
.
LittleEndian
,
name
);
err
!=
nil
{
return
err
}
}
if
hdr
.
Id
==
BackupSparseBlock
{
if
err
:=
binary
.
Write
(
w
.
w
,
binary
.
LittleEndian
,
hdr
.
Offset
);
err
!=
nil
{
return
err
}
}
w
.
bytesLeft
=
hdr
.
Size
return
nil
}
// Write writes to the current backup stream.
func
(
w
*
BackupStreamWriter
)
Write
(
b
[]
byte
)
(
int
,
error
)
{
if
w
.
bytesLeft
<
int64
(
len
(
b
))
{
return
0
,
fmt
.
Errorf
(
"too many bytes by %d"
,
int64
(
len
(
b
))
-
w
.
bytesLeft
)
}
n
,
err
:=
w
.
w
.
Write
(
b
)
w
.
bytesLeft
-=
int64
(
n
)
return
n
,
err
}
// BackupFileReader provides an io.ReadCloser interface on top of the BackupRead Win32 API.
type
BackupFileReader
struct
{
f
*
os
.
File
includeSecurity
bool
ctx
uintptr
}
// NewBackupFileReader returns a new BackupFileReader from a file handle. If includeSecurity is true,
// Read will attempt to read the security descriptor of the file.
func
NewBackupFileReader
(
f
*
os
.
File
,
includeSecurity
bool
)
*
BackupFileReader
{
r
:=
&
BackupFileReader
{
f
,
includeSecurity
,
0
}
runtime
.
SetFinalizer
(
r
,
func
(
r
*
BackupFileReader
)
{
r
.
Close
()
})
return
r
}
// Read reads a backup stream from the file by calling the Win32 API BackupRead().
func
(
r
*
BackupFileReader
)
Read
(
b
[]
byte
)
(
int
,
error
)
{
var
bytesRead
uint32
err
:=
backupRead
(
syscall
.
Handle
(
r
.
f
.
Fd
()),
b
,
&
bytesRead
,
false
,
r
.
includeSecurity
,
&
r
.
ctx
)
if
err
!=
nil
{
return
0
,
&
os
.
PathError
{
"BackupRead"
,
r
.
f
.
Name
(),
err
}
}
if
bytesRead
==
0
{
return
0
,
io
.
EOF
}
return
int
(
bytesRead
),
nil
}
// Close frees Win32 resources associated with the BackupFileReader. It does not close
// the underlying file.
func
(
r
*
BackupFileReader
)
Close
()
error
{
if
r
.
ctx
!=
0
{
backupRead
(
syscall
.
Handle
(
r
.
f
.
Fd
()),
nil
,
nil
,
true
,
false
,
&
r
.
ctx
)
r
.
ctx
=
0
}
return
nil
}
// BackupFileWriter provides an io.WriteCloser interface on top of the BackupWrite Win32 API.
type
BackupFileWriter
struct
{
f
*
os
.
File
includeSecurity
bool
ctx
uintptr
}
// NewBackupFileWrtier returns a new BackupFileWriter from a file handle. If includeSecurity is true,
// Write() will attempt to restore the security descriptor from the stream.
func
NewBackupFileWriter
(
f
*
os
.
File
,
includeSecurity
bool
)
*
BackupFileWriter
{
w
:=
&
BackupFileWriter
{
f
,
includeSecurity
,
0
}
runtime
.
SetFinalizer
(
w
,
func
(
w
*
BackupFileWriter
)
{
w
.
Close
()
})
return
w
}
// Write restores a portion of the file using the provided backup stream.
func
(
w
*
BackupFileWriter
)
Write
(
b
[]
byte
)
(
int
,
error
)
{
var
bytesWritten
uint32
err
:=
backupWrite
(
syscall
.
Handle
(
w
.
f
.
Fd
()),
b
,
&
bytesWritten
,
false
,
w
.
includeSecurity
,
&
w
.
ctx
)
if
err
!=
nil
{
return
0
,
&
os
.
PathError
{
"BackupWrite"
,
w
.
f
.
Name
(),
err
}
}
if
int
(
bytesWritten
)
!=
len
(
b
)
{
return
int
(
bytesWritten
),
errors
.
New
(
"not all bytes could be written"
)
}
return
len
(
b
),
nil
}
// Close frees Win32 resources associated with the BackupFileWriter. It does not
// close the underlying file.
func
(
w
*
BackupFileWriter
)
Close
()
error
{
if
w
.
ctx
!=
0
{
backupWrite
(
syscall
.
Handle
(
w
.
f
.
Fd
()),
nil
,
nil
,
true
,
false
,
&
w
.
ctx
)
w
.
ctx
=
0
}
return
nil
}
// OpenForBackup opens a file or directory, potentially skipping access checks if the backup
// or restore privileges have been acquired.
//
// If the file opened was a directory, it cannot be used with Readdir().
func
OpenForBackup
(
path
string
,
access
uint32
,
share
uint32
,
createmode
uint32
)
(
*
os
.
File
,
error
)
{
winPath
,
err
:=
syscall
.
UTF16FromString
(
path
)
if
err
!=
nil
{
return
nil
,
err
}
h
,
err
:=
syscall
.
CreateFile
(
&
winPath
[
0
],
access
,
share
,
nil
,
createmode
,
syscall
.
FILE_FLAG_BACKUP_SEMANTICS
,
0
)
if
err
!=
nil
{
err
=
&
os
.
PathError
{
Op
:
"open"
,
Path
:
path
,
Err
:
err
}
return
nil
,
err
}
return
os
.
NewFile
(
uintptr
(
h
),
path
),
nil
}
Godeps/_workspace/src/github.com/microsoft/go-winio/file.go
0 → 100644
View file @
467bb7a7
package
winio
import
(
"errors"
"io"
"runtime"
"sync"
"syscall"
"time"
)
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
//sys timeBeginPeriod(period uint32) (n int32) = winmm.timeBeginPeriod
const
(
cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS
=
1
cFILE_SKIP_SET_EVENT_ON_HANDLE
=
2
)
var
(
ErrFileClosed
=
errors
.
New
(
"file has already been closed"
)
ErrTimeout
=
&
timeoutError
{}
)
type
timeoutError
struct
{}
func
(
e
*
timeoutError
)
Error
()
string
{
return
"i/o timeout"
}
func
(
e
*
timeoutError
)
Timeout
()
bool
{
return
true
}
func
(
e
*
timeoutError
)
Temporary
()
bool
{
return
true
}
var
ioInitOnce
sync
.
Once
var
ioCompletionPort
syscall
.
Handle
// ioResult contains the result of an asynchronous IO operation
type
ioResult
struct
{
bytes
uint32
err
error
}
// ioOperation represents an outstanding asynchronous Win32 IO
type
ioOperation
struct
{
o
syscall
.
Overlapped
ch
chan
ioResult
}
func
initIo
()
{
h
,
err
:=
createIoCompletionPort
(
syscall
.
InvalidHandle
,
0
,
0
,
0xffffffff
)
if
err
!=
nil
{
panic
(
err
)
}
ioCompletionPort
=
h
go
ioCompletionProcessor
(
h
)
}
// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
// It takes ownership of this handle and will close it if it is garbage collected.
type
win32File
struct
{
handle
syscall
.
Handle
wg
sync
.
WaitGroup
closing
bool
readDeadline
time
.
Time
writeDeadline
time
.
Time
}
// makeWin32File makes a new win32File from an existing file handle
func
makeWin32File
(
h
syscall
.
Handle
)
(
*
win32File
,
error
)
{
f
:=
&
win32File
{
handle
:
h
}
ioInitOnce
.
Do
(
initIo
)
_
,
err
:=
createIoCompletionPort
(
h
,
ioCompletionPort
,
0
,
0xffffffff
)
if
err
!=
nil
{
return
nil
,
err
}
err
=
setFileCompletionNotificationModes
(
h
,
cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS
|
cFILE_SKIP_SET_EVENT_ON_HANDLE
)
if
err
!=
nil
{
return
nil
,
err
}
runtime
.
SetFinalizer
(
f
,
(
*
win32File
)
.
closeHandle
)
return
f
,
nil
}
func
MakeOpenFile
(
h
syscall
.
Handle
)
(
io
.
ReadWriteCloser
,
error
)
{
return
makeWin32File
(
h
)
}
// closeHandle closes the resources associated with a Win32 handle
func
(
f
*
win32File
)
closeHandle
()
{
if
!
f
.
closing
{
// cancel all IO and wait for it to complete
f
.
closing
=
true
cancelIoEx
(
f
.
handle
,
nil
)
f
.
wg
.
Wait
()
// at this point, no new IO can start
syscall
.
Close
(
f
.
handle
)
f
.
handle
=
0
}
}
// Close closes a win32File.
func
(
f
*
win32File
)
Close
()
error
{
f
.
closeHandle
()
runtime
.
SetFinalizer
(
f
,
nil
)
return
nil
}
// prepareIo prepares for a new IO operation
func
(
f
*
win32File
)
prepareIo
()
(
*
ioOperation
,
error
)
{
f
.
wg
.
Add
(
1
)
if
f
.
closing
{
return
nil
,
ErrFileClosed
}
c
:=
&
ioOperation
{}
c
.
ch
=
make
(
chan
ioResult
)
return
c
,
nil
}
// ioCompletionProcessor processes completed async IOs forever
func
ioCompletionProcessor
(
h
syscall
.
Handle
)
{
// Set the timer resolution to 1. This fixes a performance regression in golang 1.6.
timeBeginPeriod
(
1
)
for
{
var
bytes
uint32
var
key
uintptr
var
op
*
ioOperation
err
:=
getQueuedCompletionStatus
(
h
,
&
bytes
,
&
key
,
&
op
,
syscall
.
INFINITE
)
if
op
==
nil
{
panic
(
err
)
}
op
.
ch
<-
ioResult
{
bytes
,
err
}
}
}
// asyncIo processes the return value from ReadFile or WriteFile, blocking until
// the operation has actually completed.
func
(
f
*
win32File
)
asyncIo
(
c
*
ioOperation
,
deadline
time
.
Time
,
bytes
uint32
,
err
error
)
(
int
,
error
)
{
if
err
!=
syscall
.
ERROR_IO_PENDING
{
f
.
wg
.
Done
()
return
int
(
bytes
),
err
}
else
{
var
r
ioResult
wait
:=
true
timedout
:=
false
if
f
.
closing
{
cancelIoEx
(
f
.
handle
,
&
c
.
o
)
}
else
if
!
deadline
.
IsZero
()
{
now
:=
time
.
Now
()
if
!
deadline
.
After
(
now
)
{
timedout
=
true
}
else
{
timeout
:=
time
.
After
(
deadline
.
Sub
(
now
))
select
{
case
r
=
<-
c
.
ch
:
wait
=
false
case
<-
timeout
:
timedout
=
true
}
}
}
if
timedout
{
cancelIoEx
(
f
.
handle
,
&
c
.
o
)
}
if
wait
{
r
=
<-
c
.
ch
}
err
=
r
.
err
if
err
==
syscall
.
ERROR_OPERATION_ABORTED
{
if
f
.
closing
{
err
=
ErrFileClosed
}
else
if
timedout
{
err
=
ErrTimeout
}
}
f
.
wg
.
Done
()
return
int
(
r
.
bytes
),
err
}
}
// Read reads from a file handle.
func
(
f
*
win32File
)
Read
(
b
[]
byte
)
(
int
,
error
)
{
c
,
err
:=
f
.
prepareIo
()
if
err
!=
nil
{
return
0
,
err
}
var
bytes
uint32
err
=
syscall
.
ReadFile
(
f
.
handle
,
b
,
&
bytes
,
&
c
.
o
)
n
,
err
:=
f
.
asyncIo
(
c
,
f
.
readDeadline
,
bytes
,
err
)
// Handle EOF conditions.
if
err
==
nil
&&
n
==
0
&&
len
(
b
)
!=
0
{
return
0
,
io
.
EOF
}
else
if
err
==
syscall
.
ERROR_BROKEN_PIPE
{
return
0
,
io
.
EOF
}
else
{
return
n
,
err
}
}
// Write writes to a file handle.
func
(
f
*
win32File
)
Write
(
b
[]
byte
)
(
int
,
error
)
{
c
,
err
:=
f
.
prepareIo
()
if
err
!=
nil
{
return
0
,
err
}
var
bytes
uint32
err
=
syscall
.
WriteFile
(
f
.
handle
,
b
,
&
bytes
,
&
c
.
o
)
return
f
.
asyncIo
(
c
,
f
.
writeDeadline
,
bytes
,
err
)
}
func
(
f
*
win32File
)
SetReadDeadline
(
t
time
.
Time
)
error
{
f
.
readDeadline
=
t
return
nil
}
func
(
f
*
win32File
)
SetWriteDeadline
(
t
time
.
Time
)
error
{
f
.
writeDeadline
=
t
return
nil
}
Godeps/_workspace/src/github.com/microsoft/go-winio/fileinfo.go
0 → 100644
View file @
467bb7a7
package
winio
import
(
"os"
"syscall"
"unsafe"
)
//sys getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = GetFileInformationByHandleEx
//sys setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = SetFileInformationByHandle
const
(
fileBasicInfo
=
0
fileIDInfo
=
0x12
)
// FileBasicInfo contains file access time and file attributes information.
type
FileBasicInfo
struct
{
CreationTime
,
LastAccessTime
,
LastWriteTime
,
ChangeTime
syscall
.
Filetime
FileAttributes
uintptr
// includes padding
}
// GetFileBasicInfo retrieves times and attributes for a file.
func
GetFileBasicInfo
(
f
*
os
.
File
)
(
*
FileBasicInfo
,
error
)
{
bi
:=
&
FileBasicInfo
{}
if
err
:=
getFileInformationByHandleEx
(
syscall
.
Handle
(
f
.
Fd
()),
fileBasicInfo
,
(
*
byte
)(
unsafe
.
Pointer
(
bi
)),
uint32
(
unsafe
.
Sizeof
(
*
bi
)));
err
!=
nil
{
return
nil
,
&
os
.
PathError
{
Op
:
"GetFileInformationByHandleEx"
,
Path
:
f
.
Name
(),
Err
:
err
}
}
return
bi
,
nil
}
// SetFileBasicInfo sets times and attributes for a file.
func
SetFileBasicInfo
(
f
*
os
.
File
,
bi
*
FileBasicInfo
)
error
{
if
err
:=
setFileInformationByHandle
(
syscall
.
Handle
(
f
.
Fd
()),
fileBasicInfo
,
(
*
byte
)(
unsafe
.
Pointer
(
bi
)),
uint32
(
unsafe
.
Sizeof
(
*
bi
)));
err
!=
nil
{
return
&
os
.
PathError
{
Op
:
"SetFileInformationByHandle"
,
Path
:
f
.
Name
(),
Err
:
err
}
}
return
nil
}
// FileIDInfo contains the volume serial number and file ID for a file. This pair should be
// unique on a system.
type
FileIDInfo
struct
{
VolumeSerialNumber
uint64
FileID
[
16
]
byte
}
// GetFileID retrieves the unique (volume, file ID) pair for a file.
func
GetFileID
(
f
*
os
.
File
)
(
*
FileIDInfo
,
error
)
{
fileID
:=
&
FileIDInfo
{}
if
err
:=
getFileInformationByHandleEx
(
syscall
.
Handle
(
f
.
Fd
()),
fileIDInfo
,
(
*
byte
)(
unsafe
.
Pointer
(
fileID
)),
uint32
(
unsafe
.
Sizeof
(
*
fileID
)));
err
!=
nil
{
return
nil
,
&
os
.
PathError
{
Op
:
"GetFileInformationByHandleEx"
,
Path
:
f
.
Name
(),
Err
:
err
}
}
return
fileID
,
nil
}
Godeps/_workspace/src/github.com/microsoft/go-winio/pipe.go
0 → 100644
View file @
467bb7a7
This diff is collapsed.
Click to expand it.
Godeps/_workspace/src/github.com/microsoft/go-winio/privilege.go
0 → 100644
View file @
467bb7a7
package
winio
import
(
"bytes"
"encoding/binary"
"fmt"
"runtime"
"syscall"
"unicode/utf16"
)
//sys adjustTokenPrivileges(token syscall.Handle, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges
//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf
//sys revertToSelf() (err error) = advapi32.RevertToSelf
//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *syscall.Handle) (err error) = advapi32.OpenThreadToken
//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread
//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW
//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
const
(
SE_PRIVILEGE_ENABLED
=
2
ERROR_NOT_ALL_ASSIGNED
syscall
.
Errno
=
1300
SeBackupPrivilege
=
"SeBackupPrivilege"
SeRestorePrivilege
=
"SeRestorePrivilege"
)
const
(
securityAnonymous
=
iota
securityIdentification
securityImpersonation
securityDelegation
)
type
PrivilegeError
struct
{
privileges
[]
uint64
}
func
(
e
*
PrivilegeError
)
Error
()
string
{
s
:=
""
if
len
(
e
.
privileges
)
>
1
{
s
=
"Could not enable privileges "
}
else
{
s
=
"Could not enable privilege "
}
for
i
,
p
:=
range
e
.
privileges
{
if
i
!=
0
{
s
+=
", "
}
s
+=
`"`
s
+=
getPrivilegeName
(
p
)
s
+=
`"`
}
return
s
}
func
RunWithPrivilege
(
name
string
,
fn
func
()
error
)
error
{
return
RunWithPrivileges
([]
string
{
name
},
fn
)
}
func
RunWithPrivileges
(
names
[]
string
,
fn
func
()
error
)
error
{
var
privileges
[]
uint64
for
_
,
name
:=
range
names
{
p
:=
uint64
(
0
)
err
:=
lookupPrivilegeValue
(
""
,
name
,
&
p
)
if
err
!=
nil
{
return
err
}
privileges
=
append
(
privileges
,
p
)
}
runtime
.
LockOSThread
()
defer
runtime
.
UnlockOSThread
()
token
,
err
:=
newThreadToken
()
if
err
!=
nil
{
return
err
}
defer
releaseThreadToken
(
token
)
err
=
adjustPrivileges
(
token
,
privileges
)
if
err
!=
nil
{
return
err
}
return
fn
()
}
func
adjustPrivileges
(
token
syscall
.
Handle
,
privileges
[]
uint64
)
error
{
var
b
bytes
.
Buffer
binary
.
Write
(
&
b
,
binary
.
LittleEndian
,
uint32
(
len
(
privileges
)))
for
_
,
p
:=
range
privileges
{
binary
.
Write
(
&
b
,
binary
.
LittleEndian
,
p
)
binary
.
Write
(
&
b
,
binary
.
LittleEndian
,
uint32
(
SE_PRIVILEGE_ENABLED
))
}
prevState
:=
make
([]
byte
,
b
.
Len
())
reqSize
:=
uint32
(
0
)
success
,
err
:=
adjustTokenPrivileges
(
token
,
false
,
&
b
.
Bytes
()[
0
],
uint32
(
len
(
prevState
)),
&
prevState
[
0
],
&
reqSize
)
if
!
success
{
return
err
}
if
err
==
ERROR_NOT_ALL_ASSIGNED
{
return
&
PrivilegeError
{
privileges
}
}
return
nil
}
func
getPrivilegeName
(
luid
uint64
)
string
{
var
nameBuffer
[
256
]
uint16
bufSize
:=
uint32
(
len
(
nameBuffer
))
err
:=
lookupPrivilegeName
(
""
,
&
luid
,
&
nameBuffer
[
0
],
&
bufSize
)
if
err
!=
nil
{
return
fmt
.
Sprintf
(
"<unknown privilege %d>"
,
luid
)
}
var
displayNameBuffer
[
256
]
uint16
displayBufSize
:=
uint32
(
len
(
displayNameBuffer
))
var
langId
uint32
err
=
lookupPrivilegeDisplayName
(
""
,
&
nameBuffer
[
0
],
&
displayNameBuffer
[
0
],
&
displayBufSize
,
&
langId
)
if
err
!=
nil
{
return
fmt
.
Sprintf
(
"<unknown privilege %s>"
,
utf16
.
Decode
(
nameBuffer
[
:
bufSize
]))
}
return
string
(
utf16
.
Decode
(
displayNameBuffer
[
:
displayBufSize
]))
}
func
newThreadToken
()
(
syscall
.
Handle
,
error
)
{
err
:=
impersonateSelf
(
securityImpersonation
)
if
err
!=
nil
{
panic
(
err
)
return
0
,
err
}
var
token
syscall
.
Handle
err
=
openThreadToken
(
getCurrentThread
(),
syscall
.
TOKEN_ADJUST_PRIVILEGES
|
syscall
.
TOKEN_QUERY
,
false
,
&
token
)
if
err
!=
nil
{
rerr
:=
revertToSelf
()
if
rerr
!=
nil
{
panic
(
rerr
)
}
return
0
,
err
}
return
token
,
nil
}
func
releaseThreadToken
(
h
syscall
.
Handle
)
{
err
:=
revertToSelf
()
if
err
!=
nil
{
panic
(
err
)
}
syscall
.
Close
(
h
)
}
Godeps/_workspace/src/github.com/microsoft/go-winio/reparse.go
0 → 100644
View file @
467bb7a7
package
winio
import
(
"bytes"
"encoding/binary"
"fmt"
"strings"
"unicode/utf16"
"unsafe"
)
const
(
reparseTagMountPoint
=
0xA0000003
reparseTagSymlink
=
0xA000000C
)
type
reparseDataBuffer
struct
{
ReparseTag
uint32
ReparseDataLength
uint16
Reserved
uint16
SubstituteNameOffset
uint16
SubstituteNameLength
uint16
PrintNameOffset
uint16
PrintNameLength
uint16
}
// ReparsePoint describes a Win32 symlink or mount point.
type
ReparsePoint
struct
{
Target
string
IsMountPoint
bool
}
// UnsupportedReparsePointError is returned when trying to decode a non-symlink or
// mount point reparse point.
type
UnsupportedReparsePointError
struct
{
Tag
uint32
}
func
(
e
*
UnsupportedReparsePointError
)
Error
()
string
{
return
fmt
.
Sprintf
(
"unsupported reparse point %x"
,
e
.
Tag
)
}
// DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink
// or a mount point.
func
DecodeReparsePoint
(
b
[]
byte
)
(
*
ReparsePoint
,
error
)
{
isMountPoint
:=
false
tag
:=
binary
.
LittleEndian
.
Uint32
(
b
[
0
:
4
])
switch
tag
{
case
reparseTagMountPoint
:
isMountPoint
=
true
case
reparseTagSymlink
:
default
:
return
nil
,
&
UnsupportedReparsePointError
{
tag
}
}
nameOffset
:=
16
+
binary
.
LittleEndian
.
Uint16
(
b
[
12
:
14
])
if
!
isMountPoint
{
nameOffset
+=
4
}
nameLength
:=
binary
.
LittleEndian
.
Uint16
(
b
[
14
:
16
])
name
:=
make
([]
uint16
,
nameLength
/
2
)
err
:=
binary
.
Read
(
bytes
.
NewReader
(
b
[
nameOffset
:
nameOffset
+
nameLength
]),
binary
.
LittleEndian
,
&
name
)
if
err
!=
nil
{
return
nil
,
err
}
return
&
ReparsePoint
{
string
(
utf16
.
Decode
(
name
)),
isMountPoint
},
nil
}
func
isDriveLetter
(
c
byte
)
bool
{
return
(
c
>=
'a'
&&
c
<=
'z'
)
||
(
c
>=
'A'
&&
c
<=
'Z'
)
}
// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or
// mount point.
func
EncodeReparsePoint
(
rp
*
ReparsePoint
)
[]
byte
{
// Generate an NT path and determine if this is a relative path.
var
ntTarget
string
relative
:=
false
if
strings
.
HasPrefix
(
rp
.
Target
,
`\\?\`
)
{
ntTarget
=
rp
.
Target
}
else
if
strings
.
HasPrefix
(
rp
.
Target
,
`\\`
)
{
ntTarget
=
`\??\UNC\`
+
rp
.
Target
[
2
:
]
}
else
if
len
(
rp
.
Target
)
>=
2
&&
isDriveLetter
(
rp
.
Target
[
0
])
&&
rp
.
Target
[
1
]
==
':'
{
ntTarget
=
`\??\`
+
rp
.
Target
}
else
{
ntTarget
=
rp
.
Target
relative
=
true
}
// The paths must be NUL-terminated even though they are counted strings.
target16
:=
utf16
.
Encode
([]
rune
(
rp
.
Target
+
"
\x00
"
))
ntTarget16
:=
utf16
.
Encode
([]
rune
(
ntTarget
+
"
\x00
"
))
size
:=
int
(
unsafe
.
Sizeof
(
reparseDataBuffer
{}))
-
8
size
+=
len
(
ntTarget16
)
*
2
+
len
(
target16
)
*
2
tag
:=
uint32
(
reparseTagMountPoint
)
if
!
rp
.
IsMountPoint
{
tag
=
reparseTagSymlink
size
+=
4
// Add room for symlink flags
}
data
:=
reparseDataBuffer
{
ReparseTag
:
tag
,
ReparseDataLength
:
uint16
(
size
),
SubstituteNameOffset
:
0
,
SubstituteNameLength
:
uint16
((
len
(
ntTarget16
)
-
1
)
*
2
),
PrintNameOffset
:
uint16
(
len
(
ntTarget16
)
*
2
),
PrintNameLength
:
uint16
((
len
(
target16
)
-
1
)
*
2
),
}
var
b
bytes
.
Buffer
binary
.
Write
(
&
b
,
binary
.
LittleEndian
,
&
data
)
if
!
rp
.
IsMountPoint
{
flags
:=
uint32
(
0
)
if
relative
{
flags
|=
1
}
binary
.
Write
(
&
b
,
binary
.
LittleEndian
,
flags
)
}
binary
.
Write
(
&
b
,
binary
.
LittleEndian
,
ntTarget16
)
binary
.
Write
(
&
b
,
binary
.
LittleEndian
,
target16
)
return
b
.
Bytes
()
}
Godeps/_workspace/src/github.com/microsoft/go-winio/sd.go
0 → 100644
View file @
467bb7a7
package
winio
import
(
"syscall"
"unsafe"
)
//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
//sys localFree(mem uintptr) = LocalFree
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
const
(
cERROR_NONE_MAPPED
=
syscall
.
Errno
(
1332
)
)
type
AccountLookupError
struct
{
Name
string
Err
error
}
func
(
e
*
AccountLookupError
)
Error
()
string
{
if
e
.
Name
==
""
{
return
"lookup account: empty account name specified"
}
var
s
string
switch
e
.
Err
{
case
cERROR_NONE_MAPPED
:
s
=
"not found"
default
:
s
=
e
.
Err
.
Error
()
}
return
"lookup account "
+
e
.
Name
+
": "
+
s
}
type
SddlConversionError
struct
{
Sddl
string
Err
error
}
func
(
e
*
SddlConversionError
)
Error
()
string
{
return
"convert "
+
e
.
Sddl
+
": "
+
e
.
Err
.
Error
()
}
// LookupSidByName looks up the SID of an account by name
func
LookupSidByName
(
name
string
)
(
sid
string
,
err
error
)
{
if
name
==
""
{
return
""
,
&
AccountLookupError
{
name
,
cERROR_NONE_MAPPED
}
}
var
sidSize
,
sidNameUse
,
refDomainSize
uint32
err
=
lookupAccountName
(
nil
,
name
,
nil
,
&
sidSize
,
nil
,
&
refDomainSize
,
&
sidNameUse
)
if
err
!=
nil
&&
err
!=
syscall
.
ERROR_INSUFFICIENT_BUFFER
{
return
""
,
&
AccountLookupError
{
name
,
err
}
}
sidBuffer
:=
make
([]
byte
,
sidSize
)
refDomainBuffer
:=
make
([]
uint16
,
refDomainSize
)
err
=
lookupAccountName
(
nil
,
name
,
&
sidBuffer
[
0
],
&
sidSize
,
&
refDomainBuffer
[
0
],
&
refDomainSize
,
&
sidNameUse
)
if
err
!=
nil
{
return
""
,
&
AccountLookupError
{
name
,
err
}
}
var
strBuffer
*
uint16
err
=
convertSidToStringSid
(
&
sidBuffer
[
0
],
&
strBuffer
)
if
err
!=
nil
{
return
""
,
&
AccountLookupError
{
name
,
err
}
}
sid
=
syscall
.
UTF16ToString
((
*
[
0xffff
]
uint16
)(
unsafe
.
Pointer
(
strBuffer
))[
:
])
localFree
(
uintptr
(
unsafe
.
Pointer
(
strBuffer
)))
return
sid
,
nil
}
func
SddlToSecurityDescriptor
(
sddl
string
)
([]
byte
,
error
)
{
var
sdBuffer
uintptr
err
:=
convertStringSecurityDescriptorToSecurityDescriptor
(
sddl
,
1
,
&
sdBuffer
,
nil
)
if
err
!=
nil
{
return
nil
,
&
SddlConversionError
{
sddl
,
err
}
}
defer
localFree
(
sdBuffer
)
sd
:=
make
([]
byte
,
getSecurityDescriptorLength
(
sdBuffer
))
copy
(
sd
,
(
*
[
0xffff
]
byte
)(
unsafe
.
Pointer
(
sdBuffer
))[
:
len
(
sd
)])
return
sd
,
nil
}
func
SecurityDescriptorToSddl
(
sd
[]
byte
)
(
string
,
error
)
{
var
sddl
*
uint16
// The returned string length seems to including an aribtrary number of terminating NULs.
// Don't use it.
err
:=
convertSecurityDescriptorToStringSecurityDescriptor
(
&
sd
[
0
],
1
,
0xff
,
&
sddl
,
nil
)
if
err
!=
nil
{
return
""
,
err
}
defer
localFree
(
uintptr
(
unsafe
.
Pointer
(
sddl
)))
return
syscall
.
UTF16ToString
((
*
[
0xffff
]
uint16
)(
unsafe
.
Pointer
(
sddl
))[
:
]),
nil
}
Godeps/_workspace/src/github.com/microsoft/go-winio/syscall.go
0 → 100644
View file @
467bb7a7
package
winio
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go
Godeps/_workspace/src/github.com/microsoft/go-winio/zsyscall.go
0 → 100644
View file @
467bb7a7
This diff is collapsed.
Click to expand it.
rpc/ipc_windows.go
View file @
467bb7a7
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment