forked from elves/elvish
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
6 changed files
with
165 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// +build !windows,!plan9 | ||
|
||
package unix | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"math" | ||
"strconv" | ||
"syscall" | ||
|
||
"github.com/elves/elvish/pkg/eval" | ||
"github.com/elves/elvish/pkg/eval/vars" | ||
) | ||
|
||
//elvdoc:var umask | ||
// | ||
// The file system creation mask. When used in a string context the output is | ||
// its Elvish octal representation; e.g. 0o027. This makes it possible to use | ||
// it in any context that expects a `$number`. | ||
// | ||
// When assigning a new value a string is implicitly treated as an octal | ||
// number. If that fails the usual rules for interpreting | ||
// [numbers](./language.html#number) are used. This means you can do both | ||
// `unix:umask = 027` and `unix:umask = 0o27`. You can also assign to it a | ||
// `float64` data type that has no fractional component. The legal values are | ||
// in the range [0 .. 0o777]. | ||
// | ||
// You can do a temporary assignment to affect a single command; e.g. | ||
// `umask=077 touch a_file`. After the command completes the old umask will be | ||
// restored. **Warning**: Since the umask applies to the entire process, not | ||
// individual threads, changing it temporarily in this manner is dangerous if | ||
// you are doing anything in parallel. Such as via the | ||
// [`peach`](ref/builtin.html#peach) command. | ||
// | ||
// This variable only has meaning on UNIX like operating systems and does not | ||
// exist on other platforms. Do not use this in elvish scripts meant to work | ||
// on non-UNIX compatible systems. | ||
|
||
// UmaskVariable is a variable whose value always reflects the current file | ||
// creation permission mask. Setting it changes the current file creation | ||
// permission mask for the process (not an individual thread). | ||
type UmaskVariable struct { | ||
ev *eval.Evaler | ||
} | ||
|
||
var _ vars.Var = UmaskVariable{} | ||
|
||
// Get returns the current file creation umask as a string. | ||
func (UmaskVariable) Get() interface{} { | ||
// Note: The seemingly redundant syscall is because the syscall.Umask() API | ||
// doesn't allow querying the current value without changing it. So ensure | ||
// we reinstate the curent value. | ||
umask := syscall.Umask(0) | ||
syscall.Umask(umask) | ||
return fmt.Sprintf("0o%03o", umask) | ||
} | ||
|
||
// Set changes the current file creation umask. It can be called with a string | ||
// (the usual case) or a float64. | ||
func (UmaskVariable) Set(v interface{}) error { | ||
var umask int | ||
|
||
switch v := v.(type) { | ||
case string: | ||
i, err := strconv.ParseInt(v, 8, 0) | ||
if err != nil { | ||
i, err = strconv.ParseInt(v, 0, 0) | ||
if err != nil { | ||
return errors.New("umask value not a valid number") | ||
} | ||
} | ||
umask = int(i) | ||
case float64: | ||
int_part, frac_part := math.Modf(v) | ||
if frac_part != 0 { | ||
return errors.New("umask value must be an integer") | ||
} | ||
umask = int(int_part) | ||
default: | ||
return errors.New("umask value must be a string or float64") | ||
} | ||
|
||
if umask < 0 || umask > 0o777 { | ||
return errors.New("umask value outside the range [0..0o777]") | ||
} | ||
|
||
syscall.Umask(umask) | ||
return nil | ||
} | ||
|
||
func init() { | ||
Ns.Add("umask", UmaskVariable{}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// +build !windows,!plan9 | ||
|
||
// Note that this unit test assumes a UNIX environment with a POSIX compatible | ||
// /bin/sh program. | ||
package unix | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/elves/elvish/pkg/eval" | ||
) | ||
|
||
var That = eval.That | ||
|
||
func TestUmask(t *testing.T) { | ||
setup := func(ev *eval.Evaler) { ev.Builtin.AddNs("unix", Ns) } | ||
eval.TestWithSetup(t, setup, | ||
// We have to start with a known umask value. | ||
That(`unix:umask = 022`).Puts(), | ||
That(`put $unix:umask`).Puts(`0o022`), | ||
// Now verify that mutating the value and outputing it works. | ||
That(`unix:umask = 23`).Puts(), | ||
That(`put $unix:umask`).Puts(`0o023`), | ||
That(`unix:umask = 0o75`).Puts(), | ||
That(`put $unix:umask`).Puts(`0o075`), | ||
// Verify that a temporary umask change is reverted upon completion of | ||
// the command. Both for builtin and external commands. | ||
That(`unix:umask=012 put $unix:umask`).Puts(`0o012`), | ||
That(`unix:umask=0o23 /bin/sh -c 'umask'`).Prints("0023\n"), | ||
That(`unix:umask=56 /bin/sh -c 'umask'`).Prints("0056\n"), | ||
That(`put $unix:umask`).Puts(`0o075`), | ||
// People won't normally use non-octal bases but make sure these cases | ||
// behave sensibly given that Elvish supports number literals with an | ||
// explicit base. | ||
That(`unix:umask=0x43 /bin/sh -c 'umask'`).Prints("0103\n"), | ||
That(`unix:umask=0b001010100 sh -c 'umask'`).Prints("0124\n"), | ||
// We should be back to our expected umask given the preceding tests | ||
// applied a temporary change to that process attribute. | ||
That(`put $unix:umask`).Puts(`0o075`), | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Package `unix` exposes variables and functions that deal with features | ||
// unique to UNIX like operating systems. On other operating systems it will | ||
// be an empty namespace; or have a subset of the features normally available | ||
// on a UNIX like operating system. | ||
package unix | ||
|
||
import ( | ||
"github.com/elves/elvish/pkg/eval" | ||
) | ||
|
||
var Ns = eval.Ns{} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<!-- toc --> | ||
|
||
# Introduction | ||
|
||
The `unix:` module provides access to features that only make sense on UNIX | ||
compatible operating systems such as Linux, FreeBSD, macOS, etc. Do not use | ||
the features in this module in Elvish scripts that need to work on non-UNIX | ||
operating systems such as MS Windows. | ||
|
||
@elvdoc -ns unix: -dir ../pkg/eval/unix |