builder: create shards respecting umask

Change-Id: I55412bb11bd1e6bcad089e56229b76edfe5c45b9
diff --git a/build/builder.go b/build/builder.go
index 00d6429..159e890 100644
--- a/build/builder.go
+++ b/build/builder.go
@@ -28,6 +28,7 @@
 	"runtime/pprof"
 	"strings"
 	"sync"
+	"syscall"
 
 	"github.com/google/zoekt"
 	"github.com/google/zoekt/ctags"
@@ -385,6 +386,9 @@
 	if err != nil {
 		return nil, err
 	}
+	if err := f.Chmod(0666 &^ umask); err != nil {
+		return nil, err
+	}
 
 	defer f.Close()
 	if err := ib.Write(f); err != nil {
@@ -403,3 +407,10 @@
 
 	return &finishedShard{f.Name(), fn}, nil
 }
+
+var umask os.FileMode
+
+func init() {
+	umask = os.FileMode(syscall.Umask(0))
+	syscall.Umask(int(umask))
+}
diff --git a/build/e2e_test.go b/build/e2e_test.go
index 8d0850f..2b2b8a9 100644
--- a/build/e2e_test.go
+++ b/build/e2e_test.go
@@ -212,6 +212,13 @@
 		t.Fatalf("Glob(%s): got %v, want 4 shards", glob, fs)
 	}
 
+	if fi, err := os.Lstat(fs[0]); err != nil {
+		t.Fatalf("Lstat: %v", err)
+	} else if fi.Mode()&0666 == 0600 {
+		// This fails spuriously if your umask is very restrictive.
+		t.Errorf("got mode %o, should respect umask.", fi.Mode())
+	}
+
 	// Do again, without sharding.
 	opts.ShardMax = 1 << 20
 	b, err = NewBuilder(opts)