#3281 fix x.Iterate returns nothing inside session scope with SQLite3

This commit is contained in:
Unknwon 2016-07-26 17:26:48 +08:00
parent 4d8b905541
commit 2d76de2574
6 changed files with 35 additions and 98 deletions

View file

@ -3,7 +3,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra
![](https://github.com/gogits/gogs/blob/master/public/img/gogs-large-resize.png?raw=true) ![](https://github.com/gogits/gogs/blob/master/public/img/gogs-large-resize.png?raw=true)
##### Current tip version: 0.9.56 (see [Releases](https://github.com/gogits/gogs/releases) for binary versions) ##### Current tip version: 0.9.57 (see [Releases](https://github.com/gogits/gogs/releases) for binary versions)
| Web | UI | Preview | | Web | UI | Preview |
|:-------------:|:-------:|:-------:| |:-------------:|:-------:|:-------:|

View file

@ -17,7 +17,7 @@ import (
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
const APP_VER = "0.9.56.0726" const APP_VER = "0.9.57.0726"
func init() { func init() {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())

View file

@ -27,9 +27,10 @@ type Engine interface {
Exec(string, ...interface{}) (sql.Result, error) Exec(string, ...interface{}) (sql.Result, error)
Find(interface{}, ...interface{}) error Find(interface{}, ...interface{}) error
Get(interface{}) (bool, error) Get(interface{}) (bool, error)
Id(interface{}) *xorm.Session
Insert(...interface{}) (int64, error) Insert(...interface{}) (int64, error)
InsertOne(interface{}) (int64, error) InsertOne(interface{}) (int64, error)
Id(interface{}) *xorm.Session Iterate(interface{}, xorm.IterFunc) error
Sql(string, ...interface{}) *xorm.Session Sql(string, ...interface{}) *xorm.Session
Where(string, ...interface{}) *xorm.Session Where(string, ...interface{}) *xorm.Session
} }

View file

@ -5,12 +5,10 @@
package models package models
import ( import (
"bufio"
"encoding/base64" "encoding/base64"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"math/big" "math/big"
"os" "os"
@ -24,6 +22,7 @@ import (
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process" "github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
@ -457,96 +456,20 @@ func ListPublicKeys(uid int64) ([]*PublicKey, error) {
return keys, x.Where("owner_id = ?", uid).Find(&keys) return keys, x.Where("owner_id = ?", uid).Find(&keys)
} }
// rewriteAuthorizedKeys finds and deletes corresponding line in authorized_keys file.
func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error {
fr, err := os.Open(p)
if err != nil {
return err
}
defer fr.Close()
fw, err := os.OpenFile(tmpP, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil {
return err
}
defer fw.Close()
isFound := false
keyword := fmt.Sprintf("key-%d", key.ID)
buf := bufio.NewReader(fr)
for {
line, errRead := buf.ReadString('\n')
line = strings.TrimSpace(line)
if errRead != nil {
if errRead != io.EOF {
return errRead
}
// Reached end of file, if nothing to read then break,
// otherwise handle the last line.
if len(line) == 0 {
break
}
}
// Found the line and copy rest of file.
if !isFound && strings.Contains(line, keyword) && strings.Contains(line, key.Content) {
isFound = true
continue
}
// Still finding the line, copy the line that currently read.
if _, err = fw.WriteString(line + "\n"); err != nil {
return err
}
if errRead == io.EOF {
break
}
}
if !isFound {
log.Warn("SSH key %d not found in authorized_keys file for deletion", key.ID)
}
return nil
}
// UpdatePublicKey updates given public key. // UpdatePublicKey updates given public key.
func UpdatePublicKey(key *PublicKey) error { func UpdatePublicKey(key *PublicKey) error {
_, err := x.Id(key.ID).AllCols().Update(key) _, err := x.Id(key.ID).AllCols().Update(key)
return err return err
} }
func deletePublicKey(e *xorm.Session, keyID int64) error { // deletePublicKeys does the actual key deletion but does not update authorized_keys file.
sshOpLocker.Lock() func deletePublicKeys(e *xorm.Session, keyIDs ...int64) error {
defer sshOpLocker.Unlock() if len(keyIDs) == 0 {
key := &PublicKey{ID: keyID}
has, err := e.Get(key)
if err != nil {
return err
} else if !has {
return nil return nil
} }
if _, err = e.Id(key.ID).Delete(new(PublicKey)); err != nil { _, err := e.In("id", strings.Join(base.Int64sToStrings(keyIDs), ",")).Delete(new(PublicKey))
return err return err
}
// Don't need to rewrite this file if builtin SSH server is enabled.
if setting.SSH.StartBuiltinServer {
return nil
}
fpath := filepath.Join(setting.SSH.RootPath, "authorized_keys")
tmpPath := fpath + ".tmp"
if err = rewriteAuthorizedKeys(key, fpath, tmpPath); err != nil {
return err
} else if err = os.Remove(fpath); err != nil {
return err
}
return os.Rename(tmpPath, fpath)
} }
// DeletePublicKey deletes SSH key information both in database and authorized_keys file. // DeletePublicKey deletes SSH key information both in database and authorized_keys file.
@ -570,14 +493,20 @@ func DeletePublicKey(doer *User, id int64) (err error) {
return err return err
} }
if err = deletePublicKey(sess, id); err != nil { if err = deletePublicKeys(sess, id); err != nil {
return err return err
} }
return sess.Commit() if err = sess.Commit(); err != nil {
return err
}
return RewriteAllPublicKeys()
} }
// RewriteAllPublicKeys removes any authorized key and rewrite all keys from database again. // RewriteAllPublicKeys removes any authorized key and rewrite all keys from database again.
// Note: x.Iterate does not get latest data after insert/delete, so we have to call this function
// outsite any session scope independently.
func RewriteAllPublicKeys() error { func RewriteAllPublicKeys() error {
sshOpLocker.Lock() sshOpLocker.Lock()
defer sshOpLocker.Unlock() defer sshOpLocker.Unlock()
@ -814,7 +743,7 @@ func DeleteDeployKey(doer *User, id int64) error {
if err != nil { if err != nil {
return err return err
} else if !has { } else if !has {
if err = deletePublicKey(sess, key.KeyID); err != nil { if err = deletePublicKeys(sess, key.KeyID); err != nil {
return err return err
} }
} }

View file

@ -768,10 +768,13 @@ func deleteUser(e *xorm.Session, u *User) error {
if err = e.Find(&keys, &PublicKey{OwnerID: u.ID}); err != nil { if err = e.Find(&keys, &PublicKey{OwnerID: u.ID}); err != nil {
return fmt.Errorf("get all public keys: %v", err) return fmt.Errorf("get all public keys: %v", err)
} }
for _, key := range keys {
if err = deletePublicKey(e, key.ID); err != nil { keyIDs := make([]int64, len(keys))
return fmt.Errorf("deletePublicKey: %v", err) for i := range keys {
} keyIDs[i] = keys[i].ID
}
if err = deletePublicKeys(e, keyIDs...); err != nil {
return fmt.Errorf("deletePublicKeys: %v", err)
} }
// ***** END: PublicKey ***** // ***** END: PublicKey *****
@ -788,7 +791,6 @@ func deleteUser(e *xorm.Session, u *User) error {
// Note: There are something just cannot be roll back, // Note: There are something just cannot be roll back,
// so just keep error logs of those operations. // so just keep error logs of those operations.
RewriteAllPublicKeys()
os.RemoveAll(UserPath(u.Name)) os.RemoveAll(UserPath(u.Name))
os.Remove(u.CustomAvatarPath()) os.Remove(u.CustomAvatarPath())
@ -809,15 +811,20 @@ func DeleteUser(u *User) (err error) {
return err return err
} }
return sess.Commit() if err = sess.Commit(); err != nil {
return err
}
return RewriteAllPublicKeys()
} }
// DeleteInactivateUsers deletes all inactivate users and email addresses. // DeleteInactivateUsers deletes all inactivate users and email addresses.
func DeleteInactivateUsers() (err error) { func DeleteInactivateUsers() (err error) {
users := make([]*User, 0, 10) users := make([]*User, 0, 10)
if err = x.Where("is_active=?", false).Find(&users); err != nil { if err = x.Where("is_active = ?", false).Find(&users); err != nil {
return fmt.Errorf("get all inactive users: %v", err) return fmt.Errorf("get all inactive users: %v", err)
} }
// FIXME: should only update authorized_keys file once after all deletions.
for _, u := range users { for _, u := range users {
if err = DeleteUser(u); err != nil { if err = DeleteUser(u); err != nil {
// Ignore users that were set inactive by admin. // Ignore users that were set inactive by admin.
@ -828,7 +835,7 @@ func DeleteInactivateUsers() (err error) {
} }
} }
_, err = x.Where("is_activated=?", false).Delete(new(EmailAddress)) _, err = x.Where("is_activated = ?", false).Delete(new(EmailAddress))
return err return err
} }

View file

@ -1 +1 @@
0.9.56.0726 0.9.57.0726