aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorleongross <[email protected]>2024-03-26 13:21:50 +0100
committerRon Evans <[email protected]>2024-04-14 16:56:53 +0200
commitdcee228c4e29af5c06112f0ccc093c8f6483d64f (patch)
treefeaa50819ed9032ed31ab45bd693afd332f21596
parent9d6e30701b98f856125e55ba3fd26fa6b8f4a280 (diff)
downloadtinygo-dcee228c4e29af5c06112f0ccc093c8f6483d64f.tar.gz
tinygo-dcee228c4e29af5c06112f0ccc093c8f6483d64f.zip
add os.Link
Signed-off-by: leongross <[email protected]>
-rw-r--r--src/os/file_unix.go13
-rw-r--r--src/os/os_hardlink_test.go53
-rw-r--r--src/syscall/syscall_libc.go15
3 files changed, 81 insertions, 0 deletions
diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index 665fb0937..25f0266a6 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -74,6 +74,19 @@ func tempDir() string {
return dir
}
+// Link creates newname as a hard link to the oldname file.
+// If there is an error, it will be of type *LinkError.
+func Link(oldname, newname string) error {
+ e := ignoringEINTR(func() error {
+ return syscall.Link(oldname, newname)
+ })
+
+ if e != nil {
+ return &LinkError{"link", oldname, newname, e}
+ }
+ return nil
+}
+
// Symlink creates newname as a symbolic link to oldname.
// On Windows, a symlink to a non-existent oldname creates a file symlink;
// if oldname is later created as a directory the symlink will not work.
diff --git a/src/os/os_hardlink_test.go b/src/os/os_hardlink_test.go
new file mode 100644
index 000000000..96f1c9bbb
--- /dev/null
+++ b/src/os/os_hardlink_test.go
@@ -0,0 +1,53 @@
+//go:build !windows && !baremetal && !js && !wasi && !wasip1 && !wasm_unknown
+
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os_test
+
+import (
+ . "os"
+ "syscall"
+ "testing"
+)
+
+func TestHardlink(t *testing.T) {
+ defer chtmpdir(t)()
+ from, to := "hardlinktestfrom", "hardlinktestto"
+
+ file, err := Create(to)
+ if err != nil {
+ t.Fatalf("Create(%q) failed: %v", to, err)
+ }
+ 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)
+ }
+
+ tostat, err := Lstat(to)
+ if err != nil {
+ t.Fatalf("Lstat(%q) failed: %v", to, err)
+ }
+ fromstat, err := Stat(from)
+ if err != nil {
+ t.Fatalf("Stat(%q) failed: %v", from, err)
+ }
+ if !SameFile(tostat, fromstat) {
+ 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 they have the same inode, they are hard links
+ if fromstat.Sys().(*syscall.Stat_t).Ino != tostat.Sys().(*syscall.Stat_t).Ino {
+ t.Fatalf("Lstat(%q).Sys().Ino = %v, Lstat(%q).Sys().Ino = %v, want the same", to, tostat.Sys().(*syscall.Stat_t).Ino, from, fromstat.Sys().(*syscall.Stat_t).Ino)
+ }
+
+ file.Close()
+}
diff --git a/src/syscall/syscall_libc.go b/src/syscall/syscall_libc.go
index 7a13245b6..fb2e23968 100644
--- a/src/syscall/syscall_libc.go
+++ b/src/syscall/syscall_libc.go
@@ -134,6 +134,16 @@ func Rename(from, to string) (err error) {
return
}
+func Link(oldname, newname string) (err error) {
+ fromdata := cstring(oldname)
+ todata := cstring(newname)
+ fail := int(libc_link(&fromdata[0], &todata[0]))
+ if fail < 0 {
+ err = getErrno()
+ }
+ return
+}
+
func Symlink(from, to string) (err error) {
fromdata := cstring(from)
todata := cstring(to)
@@ -416,6 +426,11 @@ func libc_rename(from, to *byte) int32
//export symlink
func libc_symlink(from, to *byte) int32
+// int link(const char *oldname, *newname);
+//
+//export link
+func libc_link(oldname, newname *byte) int32
+
// int fsync(int fd);
//
//export fsync