Message:
Hello golan...@googlegroups.com,
I'd like you to review this change to
https://go.googlecode.com/hg/
Description:
os: make FileInfo.Size() portable (zero on non-regular files)
This behavior was different between operating systems and bit
us when writing tar files.
Define the FileInfo.Size to be zero on non-regular files.
Please review this at http://codereview.appspot.com/5798062/
Affected files:
M src/pkg/os/os_test.go
M src/pkg/os/stat_darwin.go
M src/pkg/os/stat_freebsd.go
M src/pkg/os/stat_linux.go
M src/pkg/os/stat_netbsd.go
M src/pkg/os/stat_openbsd.go
M src/pkg/os/stat_plan9.go
M src/pkg/os/stat_windows.go
M src/pkg/os/types.go
Index: src/pkg/os/os_test.go
===================================================================
--- a/src/pkg/os/os_test.go
+++ b/src/pkg/os/os_test.go
@@ -1047,3 +1047,16 @@
t.Errorf("files should be different")
}
}
+
+func TestStatDirectorySizeZero(t *testing.T) {
+ fi, err := Stat(".")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !fi.IsDir() {
+ t.Fatal("expecting dir")
+ }
+ if fi.Size() != 0 {
+ t.Fatalf("got directory size %d; want 0", fi.Size())
+ }
+}
Index: src/pkg/os/stat_darwin.go
===================================================================
--- a/src/pkg/os/stat_darwin.go
+++ b/src/pkg/os/stat_darwin.go
@@ -18,7 +18,6 @@
func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
fs := &fileStat{
name: basename(name),
- size: int64(st.Size),
modTime: timespecToTime(st.Mtimespec),
sys: st,
}
@@ -35,7 +34,7 @@
case syscall.S_IFLNK:
fs.mode |= ModeSymlink
case syscall.S_IFREG:
- // nothing to do
+ fs.size = int64(st.Size)
case syscall.S_IFSOCK:
fs.mode |= ModeSocket
}
Index: src/pkg/os/stat_freebsd.go
===================================================================
--- a/src/pkg/os/stat_freebsd.go
+++ b/src/pkg/os/stat_freebsd.go
@@ -18,7 +18,6 @@
func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
fs := &fileStat{
name: basename(name),
- size: int64(st.Size),
modTime: timespecToTime(st.Mtimespec),
sys: st,
}
@@ -35,7 +34,7 @@
case syscall.S_IFLNK:
fs.mode |= ModeSymlink
case syscall.S_IFREG:
- // nothing to do
+ fs.size = int64(st.Size)
case syscall.S_IFSOCK:
fs.mode |= ModeSocket
}
Index: src/pkg/os/stat_linux.go
===================================================================
--- a/src/pkg/os/stat_linux.go
+++ b/src/pkg/os/stat_linux.go
@@ -18,7 +18,6 @@
func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
fs := &fileStat{
name: basename(name),
- size: int64(st.Size),
modTime: timespecToTime(st.Mtim),
sys: st,
}
@@ -35,7 +34,7 @@
case syscall.S_IFLNK:
fs.mode |= ModeSymlink
case syscall.S_IFREG:
- // nothing to do
+ fs.size = int64(st.Size)
case syscall.S_IFSOCK:
fs.mode |= ModeSocket
}
Index: src/pkg/os/stat_netbsd.go
===================================================================
--- a/src/pkg/os/stat_netbsd.go
+++ b/src/pkg/os/stat_netbsd.go
@@ -18,7 +18,6 @@
func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
fs := &fileStat{
name: basename(name),
- size: int64(st.Size),
modTime: timespecToTime(st.Mtim),
sys: st,
}
@@ -35,7 +34,7 @@
case syscall.S_IFLNK:
fs.mode |= ModeSymlink
case syscall.S_IFREG:
- // nothing to do
+ fs.size = int64(st.Size)
case syscall.S_IFSOCK:
fs.mode |= ModeSocket
}
Index: src/pkg/os/stat_openbsd.go
===================================================================
--- a/src/pkg/os/stat_openbsd.go
+++ b/src/pkg/os/stat_openbsd.go
@@ -18,7 +18,6 @@
func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
fs := &fileStat{
name: basename(name),
- size: int64(st.Size),
modTime: timespecToTime(st.Mtim),
sys: st,
}
@@ -35,7 +34,7 @@
case syscall.S_IFLNK:
fs.mode |= ModeSymlink
case syscall.S_IFREG:
- // nothing to do
+ fs.size = int64(st.Size)
case syscall.S_IFSOCK:
fs.mode |= ModeSocket
}
Index: src/pkg/os/stat_plan9.go
===================================================================
--- a/src/pkg/os/stat_plan9.go
+++ b/src/pkg/os/stat_plan9.go
@@ -18,7 +18,6 @@
func fileInfoFromStat(d *Dir) FileInfo {
fs := &fileStat{
name: d.Name,
- size: int64(d.Length),
modTime: time.Unix(int64(d.Mtime), 0),
sys: d,
}
@@ -35,6 +34,9 @@
if d.Mode&syscall.DMTMP != 0 {
fs.mode |= ModeTemporary
}
+ if fs.mode&ModeType == 0 {
+ fs.size = int64(d.Length)
+ }
return fs
}
Index: src/pkg/os/stat_windows.go
===================================================================
--- a/src/pkg/os/stat_windows.go
+++ b/src/pkg/os/stat_windows.go
@@ -26,13 +26,17 @@
if e != nil {
return nil, &PathError{"GetFileInformationByHandle", file.name, e}
}
- return &fileStat{
+ fs := &fileStat{
name: basename(file.name),
- size: mkSize(d.FileSizeHigh, d.FileSizeLow),
modTime: mkModTime(d.LastWriteTime),
mode: mkMode(d.FileAttributes),
sys: mkSysFromFI(&d),
- }, nil
+ }
+ if fs.Mode()&ModeType == 0 {
+ // Only for regular files.
+ fs.size = mkSize(d.FileSizeHigh, d.FileSizeLow)
+ }
+ return fi, nil
}
// Stat returns a FileInfo structure describing the named file.
Index: src/pkg/os/types.go
===================================================================
--- a/src/pkg/os/types.go
+++ b/src/pkg/os/types.go
@@ -15,7 +15,7 @@
// A FileInfo describes a file and is returned by Stat and Lstat
type FileInfo interface {
Name() string // base name of the file
- Size() int64 // length in bytes
+ Size() int64 // length in bytes (0 if not a regular file)
Mode() FileMode // file mode bits
ModTime() time.Time // modification time
IsDir() bool // abbreviation for Mode().IsDir()
To be facetious, you had a bug; why take it out on os?
I expect to be outvoted, but if this CL is going in, it needs
documentation and justification.
-rob
Where does this CL define that property? I see code but no definition.
Nor am I even convinced it's the correct thing to do. There may be
systems where directories have a valid non-zero size. There certainly
used to be, Unix among them (although directories are made "special"
these days)
and package os's purpose is not to hide every detail, just
to provide a consistent interface.
The operating system may do
different things with that interface, and often will. I don't see the
contract going all the way to defining the properties of directory
stats. It may even be a dangerous precedent to overstep like that, by
arguing that package os will hide valid differences.
To be facetious, you had a bug; why take it out on os?
I expect to be outvoted, but if this CL is going in, it needs
documentation and justification.
Go already doesn't let you read directories' bytes, though:func main() {f, _ := os.Open(".")buf, err := ioutil.ReadAll(f)fmt.Printf("read: %q, %v\n", buf, err)}read: "", read .: is a directory
Also, the fact that ls -l /dev/hda doesn't show me the
size of the disk on Linux is a bug anyway. I don't want
to require this behavior.
If this CL were requiring 0 size only for directories, I might
go along with it, but even then I think it is probably safer
to write code that doesn't depend on this assumption.
I know it sucks.
Russ
I believe that's Linux, not Go. There are some Unices where you can still read directories, e.g. Solaris.That was on Go on a Mac.
Undefined makes it sound like I can return 42.
// length in bytes; system-dependent for device files, directories
On Mon, Mar 12, 2012 at 13:11, Brad Fitzpatrick <brad...@golang.org> wrote:Undefined makes it sound like I can return 42.
> What about the one-liner documentation change I proposed as an alternative
> then?
// length in bytes; system-dependent for device files, directories