26
\$\begingroup\$

File Permissions

Adapted from the UIL - Computer Science Programming free response question "Carla" for 2018 District.

Introduction

In UNIX-like operating systems, each file, directory, or link is "owned" by a "user", who is a member of a "group", and has certain "permissions" represented by a ten-character string such as "drwxrwxrwx". The first character is 'd', '-', or 'l' (directory, file, or link), followed by three sets of "rwx" values, indicating "read, write, execute" permissions. The first set is the user's rights, the middle set the group's rights, and the third everyone else's rights to that object.

Permission denied for any of these rights is represented by a '-' in place of the 'r', 'w', or 'x'. For example, a sample directory permission string would be "drwxr--r--", indicating full directory rights for the user, but "read-only" rights for the group member and all others.

Each "rwx" combination can also be represented by an octal value (0-7) with the most significant bit representing read permission, the next most significant bit representing write permission, and the least significant bit representing execute permission.

Challenge

Given a four-character code string made up of a character: 'D', 'F', or 'L', followed by a three-digit octal integer value, like 664, output the resulting 10 character string that represents the permission value indicated.

Input

Your program or function may either read the input from standard in (four characters will be entered, optionally followed by a newline) or be passed the input as an argument.

Your program may accept uppercase or lowercase inputs but must be consistent (either all inputs are uppercase or all inputs are lowercase).

Output

Your program must print the resulting ten-character string that represents the permission value indicated in the exact format specified above. Tailing white space is allowed.

Test Cases

In: F664 Out: -rw-rw-r--
In: D775 Out: drwxrwxr-x
In: L334 Out: l-wx-wxr--
In: F530 Out: -r-x-wx---
In: D127 Out: d--x-w-rwx

Scoring and Rules

\$\endgroup\$
4
  • \$\begingroup\$ Wait what, asked yesterday and answer accepted already? Does this mean no more answers are expected or what? \$\endgroup\$
    – Etheryte
    Apr 30, 2018 at 8:35
  • 1
    \$\begingroup\$ @Nit More answers are always welcome, regardless of whether an answer is accepted. \$\endgroup\$
    – isaacg
    Apr 30, 2018 at 9:02
  • 1
    \$\begingroup\$ @Nit I was on mobile and trying to downvote an unrelated answer (which has been removed since). I accidentally hit the accept answer button with my fat finger. I couldn't figure out how to unaccept so I just changed the accepted answer to the shortest one as of now. \$\endgroup\$ Apr 30, 2018 at 17:27
  • 2
    \$\begingroup\$ @Nit I mean... he did accept a Dennis answer, so he honestly may be correct. \$\endgroup\$ May 1, 2018 at 16:55

24 Answers 24

17
\$\begingroup\$

bash, 59 53 bytes

chmod ${1:1} a>a;stat -c%A a|sed s/./${1:0:1}/|tr f -

Right tool for the job?

Thanks to Dennis for saving 5 bytes and HTNW for saving one.

Try it online!

chmod ${1:1} a>a;  # call chmod with the input with its first character removed
                   # note that the redirection creates the file a *before* the
                   #   chmod is run, because of the way bash works
stat -c%A a|       # get the human readable access rights
sed s/./${1:0:1}/  # replace the first character with the first char of input
|tr f -            # transliterate, replacing f with -
\$\endgroup\$
6
  • \$\begingroup\$ Well that was fast. Certainly the right tool for the job. \$\endgroup\$ Apr 29, 2018 at 0:02
  • \$\begingroup\$ chmod ${1:1} a>a;stat -c%A a|sed "s/-/\L${1:0:1}/;s/f/-/" saves two bytes. \$\endgroup\$
    – Dennis
    Apr 29, 2018 at 0:19
  • \$\begingroup\$ Going off @Dennis, I think you can shave off one more with tr instead of y: chmod ${1:1} a>a;stat -c%A a|sed s/./\\L${1:0:1}/|tr f - \$\endgroup\$
    – HTNW
    Apr 29, 2018 at 2:43
  • 2
    \$\begingroup\$ Is it legit to assume there is no file a and the user has permission to make it or there is the file a and it is writable by the user? Because if there is a file a owned by root with permissions 700, this shouldn't work. \$\endgroup\$ Apr 29, 2018 at 9:43
  • 2
    \$\begingroup\$ @NoOneIsHere While permissions in particular never came up in the discussion, the community decided that creating temporary files in the current directory is allowed by default. By extension, we can assume that it's possible. \$\endgroup\$
    – Dennis
    Apr 29, 2018 at 13:57
10
\$\begingroup\$

Python 2, 78 bytes

lambda a,*b:[a,'-'][a=='f']+''.join('-r'[x/4]+'-w-w'[x/2]+'-x'[x%2]for x in b)

Takes input as a character and three ints.
Try it online!

Explanation

[a,'-'][a=='f'] takes either the input character or -, if the character is f.
'-r'[x/4]+'-w-w'[x/2]+'-x'[x%2] is essentially an octal conversion to get the rwx string.

\$\endgroup\$
7
\$\begingroup\$

Jelly, 19 bytes

“rwx“-”Œp⁺;Ṁ⁾f-yị@~

Try it online!

How it works

“rwx“-”Œp⁺;Ṁ⁾f-yị@~  Main link. Argument: s (string)

“rwx“-”              Set the return value to ["rwx, "-"].
       Œp            Take the Cartesian product, yielding ["r-", "w-", "x-"].
         ⁺           Take the Cartesian product, yielding
                     ["rwx", "rw-", "r-x", "r--", "-wx", "-w-", "--x", "---"].
          ;Ṁ         Append the maximum of s (the letter).
            ⁾f-y     Translate 'f' to '-'.
                  ~  Map bitwise NOT over s.
                     This maps the letter to 0, because it cannot be cast to int,
                     and each digit d to ~d = -(d+1).
                ị@   Retrieve the results from the array to the left at the indices
                     calculated to the right.
                     Indexing is modular and 1-based, so the letter from s is at
                     index 0, "---" at index -1, ..., and "rwx" at index -8.
\$\endgroup\$
5
\$\begingroup\$

Perl 5 with -p, 37 bytes

s/\d/(<{-,r}{-,w}{-,x}>)[$&]/ge;y;f;-

Takes input in lowercase.

Try it online!

\$\endgroup\$
5
\$\begingroup\$

Retina 0.8.2, 43 bytes

\d
$&r$&w$&x
f|[0-3]r|[0145]w|[0246]x
-
\d

Try it online! Link includes test cases. Takes input in lower case. Explanation:

\d
$&r$&w$&x

Triplicate each digit, suffixing with r, w and x.

f|[0-3]r|[0145]w|[0246]x
-

Change all the incorrect letters to -s.

\d

Delete any remaining digits.

\$\endgroup\$
4
\$\begingroup\$

Retina, 51 bytes

f
-
0
---
1
--x
2
-w-
3
-wx
4
r--
5
r-x
6
rw-
7
rwx

Try it online!

No idea how to use Retina, so please let me know how to do this better. I just figured I'd try to learn at least one language that isn't Pyth.

Explanation:

Replace f with - (leaving d and l unchanged), then replace each digit with the appropriate rwx.

\$\endgroup\$
3
  • \$\begingroup\$ :/ I can get as far as this but no further. and the smart way is super ungolfy \$\endgroup\$
    – ASCII-only
    Apr 29, 2018 at 1:49
  • \$\begingroup\$ It would be so much golfier with some kind of ternary/logical or/add and trim operators \$\endgroup\$
    – ASCII-only
    Apr 29, 2018 at 1:53
  • \$\begingroup\$ @ASCII-only Your idea was quite nice, I've used it for this answer :) \$\endgroup\$
    – Leo
    Apr 30, 2018 at 5:03
4
\$\begingroup\$

JavaScript (ES6), 63 bytes

Expects the input string in lowercase.

s=>s.replace(/\d|f/g,c=>1/c?s[c&4]+s[c&2]+s[c&1]:'-',s='-xw-r')

Try it online!

Commented

s => s.replace(   // replace in the input string s
  /\d|f/g, c =>   //   each character c which is either a digit or the letter 'f'
    1 / c ?       //   if c is a digit:
      s[c & 4] +  //     append '-' or 'r'
      s[c & 2] +  //     append '-' or 'w'
      s[c & 1]    //     append '-' or 'x'
    :             //   else:
      '-',        //     just replace 'f' with '-'
  s = '-xw-r'     //   s holds the permission characters
)                 // end of replace()
\$\endgroup\$
4
\$\begingroup\$

Charcoal, 27 bytes

FS≡ιdιlιf¦-⭆rwx⎇§↨⁺⁸Iι²⊕λκ-

Try it online! Link is to verbose version of code. Explanation:

 S                          Input string
F                           Loop over characters
   ι                        Current character
  ≡                         Switch
    d                       Literal `d`
     ι                      Implicitly print current character
      l                     Literal `l`
       ι                    Implicitly print current character
        f                   Literal `f`
         ¦                  (Separator between string literals)
          -                 Implicitly print literal `-`
                            Implicit default case
            rwx             Literal `rwx`
           ⭆                Map over characters
                     ι      Input character
                    I       Cast to integer
                   ⁸        Literal 8
                  ⁺         Sum
                      ²     Literal 2
                 ↨          Base conversion
                        λ   Inner index
                       ⊕    Incremented
                §           Index into base conversion
                         κ  Inner character
                          - Literal `-`
               ⎇            Ternary
                            Implicitly print
\$\endgroup\$
4
\$\begingroup\$

Haskell, 84 83 81 bytes

f 'f'='-'
f y=y
t#n=f t:((\x->["-r"!!div x 4,"-w-w"!!div x 2,"-x"!!mod x 2])=<<n)

Try it online!

Ended up being pretty similar in concept to Mnemonic's Python 2 answer. f creates the file type, the rest is the gets permissions from the octal number. This one really made me wish & was a bitwise and operator included in prelude.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ You can use div instead of quot. \$\endgroup\$
    – nimi
    Apr 30, 2018 at 0:15
4
\$\begingroup\$

Java 8, 100 bytes

s->s.replaceAll("(\\d)","$1r$1w$1x").replaceAll("f|[0-3]r|[0145]w|[0246]x","-").replaceAll("\\d","")

Try it online.

Port of @Neil's Retina answer.

Explanation:

s->                                 // Method with String as both parameter and return-type
  s.replaceAll("(\\d)","$1r$1w$1x") //  Replace every digit `d` with 'drdwdx'
   .replaceAll("f                   //  Replace every "f",
                |[0-3]r             //  every "0r", "1r", "2r", "3r",
                |[0145]w            //  every "0w", "1w", "4w", "5w",
                |[0246]x",          //  and every "0x", "2x", "4x", "6x"
               "-")                 //  with a "-"
   .replaceAll("\\d","")            //  Remove any remaining digits
\$\endgroup\$
2
  • \$\begingroup\$ This is smart! ;) \$\endgroup\$ Apr 30, 2018 at 10:03
  • \$\begingroup\$ @OlivierGrégoire Well, mainly because it saves on the return statement and loops. Too bad three individual .replaceAll is still less bytes than a loop with .replaceAll and added return and String-array.. But credit of course goes to Neil, who's Retina answer I used as base to port from. \$\endgroup\$ Apr 30, 2018 at 10:16
3
\$\begingroup\$

Jelly, 21 bytes

Ḣ⁾f-yɓOBṫ€4a“rwx”o”-ṭ

A full program printing to STDOUT. (As a monadic link the return value is a list containing a character and a list of three lists of characters.)

Try it online! Or see the test-suite.

How?

Ḣ⁾f-yɓOBṫ€4a“rwx”o”-ṭ | Main Link: list of characters
Ḣ                     | head & pop (get the 1st character and modify the list)
 ⁾f-                  | list of characters = ['f', '-']
    y                 | translate (replacing 'f' with '-'; leaving 'd' and 'l' unaffected)
     ɓ                | (call that X) new dyadic chain: f(modified input; X)
      O               | ordinals ('0'->48, '1'->59, ..., '7'->55 -- notably 32+16+value)
       B              | convert to binary (vectorises) (getting three lists of six 1s and 0s)
        ṫ€4           | tail €ach from index 4 (getting the three least significant bits)
           “rwx”      | list of characters ['r', 'w', 'x']
          a           | logical AND (vectorises) (1s become 'r', 'w', or 'x'; 0s unaffected)
                 ”-   | character '-'
                o     | logical OR (vectorises) (replacing any 0s with '-'s)
                   ṭ  | tack (prepend the character X) 
                      | implicit print (smashes everything together)
\$\endgroup\$
3
\$\begingroup\$

Perl 6 -p, 37 bytes

s:g[\d]=[X~]('-'X <r w x>)[$/];s/f/-/

Try it online!

Port of Dom Hastings' Perl 5 solution.

\$\endgroup\$
3
\$\begingroup\$

Retina, 38 bytes

Inspired by a comment from ASCII-only.

\d
---$&*
---____
r--
--__
w-
-_
x
f
-

Try it online!

The idea is converting each digit to unary (the default unary digit in Retina is _) with three leading -, and then converting binary digits from the most to the least significant.

\$\endgroup\$
2
\$\begingroup\$

Python 3, 71 bytes

lambda s:("-"+s)[s[0]!="f"]+stat.filemode(int(s[1:],8))[1:]
import stat

Try it online!

Python 3.3+ has a built-in for that, although due to the need for an import, and differences in expected input format, it is not very golf-friendly.

\$\endgroup\$
2
\$\begingroup\$

Tcl, 139 bytes

proc P s {join [lmap c [split $s ""] {expr {[regexp \\d $c]?"[expr $c&4?"r":"-"][expr $c&2?"w":"-"][expr $c&1?"x":"-"]":$c==f?"-":$c}}] ""}

Try it online!


Tcl, 144 bytes

proc P s {join [lmap c [split $s ""] {expr {[regexp \\d $c]?[list [expr $c&4?"r":"-"][expr $c&2?"w":"-"][expr $c&1?"x":"-"]]:$c==f?"-":$c}}] ""}

Try it online!

Tcl, 149 bytes

proc P s {join [lmap c [split $s ""] {if [regexp \\d $c] {list [expr $c&4?"r":"-"][expr $c&2?"w":"-"][expr $c&1?"x":"-"]} {expr {$c==f?"-":$c}}}] ""}

Try it online!

Tcl, 150 bytes

proc P s {join [lmap c [split $s ""] {if [regexp \\d $c] {set v [expr $c&4?"r":"-"][expr $c&2?"w":"-"][expr $c&1?"x":"-"]} {expr {$c==f?"-":$c}}}] ""}

Try it online!

Tcl, 180 bytes

proc P s {join [lmap c [split $s ""] {if [regexp \\d $c] {[set R regsub] (..)1 [$R (.)1(.) [$R 1(..) [$R -all 0 [format %03b $c] -] r\\1] \\1w\\2] \\1x} {expr {$c==f?"-":$c}}}] ""}

Try it online!

Still very ungolfed!

\$\endgroup\$
2
\$\begingroup\$

Java (JDK 10), 118 bytes

s->{var r=s[0]=='f'?"-":""+s[0];var z="-xw r".split("");for(int i=0;++i<4;)r+=z[s[i]&4]+z[s[i]&2]+z[s[i]&1];return r;}

Try it online!

Credits

\$\endgroup\$
2
  • 2
    \$\begingroup\$ When you take the input as lowercase fdl, you can change the var r=s[0]<70?"d":s[0]<72?"-":"l"; to var r=s[0]=='f'?"-":s[0]+""; to save 6 bytes. Also, .toCharArray() can be .split("") to save an additional 4 bytes. \$\endgroup\$ Apr 30, 2018 at 9:32
  • 2
    \$\begingroup\$ @KevinCruijssen Your idea made me save 13 bytes, not 10 (since I could remove the ""+ later on to "cast" a char into a String) ;) Thanks! \$\endgroup\$ Apr 30, 2018 at 9:45
2
\$\begingroup\$

Excel, 224 bytes

=IF(LEFT(A1,1)="f","-",LEFT(A1,1))&CHOOSE(MID(A1,2,1)+1,"---","--x","-w-","-wx","r--","r-x","rw-","rwx")&CHOOSE(MID(A1,3,1)+1,"---","--x","-w-","-wx","r--","r-x","rw-","rwx")&CHOOSE(MID(A1,4,1)+1,"---","--x","-w-","-wx","r--","r-x","rw-","rwx")

Done in 4 stages:

IF(LEFT(A1,1)="f","-",LEFT(A1,1))    Replace "f" with "-".

And 3 times:

CHOOSE(MID(A1,2,1)+1,"---","--x","-w-","-wx","r--","r-x","rw-","rwx")

Trying to be smarter, adds 25 bytes per set of rights, 75 in total:

IF(INT(MID(A1,2,1))>3,"r","-")&IF(MOD(MID(A1,2,1),4)>1,"w","-")&IF(ISODD(MID(A1,2,1)),"x","-")
\$\endgroup\$
2
\$\begingroup\$

05AB1E, 34 27 bytes

ćls8βbvyi…rwx3*Nèë'-}J'f'-:

Try it online!

Golfed down 7 bytes by @MagicOctopusUrn


ć                           # Remove head from string.
 ls                         # Lowercase swap.
   8βb                      # Octal convert to binary.
      vy                    # For each...
        i        ë  }
         …rwx3*Nè           # If true, push the correct index of rwx.
                  '-        # Else push '-'.
                     J      # Repeatedly join stack inside the loop.
                      'f'-: # Repeatedly replace 'f' with '-' inside the loop.
\$\endgroup\$
4
  • \$\begingroup\$ ćls8βbvyi…rwx3*Nèë'-}J'f'-: for 7 less... \$\endgroup\$ May 1, 2018 at 17:01
  • \$\begingroup\$ Basically just a different ordering using if statements, and instead of removing the f I'm just replacing all f's in the final string with -. \$\endgroup\$ May 1, 2018 at 17:09
  • \$\begingroup\$ i <CODE FOR TRUE> ë <CODE FOR FALSE> } \$\endgroup\$ May 1, 2018 at 17:10
  • \$\begingroup\$ @MagicOctopusUrn Nice! \$\endgroup\$ May 1, 2018 at 17:18
1
\$\begingroup\$

Python 2, 238 bytes

lambda m,r=str.replace,s=str.split,j="".join,b=bin,i=int,z=str.zfill,g=lambda h,y:y if int(h)else "-":r(m[0],"f","-")+j(j([g(z(s(b(i(x)),"b")[1],3)[0],"r"),g(z(s(b(i(x)),"b")[1],3)[1],"w"),g(z(s(b(i(x)),"b")[1],3)[2],"x")])for x in m[1:])

Try it online!

I had assumed this would be a drop in the bucket, but I was wrong indeed. Probably should have realized that a lambda wasn't the best idea at some point.

\$\endgroup\$
1
  • \$\begingroup\$ :| too many builtins = too long \$\endgroup\$
    – ASCII-only
    Apr 29, 2018 at 1:46
1
\$\begingroup\$

APL+WIN, 55 bytes

Prompts for input string with leading character lower case:

('dl-'['dlf'⍳↑t]),⎕av[46+(,⍉(3⍴2)⊤⍎¨⍕1↓t←⎕)×9⍴69 74 75]

Explanation:

9⍴69 74 75 create a vector of ascii character codes for rwx -46, index origin 1

1↓t←⎕ prompt for input and drop first character

,⍉(3⍴2)⊤⍎¨⍕ create a 9 element vector by concatenating the binary representation for each digit 

46+(,⍉(3⍴2)⊤⍎¨⍕1↓t←⎕)×9⍴69 74 75 multiply the two vectors and add 46

⎕av[.....] convert back from ascii code to characters, 46 being '-'

('dl-'['dlf'⍳↑t]), append first character from input swapping '-' for 'f'
\$\endgroup\$
1
\$\begingroup\$

Python 3, 77 bytes

lambda a,*b,k='-xw-r':f'{a}-'[a=='f']+''.join(k[x&4]+k[x&2]+k[x&1]for x in b)

Try it online!

\$\endgroup\$
1
\$\begingroup\$

J, 57 52 bytes

5 bytes saved thanks to FrownyFrog!

-&.('-DLld'i.{.),[:,('-',:'rwx'){"0 1&.|:~1#:@}."."0

Try it online!

Yet another long solution... I don't know how to make } work in tacit verbs and that's why I used the much longer {"0 1&.|: for selection.

Explanation:

@}. Drop the first symbol and

,.&.": convert the rest to a list of desimal digits

]:#: convert each digit to a list of binary digits (and cap the fork)

('-',:'rwx') creates a 2-row table and use 0 to select from its first row / 1 - from its second one

   '-',:'rwx'
---
rwx

{"0 1&.|:~ uses the binary digits to select from the table above

[:, flattens the result

('d-l'{~'DFL'i.{.) formats the first symbol

, appends the fisrt symbol to the list of permissions

\$\endgroup\$
5
  • 1
    \$\begingroup\$ The input is already a string, you need 1#:@}."."0 \$\endgroup\$
    – FrownyFrog
    Apr 29, 2018 at 11:57
  • 1
    \$\begingroup\$ This seems to work: ('d-l'{~'DFL'i.{.)-&.('-DLld'i.{.) \$\endgroup\$
    – FrownyFrog
    Apr 29, 2018 at 12:18
  • \$\begingroup\$ @FrownyFrog Very nice use of i. and &. Thanks a lot! By the way, can you explain to me how to use select } in tacit verbs? \$\endgroup\$ Apr 29, 2018 at 14:07
  • 1
    \$\begingroup\$ 2 2 2&#:`('-',:'rwx'"_)}@"."0@}. is exactly the same length \$\endgroup\$
    – FrownyFrog
    Apr 29, 2018 at 18:09
  • \$\begingroup\$ However it doesn’t break on 333 :) \$\endgroup\$
    – FrownyFrog
    Apr 29, 2018 at 18:15
1
\$\begingroup\$

PHP, 68 bytes

<?=strtr(strtr($argn,[f=>_,___,__x,_w_,_wx,r__,r_x,rw_,rwx]),_,"-");

translates f in lowercase input to underscore and every octal number to its rwx equivalent, using underscores instead of dashes (to save the need for quotes), then replaces the _ with -.

Run as pipe with -nF or try it online.

\$\endgroup\$
1
\$\begingroup\$

C (gcc), 109 104 bytes

At least C can convert octal input.... :-)

Edit: I realized that the size modifier wasn't strictly required, and that putchar() is shorter than printf() in this case!

f(a,b){char*s="-xwr";scanf("%c%o",&a,&b);putchar(a-70?a:*s);for(a=9;~--a;putchar(s[(1&b>>a)*(a%3+1)]));}

Try it online!

Original:

f(a,b){char*s="-xwr";scanf("%c%3o",&a,&b);putchar(a-70?a:*s);for(a=9;~--a;printf("%c",s[(1&b>>a)*(a%3+1)]));}

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.