Taking a stab at the Go Language and file permissions

Go is a C-like language and initially developed at Google, it has caught my attention by some members of the node.js and web development community giving it a shot and also some interesting looking projects. You can check it out at golang.org.

Further I wanted to look beyond my own plate of mainly scripting languages and gain some experience in something statically typed. Usually it's all JavaScript, PHP and a little ruby in my code editor, so this was a lot of fun biting down on some more typecasting and a compiler that doesn't let you import a library without using it.

My first program in GoLang

Since I learn best by writing something that actually is of use to me, I decided to use go to write a little testing tool for one of the assignments I put my students through ;)

It's for the time after they have been through the obligatory classes and have to specialise themselves, so this assignment would only be given to those who choose to have their specialisation in Linux client or server.

Here's a simplified version of the code that is the testing program which tests if the permissions are set right with chmod.

package main

import (
  "os"
  "fmt"
)

func main() {
  /* define which folder the files are expected in */
  var path string = "files/"
  /* define the files that are expected to be in that folder */
  expected_files := map[string]string{
    "secret.txt": "-rw-------",
    "secret2.txt": "-rw-------",
    /* in live version more files here */
  }

  fmt.Println("starting the test: \n")

  for i := range expected_files {
    var thispath string = ""
    thispath += path
    thispath += i
    file, error := os.Lstat(thispath)
    if error != nil {
      panic(error)
    }

    var thismode = file.Mode().String()
    if thismode == expected_files[i]{
      fmt.Printf("%s looks great! \n", i)
    } else {
      fmt.Printf("%s does not have the right permissions \n", i)
      fmt.Printf("expected:\t%s \n", expected_files[i])
      fmt.Printf("actual value:\t%s \n", thismode)
      fmt.Println()
    }
  }
}

So this enables the student to test themselves if the permissions are set correctly. I'm using a map with strings as both key and value, for filename and the desired permissions. That the order the map is processed in with the loop is not necessarily the same every time doesn't bother me, since in the end just all the files have to be set correctly. If a file does not have the right permissions, it shows what was expected and what actually was met, kind of like a unit test. Here an example output:

[geronimo@Shelly test-04]$ go run fs-check-blog.go
starting the test:

secret.txt looks great!
secret2.txt does not have the right permissions
expected:    -rw-------
actual value:    -rwxrwxrwx

So the point of this assignment is to make the student work with chmod and ls -l to validate. To be sure the assignment is done, this little testing tool exists, plus I really wanted to code a little with go.

golang dependencies and unused errors

Go is pretty cool, the compiler feels very thorough and tries to make you a better programmer. I uncommented some things while I was writing this just to try to output something inside a loop and I wasn't using the os library, which just made my program fail like this:

[geronimo@Shelly test-04]$ go run tmp-os.go
# command-line-arguments
./tmp-os.go:4: imported and not used: "os"

So I'm importing a library without using it, in production I know I shouldn't be doing that! The comforting thing about this is that go will nag you about this, so actually you don't have to have all the dependencies in your head and remember what you have to toggle on and off. It keeps your programs smaller and tidier. The way dependencies are imported feels very natural if you come from C or also node, where you just var request = require('request'); or similar.

Debugging and interfaces in go

Debugging actually was not that easy to figure out, also because the verbose version of values emitted by interfaces can have a different go-internal format. Also if you come from the JavaScript

In JavaScript we can output values with a simple console.log and we don't have to have any idea what on earth is inside it. Is it an object, array, string, integer or double? We don't care!

var someThing = [1,2,3,4];
console.log(someThing);
someThing = 'woop';
console.log('what? ' + someThing);

In go if we want to get a verbose look at what is inside an interface we can use fmt.Printf like so:

file, error := os.Lstat(thispath)
if error != nil {
  panic(error)
}
fmt.Printf("%+v", file)

Example program:

package main

import (
  "os"
  "fmt"
)

func main() {
  file, error := os.Lstat("files/secret.txt")
  if error != nil {
    panic(error)
  }
  fmt.Printf("%v \n", file)
  fmt.Printf("%&v \n", file)
  fmt.Printf("%+v \n", file)
  fmt.Printf("%s \n", file.Mode())
}

Output:

&{secret.txt 30 384 {63552784023 203433791 0x5449c0} 0xc208034000}

&{%!&(string=secret.txt) %!&(int64=30) %!&(os.FileMode=384) {%!&(int64=63552784023) %!&(uintptr=203433791) %!&(*time.Location=&{ [] [] 0 0 <nil>})} %!&(*syscall.Stat_t=&{2051 657804 1 33152 1000 100 0 0 30 4096 8 {1417350589 901935340} {1417187223 203433791} {1417187225 416696880} [0 0 0]})}v

&{name:secret.txt size:30 mode:384 modTime:{sec:63552784023 nsec:203433791 loc:0x5449c0} sys:0xc208034000}

-rw-------

This can be a little confusing, because the corresponding functions can emit other falues, like the mode, which in the above output is 384 will actually be result in:

-rw-------

Will I write more in golang?

The documentation has been great and it was pretty easy to find what you need, if you know what you're looking for. The thing you have to get over if you come from the scripting world is to remember your types and if you write something where performance is crucial, pick the right ones from the start.

The big advantage for me is that I can hand people a binary they can run to verify that they have completed a task according to the specifications and it's more trouble to disassemble the binary than it is to learn the tool I want them to learn. Written in node, they would probably open up the file instead of looking at the written assignment ;)

This idea of learning is by the way pretty much inspired by nodeschool, which have some very admirable courses on everything having to do with node, express, streams and a bunch of other things.

Tagged with: #go #golang

Thank you for reading! If you have any comments, additions or questions, please tweet or toot them at me!