ronantakizawa/codereview-bench huggingface dataset:
Repository: syncthing/syncthing
File: lib/fs/basicfs_windows.go (Go)

Code before:
	for _, part := range parts {
		if len(part) == 0 {
			break
		}
		drives = append(drives, string(part))
	}

	return drives, nil
}

func (f *BasicFilesystem) resolveWin83(absPath string) string {
	if !strings.Contains(absPath, "~") {
		return absPath
	}
	if in, err := syscall.UTF16FromString(absPath); err != nil {
		out := make([]uint16, 2*len(absPath))
		n := uint32(len(out))
		for {
			n, err = syscall.GetLongPathName(&in[0], &out[0], n)
			if err != nil {
				break
			}
			if n <= uint32(len(out)) {
				return syscall.UTF16ToString(out[:n])
			}
			out = make([]uint16, n)
		}
	}
	// Failed getting the long path. Return the part of the path which is
	// already a long path.
	for absPath = filepath.Dir(absPath); strings.HasPrefix(absPath, f.rootSymlinkEvaluated); absPath = filepath.Dir(absPath) {
		if !strings.Contains(absPath, "~") {
			return absPath
		}
	}
	return f.rootSymlinkEvaluated
}


Review comment (bug):
The returned `n` is:

> the length, in TCHARs, of the string copied to lpszLongPath, not including the terminating null character.

Apparently `TCHAR` can mean `char` or `wchar_t` depending on whether your project is compiled as unicode or not. I'm not sure what Go does here, but it's possible that it might actually want a buffer with `2*n` *bytes*. 

If it does, this combined with the loop will throw this function into an infinite loop. I think one of those test things might be a good idea here...

Code after:
	for _, part := range parts {
		if len(part) == 0 {
			break
		}
		drives = append(drives, string(part))
	}

	return drives, nil
}

func (f *BasicFilesystem) resolveWin83(absPath string) string {
	if !isMaybeWin83(absPath) {
		return absPath
	}
	if in, err := syscall.UTF16FromString(absPath); err == nil {
		out := make([]uint16, 4*len(absPath)) // *2 for UTF16 and *2 to double path length
		if n, err := syscall.GetLongPathName(&in[0], &out[0], uint32(len(out))); err == nil {
			if n <= uint32(len(out)) {
				return syscall.UTF16ToString(out[:n])
			}
			out = make([]uint16, n)
			if _, err = syscall.GetLongPathName(&in[0], &out[0], n); err == nil {
				return syscall.UTF16ToString(out)
			}
		}
	}
	// Failed getting the long path. Return the part of the path which is
	// already a long path.
	for absPath = filepath.Dir(absPath); strings.HasPrefix(absPath, f.rootSymlinkEvaluated); absPath = filepath.Dir(absPath) {
		if !isMaybeWin83(absPath) {
			return absPath
		}
	}
	return f.rootSymlinkEvaluated
}

func isMaybeWin83(absPath string) bool {
	if !strings.Contains(absPath, "~") {
		return false
	}
	if strings.Contains(filepath.Dir(absPath), "~") {
		return true
	}
	return strings.Contains(strings.TrimPrefix(filepath.Base(absPath), WindowsTempPrefix), "~")
}
Repository: syncthing/syncthing
File: lib/fs/basicfs_windows.go (Go)

Code before:
	hr, _, _ := getLogicalDriveStringsHandle.Call(uintptr(unsafe.Pointer(&bufferSize)), uintptr(unsafe.Pointer(&buffer)))
	if hr == 0 {
		return nil, fmt.Errorf("Syscall failed")
	}

	var drives []string
	parts := bytes.Split(buffer[:], []byte{0})
	for _, part := range parts {
		if len(part) == 0 {
			break
		}
		drives = append(drives, string(part))
	}

	return drives, nil
}

func (f *BasicFilesystem) resolveWin83(absPath string) string {
	if !strings.Contains(absPath, "~") {
		return absPath
	}
	if in, err := syscall.UTF16FromString(absPath); err != nil {
		out := make([]uint16, 2*len(absPath))
		n := uint32(len(out))
		for {
			n, err = syscall.GetLongPathName(&in[0], &out[0], n)
			if err != nil {
				break
			}
			if n <= uint32(len(out)) {
				return syscall.UTF16ToString(out[:n])
			}
			out = make([]uint16, n)
		}
	}
	// Failed getting the long path. Return the part of the path which is
	// already a long path.
	for absPath = filepath.Dir(absPath); strings.HasPrefix(absPath, f.rootSymlinkEvaluated); absPath = filepath.Dir(absPath) {
		if !strings.Contains(absPath, "~") {
			return absPath
		}
	}
	return f.rootSymlinkEvaluated
}


Review comment (suggestion):
According to this docs, the last param is:

> The size of the buffer lpszLongPath points to, in TCHARs.

Apparently TCHAR can mean char or wchar_t depending on whether your project is compiled as unicode or not. I'm not sure what Go does here, but it's possible you're telling `GetLongPathName` that it's got double the amount of space available that it actually does.

Code after:
	hr, _, _ := getLogicalDriveStringsHandle.Call(uintptr(unsafe.Pointer(&bufferSize)), uintptr(unsafe.Pointer(&buffer)))
	if hr == 0 {
		return nil, fmt.Errorf("Syscall failed")
	}

	var drives []string
	parts := bytes.Split(buffer[:], []byte{0})
	for _, part := range parts {
		if len(part) == 0 {
			break
		}
		drives = append(drives, string(part))
	}

	return drives, nil
}

func (f *BasicFilesystem) resolveWin83(absPath string) string {
	if !isMaybeWin83(absPath) {
		return absPath
	}
	if in, err := syscall.UTF16FromString(absPath); err == nil {
		out := make([]uint16, 4*len(absPath)) // *2 for UTF16 and *2 to double path length
		if n, err := syscall.GetLongPathName(&in[0], &out[0], uint32(len(out))); err == nil {
			if n <= uint32(len(out)) {
				return syscall.UTF16ToString(out[:n])
			}
			out = make([]uint16, n)
			if _, err = syscall.GetLongPathName(&in[0], &out[0], n); err == nil {
				return syscall.UTF16ToString(out)
			}
		}
	}
	// Failed getting the long path. Return the part of the path which is
	// already a long path.
	for absPath = filepath.Dir(absPath); strings.HasPrefix(absPath, f.rootSymlinkEvaluated); absPath = filepath.Dir(absPath) {
		if !isMaybeWin83(absPath) {
			return absPath
		}
	}
	return f.rootSymlinkEvaluated
}

func isMaybeWin83(absPath string) bool {
	if !strings.Contains(absPath, "~") {
		return false
	}
	if strings.Contains(filepath.Dir(absPath), "~") {
		return true
	}
	return strings.Contains(strings.TrimPrefix(filepath.Base(absPath), WindowsTempPrefix), "~")
Repository: syncthing/syncthing
File: lib/model/folder.go (Go)

Code before:
	f.scanNow <- req
	return <-req.err
}

func (f *folder) Reschedule() {
	if f.scanInterval == 0 {
		return
	}
	// Sleep a random time between 3/4 and 5/4 of the configured interval.
	sleepNanos := (f.scanInterval.Nanoseconds()*3 + rand.Int63n(2*f.scanInterval.Nanoseconds())) / 4
	interval := time.Duration(sleepNanos) * time.Nanosecond
	l.Debugln(f, "next rescan in", interval)
	f.scanTimer.Reset(interval)
}

func (f *folder) Delay(next time.Duration) {
	f.scanDelay <- next
}

func (f *folder) Stop() {
	f.cancel()
}

func (f *folder) Stopped() <-chan struct{} {
	return f.stopped
}

// CheckHealth checks the folder for common errors, updates the folder state
// and returns the current folder error, or nil if the folder is healthy.
func (f *folder) CheckHealth() error {
	err := f.getHealthError()
	f.setError(err)
	return err
}

func (f *folder) getHealthError() error {
	// Check for folder errors, with the most serious and specific first and
	// generic ones like out of space on the home disk later.

	if err := f.CheckPath(); err != nil {
		return err
	}

	if err := f.CheckFreeSpace(); err != nil {
		return err
	}

	if err := f.model.cfg.CheckHomeFreeSpace(); err != nil {
		return err
	}


Review comment (suggestion):
I *think*, Stop() could wait for f.stopped to be closed, at which point m.Remove(id) would block until Stop() returns.

Code after:
	f.scanNow <- req
	return <-req.err
}

func (f *folder) Reschedule() {
	if f.scanInterval == 0 {
		return
	}
	// Sleep a random time between 3/4 and 5/4 of the configured interval.
	sleepNanos := (f.scanInterval.Nanoseconds()*3 + rand.Int63n(2*f.scanInterval.Nanoseconds())) / 4
	interval := time.Duration(sleepNanos) * time.Nanosecond
	l.Debugln(f, "next rescan in", interval)
	f.scanTimer.Reset(interval)
}

func (f *folder) Delay(next time.Duration) {
	f.scanDelay <- next
}

func (f *folder) Stop() {
	f.cancel()
	<-f.stopped
}

// CheckHealth checks the folder for common errors, updates the folder state
// and returns the current folder error, or nil if the folder is healthy.
func (f *folder) CheckHealth() error {
	err := f.getHealthError()
	f.setError(err)
	return err
}

func (f *folder) getHealthError() error {
	// Check for folder errors, with the most serious and specific first and
	// generic ones like out of space on the home disk later.

	if err := f.CheckPath(); err != nil {
		return err
	}

	if err := f.CheckFreeSpace(); err != nil {
		return err
	}

	if err := f.model.cfg.CheckHomeFreeSpace(); err != nil {
		return err
	}

	return nil
}
Repository: syncthing/syncthing
File: cmd/strelaypoolsrv/stats.go (Go)

Code before:
}

// Due to some unexplainable behaviour, some of the numbers sometimes travel slightly backwards (by less than 1%)
// This happens between scrapes, which is 30s, so this can't be a race.
// This causes prometheus to assume a "rate reset", hence causes phenomenal spikes.
// One of the number that moves backwards is BytesProxied, which atomically increments a counter with numeric value
// returned by net.Conn.Read(). I don't think that can return a negative value, so I have no idea what's going on.
func mergeStats(new stats, old stats) stats {
	new.UptimeSeconds = mergeValue(new.UptimeSeconds, old.UptimeSeconds)
	new.PendingSessionKeys = mergeValue(new.PendingSessionKeys, old.PendingSessionKeys)
	new.ActiveSessions = mergeValue(new.ActiveSessions, old.ActiveSessions)
	new.Connections = mergeValue(new.Connections, old.Connections)
	new.Proxies = mergeValue(new.Proxies, old.Proxies)
	new.BytesProxied = mergeValue(new.BytesProxied, old.BytesProxied)
	new.GoRoutines = mergeValue(new.GoRoutines, old.GoRoutines)
	new.Options.SessionRate = mergeValue(new.Options.SessionRate, old.Options.SessionRate)
	new.Options.GlobalRate = mergeValue(new.Options.GlobalRate, old.Options.GlobalRate)
	return new
}

func mergeValue(new, old int) int {
	if new >= old || old == 0 || new == 0 {
		return new
	}
	delta := (float64(old-new) * 100) / float64(new)
	if delta > 1.0 {
		return new
	}
	return old
}


Review comment (bug):
Does this intentionally return `new` if `old` is 1% *larger* than `new` or is my brain failing? And what's the 1% thing anyway? From the comment on `mergeStats` I'd expect a simple `if new < old { return old } return new`.

Code after:
}

// Due to some unexplainable behaviour, some of the numbers sometimes travel slightly backwards (by less than 1%)
// This happens between scrapes, which is 30s, so this can't be a race.
// This causes prometheus to assume a "rate reset", hence causes phenomenal spikes.
// One of the number that moves backwards is BytesProxied, which atomically increments a counter with numeric value
// returned by net.Conn.Read(). I don't think that can return a negative value, so I have no idea what's going on.
func mergeStats(new stats, old stats) stats {
	new.UptimeSeconds = mergeValue(new.UptimeSeconds, old.UptimeSeconds)
	new.PendingSessionKeys = mergeValue(new.PendingSessionKeys, old.PendingSessionKeys)
	new.ActiveSessions = mergeValue(new.ActiveSessions, old.ActiveSessions)
	new.Connections = mergeValue(new.Connections, old.Connections)
	new.Proxies = mergeValue(new.Proxies, old.Proxies)
	new.BytesProxied = mergeValue(new.BytesProxied, old.BytesProxied)
	new.GoRoutines = mergeValue(new.GoRoutines, old.GoRoutines)
	new.Options.SessionRate = mergeValue(new.Options.SessionRate, old.Options.SessionRate)
	new.Options.GlobalRate = mergeValue(new.Options.GlobalRate, old.Options.GlobalRate)
	return new
}

func mergeValue(new, old int) int {
	if new >= old {
		return new // normal increase
	}
	if float64(new) > 0.99*float64(old) {
		return old // slight backward movement
	}
	return new // reset (relay restart)
}
Repository: syncthing/syncthing
File: lib/config/wrapper.go (Go)

Code before:
	return append([]FolderConfiguration(nil), w.cfg.Copy().Folders...)
}

// SetFolder adds a new folder to the configuration, or overwrites an existing
// folder with the same ID.
func (w *Wrapper) SetFolder(fld FolderConfiguration) (Waiter, error) {
	w.mut.Lock()
	defer w.mut.Unlock()

	newCfg := w.cfg.Copy()

	for i := range newCfg.Folders {
		if newCfg.Folders[i].ID == fld.ID {
			newCfg.Folders[i] = fld.Copy()
			return w.replaceLocked(newCfg)
		}
	}

	newCfg.Folders = append(newCfg.Folders, fld.Copy())

	return w.replaceLocked(newCfg)
}

// Options returns the current options configuration object.
func (w *Wrapper) Options() OptionsConfiguration {
	w.mut.Lock()
	defer w.mut.Unlock()
	return w.cfg.Options.Copy()
}

// SetOptions replaces the current options configuration object.
func (w *Wrapper) SetOptions(opts OptionsConfiguration) (Waiter, error) {
	w.mut.Lock()
	defer w.mut.Unlock()
	newCfg := w.cfg.Copy()
	newCfg.Options = opts.Copy()
	return w.replaceLocked(newCfg)
}

// GUI returns the current GUI configuration object.
func (w *Wrapper) GUI() GUIConfiguration {
	w.mut.Lock()
	defer w.mut.Unlock()
	return w.cfg.GUI.Copy()
}

// SetGUI replaces the current GUI configuration object.
func (w *Wrapper) SetGUI(gui GUIConfiguration) (Waiter, error) {
	w.mut.Lock()
	defer w.mut.Unlock()
	newCfg := w.cfg.Copy()

Review comment (suggestion):
So after a bunch of bisecting, this seems to be an issue, essentially appending old folders to a new copy, yet I don't understand why this could be an issue, as all of this happens under a lock.

Code after:
	return w.cfg.Copy().Folders
}

// SetFolder adds a new folder to the configuration, or overwrites an existing
// folder with the same ID.
func (w *Wrapper) SetFolder(fld FolderConfiguration) (Waiter, error) {
	w.mut.Lock()
	defer w.mut.Unlock()

	newCfg := w.cfg.Copy()

	for i := range newCfg.Folders {
		if newCfg.Folders[i].ID == fld.ID {
			newCfg.Folders[i] = fld
			return w.replaceLocked(newCfg)
		}
	}

	newCfg.Folders = append(newCfg.Folders, fld)

	return w.replaceLocked(newCfg)
}

// Options returns the current options configuration object.
func (w *Wrapper) Options() OptionsConfiguration {
	w.mut.Lock()
	defer w.mut.Unlock()
	return w.cfg.Options.Copy()
}

// SetOptions replaces the current options configuration object.
func (w *Wrapper) SetOptions(opts OptionsConfiguration) (Waiter, error) {
	w.mut.Lock()
	defer w.mut.Unlock()
	newCfg := w.cfg.Copy()
	newCfg.Options = opts.Copy()
	return w.replaceLocked(newCfg)
}

// GUI returns the current GUI configuration object.
func (w *Wrapper) GUI() GUIConfiguration {
	w.mut.Lock()
	defer w.mut.Unlock()
	return w.cfg.GUI.Copy()
}

// SetGUI replaces the current GUI configuration object.
func (w *Wrapper) SetGUI(gui GUIConfiguration) (Waiter, error) {
	w.mut.Lock()
	defer w.mut.Unlock()
	newCfg := w.cfg.Copy()
Repository: syncthing/syncthing
File: lib/config/wrapper.go (Go)

Code before:
// configuration changes
func (w *Wrapper) Unsubscribe(c Committer) {
	w.mut.Lock()
	for i := range w.subs {
		if w.subs[i] == c {
			copy(w.subs[i:], w.subs[i+1:])
			w.subs[len(w.subs)-1] = nil
			w.subs = w.subs[:len(w.subs)-1]
			break
		}
	}
	w.mut.Unlock()
}

// RawCopy returns a copy of the currently wrapped Configuration object.
func (w *Wrapper) RawCopy() Configuration {
	w.mut.Lock()
	defer w.mut.Unlock()
	return w.cfg.Copy()
}

// Replace swaps the current configuration object for the given one.
func (w *Wrapper) Replace(cfg Configuration) (Waiter, error) {
	w.mut.Lock()
	defer w.mut.Unlock()
	return w.replaceLocked(cfg)
}

func (w *Wrapper) replaceLocked(to Configuration) (Waiter, error) {
	from := w.cfg

	if err := to.clean(); err != nil {
		return noopWaiter{}, err
	}

	for _, sub := range w.subs {
		l.Debugln(sub, "verifying configuration")
		if err := sub.VerifyConfiguration(from, to); err != nil {
			l.Debugln(sub, "rejected config:", err)
			return noopWaiter{}, err
		}
	}

	w.cfg = to
	w.deviceMap = nil
	w.folderMap = nil

	return w.notifyListeners(from, to), nil
}

func (w *Wrapper) notifyListeners(from, to Configuration) Waiter {

Review comment (suggestion):
I think this copy and the one in `replaceLocked` are redundant.

Code after:
// configuration changes
func (w *Wrapper) Unsubscribe(c Committer) {
	w.mut.Lock()
	for i := range w.subs {
		if w.subs[i] == c {
			copy(w.subs[i:], w.subs[i+1:])
			w.subs[len(w.subs)-1] = nil
			w.subs = w.subs[:len(w.subs)-1]
			break
		}
	}
	w.mut.Unlock()
}

// RawCopy returns a copy of the currently wrapped Configuration object.
func (w *Wrapper) RawCopy() Configuration {
	w.mut.Lock()
	defer w.mut.Unlock()
	return w.cfg.Copy()
}

// Replace swaps the current configuration object for the given one.
func (w *Wrapper) Replace(cfg Configuration) (Waiter, error) {
	w.mut.Lock()
	defer w.mut.Unlock()
	return w.replaceLocked(cfg.Copy())
}

func (w *Wrapper) replaceLocked(to Configuration) (Waiter, error) {
	from := w.cfg

	if err := to.clean(); err != nil {
		return noopWaiter{}, err
	}

	for _, sub := range w.subs {
		l.Debugln(sub, "verifying configuration")
		if err := sub.VerifyConfiguration(from.Copy(), to.Copy()); err != nil {
			l.Debugln(sub, "rejected config:", err)
			return noopWaiter{}, err
		}
	}

	w.cfg = to
	w.deviceMap = nil
	w.folderMap = nil

	return w.notifyListeners(from.Copy(), to.Copy()), nil
}

func (w *Wrapper) notifyListeners(from, to Configuration) Waiter {
Repository: syncthing/syncthing
File: lib/logger/logger.go (Go)

Code before:
		initial: initial,
	}
	l.AddHandler(level, r.append)
	return r
}

func (r *recorder) Since(t time.Time) []Line {
	r.mut.Lock()
	defer r.mut.Unlock()

	res := r.lines

	for i := 0; i < len(res); i++ {
		if res[i].When.After(t) {
			// We must copy the result as r.lines can be mutated as soon as the lock
			// is released.
			res = res[i:]
			cp := make([]Line, len(res))
			copy(cp, res)
			return cp
		}
	}
	return nil
}

func (r *recorder) All() []Line {
	r.mut.Lock()
	defer r.mut.Unlock()

	res := r.lines

	for i := 0; i < len(res); i++ {

		// We must copy the result as r.lines can be mutated as soon as the lock
		// is released.

		cp := make([]Line, len(res))
		copy(cp, res)
		return cp

	}
	return nil
}

func (r *recorder) Clear() {
	r.mut.Lock()
	r.lines = r.lines[:0]
	r.mut.Unlock()
}

func (r *recorder) append(l LogLevel, msg string) {

Review comment (bug):
I think this method is not really necessary as it's equivalent to `Since(time.Time{})` (i.e., everything since the zero time).

(Removing it here and from the logger interface will also make the build pass, as it currently fails due to the test version of the recorder not fulfilling the updated interface.)

Code after:
	}
	l.AddHandler(level, r.append)
	return r
}

func (r *recorder) Since(t time.Time) []Line {
	r.mut.Lock()
	defer r.mut.Unlock()

	res := r.lines

	for i := 0; i < len(res); i++ {
		if res[i].When.After(t) {
			// We must copy the result as r.lines can be mutated as soon as the lock
			// is released.
			res = res[i:]
			cp := make([]Line, len(res))
			copy(cp, res)
			return cp
		}
	}
	return nil
}

func (r *recorder) Clear() {
	r.mut.Lock()
	r.lines = r.lines[:0]
	r.mut.Unlock()
}

func (r *recorder) append(l LogLevel, msg string) {
	line := Line{
		When:    time.Now(),
		Message: msg,
		Level:   l,
	}

	r.mut.Lock()
	defer r.mut.Unlock()

	if len(r.lines) == cap(r.lines) {
		if r.initial > 0 {
			// Shift all lines one step to the left, keeping the "initial" first intact.
			copy(r.lines[r.initial+1:], r.lines[r.initial+2:])
		} else {
			copy(r.lines, r.lines[1:])
		}
		// Add the new one at the end
		r.lines[len(r.lines)-1] = line
		return
	}
Repository: syncthing/syncthing
File: cmd/syncthing/support_bundle.go (Go)

Code before:
package main

import (
	"archive/zip"
	"io"
	"log"
	"os"
)

// ZipFiles compresses one or many files into a single zip archive file
func ZipFiles(filename *os.File, files []string) error {

	zipWriter := zip.NewWriter(filename)
	defer zipWriter.Close()

	// Add files to zip
	for _, file := range files {

		zipfile, err := os.Open(file)
		if err != nil {
			return err
		}
		defer zipfile.Close()

		// Get the file information
		info, err := zipfile.Stat()
		if err != nil {
			return err
		}

		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}

		// Change to deflate to gain better compression

Review comment (suggestion):
That is, if this took a slice of `struct { Name string, Data io.Reader }` then the Data can be a `bytes.Buffer` and the rest of the zip code is roughly the same, minus open/close stuff.

Code after:
// Copyright (C) 2018 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

package main

import (
	"archive/zip"
	"io"

	"github.com/syncthing/syncthing/lib/config"
)

// getRedactedConfig redacting some parts of config
func getRedactedConfig(s *apiService) config.Configuration {
	rawConf := s.cfg.RawCopy()
	rawConf.GUI.APIKey = "REDACTED"
	if rawConf.GUI.Password != "" {
		rawConf.GUI.Password = "REDACTED"
	}
	if rawConf.GUI.User != "" {
		rawConf.GUI.User = "REDACTED"
	}
	return rawConf
}

// writeZip writes a zip file containing the given entries
func writeZip(writer io.Writer, files []fileEntry) error {
	zipWriter := zip.NewWriter(writer)
	defer zipWriter.Close()

	for _, file := range files {
		zipFile, err := zipWriter.Create(file.name)
		if err != nil {
Repository: syncthing/syncthing
File: cmd/syncthing/support_bundle.go (Go)

Code before:
// Copyright (C) 2014 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

package main

import (
	"archive/zip"
	"io"
	"io/ioutil"
	"net/http"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/syncthing/syncthing/lib/config"
)

// AddBufferFile adds new json to fileByte(name, bytes.Buffer)
func addBufferFile(arrayFile []fileByte, name string, json []byte) []fileByte {
	var singleFile fileByte
	singleFile.name = name
	singleFile.buf.Write(json)
	arrayFile = append(arrayFile, singleFile)
	return arrayFile
}

// GetRedactedConfig redacting some parts of config
func getRedactedConfig(s *apiService) config.Configuration {
	rawConf := s.cfg.RawCopy()
	rawConf.GUI.APIKey = "REDACTED"
	rawConf.GUI.Password = "REDACTED"
	rawConf.GUI.User = "REDACTED"
	return rawConf
}

// GetusageReportingData collects needed data for support personnel
func getusageReportingData(s *apiService, r *http.Request) map[string]interface{} {
	data := make(map[string]interface{})
	folders := make(map[string]interface{})

	version := usageReportVersion
	if val, _ := strconv.Atoi(r.URL.Query().Get("version")); val > 0 {
		version = val
	}

Review comment (suggestion):
Instead of using this function, it's more idiomatic Go to just

```
arrayFile = append(arrayFile, fileEntry{name: name, data: data})
```

where `fileEntry` is something like

```
type fileEntry struct {
  name string
  data []byte
}
```

I don't think keeping a buffer directly in the `fileByte` (as it's called now) here adds much value. Instead, the buffer handling can be done as necessary by the creator / user of these structs.

Code after:
// Copyright (C) 2018 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

package main

import (
	"archive/zip"
	"io"

	"github.com/syncthing/syncthing/lib/config"
)

// getRedactedConfig redacting some parts of config
func getRedactedConfig(s *apiService) config.Configuration {
	rawConf := s.cfg.RawCopy()
	rawConf.GUI.APIKey = "REDACTED"
	if rawConf.GUI.Password != "" {
		rawConf.GUI.Password = "REDACTED"
	}
	if rawConf.GUI.User != "" {
		rawConf.GUI.User = "REDACTED"
	}
	return rawConf
}

// writeZip writes a zip file containing the given entries
func writeZip(writer io.Writer, files []fileEntry) error {
	zipWriter := zip.NewWriter(writer)
	defer zipWriter.Close()

	for _, file := range files {
		zipFile, err := zipWriter.Create(file.name)
		if err != nil {
			return err
		}

		_, err = zipFile.Write(file.data)
		if err != nil {
			return err
		}
	}

	return zipWriter.Close()
}