Manage permissions

593 views
Skip to first unread message

Joan Miller

unread,
Mar 24, 2010, 9:12:00 AM3/24/10
to golang-nuts
This function will be very useful to working with permissions. Instead
of to write a number you could use constants to define it.

Please add it to Go.

---------------
// Thess constants shoud be in 'os' package.
const (
PERM_X = 1
PERM_W = 2
PERM_R = 4
)

func PermToInt(perm_const []int) (perm_num int) {
var perm string

for i := 0; i < len(perm_const); i++ {
perm += strconv.Itoa(perm_const[i])
}

perm_num, _ = strconv.Atoi(perm)
return perm_num
}
---------------
To use it:

perm := PermToInt([]int {PERM_W+PERM_R, PERM_R, PERM_R}) // Should
have 644

Samuel Baldwin

unread,
Mar 24, 2010, 9:24:24 AM3/24/10
to Joan Miller, golang-nuts
2010/3/24 Joan Miller <pelo...@gmail.com>:

> perm := PermToInt([]int {PERM_W+PERM_R, PERM_R, PERM_R})  // Should

Could be:

... PERM_W|PERM_R ...

rather than +; seems to be more canonical.

I like the idea, but there's probably a better implementation. The
function should probably look more like:

func PermToInt(all, group, user int) (perm int) {
return (all * 100) + (group * 10) + user
}

Or even use the variadic argument list '...' if you don't want more
than just three (not sure what the use case for that is, though).
--
Samuel Baldwin - logik.li

Joan Miller

unread,
Mar 24, 2010, 9:37:29 AM3/24/10
to golang-nuts

On 24 mar, 13:24, Samuel Baldwin <recursive.for...@gmail.com> wrote:
> 2010/3/24 Joan Miller <pelok...@gmail.com>:


>
> > perm := PermToInt([]int {PERM_W+PERM_R, PERM_R, PERM_R})  // Should
>
> Could be:
>
>         ... PERM_W|PERM_R ...
>
> rather than +; seems to be more canonical.
>
> I like the idea, but there's probably a better implementation. The
> function should probably look more like:
>
> func PermToInt(all, group, user int) (perm int) {
>         return (all * 100) + (group * 10) + user
>
> }

Your implementation is better. Down is the correct name used for the
permissions:

func PermToInt(owner, group, others int) (perm int) {
return (owner * 100) + (group * 10) + others
}

Joan Miller

unread,
Mar 24, 2010, 9:46:13 AM3/24/10
to golang-nuts

And could be checked if the arguments has any of the values in
permissions constants

Anything as (for each argument):

if perm_const != os.PERM_X || perm_const != PERM_W || perm_const !=
PERM_R {*error*}

chris dollin

unread,
Mar 24, 2010, 9:49:57 AM3/24/10
to Joan Miller, golang-nuts

What's the meaning of the returned integer supposed to be? If it's
to be passed as a permissions value, shouldn't those multipliers
be 64 and 8? If it's supposed to be printed out and "look like" a Unixy
octal permission number, wouldn't using a string be less fragile?

(Since new types are cheap in Go, I'd suggest creating a type
Perm or Permission for permission values, so as not to confuse
them with integers you might increment or strings you might
concatenate.)

--
Chris "permissive" Dollin

Samuel Baldwin

unread,
Mar 24, 2010, 9:54:12 AM3/24/10
to Joan Miller, golang-nuts
const (
PERM_X = 1
PERM_W = 2
PERM_R = 4
)

func PermToInt(owner, group, others int) (perm int) {
if owner > 7 || owner owner < 0 || group > 7 || group < 0 ||
others > 7 || others < 0 {
return -1


}
return (owner * 100) + (group * 10) + others
}

--
Samuel Baldwin - logik.li

chris dollin

unread,
Mar 24, 2010, 9:55:44 AM3/24/10
to Joan Miller, golang-nuts
On 24 March 2010 13:46, Joan Miller <pelo...@gmail.com> wrote:

And could be checked if the arguments has any of the values in
permissions constants

Anything as (for each argument):

if perm_const != os.PERM_X || perm_const != PERM_W || perm_const !=
PERM_R {*error*}

PERM_X|PERM_W is a sensible example value this test will reject.

Better (and simpler) would be

 (perm_const &^ 7) != 0

if I've understood things correctly.

--
Chris "bitwise even if not wise" Dollin

Joan Miller

unread,
Mar 24, 2010, 9:58:22 AM3/24/10
to golang-nuts

On 24 mar, 13:12, Joan Miller <pelok...@gmail.com> wrote:
> This function will be very useful to working with permissions. Instead
> of to write a number you could use constants to define it.
>
> Please add it to Go.
>
> ---------------
> // Thess constants shoud be in 'os' package.
> const (
>         PERM_X = 1
>         PERM_W = 2
>         PERM_R = 4
> )

I forgot myself of that there is another constant; for '-' which is 0:

It could be defined as:

PERM_N = 0
or
PERM_Z = 0
or simply
PERM_ = 0

Joan Miller

unread,
Mar 24, 2010, 10:00:48 AM3/24/10
to golang-nuts
If you see in os package [1] the functions that use perm as parameter,
you'll see that perm is an integer. Anyway I'm agree in creating a
type for permission values.

[1] http://golang.org/pkg/os/

On 24 mar, 13:49, chris dollin <ehog.he...@googlemail.com> wrote:

chris dollin

unread,
Mar 24, 2010, 10:16:09 AM3/24/10
to Joan Miller, golang-nuts
On 24 March 2010 14:00, Joan Miller <pelo...@gmail.com> wrote:
If you see in os package [1] the functions that use perm as parameter,
you'll see that perm is an integer.

In that case, if the PermToInt function is supposed to deliver
values to those functions, the multipliers are wrong, AFAICS.

--
Chris "once was octal" Dollin

Joan Miller

unread,
Mar 24, 2010, 11:02:25 AM3/24/10
to golang-nuts
Resuming code:

----------------
const (
PERM_ = 0


PERM_X = 1
PERM_W = 2
PERM_R = 4
)

// 'PermToInt' convert permissions defined with constants to an
integer.


func PermToInt(owner, group, others int) (perm int) {

// Check if the permissions are correct.
if (owner &^ 7) != 0 || (group &^ 7) != 0 || (others &^ 7) != 0 {
return -1
}

return (owner * 100) + (group * 10) + others

----------------
It returns correctly the integer; to checking it:

----------------
perm := PermToInt(PERM_W|PERM_R, PERM_R, PERM_R)
if 644 != perm {
fmt.Println("error")
}
----------------


On 24 mar, 14:16, chris dollin <ehog.he...@googlemail.com> wrote:

Joan Miller

unread,
Mar 24, 2010, 11:13:18 AM3/24/10
to golang-nuts
There is a bug.

Cann't be passed a permission as 644 else that there is to prepend a 0
(if it's a file), else the permissions will be wrond created.

Then, if you pass directly 0644 to any function in os package will
works ok because it reads that 0 too, but if you save a permission as
0644 into a variable then that 0 is deleted.

So, one solution would be use that the parameter 'perm' (in os package
and another ones) were as string instead of integer.

chris dollin

unread,
Mar 24, 2010, 11:17:42 AM3/24/10
to Joan Miller, golang-nuts
On 24 March 2010 15:02, Joan Miller <pelo...@gmail.com> wrote:
Resuming code:

----------------
const (
       PERM_  = 0
       PERM_X = 1
       PERM_W = 2
       PERM_R = 4
)

// 'PermToInt' convert permissions defined with constants to an
integer.
func PermToInt(owner, group, others int) (perm int) {
       // Check if the permissions are correct.
       if (owner &^ 7) != 0 || (group &^ 7) != 0 || (others &^ 7) != 0 {
               return -1
       }

       return (owner * 100) + (group * 10) + others
----------------
It returns correctly the integer; to checking it:

----------------
perm := PermToInt(PERM_W|PERM_R, PERM_R, PERM_R)
if 644 != perm {
       fmt.Println("error")
}

You want the answer to be /octal/ 644, ie 0644, not /decimal/ 644.

--
Chris "allusive" Dollin

Daniel Smith

unread,
Mar 24, 2010, 11:18:19 AM3/24/10
to Joan Miller, golang-nuts
0644 is an octal number (It's 420 in decimal). 644 is a decimal number. Your * 10 and * 100 are for base 10 numbers, but permissions are octal. They should be * 8 and * 64.

To unsubscribe from this group, send email to golang-nuts+unsubscribegooglegroups.com or reply to this email with the words "REMOVE ME" as the subject.



--
Daniel Smith
http://www.schaumburggoclub.org/

chris dollin

unread,
Mar 24, 2010, 11:25:35 AM3/24/10
to Joan Miller, golang-nuts
On 24 March 2010 15:13, Joan Miller <pelo...@gmail.com> wrote:
There is a bug.

Then, if you pass directly 0644 to any function in os package will
works ok because it reads that 0 too,

No, it doesn't. The leading 0 is handled by the compiler; it says
that the value is /written/, in text, in octal. It represents the same value
as the decimal representation 420.

but if you save a permission as
0644 into a variable then that 0 is deleted.

No, it isn't. It was only ever there at compile-time; "saving" the
permission doesn't delete anything. The value 420 gets copied.
 
So, one solution would be use that the parameter 'perm' (in os package
and another ones) were as string instead of integer.

That would be silly; the integer values work perfectly well so long
as you realise that they correspond to bits in the binary representation,
and octal is a convenient way to take the bits three at a time.
 
--
Chris "remembering PDP 8s and 11s" Dollin

Joan Miller

unread,
Mar 24, 2010, 6:58:28 PM3/24/10
to golang-nuts
Now, it's all fixed. Thanks all for to get it!

----------------
const (
PERM_ = 0 // No permission
PERM_X = 1 // Execute (for files); go through (for directories)
PERM_W = 2 // Write
PERM_R = 4 // Read
)

// 'PermToInt' convert permissions defined with constants to an
integer.
func PermToInt(owner, group, others int) (perm int) {
// Check if the permissions are correct.
if (owner &^ 7) != 0 || (group &^ 7) != 0 || (others &^ 7) != 0 {

fmt.Fprintf(os.Stderr, "Permission is not octal: %d%d%d\n", owner,
group, others)
os.Exit(1)
}

// Since the constants of permissions are in octal, there is to do
// the multiplication in octal, and get the value in decimal.
return (owner * 64) + (group * 8) + others
----------------

Message has been deleted

peterGo

unread,
Mar 24, 2010, 11:49:22 PM3/24/10
to golang-nuts
Joan,

The Go syscall package already has the standard *nix mode_t constants.
Why not use them to construct or test permissions?

S_IEXEC = 0x40
S_IREAD = 0x100
S_IRGRP = 0x20
S_IROTH = 0x4
S_IRUSR = 0x100
S_IRWXG = 0x38
S_IRWXO = 0x7
S_IRWXU = 0x1c0
S_IWGRP = 0x10
S_IWOTH = 0x2
S_IWRITE = 0x80
S_IWUSR = 0x80
S_IXGRP = 0x8
S_IXOTH = 0x1
S_IXUSR = 0x40

For example, for full permissions:

perm := syscall.S_IRWXU | syscall.S_IRWXG | syscall.S_IRWXO.

which avoids octal magic numbers:

perm := (07 << (2 * 3)) + (07 << (1 * 3)) + (07 << (0 * 3))

Peter

Russ Cox

unread,
Mar 24, 2010, 11:50:28 PM3/24/10
to peterGo, golang-nuts
> The Go syscall package already has the standard *nix mode_t constants.
> Why not use them to construct or test permissions?

Nothing in syscall is guaranteed to be present from
system to system; os is the portable interface.

Why not just write octal constants?
This is almost the only reason they're in the language.
0755 is far clearer, to people who read that kind of code, than
S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH.

Russ

Joan Miller

unread,
Mar 25, 2010, 4:22:07 AM3/25/10
to golang-nuts

Having a function that converts constants to octal (for permissions)
doesn't hurt to anybody. Whatever could follow using octal constants.

Having a constants as
const (
P_READ = 4
P_WRITE = 2
P_EXEC = 1
)

it's far clearer, when you read the code
perm := PermToInt(os.P_READ|os.P_WRITE|os.P_EXEC, os.P_READ,
os.P_READ)

than 0755, overall because a developer doesn't have to know how works
the permissions in octal.

Althought it been more verbose but its meaning remains enough clear
for everybody.

Joan Miller

unread,
Mar 25, 2010, 4:26:30 AM3/25/10
to golang-nuts

On 25 mar, 08:22, Joan Miller <pelok...@gmail.com> wrote:
> Having a constants as
>     const (
>             P_READ = 4
>             P_WRITE = 2
>             P_EXEC = 1
>     )
>
> it's far clearer, when you read the code
>     perm := PermToInt(os.P_READ|os.P_WRITE|os.P_EXEC, os.P_READ,
> os.P_READ)
>
> than 0755, overall because a developer doesn't have to know how works
> the permissions in octal.

For 0755, it should be:

perm := PermToInt(os.P_READ|os.P_WRITE|os.P_EXEC, os.P_READ|P_EXEC,
os.P_READ|P_EXEC)

Kevin Ballard

unread,
Mar 25, 2010, 5:09:05 AM3/25/10
to Joan Miller, golang-nuts
I disagree.

> perm := PermToInt(os.P_READ|os.P_WRITE|os.P_EXEC, os.P_READ,
> os.P_READ)

is much harder to read than 0755 for anybody that understands octal
permissions. And since octal permissions are relatively trivial to
learn, I see no reason why we should encourage developers to be
unnecessarily verbose.

-Kevin Ballard

> To unsubscribe from this group, send email to golang-nuts+unsubscribegooglegroups.com or reply to this email with the words "REMOVE ME" as the subject.
>

--
Kevin Ballard
http://kevin.sb.org
kbal...@gmail.com

dipoll

unread,
Mar 25, 2010, 5:11:02 AM3/25/10
to golang-nuts
> Why not just write octal constants?
> This is almost the only reason they're in the language.
> 0755 is far clearer, to people who read that kind of code, than
> S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH.

I assume that 0752 should give the same permissions as `chmod 0752
FPERM_test`


package main

import "os"

func main(){
file, _ := os.Open("FPERM_test", os.O_CREATE, 0652)
file.Close()
}


0755 :
chmod : -rwxr-xr-x
prog : -rwxr-xr-x

0752 :
chmod : -rwxr-x-w-
prog: -rw-r-x---

So is it a difference between chmod and os.Open permission values?


Regards,
Dmytro

chris dollin

unread,
Mar 25, 2010, 5:14:22 AM3/25/10
to dipoll, golang-nuts
On 25 March 2010 09:11, dipoll <mcyb...@gmail.com> wrote:

I assume that 0752 should give the same permissions as `chmod 0752
FPERM_test`
 
       file, _ := os.Open("FPERM_test", os.O_CREATE, 0652)

Did your program really use 0652 rather than 0752?

--
Chris "allusive" Dollin

roger peppe

unread,
Mar 25, 2010, 5:26:51 AM3/25/10
to dipoll, golang-nuts
On 25 March 2010 09:11, dipoll <mcyb...@gmail.com> wrote:
> I assume that 0752 should give the same permissions as `chmod 0752
> FPERM_test`

no, because os.Open will be subject to umask
(often 022) which can mask out some bits of the
file's permissions on create. it looks like that's what has
happened in your case: (0652 &^ 022) == 0650

(N.B. your code has 0652, not 0752)

if you use os.Chmod instead, you should see the answer
you were expecting.

Joan Miller

unread,
Mar 25, 2010, 5:48:11 AM3/25/10
to golang-nuts

On 25 mar, 09:09, Kevin Ballard <kball...@gmail.com> wrote:
> I disagree.
>
> >    perm := PermToInt(os.P_READ|os.P_WRITE|os.P_EXEC, os.P_READ,
> > os.P_READ)
>
> is much harder to read than 0755 for anybody that understands octal
> permissions. And since octal permissions are relatively trivial to
> learn, I see no reason why we should encourage developers to be
> unnecessarily verbose.
You are not encouraging developers to be unnecessarily verbose because
*they can use octal permissions*.

In change, you are forcing to them to use octal when anybody could
want to use those constants.

Joan Miller

unread,
Mar 25, 2010, 6:12:13 AM3/25/10
to golang-nuts
Anyway, to doesn't be too verbose, could be used the next constants:

const (
P_RWX = 7
P_RW = 6
P_RX = 5
P_R = 4
P_WX = 3
P_W = 2
P_X = 1
)
so,

perm := PermToInt(os.P_RWX, os.P_R, os.P_R)

Dmitry Panchenko

unread,
Mar 25, 2010, 7:53:17 AM3/25/10
to roger peppe, golang-nuts
Thank you guys,

I forgot about umask. After I set it to 0000 I got the correct permissions.


> it's far clearer, when you read the code 
>     perm := PermToInt(os.P_READ|os.P_WRITE|os.P_EXEC, os.P_READ, 
> os.P_READ)
 
As for me this looks better:
 UnixPerm("rwx","rx","r")

--
Regards,

Dmitry Panchenko

Joan Miller

unread,
Mar 25, 2010, 8:53:43 AM3/25/10
to golang-nuts

On 25 mar, 11:53, Dmitry Panchenko <mcybe...@gmail.com> wrote:
> Thank you guys,
>
> I forgot about umask. After I set it to 0000 I got the correct permissions.
>
> > it's far clearer, when you read the code
> >     perm := PermToInt(os.P_READ|os.P_WRITE|os.P_EXEC, os.P_READ,
> > os.P_READ)
>
> As for me this looks better:
>  UnixPerm("rwx","rx","r")

To use it as string there would be to implement it through switch for
each argument which affects to its performance.

In change, anything as the next one has greater performance and its
readable for whatever.
UnixPerm(os.P_RWX, os.P_RX, os.P_R)

or removing thath "P_" to get it less verbose
UnixPerm(os.RWX, os.RX, os.R)

dipoll

unread,
Mar 25, 2010, 9:11:12 AM3/25/10
to golang-nuts
> In change, anything as the next one has greater performance and its
> readable for whatever.
>     UnixPerm(os.P_RWX, os.P_RX, os.P_R)
>
> or removing thath "P_" to get it less verbose
>     UnixPerm(os.RWX, os.RX, os.R)

Agree,

os.RWX
os.R
os.W
os.WX
os.RW
os.RX
os.X
looks simple

Joan Miller

unread,
Mar 25, 2010, 9:23:53 AM3/25/10
to golang-nuts
I agree too. Resuming code:

----------------------

// Permissions in octal
const (
RWX = 7
RW = 6
RX = 5
R = 4
WX = 3
W = 2
X = 1
)

/* Convert permissions defined with constants to an integer.

Return the value in decimal.
*/
func UnixPerm(owner, group, others int) (perm int) {


// Check if the permissions are correct.
if (owner &^ 7) != 0 || (group &^ 7) != 0 || (others &^ 7) != 0 {

fmt.Fprintf(os.Stderr, "(UnixPerm) permission is not octal: %d%d%d


\n",
owner, group, others)
os.Exit(1)
}

// Since the constants of permissions are in octal, there is to do

// the multiplication in octal.


return (owner * 64) + (group * 8) + others
}

----------------------

If I'm not wrong those multiplications could be made through bits
which would be a lot of faster. I believe that was using '<<'.

chris dollin

unread,
Mar 25, 2010, 10:12:30 AM3/25/10
to Joan Miller, golang-nuts
On 25 March 2010 13:23, Joan Miller <pelo...@gmail.com> wrote:


/* Convert permissions defined with constants to an integer.

Return the value in decimal.

NO, NO, NO. The value returned is not "in decimal". It's just a
value (or, if you're concerned with representation, it's (typically)
in /binary/).           
 
fmt.Fprintf(os.Stderr, "(UnixPerm) permission is not octal: %d%d%d
\n",

It's not that the permission is "not octal". It's that it has bits that
are not allowed in a 3-bit permission field.


       // Since the constants of permissions are in octal, there is to do
       // the multiplication in octal.
       return (owner * 64) + (group * 8) + others

The multiplication is not "in octal", although it multiplying
by powers of 8.
 
If I'm not wrong those multiplications could be made through bits
which would be a lot of faster.

Hardly, even if the compiler doesn't optimise it.
 
I think I'm with Russ et al on this: what you're doing is actually
making the use of bit-encoded permissions /harder/: more verbose
and hiding the underlying simple bit representation.

(And doing an os.Exit if the values are out of range? That;'s surely
not a good plan.)

--
Chris "allusive" Dollin

Joan Miller

unread,
Mar 25, 2010, 12:42:38 PM3/25/10
to golang-nuts
I don't know if would be correct that it returns an instance of
os.Error.

--------------------


/* Convert permissions defined with constants to an integer.

Return the permission as integer.
*/
func UnixPerm(owner, group, others int) (perm int, err os.Error) {


// Check if the permissions are correct.
if (owner &^ 7) != 0 || (group &^ 7) != 0 || (others &^ 7) != 0 {

err := fmt.Sprintf("(UnixPerm) permission is not octal: %d%d%d\n",
owner, group, others)
return 0, os.NewError(err)
}

// In octal, numerals each place is a power with base 8.
return (owner * 64) + (group * 8) + others, nil
}

On 25 mar, 14:12, chris dollin <ehog.he...@googlemail.com> wrote:

Joan Miller

unread,
Mar 25, 2010, 1:30:06 PM3/25/10
to golang-nuts
Fixed:

----------------------
// Permissions in octal
const (
RWX = 7
RW = 6
RX = 5
R = 4
WX = 3
W = 2
X = 1
)

/* Convert permissions defined in octal with constants to an integer.

Unix file permissions are nine bits of information (3 types x 3 type
of users),
each of them may have just one of two values: allowed or denied.

Return the permission as integer.
*/

func UnixPerm(owner, group, other int) (perm int, err os.Error) {


// Check if the permissions are correct.

if (owner &^ 7) != 0 || (group &^ 7) != 0 || (other &^ 7) != 0 {
err := fmt.Sprintf("[UnixPerm] wrong permission: %d (owner), %d
(group), %d (other)\n",
owner, group, other)
return 0, os.NewError(err)
}

// In octal, numerals each place is a power with base 8.

return (owner << (2*3)) + (group << (1*3)) + other, nil
}

On 25 mar, 14:12, chris dollin <ehog.he...@googlemail.com> wrote:

Joan Miller

unread,
Mar 25, 2010, 1:54:04 PM3/25/10
to golang-nuts

This error message could be better:

err := fmt.Sprintf("[UnixPerm] permission with any non-octal
value: %d (owner), %d (group), %d (other)\n", owner, group, other)

Giles Lean

unread,
Mar 25, 2010, 6:43:56 PM3/25/10
to Joan Miller, golang-nuts

Hi Joan,

I've been trying to stay out of this discussion, but 2c is now
inisting on being heard.

First up: I think the proposal is far too modest. I challenge
you to find a real, live, Unix programmer who is happier with
the named constants than they are with actual octal values,
and who can't write the necessary bit shifts (and get them
right) off the top of their head.

(OK, the second or third time they write them at least. We
all played the decimal v. ocatal game once or twice early
on. ;-)

Secondly, you are missing three of the twelve permissions
bits: the "sticky" bit (so called, now generally used on /tmp
et al to control deletion permissions on directories), the
setgid bit, and the setuid bit.

If you're going to continue to spend time on this effort, I'd
recommend creating something that does more than replace the
one line of very obvious bit-shifting and or-ing or and-ing
that most programmers will still write instead of using this
proposed function.

Of course, what you do for your own interest, in your own
time, and what you promote is up to you, and your 2c counts
for as much as mine. (Possibly more, if your 2c is in $USD, €
(Euros), or 2p in £ (UKP); my AUD$ is still worth less than
1:1 against any of those currencies for the moment.)

A more interesting option might be to look into supporting not
the current three arguments you have, but instead a string of
the format of the full symbolic syntax accepted by chmod(1).

Translating chmod's symbolic modes to an integer value isn't
terribly difficult, but it's more complex than most people are
aware and getting it right for the complex cases (and creating
tests for them) would offer more of a challenge:

http://www.opengroup.org/onlinepubs/009695399/utilities/chmod.html

n.b. While the format is documented in the chmod(1)
description, at least a couple of other utilities use it too,
so there's a limited argument for making it a package
function.

The idea has the additional advantage of being targeted at
users, who typically in my experience have a less solid
understanding of Unix permissions than programmers, who
usually either are up to speed already or who can be brought
up to speed very quickly.

(Except, off course, nobody can be brought up to speed on
Access Control Lists (ACLs) very quickly, as every vendor of
Unix-like systems does them differently, if they support
them at all.)

The reverse of the chmod-style symbolic mode (translating
integer permissions to something like ls(1) output), is, of
course, much easier:

http://www.opengroup.org/onlinepubs/009695399/utilities/ls.html

Now, some general comments on your code: as well as the
missing functionality mentioned above (twelve permissions
bits, not nine) he code itself I find less clear than it could
be.

Joan Miller <pelo...@gmail.com> wrote:

> Fixed:
>
> ----------------------
> // Permissions in octal
> const (
> RWX = 7
> RW = 6
> RX = 5
> R = 4
> WX = 3
> W = 2
> X = 1
> )

What about the sticky bit, the setgid bit, and the setuid bit?
They're part of the permissions too:

http://www.opengroup.org/onlinepubs/007908799/xsh/sysstat.h.html

...
S_ISUID
set-user-ID on execution
S_ISGID
set-group-ID on execution
S_ISVTX
on directories, restricted deletion flag
...

From:

http://golang.org/pkg/syscall/

S_ISGID = 0x400
S_ISUID = 0x800
S_ISVTX = 0x200

Note how unobvious those values become in hexadecimal.
Wouldn't the following using octal be clearer?

S_ISGID = 02000
S_ISUID = 04000
S_ISVTX = 01000

> ...


> Unix file permissions are nine bits of information (3 types x 3 type
> of users),

> ...

s/nine/twelve/ and the reset of the sentence then needs changing.

> func UnixPerm(owner, group, other int) (perm int, err os.Error) {
> // Check if the permissions are correct.
> if (owner &^ 7) != 0 || (group &^ 7) != 0 || (other &^ 7) != 0 {
> err := fmt.Sprintf("[UnixPerm] wrong permission: %d (owner), %d
> (group), %d (other)\n",
> owner, group, other)
> return 0, os.NewError(err)
> }

Not sure where you'd choose to put the extra three bits I
mentioned, but one way would be to make each of these values
four bits; another would be to add a fourth argument; another
would be to take a single string argument a la chmod(1) as I
suggested above.

Further, you might as well go ahead and make the error message
specific about which argument(s) are outside their allowed
domain. (It's usually helpful to specify what the acceptable
domain is too: someone who has got it wrong other than through
a simple typo will appreciate the extra help.)

I would use octal output in any error message too: even I
don't read decimal permissions values fluently. Based on a
comment of Russ's, Unix permissions are the main reason octal
constants are supported in Go: that's how strongly they've
fixed themselves in people's minds since the time Unix
introduced its permissions style decades ago.

> // In octal, numerals each place is a power with base 8.

Er ... 'add one to a'? Octal _is_ base 8.

> return (owner << (2*3)) + (group << (1*3)) + other, nil

Again, needs enhancement for the missing bits, and the
multiplications don't add anything to make this readable IMHO:
indeed they make it less so; pure bit shifts are the more
usual way of writing this code in all the Unix utilities and
application code I've seen.

In summary, I'd recommend either taking on the chmod(1)
symbolic mode representation translation, or just dropping
this quietly. Given the resistance we're starting to see
about expanding the standard library, I don't expect either
function to make the Go core distribution.

You may, of course, disagree with me (and probably will), and
I'll shut up from this point on unless you ask for comment
after taking the idea in the direction of the POSIX symbolic
permisssions.

Regards,

Giles

P.S. If you do carry on with this, you'd want to figure how to
document the influence of umask, and whether it should be an
option to your function to see the effect of the current umask
or whether you should have two functions.

Either way I suggest it's interesting to get the integer that
represents the permissions you're about to ask for, or the
permisssions you'll actually get (race conditions with Umask()
calls in other goroutines allowing).

Happily, at least someone arranged to fix Umask() for the
platforms for which it was broken and that fix has been in the
last couple of releases at minimum. :-)

Joan Miller

unread,
Mar 26, 2010, 4:54:18 AM3/26/10
to golang-nuts
Thanks Giles for take your time on write all that. I'll try to
implement it when I've any time and I have finished another packages.

It's possible that Unix programmers been happier using the octal
values, but I'm sure that there are another programmers (overall
coming from dynamic languages) that will be happier using constants.

and who can't write the necessary bit shifts (and get them
right) off the top of their head.

Joan Miller

unread,
Mar 27, 2010, 9:44:00 AM3/27/10
to golang-nuts
I've changed it to use a map (like a dictionary in python) instead of
constants. It remains less verbose.

http://bitbucket.org/ares/go-osutil/src/tip/osutil/posixperm.go#cl-63

On 25 mar, 11:53, Dmitry Panchenko <mcybe...@gmail.com> wrote:

Russ Cox

unread,
Mar 27, 2010, 5:13:53 PM3/27/10
to golang-nuts
Drifting slightly off topic, but
even the Wall Street Journal agrees.
Friday's crossword puzzle's 6 across is
"Notation used for Unix permissions" and
the answer is OCTAL.

Russ

Joan Miller

unread,
Mar 27, 2010, 8:21:18 PM3/27/10
to golang-nuts
1) That function doesn't hurts to anybody since that whatever can use
octal.

2) It's more readable 'UnixPerm("rw","r","r")' than '0644'

3) I don't pretend that it been added to the Go core. It will be into
an external package together to all functions related to operations on
Posix paths where I'm working.

Reply all
Reply to author
Forward
0 new messages