mirror of
https://github.com/syncthing/syncthing.git
synced 2026-06-09 17:25:51 -04:00
We had a few places where we had perhaps too much of an opinion on the permissions on created files and directories, sometimes fuled by a misconception about how permissions work in both Unix and Windows. Recap on the ground rules: - On all unixes, all file & directory creation (`Mkdir`, `MkdirAll`, `Create`, `WriteFile`, `Open`) has the given permission bits filtered via the user's umask. The proper permissions for us to use are in almost all cases 0o666 for files and 0o777 for directories, strange as that may look at the call site. - On Windows, there is no umask but in turn all of the permission bits except the user write bit are ignored. The absence of user write bit is converted into the read only attribute. This means that what is proper for Unix above is also proper for Windows. - We make an exception when creating files for certificate keys and the config / database directories, as those contain secrets we think should remain closed even if the user generally collaborates with other users on the system. (Also removal of a bugfixed copy of MkdirAll for Windows that hasn't been necessary for a few years.) --------- Signed-off-by: Jakob Borg <jakob@kastelo.net>
118 lines
3.0 KiB
Go
118 lines
3.0 KiB
Go
// Copyright (C) 2016 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/.
|
|
|
|
//go:build !windows
|
|
// +build !windows
|
|
|
|
package fs
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
func (f *BasicFilesystem) CreateSymlink(target, name string) error {
|
|
name, err := f.rooted(name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.Symlink(target, name)
|
|
}
|
|
|
|
func (f *BasicFilesystem) ReadSymlink(name string) (string, error) {
|
|
name, err := f.rooted(name)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return os.Readlink(name)
|
|
}
|
|
|
|
// Unhide is a noop on unix, as unhiding files requires renaming them.
|
|
// We still check that the relative path does not try to escape the root
|
|
func (f *BasicFilesystem) Unhide(name string) error {
|
|
_, err := f.rooted(name)
|
|
return err
|
|
}
|
|
|
|
// Hide is a noop on unix, as hiding files requires renaming them.
|
|
// We still check that the relative path does not try to escape the root
|
|
func (f *BasicFilesystem) Hide(name string) error {
|
|
_, err := f.rooted(name)
|
|
return err
|
|
}
|
|
|
|
func (*BasicFilesystem) Roots() ([]string, error) {
|
|
return []string{"/"}, nil
|
|
}
|
|
|
|
func (f *BasicFilesystem) Lchown(name, uid, gid string) error {
|
|
name, err := f.rooted(name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nuid, err := strconv.Atoi(uid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ngid, err := strconv.Atoi(gid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.Lchown(name, nuid, ngid)
|
|
}
|
|
|
|
func (f *BasicFilesystem) Remove(name string) error {
|
|
name, err := f.rooted(name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.Remove(name)
|
|
}
|
|
|
|
// unrootedChecked returns the path relative to the folder root (same as
|
|
// unrooted) or an error if the given path is not a subpath and handles the
|
|
// special case when the given path is the folder root without a trailing
|
|
// pathseparator.
|
|
func (f *BasicFilesystem) unrootedChecked(absPath string, roots []string) (string, *WatchEventOutsideRootError) {
|
|
for _, root := range roots {
|
|
// Make sure the root ends with precisely one path separator, to
|
|
// ease prefix comparisons.
|
|
root := strings.TrimRight(root, string(PathSeparator)) + string(PathSeparator)
|
|
|
|
if absPath+string(PathSeparator) == root {
|
|
return ".", nil
|
|
}
|
|
if strings.HasPrefix(absPath, root) {
|
|
return rel(absPath, root), nil
|
|
}
|
|
}
|
|
return "", f.newErrWatchEventOutsideRoot(absPath, roots)
|
|
}
|
|
|
|
func rel(path, prefix string) string {
|
|
return strings.TrimPrefix(strings.TrimPrefix(path, prefix), string(PathSeparator))
|
|
}
|
|
|
|
var evalSymlinks = filepath.EvalSymlinks
|
|
|
|
// watchPaths adjust the folder root for use with the notify backend and the
|
|
// corresponding absolute path to be passed to notify to watch name.
|
|
func (f *BasicFilesystem) watchPaths(name string) (string, []string, error) {
|
|
root, err := evalSymlinks(f.root)
|
|
if err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
absName, err := rooted(name, root)
|
|
if err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
return filepath.Join(absName, "..."), []string{root}, nil
|
|
}
|