Skip to content

Commit

Permalink
Fix IsPrivate (#386)
Browse files Browse the repository at this point in the history
Fix IsPrivate
  • Loading branch information
twpayne committed Jul 7, 2019
2 parents cb49f8d + 131ed26 commit 77b8641
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 57 deletions.
1 change: 1 addition & 0 deletions .golangci.yml
@@ -1,6 +1,7 @@
linters:
enable-all: true
disable:
- goconst
- gocyclo
- lll
- maligned
Expand Down
53 changes: 34 additions & 19 deletions cmd/add_test.go
@@ -1,6 +1,7 @@
package cmd

import (
"runtime"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -44,11 +45,12 @@ func TestAddAfterModification(t *testing.T) {

func TestAddCommand(t *testing.T) {
for _, tc := range []struct {
name string
args []string
add addCmdConfig
root interface{}
tests interface{}
name string
skipOnWindows bool
args []string
add addCmdConfig
root interface{}
tests interface{}
}{
{
name: "add_first_file",
Expand Down Expand Up @@ -88,8 +90,9 @@ func TestAddCommand(t *testing.T) {
},
},
{
name: "add_recursive",
args: []string{"/home/user/.config"},
name: "add_recursive",
skipOnWindows: true,
args: []string{"/home/user/.config"},
add: addCmdConfig{
recursive: true,
},
Expand All @@ -106,8 +109,9 @@ func TestAddCommand(t *testing.T) {
},
},
{
name: "add_nested_directory",
args: []string{"/home/user/.config/micro/settings.json"},
name: "add_nested_directory",
skipOnWindows: true,
args: []string{"/home/user/.config/micro/settings.json"},
root: map[string]interface{}{
"/home/user": &vfst.Dir{Perm: 0755},
"/home/user/.chezmoi": &vfst.Dir{Perm: 0700},
Expand All @@ -121,8 +125,9 @@ func TestAddCommand(t *testing.T) {
},
},
{
name: "add_exact_dir",
args: []string{"/home/user/dir"},
name: "add_exact_dir",
skipOnWindows: true,
args: []string{"/home/user/dir"},
add: addCmdConfig{
options: chezmoi.AddOptions{
Exact: true,
Expand All @@ -140,8 +145,9 @@ func TestAddCommand(t *testing.T) {
},
},
{
name: "add_exact_dir_recursive",
args: []string{"/home/user/dir"},
name: "add_exact_dir_recursive",
skipOnWindows: true,
args: []string{"/home/user/dir"},
add: addCmdConfig{
recursive: true,
options: chezmoi.AddOptions{
Expand Down Expand Up @@ -244,8 +250,9 @@ func TestAddCommand(t *testing.T) {
},
},
{
name: "add_symlink_in_dir_recursive",
args: []string{"/home/user/foo"},
name: "add_symlink_in_dir_recursive",
skipOnWindows: true,
args: []string{"/home/user/foo"},
add: addCmdConfig{
recursive: true,
},
Expand All @@ -265,8 +272,9 @@ func TestAddCommand(t *testing.T) {
},
},
{
name: "add_symlink_with_parent_dir",
args: []string{"/home/user/foo/bar/baz"},
name: "add_symlink_with_parent_dir",
skipOnWindows: true,
args: []string{"/home/user/foo/bar/baz"},
root: map[string]interface{}{
"/home/user": &vfst.Dir{Perm: 0755},
"/home/user/.chezmoi": &vfst.Dir{Perm: 0700},
Expand Down Expand Up @@ -305,8 +313,9 @@ func TestAddCommand(t *testing.T) {
},
},
{
name: "dont_add_ignored_file_recursive",
args: []string{"/home/user/foo"},
name: "dont_add_ignored_file_recursive",
skipOnWindows: true,
args: []string{"/home/user/foo"},
add: addCmdConfig{
recursive: true,
},
Expand Down Expand Up @@ -364,6 +373,9 @@ func TestAddCommand(t *testing.T) {
},
} {
t.Run(tc.name, func(t *testing.T) {
if runtime.GOOS == "windows" && tc.skipOnWindows {
t.Skip("add --recursive is broken on windows")
}
c := &Config{
SourceDir: "/home/user/.chezmoi",
DestDir: "/home/user",
Expand All @@ -389,6 +401,9 @@ func TestAddCommand(t *testing.T) {
}

func TestIssue192(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("add --recursive is broken on windows")
}
root := []interface{}{
map[string]interface{}{
"/local/home/offbyone": &vfst.Dir{
Expand Down
6 changes: 5 additions & 1 deletion cmd/config.go
Expand Up @@ -177,7 +177,11 @@ func (c *Config) ensureSourceDirectory(fs chezmoi.PrivacyStater, mutator chezmoi
info, err := fs.Stat(c.SourceDir)
switch {
case err == nil && info.IsDir():
if !chezmoi.IsPrivate(fs, c.SourceDir, os.FileMode(c.Umask)) {
private, err := chezmoi.IsPrivate(fs, c.SourceDir)
if err != nil {
return err
}
if !private {
if err := mutator.Chmod(c.SourceDir, 0700&^os.FileMode(c.Umask)); err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/import.go
Expand Up @@ -82,5 +82,5 @@ func (c *Config) runImportCmd(fs vfs.FS, args []string) error {
return err
}
}
return ts.ImportTAR(tar.NewReader(r), c._import.importTAROptions, mutator, fs)
return ts.ImportTAR(tar.NewReader(r), c._import.importTAROptions, mutator)
}
12 changes: 9 additions & 3 deletions cmd/root.go
Expand Up @@ -142,9 +142,15 @@ func (c *Config) persistentPreRunRootE(fs vfs.FS, args []string) error {
switch {
case err == nil && !info.IsDir():
return fmt.Errorf("%s: not a directory", c.SourceDir)
case err == nil && !chezmoi.IsPrivate(fs, c.SourceDir, os.FileMode(c.Umask)):
fmt.Fprintf(os.Stderr, "%s: not private, but should be\n", c.SourceDir)
case err != nil && !os.IsNotExist(err):
case err == nil:
private, err := chezmoi.IsPrivate(fs, c.SourceDir)
if err != nil {
return err
}
if !private {
fmt.Fprintf(os.Stderr, "%s: not private, but should be\n", c.SourceDir)
}
case !os.IsNotExist(err):
return err
}

Expand Down
13 changes: 5 additions & 8 deletions lib/chezmoi/private_posix.go
Expand Up @@ -2,15 +2,12 @@

package chezmoi

import "os"

// IsPrivate returns whether file should be considered private.
// IsPrivate returns whether path should be considered private.
// nolint:interfacer
func IsPrivate(fs PrivacyStater, file string, umask os.FileMode) bool {
info, err := fs.Stat(file)
func IsPrivate(fs PrivacyStater, path string) (bool, error) {
info, err := fs.Stat(path)
if err != nil {
return false
return false, err
}

return info.Mode().Perm()&^umask == 0700&^umask
return info.Mode().Perm()&077 == 0, nil
}
16 changes: 8 additions & 8 deletions lib/chezmoi/private_windows.go
Expand Up @@ -42,21 +42,21 @@ func resolveSymlink(file string) (string, error) {
return resolved, nil
}

func IsPrivate(fs PrivacyStater, file string, umask os.FileMode) bool {
file, err := fs.RawPath(file)
func IsPrivate(fs PrivacyStater, path string) (bool, error) {
rawPath, err := fs.RawPath(path)
if err != nil {
return false
return false, err
}

file, err = resolveSymlink(file)
resolvedPath, err := resolveSymlink(rawPath)
if err != nil {
return false
return false, err
}

mode, err := acl.GetEffectiveAccessMode(file)
mode, err := acl.GetEffectiveAccessMode(resolvedPath)
if err != nil {
return false
return false, err
}

return (uint32(mode) & 0007) == 0
return mode&07 == 0, nil
}
38 changes: 21 additions & 17 deletions lib/chezmoi/targetstate.go
Expand Up @@ -137,6 +137,13 @@ func (ts *TargetState) Add(fs vfs.FS, addOptions AddOptions, targetPath string,
return err
}
empty := len(infos) == 0
private, err := IsPrivate(fs, targetPath)
if err != nil {
return err
}
if private {
perm &^= 077
}
return ts.addDir(targetName, entries, parentDirSourceName, addOptions.Exact, perm, empty, mutator)
case info.Mode().IsRegular():
if info.Size() == 0 && !addOptions.Empty {
Expand All @@ -155,7 +162,15 @@ func (ts *TargetState) Add(fs vfs.FS, addOptions AddOptions, targetPath string,
return err
}
}
return ts.addFile(targetName, entries, parentDirSourceName, info, addOptions.Encrypt, addOptions.Template, contents, mutator, fs)
perm := info.Mode().Perm()
private, err := IsPrivate(fs, targetPath)
if err != nil {
return err
}
if private {
perm &^= 077
}
return ts.addFile(targetName, entries, parentDirSourceName, info, perm, addOptions.Encrypt, addOptions.Template, contents, mutator)
case info.Mode()&os.ModeType == os.ModeSymlink:
linkname, err := fs.Readlink(targetPath)
if err != nil {
Expand Down Expand Up @@ -277,7 +292,7 @@ func (ts *TargetState) Get(fs vfs.Stater, target string) (Entry, error) {
}

// ImportTAR imports a tar archive.
func (ts *TargetState) ImportTAR(r *tar.Reader, importTAROptions ImportTAROptions, mutator Mutator, fs PrivacyStater) error {
func (ts *TargetState) ImportTAR(r *tar.Reader, importTAROptions ImportTAROptions, mutator Mutator) error {
for {
header, err := r.Next()
if err == io.EOF {
Expand All @@ -287,7 +302,7 @@ func (ts *TargetState) ImportTAR(r *tar.Reader, importTAROptions ImportTAROption
}
switch header.Typeflag {
case tar.TypeDir, tar.TypeReg, tar.TypeSymlink:
if err := ts.importHeader(r, importTAROptions, header, mutator, fs); err != nil {
if err := ts.importHeader(r, importTAROptions, header, mutator); err != nil {
return err
}
case tar.TypeXGlobalHeader:
Expand Down Expand Up @@ -471,7 +486,7 @@ func (ts *TargetState) addDir(targetName string, entries map[string]Entry, paren
return nil
}

func (ts *TargetState) addFile(targetName string, entries map[string]Entry, parentDirSourceName string, info os.FileInfo, encrypted, template bool, contents []byte, mutator Mutator, fs PrivacyStater) error {
func (ts *TargetState) addFile(targetName string, entries map[string]Entry, parentDirSourceName string, info os.FileInfo, perm os.FileMode, encrypted, template bool, contents []byte, mutator Mutator) error {
name := filepath.Base(targetName)
var existingFile *File
var existingContents []byte
Expand All @@ -487,17 +502,6 @@ func (ts *TargetState) addFile(targetName string, entries map[string]Entry, pare
}
}

perm := info.Mode().Perm()
destFile := filepath.Join(ts.DestDir, name)
if IsPrivate(fs, destFile, ts.Umask) {
// since Windows doesn't really have the concept of "groups", the
// group permission bits might be set even on a file that should
// be considered private. This will clear them. Posix-style platforms
// remain unaffected because IsPrivate will only return true if those
// bits weren't set in the first place
perm &^= 0077
}

empty := info.Size() == 0
sourceName := FileAttributes{
Name: name,
Expand Down Expand Up @@ -685,7 +689,7 @@ func (ts *TargetState) findEntry(name string) (Entry, error) {
return entries[names[len(names)-1]], nil
}

func (ts *TargetState) importHeader(r io.Reader, importTAROptions ImportTAROptions, header *tar.Header, mutator Mutator, fs PrivacyStater) error {
func (ts *TargetState) importHeader(r io.Reader, importTAROptions ImportTAROptions, header *tar.Header, mutator Mutator) error {
targetPath := header.Name
if importTAROptions.StripComponents > 0 {
targetPath = filepath.Join(strings.Split(targetPath, string(os.PathSeparator))[importTAROptions.StripComponents:]...)
Expand Down Expand Up @@ -724,7 +728,7 @@ func (ts *TargetState) importHeader(r io.Reader, importTAROptions ImportTAROptio
if err != nil {
return err
}
return ts.addFile(targetName, entries, parentDirSourceName, info, false, false, contents, mutator, fs)
return ts.addFile(targetName, entries, parentDirSourceName, info, info.Mode().Perm(), false, false, contents, mutator)
case tar.TypeSymlink:
linkname := header.Linkname
return ts.addSymlink(targetName, entries, parentDirSourceName, linkname, mutator)
Expand Down

0 comments on commit 77b8641

Please sign in to comment.