# Umask - set default file permissions

**URL:** <https://racket.discourse.group/t/umask-set-default-file-permissions/613>\
**Category:** Show & Tell\
**Created:** [January 21, 2022, 11:09pm UTC](https://racket.discourse.group/t/umask-set-default-file-permissions/613 "2022-01-21T23:09:24Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![winny](https://avatars.discourse-cdn.com/v4/letter/w/53a042/32.png) [@winny](https://racket.discourse.group/u/winny)\
**Post date:** [January 21, 2022, 11:09pm UTC](https://racket.discourse.group/t/umask-set-default-file-permissions/613/1 "2022-01-21T23:09:24Z")

</div>

Hey all, first post here on discourse 👋 !

I had a use-case to manipulate private, information-sensitive files in Racket, didn't find a way to set the umask so new directories/files have secure permissions (race-condition free (!)) so I made a small package to fill this need.

It's a little rough around the edges — for example I don't believe this works on Mac. Any suggestions appreciated 🙂 !

## Project infos

- Install: `raco pkg install umask`
- [Docs](https://docs.racket-lang.org/umask/index.html)
- [Source](https://github.com/winny-/umask)

## Quick example

Same a SSH private key in your environment to a temporary file, return the path.

```racket
(with-umask #o077
  (let ([file (make-temporary-file)])
    (with-output-to-file file (thunk (write-string (getenv "APP_SSH_PRIVKEY")))
     #:exists 'must-truncate)
    file))

```

Get the umask

```racket
(umask) ; -> #o022

```

Set the umask

```racket
(umask #o077) ; -> void

```

(Note setting the umask does _not_ return the previous umask - this is intentional to simplify the API use.)

---

<div class="post-metadata">

**Author:** ![benknoble](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/benknoble/32/16_2.png) [@benknoble](https://racket.discourse.group/u/benknoble)\
**Post date:** [January 22, 2022, 4:06pm UTC](https://racket.discourse.group/t/umask-set-default-file-permissions/613/2 "2022-01-22T16:06:39Z")

</div>

Neat!

Without peaking, I'm assuming `umask` is a parameter, so `with-umask` is just a wrapper around `parameterize`? If so, I think it's completely normal for `(umask x)` to be `void?`.

---

<div class="post-metadata">

**Author:** ![winny](https://avatars.discourse-cdn.com/v4/letter/w/53a042/32.png) [@winny](https://racket.discourse.group/u/winny)\
**Post date:** [January 23, 2022, 2:09am UTC](https://racket.discourse.group/t/umask-set-default-file-permissions/613/3 "2022-01-23T02:09:59Z")

</div>

It feels like a parameter eh 🙂 ?

Unfortunately it's not a parameter in this case because I wasn't sure how to configure the parameter to have a side-effect when set - it'll have to do a FFI call whenever the parameter is changed.

Instead `with-umask` wraps the body with a few umask FFI calls around it. Maybe there's a better way to do this? 🤔

---

<div class="post-metadata">

**Author:** ![joskoot](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/joskoot/32/1964_2.png) [@joskoot](https://racket.discourse.group/u/joskoot)\
**Post date:** [January 23, 2022, 3:35pm UTC](https://racket.discourse.group/t/umask-set-default-file-permissions/613/4 "2022-01-23T15:35:51Z")

</div>

A parameter can have a guard that produces side effects.

See doc on make-parameter.

Jos

---

<div class="post-metadata">

**Author:** ![benknoble](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/benknoble/32/16_2.png) [@benknoble](https://racket.discourse.group/u/benknoble)\
**Post date:** [January 24, 2022, 1:34pm UTC](https://racket.discourse.group/t/umask-set-default-file-permissions/613/5 "2022-01-24T13:34:13Z")

</div>

Jos is correct; you could do something like

```scheme
(define umask (make-parameter default
                              (lambda (new-mask) side-effects… new-mask)
                              'umask)

```

You can add a wrapper on the return value with `make-derived-parameter`.

---

<div class="post-metadata">

**Author:** ![LiberalArtist](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/liberalartist/32/151_2.png) [@LiberalArtist](https://racket.discourse.group/u/LiberalArtist)\
**Post date:** [January 24, 2022, 4:29pm UTC](https://racket.discourse.group/t/umask-set-default-file-permissions/613/6 "2022-01-24T16:29:04Z")

</div>

I'd be interested to know whether this work-in-progress PR to add a `#:permissions` argument to `make-temporary-file` would work for your use-case: [https://github.com/racket/racket/pull/4126](https://github.com/racket/racket/pull/4126)

You also raise a good point that the docs don't specify how `with-output-to-file`, `open-output-port`, etc. handle `#:permissions` when `#:exists` is something like `'must-truncate`

---

<div class="post-metadata">

**Author:** ![winny](https://avatars.discourse-cdn.com/v4/letter/w/53a042/32.png) [@winny](https://racket.discourse.group/u/winny)\
**Post date:** [February 4, 2022, 7:30am UTC](https://racket.discourse.group/t/umask-set-default-file-permissions/613/7 "2022-02-04T07:30:49Z")

</div>

I gave it a go, but the tests appear to indicate my approach with parameters isn't quite working as expected, any hints?

> **[demonstration of parameter not quite working in this context ·...](https://github.com/winny-/umask/runs/5063009858?check_suite_focus=true)**
>
> Racket umask library. Contribute to winny-/umask development by creating an account on GitHub.

I added dynamic-wind on the other hand, that appears to work in more cases. It does not work across threads however (though this didn't appear to work with parameters, possibly due to the FFI nature of the umask syscall).

> **[Implement error handling · winny-/umask@9e37c94](https://github.com/winny-/umask/runs/5063033107?check_suite_focus=true)**
>
> Racket umask library. Contribute to winny-/umask development by creating an account on GitHub.

---

<div class="post-metadata">

**Author:** ![benknoble](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/benknoble/32/16_2.png) [@benknoble](https://racket.discourse.group/u/benknoble)\
**Post date:** [February 4, 2022, 2:18pm UTC](https://racket.discourse.group/t/umask-set-default-file-permissions/613/8 "2022-02-04T14:18:27Z")

</div>

It seems the guard is not applied when parameterize restores the old value, probably because that's not actually how parameterize works (something something thread cells something something ?).

I'm not sure there is a good workaround, esp. since, as you say, this is FFI-bound.

---

<div class="post-metadata">

**Author:** ![simonls](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/simonls/32/170_2.png) [@simonls](https://racket.discourse.group/u/simonls)\
**Post date:** [February 4, 2022, 4:47pm UTC](https://racket.discourse.group/t/umask-set-default-file-permissions/613/9 "2022-02-04T16:47:29Z")

</div>

I think the intent for the guard is to prevent an unwanted value to be used as the parameter value, so it seems sensible that guard is only used once to check that the value is allowed.  
Mutable values or side-effects don't seem to play nicely with that.

For opengl side-effect management I have used dynamic-wind (making setup/teardown calls).  
(That opengl code is single threaded, so didn't run into any multi-threading issues)

But I am not entirely sure about the differences between dynamic wind and parameters, I get the first is based on continuations, while the latter is based on thread cells and parameterize (but indirectly also continuations?).  
My technical understanding of how parameters / dynamic-wind are implemented is rusty, comparing the two could be interesting. Currently it seems to me like I would need to dig into both their implementations to understand fully in what ways they differ or are similar in their use.

---

<div class="post-metadata">

**Author:** ![jbclements](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/jbclements/32/11_2.png) [@jbclements](https://racket.discourse.group/u/jbclements)\
**Post date:** [February 5, 2022, 1:43am UTC](https://racket.discourse.group/t/umask-set-default-file-permissions/613/10 "2022-02-05T01:43:00Z")

</div>

I believe the intent of a parameter is to restrict dynamic-wind to a simple value binding, more or less. That is: a dynamic-wind can do any crazy thing it wants whenever control leaves or re-enters. A parameterize is a little more predictable; it just ensures that a particular binding is in place when the code in the dynamic extent of the body is being called.

In other words, if you need to perform an action on entry and a corresponding action on exit, I think you want dynamic-wind, and not parameterize.

However, I also think that @LiberalArtist 's proposal could be even better, and more well-behaved.

---

<div class="post-metadata">

**Author:** ![LiberalArtist](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/liberalartist/32/151_2.png) [@LiberalArtist](https://racket.discourse.group/u/LiberalArtist)\
**Post date:** [February 6, 2022, 6:54pm UTC](https://racket.discourse.group/t/umask-set-default-file-permissions/613/11 "2022-02-06T18:54:37Z")

</div>

One difference between `parameterize` and `dynamic-wind` is that `parameterize` will also set the initial state for child (Racket-level) threads: in other words, `thread` will capture a parameterization (but probably not call the guard when restoring the initial value), but will not capture winders.

(In addition to raising exception, a common use for a parameter guard is to do some kind of coercion, e.g. converting any non-`#false` value to `#true`.)

But I think the FFI is not going to be enough to make a really robust and general interface to `umask`. (That doesn't mean it's bad to have a less-general solution that works for some use case!) In particular, IIUC `umask` is set at the level of the OS process, so uses of `with-umask` in different Racket places will interfere with each other.

Some possible approaches I see:

- Don't rely on state: explicitly supply `#:permissions` as needed.
- Have `rktio` manage the OS-level `umask`.
- Make a parameter `current-umask` that works like `current-directory`: it is entirely independent of the OS-level state, but Racket's IO primitives respect it.
