aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2009-05-13 10:16:46 -0700
committerIan Lance Taylor <iant@golang.org>2009-05-13 10:16:46 -0700
commit7aabf2d9b1bef5bc1c5c71710a79fcab2b57166a (patch)
tree4e7598284b339a85cf649300759ba40f8603c2cc /src
parent52f071ed4318634a872e211aebf7d55ddd271bb4 (diff)
downloadgo-7aabf2d9b1bef5bc1c5c71710a79fcab2b57166a.tar.xz
Add os.Link, os.Symlink, os.Readlink.
R=r,rsc DELTA=161 (161 added, 0 deleted, 0 changed) OCL=28745 CL=28747
Diffstat (limited to 'src')
-rw-r--r--src/lib/os/file.go27
-rw-r--r--src/lib/os/os_test.go94
-rw-r--r--src/lib/syscall/file_darwin.go20
-rw-r--r--src/lib/syscall/file_linux.go20
4 files changed, 161 insertions, 0 deletions
diff --git a/src/lib/os/file.go b/src/lib/os/file.go
index 9b22a896db..2c609e3183 100644
--- a/src/lib/os/file.go
+++ b/src/lib/os/file.go
@@ -306,3 +306,30 @@ func Remove(name string) Error {
return ErrnoToError(e);
}
+// Link creates a hard link.
+func Link(oldpath, newpath string) Error {
+ r, e := syscall.Link(oldpath, newpath);
+ return ErrnoToError(e);
+}
+
+// Symlink creates a symbolic link.
+func Symlink(oldpath, newpath string) Error {
+ r, e := syscall.Symlink(oldpath, newpath);
+ return ErrnoToError(e);
+}
+
+// Readlink reads the contents of a symbolic link: the destination of
+// the link. It returns the contents and an Error, if any.
+func Readlink(path string) (string, Error) {
+ for len := int64(128); ; len *= 2 {
+ b := make([]byte, len);
+ r, e := syscall.Readlink(path, &b[0], len);
+ if r == -1 {
+ return "", ErrnoToError(e);
+ } else if r < len {
+ return string(b[0:r]), nil;
+ }
+ }
+ // Silence 6g.
+ return "", nil;
+}
diff --git a/src/lib/os/os_test.go b/src/lib/os/os_test.go
index 7349b22476..e1e2d4b4b3 100644
--- a/src/lib/os/os_test.go
+++ b/src/lib/os/os_test.go
@@ -205,3 +205,97 @@ func TestReaddirnamesOneAtATime(t *testing.T) {
}
}
+func TestHardLink(t *testing.T) {
+ from, to := "hardlinktestfrom", "hardlinktestto";
+ Remove(from); // Just in case.
+ file, err := Open(to, O_CREAT | O_WRONLY, 0666);
+ if err != nil {
+ t.Fatalf("open %q failed: %v", to, err);
+ }
+ defer Remove(to);
+ if err = file.Close(); err != nil {
+ t.Errorf("close %q failed: %v", to, err);
+ }
+ err = Link(to, from);
+ if err != nil {
+ t.Fatalf("link %q, %q failed: %v", to, from, err);
+ }
+ defer Remove(from);
+ tostat, err := Stat(to);
+ if err != nil {
+ t.Fatalf("stat %q failed: %v", to, err);
+ }
+ fromstat, err := Stat(from);
+ if err != nil {
+ t.Fatalf("stat %q failed: %v", from, err);
+ }
+ if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino {
+ t.Errorf("link %q, %q did not create hard link", to, from);
+ }
+}
+
+func TestSymLink(t *testing.T) {
+ from, to := "symlinktestfrom", "symlinktestto";
+ Remove(from); // Just in case.
+ file, err := Open(to, O_CREAT | O_WRONLY, 0666);
+ if err != nil {
+ t.Fatalf("open %q failed: %v", to, err);
+ }
+ defer Remove(to);
+ if err = file.Close(); err != nil {
+ t.Errorf("close %q failed: %v", to, err);
+ }
+ err = Symlink(to, from);
+ if err != nil {
+ t.Fatalf("symlink %q, %q failed: %v", to, from, err);
+ }
+ defer Remove(from);
+ tostat, err := Stat(to);
+ if err != nil {
+ t.Fatalf("stat %q failed: %v", to, err);
+ }
+ fromstat, err := Stat(from);
+ if err != nil {
+ t.Fatalf("stat %q failed: %v", from, err);
+ }
+ if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino {
+ t.Errorf("symlink %q, %q did not create symlink", to, from);
+ }
+ fromstat, err = Lstat(from);
+ if err != nil {
+ t.Fatalf("lstat %q failed: %v", from, err);
+ }
+ if !fromstat.IsSymlink() {
+ t.Fatalf("symlink %q, %q did not create symlink", to, from);
+ }
+ s, err := Readlink(from);
+ if err != nil {
+ t.Fatalf("readlink %q failed: %v", from, err);
+ }
+ if s != to {
+ t.Fatalf("after symlink %q != %q", s, to);
+ }
+ file, err = Open(from, O_RDONLY, 0);
+ if err != nil {
+ t.Fatalf("open %q failed: %v", from, err);
+ }
+ file.Close();
+}
+
+func TestLongSymlink(t *testing.T) {
+ s := "0123456789abcdef";
+ s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s + s + s;
+ from := "longsymlinktestfrom";
+ err := Symlink(s, from);
+ if err != nil {
+ t.Fatalf("symlink %q, %q failed: %v", s, from, err);
+ }
+ defer Remove(from);
+ r, err := Readlink(from);
+ if err != nil {
+ t.Fatalf("readlink %q failed: %v", from, err);
+ }
+ if r != s {
+ t.Fatalf("after symlink %q != %q", r, s);
+ }
+}
diff --git a/src/lib/syscall/file_darwin.go b/src/lib/syscall/file_darwin.go
index 01005d207b..558d66c917 100644
--- a/src/lib/syscall/file_darwin.go
+++ b/src/lib/syscall/file_darwin.go
@@ -110,3 +110,23 @@ func Chdir(dir string) (ret int64, errno int64) {
r1, r2, err := Syscall(SYS_CHDIR, int64(uintptr(unsafe.Pointer(namebuf))), 0, 0);
return r1, err;
}
+
+func Link(oldpath, newpath string) (ret int64, errno int64) {
+ oldbuf := StringBytePtr(oldpath);
+ newbuf := StringBytePtr(newpath);
+ r1, r2, err := Syscall(SYS_LINK, int64(uintptr(unsafe.Pointer(oldbuf))), int64(uintptr(unsafe.Pointer(newbuf))), 0);
+ return r1, err;
+}
+
+func Symlink(oldpath, newpath string) (ret int64, errno int64) {
+ oldbuf := StringBytePtr(oldpath);
+ newbuf := StringBytePtr(newpath);
+ r1, r2, err := Syscall(SYS_SYMLINK, int64(uintptr(unsafe.Pointer(oldbuf))), int64(uintptr(unsafe.Pointer(newbuf))), 0);
+ return r1, err;
+}
+
+func Readlink(path string, buf *byte, nbytes int64) (ret int64, errno int64) {
+ pathbuf := StringBytePtr(path);
+ r1, r2, err := Syscall(SYS_READLINK, int64(uintptr(unsafe.Pointer(pathbuf))), int64(uintptr(unsafe.Pointer(buf))), nbytes);
+ return r1, err;
+}
diff --git a/src/lib/syscall/file_linux.go b/src/lib/syscall/file_linux.go
index 80800b6158..c7299f8393 100644
--- a/src/lib/syscall/file_linux.go
+++ b/src/lib/syscall/file_linux.go
@@ -111,3 +111,23 @@ func Chdir(dir string) (ret int64, errno int64) {
r1, r2, err := Syscall(SYS_CHDIR, int64(uintptr(unsafe.Pointer(namebuf))), 0, 0);
return r1, err;
}
+
+func Link(oldpath, newpath string) (ret int64, errno int64) {
+ oldbuf := StringBytePtr(oldpath);
+ newbuf := StringBytePtr(newpath);
+ r1, r2, err := Syscall(SYS_LINK, int64(uintptr(unsafe.Pointer(oldbuf))), int64(uintptr(unsafe.Pointer(newbuf))), 0);
+ return r1, err;
+}
+
+func Symlink(oldpath, newpath string) (ret int64, errno int64) {
+ oldbuf := StringBytePtr(oldpath);
+ newbuf := StringBytePtr(newpath);
+ r1, r2, err := Syscall(SYS_SYMLINK, int64(uintptr(unsafe.Pointer(oldbuf))), int64(uintptr(unsafe.Pointer(newbuf))), 0);
+ return r1, err;
+}
+
+func Readlink(path string, buf *byte, nbytes int64) (ret int64, errno int64) {
+ pathbuf := StringBytePtr(path);
+ r1, r2, err := Syscall(SYS_READLINK, int64(uintptr(unsafe.Pointer(pathbuf))), int64(uintptr(unsafe.Pointer(buf))), nbytes);
+ return r1, err;
+}