ronantakizawa/codereview-bench huggingface dataset:
Repository: gogs/gogs
File: internal/email/message.go (Go)

Code before:
	return buf.String()
}

type countingWriter struct {
	w io.Writer
	n int64
}

func (cw *countingWriter) Write(p []byte) (int, error) {
	n, err := cw.w.Write(p)
	cw.n += int64(n)
	return n, err
}

func (m *message) WriteTo(w io.Writer) (int64, error) {
	cw := &countingWriter{w: w}

	for _, field := range []string{"From", "To", "Subject", "Date"} {
		vals := m.header[field]
		if len(vals) == 0 {
			continue
		}

		var encoded string
		if field == "Subject" {
			encoded = mime.QEncoding.Encode("utf-8", vals[0])
		} else {
			encoded = sanitizeHeaderValue(strings.Join(vals, ", "))
		}
		if _, err := fmt.Fprintf(cw, "%s: %s\r\n", field, foldHeaderValue(len(field)+2, encoded)); err != nil {
			return cw.n, errors.Wrap(err, "write header")
		}
	}

	if len(m.altParts) > 0 {
		mw := multipart.NewWriter(cw)
		if _, err := fmt.Fprintf(cw, "MIME-Version: 1.0\r\n"); err != nil {
			return cw.n, errors.Wrap(err, "write MIME version")
		}
		if _, err := fmt.Fprintf(cw, "Content-Type: multipart/alternative; boundary=%s\r\n\r\n", mw.Boundary()); err != nil {
			return cw.n, errors.Wrap(err, "write content type")
		}

		mainHeader := textproto.MIMEHeader{}
		mainHeader.Set("Content-Type", m.contentType+"; charset=UTF-8")
		mainHeader.Set("Content-Transfer-Encoding", "quoted-printable")
		part, err := mw.CreatePart(mainHeader)
		if err != nil {
			return cw.n, errors.Wrap(err, "create main part")
		}
		if err := qpWrite(part, m.body); err != nil {

Review comment (security):
The `Subject` header is not run through `sanitizeHeaderValue` before encoding. If `vals[0]` can contain CR/LF, this enables header injection (additional arbitrary headers) despite the sanitization applied to other headers. Sanitize (or reject) CR/LF in the subject value before calling `mime.QEncoding.Encode`.
```suggestion
			encoded = mime.QEncoding.Encode("utf-8", sanitizeHeaderValue(vals[0]))
```

Code after:
	}

	clientOpts := []gomail.Option{
		gomail.WithPort(port),
	}

	if port == 465 {
		clientOpts = append(clientOpts, gomail.WithSSL())
	} else {
		clientOpts = append(clientOpts, gomail.WithTLSPolicy(gomail.TLSOpportunistic))
	}

	if opts.HELOHostname != "" {
		clientOpts = append(clientOpts, gomail.WithHELO(opts.HELOHostname))
	}

	tlsconfig := &tls.Config{
		InsecureSkipVerify: opts.SkipVerify,
		ServerName:         host,
	}
	if opts.UseCertificate {
		cert, err := tls.LoadX509KeyPair(opts.CertFile, opts.KeyFile)
		if err != nil {
			return nil, err
		}
		tlsconfig.Certificates = []tls.Certificate{cert}
	}
	clientOpts = append(clientOpts, gomail.WithTLSConfig(tlsconfig))

	if len(opts.User) > 0 {
		clientOpts = append(clientOpts,
			gomail.WithSMTPAuth(gomail.SMTPAuthAutoDiscover),
			gomail.WithUsername(opts.User),
			gomail.WithPassword(opts.Password),
		)
	}

	return gomail.NewClient(host, clientOpts...)
}

func sendMessage(msg *message) error {
	client, err := newSMTPClient()
	if err != nil {
		return err
	}
	return client.DialAndSend(msg.msg)
}

func processMailQueue() {
	for msg := range mailQueue {
		to := strings.Join(msg.msg.GetToString(), ", ")
Repository: gogs/gogs
File: internal/email/message.go (Go)

Code before:
package email

import (
	"crypto/tls"
	"net"
	"strconv"
	"strings"

	"github.com/inbucket/html2text"
	gomail "github.com/wneessen/go-mail"
	log "unknwon.dev/clog/v2"

	"gogs.io/gogs/internal/conf"
)

type message struct {
	info        string
	msg         *gomail.Msg
	confirmChan chan struct{}
}

func newMessageFrom(to []string, from, subject, htmlBody string) *message {
	log.Trace("NewMessageFrom (htmlBody):\n%s", htmlBody)

	m := gomail.NewMsg()
	if err := m.From(from); err != nil {
		log.Error("Failed to set From address %q: %v", from, err)
	}
	if err := m.To(to...); err != nil {
		log.Error("Failed to set To addresses: %v", err)
	}
	m.Subject(conf.Email.SubjectPrefix + subject)
	m.SetDate()

	if conf.Email.UsePlainText || conf.Email.AddPlainTextAlt {
		plainBody, err := html2text.FromString(htmlBody)
		if err != nil {
			log.Error("html2text.FromString: %v", err)
			m.SetBodyString(gomail.TypeTextHTML, htmlBody)
		} else if conf.Email.UsePlainText {
			m.SetBodyString(gomail.TypeTextPlain, plainBody)
		} else {
			m.SetBodyString(gomail.TypeTextPlain, plainBody)
			m.AddAlternativeString(gomail.TypeTextHTML, htmlBody)
		}
	} else {
		m.SetBodyString(gomail.TypeTextHTML, htmlBody)

Review comment (refactor):
this function should wrap and return errors only, `internal/email` is a helper package, only the call site of this package should determine how to handle the error.

Code after:
package email

import (
	"crypto/tls"
	"net"
	"strconv"
	"strings"

	"github.com/cockroachdb/errors"
	"github.com/inbucket/html2text"
	gomail "github.com/wneessen/go-mail"
	log "unknwon.dev/clog/v2"

	"gogs.io/gogs/internal/conf"
)

type message struct {
	info        string
	msg         *gomail.Msg
	confirmChan chan struct{}
}

func newMessageFrom(to []string, from, subject, htmlBody string) (*message, error) {
	log.Trace("NewMessageFrom (htmlBody):\n%s", htmlBody)

	m := gomail.NewMsg()
	if err := m.From(from); err != nil {
		return nil, errors.Wrapf(err, "set From address %q", from)
	}
	if err := m.To(to...); err != nil {
		return nil, errors.Wrap(err, "set To addresses")
	}
	m.Subject(conf.Email.SubjectPrefix + subject)
	m.SetDate()

	if conf.Email.UsePlainText || conf.Email.AddPlainTextAlt {
		plainBody, err := html2text.FromString(htmlBody)
		if err != nil {
			return nil, errors.Wrap(err, "convert HTML to plain text")
		}
		if conf.Email.UsePlainText {
			m.SetBodyString(gomail.TypeTextPlain, plainBody)
		} else {
			m.SetBodyString(gomail.TypeTextPlain, plainBody)
			m.AddAlternativeString(gomail.TypeTextHTML, htmlBody)
		}
	} else {
Repository: gogs/gogs
File: internal/email/message.go (Go)

Code before:
		msg:         m,
		confirmChan: make(chan struct{}),
	}, nil
}

func newMessage(to []string, subject, body string) (*message, error) {
	return newMessageFrom(to, conf.Email.From, subject, body)
}

func newSMTPClient() (*gomail.Client, error) {
	opts := conf.Email

	host, portStr, err := net.SplitHostPort(opts.Host)
	if err != nil {
		return nil, err
	}
	port, err := strconv.Atoi(portStr)
	if err != nil {
		return nil, err
	}

	clientOpts := []gomail.Option{
		gomail.WithPort(port),
	}

	if strings.HasSuffix(portStr, "465") {
		clientOpts = append(clientOpts, gomail.WithSSL())
	} else {
		clientOpts = append(clientOpts, gomail.WithTLSPolicy(gomail.TLSOpportunistic))
	}

	if opts.HELOHostname != "" {
		clientOpts = append(clientOpts, gomail.WithHELO(opts.HELOHostname))
	}

	tlsconfig := &tls.Config{
		InsecureSkipVerify: opts.SkipVerify,
		ServerName:         host,
	}
	if opts.UseCertificate {
		cert, err := tls.LoadX509KeyPair(opts.CertFile, opts.KeyFile)
		if err != nil {
			return nil, err
		}
		tlsconfig.Certificates = []tls.Certificate{cert}
	}
	clientOpts = append(clientOpts, gomail.WithTLSConfig(tlsconfig))

	if len(opts.User) > 0 {
		clientOpts = append(clientOpts,
			gomail.WithSMTPAuth(gomail.SMTPAuthAutoDiscover),

Review comment (bug):
The SSL/TLS detection logic at line 76 uses `strings.HasSuffix(portStr, "465")` which will incorrectly match any port ending in "465", such as "1465", "2465", etc. This should be an exact match: `portStr == "465"` or better yet, `port == 465` (using the integer port variable already parsed on line 67).
```suggestion
	if strings.EqualFold(portStr, "465") {
```

Code after:
		msg:         m,
		confirmChan: make(chan struct{}),
	}, nil
}

func newMessage(to []string, subject, body string) (*message, error) {
	return newMessageFrom(to, conf.Email.From, subject, body)
}

func newSMTPClient() (*gomail.Client, error) {
	opts := conf.Email

	host, portStr, err := net.SplitHostPort(opts.Host)
	if err != nil {
		return nil, err
	}
	port, err := strconv.Atoi(portStr)
	if err != nil {
		return nil, err
	}

	clientOpts := []gomail.Option{
		gomail.WithPort(port),
	}

	if port == 465 {
		clientOpts = append(clientOpts, gomail.WithSSL())
	} else {
		clientOpts = append(clientOpts, gomail.WithTLSPolicy(gomail.TLSOpportunistic))
	}

	if opts.HELOHostname != "" {
		clientOpts = append(clientOpts, gomail.WithHELO(opts.HELOHostname))
	}

	tlsconfig := &tls.Config{
		InsecureSkipVerify: opts.SkipVerify,
		ServerName:         host,
	}
	if opts.UseCertificate {
		cert, err := tls.LoadX509KeyPair(opts.CertFile, opts.KeyFile)
		if err != nil {
			return nil, err
		}
		tlsconfig.Certificates = []tls.Certificate{cert}
	}
	clientOpts = append(clientOpts, gomail.WithTLSConfig(tlsconfig))

	if len(opts.User) > 0 {
		clientOpts = append(clientOpts,
			gomail.WithSMTPAuth(gomail.SMTPAuthAutoDiscover),
Repository: gogs/gogs
File: internal/email/message.go (Go)

Code before:
		msg:         m,
		confirmChan: make(chan struct{}),
	}, nil
}

func newMessage(to []string, subject, body string) (*message, error) {
	return newMessageFrom(to, conf.Email.From, subject, body)
}

func newSMTPClient() (*gomail.Client, error) {
	opts := conf.Email

	host, portStr, err := net.SplitHostPort(opts.Host)
	if err != nil {
		return nil, err
	}
	port, err := strconv.Atoi(portStr)
	if err != nil {
		return nil, err
	}

	clientOpts := []gomail.Option{
		gomail.WithPort(port),
	}

	if strings.HasSuffix(portStr, "465") {
		clientOpts = append(clientOpts, gomail.WithSSL())
	} else {
		clientOpts = append(clientOpts, gomail.WithTLSPolicy(gomail.TLSOpportunistic))
	}

	if opts.HELOHostname != "" {
		clientOpts = append(clientOpts, gomail.WithHELO(opts.HELOHostname))
	}

	tlsconfig := &tls.Config{
		InsecureSkipVerify: opts.SkipVerify,
		ServerName:         host,
	}
	if opts.UseCertificate {
		cert, err := tls.LoadX509KeyPair(opts.CertFile, opts.KeyFile)
		if err != nil {
			return nil, err
		}
		tlsconfig.Certificates = []tls.Certificate{cert}
	}
	clientOpts = append(clientOpts, gomail.WithTLSConfig(tlsconfig))

	if len(opts.User) > 0 {
		clientOpts = append(clientOpts,
			gomail.WithSMTPAuth(gomail.SMTPAuthAutoDiscover),

Review comment (bug):
The port detection logic uses `strings.HasSuffix(portStr, "465")` which will incorrectly match ports like "1465", "2465", etc. This should be an exact equality check `portStr == "465"` to ensure only port 465 triggers implicit TLS mode.
```suggestion
	if portStr == "465" {
```

Code after:
		msg:         m,
		confirmChan: make(chan struct{}),
	}, nil
}

func newMessage(to []string, subject, body string) (*message, error) {
	return newMessageFrom(to, conf.Email.From, subject, body)
}

func newSMTPClient() (*gomail.Client, error) {
	opts := conf.Email

	host, portStr, err := net.SplitHostPort(opts.Host)
	if err != nil {
		return nil, err
	}
	port, err := strconv.Atoi(portStr)
	if err != nil {
		return nil, err
	}

	clientOpts := []gomail.Option{
		gomail.WithPort(port),
	}

	if port == 465 {
		clientOpts = append(clientOpts, gomail.WithSSL())
	} else {
		clientOpts = append(clientOpts, gomail.WithTLSPolicy(gomail.TLSOpportunistic))
	}

	if opts.HELOHostname != "" {
		clientOpts = append(clientOpts, gomail.WithHELO(opts.HELOHostname))
	}

	tlsconfig := &tls.Config{
		InsecureSkipVerify: opts.SkipVerify,
		ServerName:         host,
	}
	if opts.UseCertificate {
		cert, err := tls.LoadX509KeyPair(opts.CertFile, opts.KeyFile)
		if err != nil {
			return nil, err
		}
		tlsconfig.Certificates = []tls.Certificate{cert}
	}
	clientOpts = append(clientOpts, gomail.WithTLSConfig(tlsconfig))

	if len(opts.User) > 0 {
		clientOpts = append(clientOpts,
			gomail.WithSMTPAuth(gomail.SMTPAuthAutoDiscover),
Repository: gogs/gogs
File: internal/email/message.go (Go)

Code before:
package email

import (
	"crypto/tls"
	"io"
	"net"
	"net/smtp"
	"os"
	"strings"
	"time"

	"github.com/cockroachdb/errors"
	"github.com/inbucket/html2text"
	"gopkg.in/gomail.v2"
	log "unknwon.dev/clog/v2"

	"gogs.io/gogs/internal/conf"
)

type Message struct {
	Info string // Message information for log purpose.
	*gomail.Message
	confirmChan chan struct{}
}

// NewMessageFrom creates new mail message object with custom From header.
func NewMessageFrom(to []string, from, subject, htmlBody string) *Message {
	log.Trace("NewMessageFrom (htmlBody):\n%s", htmlBody)

	msg := gomail.NewMessage()
	msg.SetHeader("From", from)
	msg.SetHeader("To", to...)
	msg.SetHeader("Subject", conf.Email.SubjectPrefix+subject)
	msg.SetDateHeader("Date", time.Now())

	contentType := "text/html"
	body := htmlBody
	switchedToPlaintext := false
	if conf.Email.UsePlainText || conf.Email.AddPlainTextAlt {
		plainBody, err := html2text.FromString(htmlBody)
		if err != nil {
			log.Error("html2text.FromString: %v", err)
		} else {
			contentType = "text/plain"
			body = plainBody
			switchedToPlaintext = true
		}
	}
	msg.SetBody(contentType, body)

Review comment (security):
`newMessageFrom` logs the full rendered email body at trace level. These bodies can contain sensitive tokens (activation/reset codes) and user content, so this risks leaking secrets into logs if trace is enabled. Consider removing this log line or logging only non-sensitive metadata (e.g., template name, recipient count, body length) with any tokens redacted.
```suggestion
	log.Trace("NewMessageFrom: from=%q to=%v subject=%q bodyLen=%d", from, to, subject, len(htmlBody))
```

Code after:
package email

import (
	"crypto/tls"
	"net"
	"strconv"
	"strings"

	"github.com/cockroachdb/errors"
	"github.com/inbucket/html2text"
	gomail "github.com/wneessen/go-mail"
	log "unknwon.dev/clog/v2"

	"gogs.io/gogs/internal/conf"
)

type message struct {
	info        string
	msg         *gomail.Msg
	confirmChan chan struct{}
}

func newMessageFrom(to []string, from, subject, htmlBody string) (*message, error) {
	log.Trace("NewMessageFrom (htmlBody):\n%s", htmlBody)

	m := gomail.NewMsg()
	if err := m.From(from); err != nil {
		return nil, errors.Wrapf(err, "set From address %q", from)
	}
	if err := m.To(to...); err != nil {
		return nil, errors.Wrap(err, "set To addresses")
	}
	m.Subject(conf.Email.SubjectPrefix + subject)
	m.SetDate()

	if conf.Email.UsePlainText || conf.Email.AddPlainTextAlt {
		plainBody, err := html2text.FromString(htmlBody)
		if err != nil {
			return nil, errors.Wrap(err, "convert HTML to plain text")
		}
		if conf.Email.UsePlainText {
			m.SetBodyString(gomail.TypeTextPlain, plainBody)
		} else {
			m.SetBodyString(gomail.TypeTextPlain, plainBody)
			m.AddAlternativeString(gomail.TypeTextHTML, htmlBody)
		}
	} else {
		m.SetBodyString(gomail.TypeTextHTML, htmlBody)
	}
Repository: gogs/gogs
File: internal/lfsutil/storage.go (Go)

Code before:
			// return the existing file's size.
			_, _ = io.Copy(io.Discard, rc)
			fi, statErr := os.Stat(fpath)
			if statErr != nil {
				err = errors.Wrap(statErr, "stat existing file")
				return 0, err
			}
			err = nil
			return fi.Size(), nil
		}
		return 0, errors.Wrap(err, "create file")
	}
	defer w.Close()

	hash := sha256.New()
	written, err := io.Copy(w, io.TeeReader(rc, hash))
	if err != nil {
		return 0, errors.Wrap(err, "copy file")
	}

	if computed := hex.EncodeToString(hash.Sum(nil)); computed != string(oid) {
		err = ErrOIDMismatch
		return 0, err
	}
	return written, nil
}

func (s *LocalStorage) Download(oid OID, w io.Writer) error {
	fpath := s.storagePath(oid)
	if !osutil.IsFile(fpath) {
		return ErrObjectNotExist
	}

	r, err := os.Open(fpath)
	if err != nil {
		return errors.Wrap(err, "open file")
	}
	defer r.Close()

	_, err = io.Copy(w, r)
	if err != nil {
		return errors.Wrap(err, "copy file")
	}
	return nil
}


Review comment (suggestion):
`ErrOIDMismatch` is newly returned from `Upload`, but there are no non-test references handling it in the codebase. As-is, the LFS upload route will treat it as an internal error and likely return 500, even though it’s a client/input error. Add explicit handling at call sites (e.g., map to 400/422 with a clear message) so clients get an appropriate response.

Code after:
	if err := os.MkdirAll(s.TempDir, os.ModePerm); err != nil {
		return 0, errors.Wrap(err, "create temp directory")
	}
	tmp, err := os.CreateTemp(s.TempDir, "upload-*")
	if err != nil {
		return 0, errors.Wrap(err, "create temp file")
	}
	tmpPath := tmp.Name()
	defer os.Remove(tmpPath)

	hash := sha256.New()
	written, err := io.Copy(tmp, io.TeeReader(rc, hash))
	if closeErr := tmp.Close(); err == nil && closeErr != nil {
		err = closeErr
	}
	if err != nil {
		return 0, errors.Wrap(err, "write object file")
	}

	if computed := hex.EncodeToString(hash.Sum(nil)); computed != string(oid) {
		return 0, ErrOIDMismatch
	}

	if err := os.Rename(tmpPath, fpath); err != nil && !os.IsExist(err) {
		return 0, errors.Wrap(err, "publish object file")
	}
	return written, nil
}

func (s *LocalStorage) Download(oid OID, w io.Writer) error {
	fpath := s.storagePath(oid)
	if !osutil.IsFile(fpath) {
		return ErrObjectNotExist
	}

	r, err := os.Open(fpath)
	if err != nil {
		return errors.Wrap(err, "open file")
	}
	defer r.Close()

	_, err = io.Copy(w, r)
	if err != nil {
		return errors.Wrap(err, "copy file")
	}
	return nil
}
Repository: gogs/gogs
File: internal/lfsutil/storage.go (Go)

Code before:
	}()

	err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm)
	if err != nil {
		return 0, errors.Wrap(err, "create directories")
	}

	w, err := os.OpenFile(fpath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o666)
	if err != nil {
		if os.IsExist(err) {
			// The file was already written by a previous upload (possibly for a
			// different repo). Since the OID is a content hash, the existing file
			// is guaranteed to have the correct content. Drain the reader and
			// return the existing file's size.
			_, _ = io.Copy(io.Discard, rc)
			fi, statErr := os.Stat(fpath)
			if statErr != nil {
				err = errors.Wrap(statErr, "stat existing file")
				return 0, err
			}
			err = nil
			return fi.Size(), nil
		}
		return 0, errors.Wrap(err, "create file")
	}
	defer w.Close()

	hash := sha256.New()
	written, err := io.Copy(w, io.TeeReader(rc, hash))
	if err != nil {
		return 0, errors.Wrap(err, "copy file")
	}

	if computed := hex.EncodeToString(hash.Sum(nil)); computed != string(oid) {
		err = ErrOIDMismatch
		return 0, err
	}
	return written, nil
}

func (s *LocalStorage) Download(oid OID, w io.Writer) error {
	fpath := s.storagePath(oid)
	if !osutil.IsFile(fpath) {
		return ErrObjectNotExist
	}

	r, err := os.Open(fpath)
	if err != nil {
		return errors.Wrap(err, "open file")
	}
	defer r.Close()

Review comment (bug):
File handle may be writable as a result of data flow from a [call to OpenFile](1) and closing it may result in data loss upon failure, which is not handled explicitly.
```suggestion
	defer func() {
		if cerr := w.Close(); cerr != nil {
			err = errors.CombineErrors(err, errors.Wrap(cerr, "close file"))
		}
	}()
```

Code after:
		return 0, errors.Wrap(err, "create directories")
	}

	// If the object file already exists, skip the upload and return the
	// existing file's size.
	if fi, err := os.Stat(fpath); err == nil {
		_, _ = io.Copy(io.Discard, rc)
		return fi.Size(), nil
	}

	// Write to a temp file and verify the content hash before publishing.
	// This ensures the final path always contains a complete, hash-verified
	// file, even when concurrent uploads of the same OID race.
	if err := os.MkdirAll(s.TempDir, os.ModePerm); err != nil {
		return 0, errors.Wrap(err, "create temp directory")
	}
	tmp, err := os.CreateTemp(s.TempDir, "upload-*")
	if err != nil {
		return 0, errors.Wrap(err, "create temp file")
	}
	tmpPath := tmp.Name()
	defer os.Remove(tmpPath)

	hash := sha256.New()
	written, err := io.Copy(tmp, io.TeeReader(rc, hash))
	if closeErr := tmp.Close(); err == nil && closeErr != nil {
		err = closeErr
	}
	if err != nil {
		return 0, errors.Wrap(err, "write object file")
	}

	if computed := hex.EncodeToString(hash.Sum(nil)); computed != string(oid) {
		return 0, ErrOIDMismatch
	}

	if err := os.Rename(tmpPath, fpath); err != nil && !os.IsExist(err) {
		return 0, errors.Wrap(err, "publish object file")
	}
	return written, nil
}

func (s *LocalStorage) Download(oid OID, w io.Writer) error {
	fpath := s.storagePath(oid)
	if !osutil.IsFile(fpath) {
		return ErrObjectNotExist
	}

	r, err := os.Open(fpath)
	if err != nil {
		return errors.Wrap(err, "open file")
Repository: gogs/gogs
File: internal/lfsutil/storage.go (Go)

Code before:
package lfsutil

import (
	"crypto/sha256"
	"encoding/hex"
	"io"
	"os"
	"path/filepath"

	"github.com/cockroachdb/errors"

	"gogs.io/gogs/internal/osutil"
)

var (
	ErrObjectNotExist = errors.New("Object does not exist")
	ErrOIDMismatch    = errors.New("content hash does not match OID")
)

// Storager is an storage backend for uploading and downloading LFS objects.
type Storager interface {
	// Storage returns the name of the storage backend.
	Storage() Storage
	// Upload reads content from the io.ReadCloser and uploads as given oid.
	// The reader is closed once upload is finished. ErrInvalidOID is returned
	// if the given oid is not valid.
	Upload(oid OID, rc io.ReadCloser) (int64, error)
	// Download streams content of given oid to the io.Writer. It is caller's
	// responsibility the close the writer when needed. ErrObjectNotExist is
	// returned if the given oid does not exist.
	Download(oid OID, w io.Writer) error
}

// Storage is the storage type of an LFS object.
type Storage string

const (
	StorageLocal Storage = "local"
)

var _ Storager = (*LocalStorage)(nil)

Review comment (suggestion):
```suggestion
	ErrObjectNotExist = errors.New("object does not exist")
```

Code after:
package lfsutil

import (
	"crypto/sha256"
	"encoding/hex"
	"io"
	"os"
	"path/filepath"

	"github.com/cockroachdb/errors"

	"gogs.io/gogs/internal/osutil"
)

var (
	ErrObjectNotExist = errors.New("object does not exist")
	ErrOIDMismatch    = errors.New("content hash does not match OID")
)

// Storager is an storage backend for uploading and downloading LFS objects.
type Storager interface {
	// Storage returns the name of the storage backend.
	Storage() Storage
	// Upload reads content from the io.ReadCloser and uploads as given oid.
	// The reader is closed once upload is finished. ErrInvalidOID is returned
	// if the given oid is not valid.
	Upload(oid OID, rc io.ReadCloser) (int64, error)
	// Download streams content of given oid to the io.Writer. It is caller's
	// responsibility the close the writer when needed. ErrObjectNotExist is
	// returned if the given oid does not exist.
	Download(oid OID, w io.Writer) error
}

// Storage is the storage type of an LFS object.
type Storage string

const (
	StorageLocal Storage = "local"
)

var _ Storager = (*LocalStorage)(nil)