Trouble writing to a directory with 600 perms

I am trying to deploy an app to Heroku, which temporarily stores uploaded files in /tmp.

ioutil.TempDir creates the directory inside /tmp just fine. Because it’s Heroku, perms are set to 0600, but the owner is the same as the user running the app.

The issue happens when I call os.Create, that ends up throwing out permission errors:

2019-12-12T12:09:21.681565+00:00 app[web.1]: 2019/12/12 12:09:21 open /tmp/stream-hot146966131/stream/1080p_001.ts: permission denied
2019-12-12T12:09:21.681571+00:00 app[web.1]: 2019/12/12 12:09:21 drw-------

I added logging to show the error in log, and show the /tmp/stream-hot146966131/stream permissions, which, as you can see, are set up correctly.
The stream directory is created if it doesn’t exist (that name can be different, it is based on the request URL)

Of course, when I run it on my system (which is Windows), that works perfectly fine.

Code:

var tempDir string

func streamHandler(w http.ResponseWriter, r *http.Request) {
	var rex = regexp.MustCompile("^\\/([a-zA-Z0-9]*)\\/([a-zA-Z0-9_]*\\.(?:m3u8|ts))$")
	url := rex.FindStringSubmatch(r.URL.String())
	if r.Method == "PUT" {
		if url == nil {
			http.Error(w, "URL has to be a path to HLS fragment/playlist.", http.StatusBadRequest)
			return
		}
		stat, err := os.Stat(filepath.Join(tempDir, url[1]))
		if os.IsNotExist(err) {
			os.MkdirAll(filepath.Join(tempDir, url[1]), 0666)
		}
		f, err := os.Create(filepath.Join(tempDir, url[1], url[2]))
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Println(err.Error())
			if stat != nil {
				log.Println(stat.Mode())
			}
			return
		}
		defer f.Close()
		_, err = io.Copy(f, r.Body)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		w.WriteHeader(200)
		w.Write([]byte("OK"))
		return
	}
}

func registerHandlers() {
	var err error
	tempDir, err = ioutil.TempDir("", "stream-hot")
	if err != nil {
		panic(err)
	}
	http.HandleFunc("/", streamHandler)
}

A directory needs the execute bit to allow “entering” it, so 0600 isn’t a very useful permission set for a directory. You want at least 0700 instead. Using 0777 (or, better, 0755) in your os.MkdirAll should work.

3 Likes

Thanks, that actually worked!

Quick question, is that just how golang does things, or is that actually a unix/linux quirk?

Unix.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.