`os.File` offers a `Chmod()` method. This is often safer and more direct
to use than `os.Chmod()` because it operates on an open file descriptor
rather than having to lookup the file by name. Without this, it's
possible for the target file to be renamed, in which case an
`os.Chmod()` would either fail or apply to any file that's taken its
place.
Therefore, add the `Chmod()` method to the `File` interface, and
implement it for all `File` implementations. The bulk of this change is
in `MemMapFs`, which required moving the chmod functionality down into
the `mem` package so that it can be shared between both `mem.File` and
`MemMapFs`.
Fixes a pass-by-value error in FileData.Name() which causes the mutex to be copied, and use that method to retrieve the name of the file from a mem.File. This really fixes the data race that motivated PR #95. (#96)
I can't explain why moving the lock improves the situation, nor why calling through the accessor Name() instead of locking and reading f.fileData.name is not the same, but go vet indicates that the mutex in fileData was being copied, not preserved.
The reproducing test case upstream is:
check out github.com/google/mtail
make install_deps
go test -race -timeout 1m -v -run TestProcessEvents --count=10000 ./vm
Prior to this change, the test reports a data race 3 times out of 10000, after, 0 times consistently.