diff options
| author | lhchavez <[email protected]> | 2019-01-12 20:56:16 +0000 |
|---|---|---|
| committer | lhchavez <[email protected]> | 2020-02-23 08:24:06 -0800 |
| commit | 37f732a833466e884fe6bf5b5612b677d485632a (patch) | |
| tree | baa6a80db2626285efca0c656b67c64cd3c1e65b | |
| parent | 45097a857c3df900111d49b9c07f2ad4645c1450 (diff) | |
Fix the Cred interface
This change adds Cred.Free() and finalizers to prevent memory leaks. It
also makes the interface for Cred more idiomatic and return actual
errors intead of ints.
| -rw-r--r-- | credentials.go | 82 | ||||
| -rw-r--r-- | remote.go | 12 |
2 files changed, 73 insertions, 21 deletions
diff --git a/credentials.go b/credentials.go index 038313b..5469b20 100644 --- a/credentials.go +++ b/credentials.go @@ -7,7 +7,10 @@ package git git_credtype_t _go_git_cred_credtype(git_cred *cred); */ import "C" -import "unsafe" +import ( + "runtime" + "unsafe" +) type CredType uint @@ -22,6 +25,12 @@ type Cred struct { ptr *C.git_cred } +func newCred() *Cred { + cred := &Cred{} + runtime.SetFinalizer(cred, (*Cred).Free) + return cred +} + func (o *Cred) HasUsername() bool { if C.git_cred_has_username(o.ptr) == 1 { return true @@ -33,24 +42,36 @@ func (o *Cred) Type() CredType { return (CredType)(C._go_git_cred_credtype(o.ptr)) } -func credFromC(ptr *C.git_cred) *Cred { - return &Cred{ptr} +func (o *Cred) Free() { + C.git_cred_free(o.ptr) + runtime.SetFinalizer(o, nil) + o.ptr = nil } -func NewCredUserpassPlaintext(username string, password string) (int, Cred) { - cred := Cred{} +func NewCredUserpassPlaintext(username string, password string) (*Cred, error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + cred := newCred() cusername := C.CString(username) defer C.free(unsafe.Pointer(cusername)) cpassword := C.CString(password) defer C.free(unsafe.Pointer(cpassword)) ret := C.git_cred_userpass_plaintext_new(&cred.ptr, cusername, cpassword) - return int(ret), cred + if ret != 0 { + cred.Free() + return nil, MakeGitError(ret) + } + return cred, nil } // NewCredSshKey creates new ssh credentials reading the public and private keys // from the file system. -func NewCredSshKey(username string, publicKeyPath string, privateKeyPath string, passphrase string) (int, Cred) { - cred := Cred{} +func NewCredSshKey(username string, publicKeyPath string, privateKeyPath string, passphrase string) (*Cred, error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + cred := newCred() cusername := C.CString(username) defer C.free(unsafe.Pointer(cusername)) cpublickey := C.CString(publicKeyPath) @@ -60,13 +81,20 @@ func NewCredSshKey(username string, publicKeyPath string, privateKeyPath string, cpassphrase := C.CString(passphrase) defer C.free(unsafe.Pointer(cpassphrase)) ret := C.git_cred_ssh_key_new(&cred.ptr, cusername, cpublickey, cprivatekey, cpassphrase) - return int(ret), cred + if ret != 0 { + cred.Free() + return nil, MakeGitError(ret) + } + return cred, nil } // NewCredSshKeyFromMemory creates new ssh credentials using the publicKey and privateKey // arguments as the values for the public and private keys. -func NewCredSshKeyFromMemory(username string, publicKey string, privateKey string, passphrase string) (int, Cred) { - cred := Cred{} +func NewCredSshKeyFromMemory(username string, publicKey string, privateKey string, passphrase string) (*Cred, error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + cred := newCred() cusername := C.CString(username) defer C.free(unsafe.Pointer(cusername)) cpublickey := C.CString(publicKey) @@ -76,19 +104,37 @@ func NewCredSshKeyFromMemory(username string, publicKey string, privateKey strin cpassphrase := C.CString(passphrase) defer C.free(unsafe.Pointer(cpassphrase)) ret := C.git_cred_ssh_key_memory_new(&cred.ptr, cusername, cpublickey, cprivatekey, cpassphrase) - return int(ret), cred + if ret != 0 { + cred.Free() + return nil, MakeGitError(ret) + } + return cred, nil } -func NewCredSshKeyFromAgent(username string) (int, Cred) { - cred := Cred{} +func NewCredSshKeyFromAgent(username string) (*Cred, error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + cred := newCred() cusername := C.CString(username) defer C.free(unsafe.Pointer(cusername)) ret := C.git_cred_ssh_key_from_agent(&cred.ptr, cusername) - return int(ret), cred + if ret != 0 { + cred.Free() + return nil, MakeGitError(ret) + } + return cred, nil } -func NewCredDefault() (int, Cred) { - cred := Cred{} +func NewCredDefault() (*Cred, error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + cred := newCred() ret := C.git_cred_default_new(&cred.ptr) - return int(ret), cred + if ret != 0 { + cred.Free() + return nil, MakeGitError(ret) + } + return cred, nil } @@ -51,7 +51,7 @@ const ( type TransportMessageCallback func(str string) ErrorCode type CompletionCallback func(RemoteCompletion) ErrorCode -type CredentialsCallback func(url string, username_from_url string, allowed_types CredType) (ErrorCode, *Cred) +type CredentialsCallback func(url string, username_from_url string, allowed_types CredType) (*Cred, error) type TransferProgressCallback func(stats TransferProgress) ErrorCode type UpdateTipsCallback func(refname string, a *Oid, b *Oid) ErrorCode type CertificateCheckCallback func(cert *Certificate, valid bool, hostname string) ErrorCode @@ -246,11 +246,17 @@ func credentialsCallback(_cred **C.git_cred, _url *C.char, _username_from_url *C } url := C.GoString(_url) username_from_url := C.GoString(_username_from_url) - ret, cred := callbacks.CredentialsCallback(url, username_from_url, (CredType)(allowed_types)) + cred, err := callbacks.CredentialsCallback(url, username_from_url, (CredType)(allowed_types)) + if err != nil { + if gitError, ok := err.(*GitError); ok { + return int(gitError.Code) + } + return C.GIT_EUSER + } if cred != nil { *_cred = cred.ptr } - return int(ret) + return 0 } //export transferProgressCallback |
