diff --git a/CHANGELOG.md b/CHANGELOG.md index 2161896..bc60848 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ## +### Breaking ### +* `pathrs_inroot_hardlink` and `pathrs_inroot_symlink` have been switched to + using the standard argument order from their respective system calls + (previously the order was swapped, which lead to possible confusion). + - Previously compiled programs will continue to work but rebuilt programs + will need to adjust their argument order. + - Rust users are not affected by this change. + - For the Go and Python bindings, the wrappers have also had their argument + orders swapped to match the C API and so will also need to be updated when + rebuilding. + ## [0.2.2] - 2025-11-25 ## > 貴様ら全員刀の錆にしてやるぜ。 diff --git a/contrib/bindings/python/pathrs/_pathrs.py b/contrib/bindings/python/pathrs/_pathrs.py index 25cfdc3..284a50f 100644 --- a/contrib/bindings/python/pathrs/_pathrs.py +++ b/contrib/bindings/python/pathrs/_pathrs.py @@ -359,7 +359,7 @@ def mknod(self, path: str, mode: int, device: int = 0, /) -> None: if _is_pathrs_err(err): raise PathrsError._fetch(err) or INTERNAL_ERROR - def hardlink(self, path: str, target: str, /) -> None: + def hardlink(self, target: str, linkname: str, /) -> None: """ Create a hardlink between two paths inside the Root. @@ -370,12 +370,12 @@ def hardlink(self, path: str, target: str, /) -> None: exists. """ err = libpathrs_so.pathrs_inroot_hardlink( - self.fileno(), _cstr(path), _cstr(target) + self.fileno(), _cstr(target), _cstr(linkname) ) if _is_pathrs_err(err): raise PathrsError._fetch(err) or INTERNAL_ERROR - def symlink(self, path: str, target: str, /) -> None: + def symlink(self, target: str, linkname: str, /) -> None: """ Create a symlink at the given path in the Root. @@ -387,7 +387,7 @@ def symlink(self, path: str, target: str, /) -> None: exists. """ err = libpathrs_so.pathrs_inroot_symlink( - self.fileno(), _cstr(path), _cstr(target) + self.fileno(), _cstr(target), _cstr(linkname) ) if _is_pathrs_err(err): raise PathrsError._fetch(err) or INTERNAL_ERROR diff --git a/e2e-tests/cmd/go/root.go b/e2e-tests/cmd/go/root.go index a0f962d..962f786 100644 --- a/e2e-tests/cmd/go/root.go +++ b/e2e-tests/cmd/go/root.go @@ -314,8 +314,7 @@ var rootHardlinkCmd = &cli.Command{ target := cmd.StringArg("target") linkname := cmd.StringArg("linkname") - // TODO: These arguments need to get swapped. - return root.Hardlink(linkname, target) + return root.Hardlink(target, linkname) }, } @@ -336,8 +335,7 @@ var rootSymlinkCmd = &cli.Command{ target := cmd.StringArg("target") linkname := cmd.StringArg("linkname") - // TODO: These arguments need to get swapped. - return root.Symlink(linkname, target) + return root.Symlink(target, linkname) }, } diff --git a/e2e-tests/cmd/python/pathrs-cmd.py b/e2e-tests/cmd/python/pathrs-cmd.py index 0c008c3..b804359 100755 --- a/e2e-tests/cmd/python/pathrs-cmd.py +++ b/e2e-tests/cmd/python/pathrs-cmd.py @@ -99,8 +99,7 @@ def root_hardlink(args: argparse.Namespace): target: str = args.target linkname: str = args.linkname - # TODO: These arguments need to get swapped. - root.hardlink(linkname, target) + root.hardlink(target, linkname) def root_symlink(args: argparse.Namespace): @@ -108,8 +107,7 @@ def root_symlink(args: argparse.Namespace): target: str = args.target linkname: str = args.linkname - # TODO: These arguments need to get swapped. - root.symlink(linkname, target) + root.symlink(target, linkname) def root_readlink(args: argparse.Namespace): diff --git a/go-pathrs/internal/libpathrs/libpathrs_linux.go b/go-pathrs/internal/libpathrs/libpathrs_linux.go index e8ca2a1..553be5c 100644 --- a/go-pathrs/internal/libpathrs/libpathrs_linux.go +++ b/go-pathrs/internal/libpathrs/libpathrs_linux.go @@ -193,26 +193,26 @@ func InRootMknod(rootFd uintptr, path string, mode uint32, dev uint64) error { } // InRootSymlink wraps pathrs_inroot_symlink. -func InRootSymlink(rootFd uintptr, path, target string) error { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) +func InRootSymlink(rootFd uintptr, target, linkpath string) error { + cLinkpath := C.CString(linkpath) + defer C.free(unsafe.Pointer(cLinkpath)) cTarget := C.CString(target) defer C.free(unsafe.Pointer(cTarget)) - err := C.pathrs_inroot_symlink(C.int(rootFd), cPath, cTarget) + err := C.pathrs_inroot_symlink(C.int(rootFd), cTarget, cLinkpath) return fetchError(err) } // InRootHardlink wraps pathrs_inroot_hardlink. -func InRootHardlink(rootFd uintptr, path, target string) error { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) +func InRootHardlink(rootFd uintptr, target, linkpath string) error { + cLinkpath := C.CString(linkpath) + defer C.free(unsafe.Pointer(cLinkpath)) cTarget := C.CString(target) defer C.free(unsafe.Pointer(cTarget)) - err := C.pathrs_inroot_hardlink(C.int(rootFd), cPath, cTarget) + err := C.pathrs_inroot_hardlink(C.int(rootFd), cTarget, cLinkpath) return fetchError(err) } diff --git a/go-pathrs/root_linux.go b/go-pathrs/root_linux.go index 5bc2e90..406b16a 100644 --- a/go-pathrs/root_linux.go +++ b/go-pathrs/root_linux.go @@ -277,26 +277,26 @@ func (r *Root) Mknod(path string, mode os.FileMode, dev uint64) error { } // Symlink creates a symlink within a [Root]'s directory tree. The symlink is -// created at path and is a link to target. +// created at newname and is a link to oldname. // // This is effectively equivalent to [os.Symlink]. -func (r *Root) Symlink(path, target string) error { +func (r *Root) Symlink(oldname, newname string) error { _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { - err := libpathrs.InRootSymlink(rootFd, path, target) + err := libpathrs.InRootSymlink(rootFd, oldname, newname) return struct{}{}, err }) return err } // Hardlink creates a hardlink within a [Root]'s directory tree. The hardlink -// is created at path and is a link to target. Both paths are within the +// is created at newname and is a link to oldname. Both paths are within the // [Root]'s directory tree (you cannot hardlink to a different [Root] or the // host). // // This is effectively equivalent to [os.Link]. -func (r *Root) Hardlink(path, target string) error { +func (r *Root) Hardlink(oldname, newname string) error { _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { - err := libpathrs.InRootHardlink(rootFd, path, target) + err := libpathrs.InRootHardlink(rootFd, oldname, newname) return struct{}{}, err }) return err diff --git a/include/pathrs.h b/include/pathrs.h index b6e81a7..1f817fa 100644 --- a/include/pathrs.h +++ b/include/pathrs.h @@ -520,7 +520,9 @@ int pathrs_inroot_mknod(int root_fd, * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ -int pathrs_inroot_symlink(int root_fd, const char *path, const char *target); +int pathrs_inroot_symlink(int root_fd, + const char *target, + const char *linkpath); /** * Create a hardlink within the rootfs referenced by root_fd. Both the hardlink @@ -535,7 +537,9 @@ int pathrs_inroot_symlink(int root_fd, const char *path, const char *target); * the system errno(7) value associated with the error, etc), use * pathrs_errorinfo(). */ -int pathrs_inroot_hardlink(int root_fd, const char *path, const char *target); +int pathrs_inroot_hardlink(int root_fd, + const char *target, + const char *linkpath); /** * Create a new (custom) procfs root handle. diff --git a/src/capi/core.rs b/src/capi/core.rs index 6167cdd..36bb652 100644 --- a/src/capi/core.rs +++ b/src/capi/core.rs @@ -623,24 +623,42 @@ utils::symver! { #[no_mangle] pub unsafe extern "C" fn pathrs_inroot_symlink( root_fd: CBorrowedFd<'_>, - path: *const c_char, target: *const c_char, + linkpath: *const c_char, ) -> c_int { || -> Result<_, Error> { let root_fd = root_fd.try_as_borrowed_fd()?; let root = RootRef::from_fd(root_fd); - let path = unsafe { utils::parse_path(path)? }; // SAFETY: C caller guarantees path is safe. let target = unsafe { utils::parse_path(target)? }; // SAFETY: C caller guarantees path is safe. - root.create(path, &InodeType::Symlink(target.into())) + let linkpath = unsafe { utils::parse_path(linkpath)? }; // SAFETY: C caller guarantees path is safe. + root.create(linkpath, &InodeType::Symlink(target.into())) }() .into_c_return() } utils::symver! { - fn pathrs_inroot_symlink <- (pathrs_inroot_symlink, version = "LIBPATHRS_0.2", default); + fn pathrs_inroot_symlink <- (pathrs_inroot_symlink, version = "LIBPATHRS_0.3", default); +} + +/// A compatibility shim for `pathrs_inroot_symlink`, which previously took its +/// arguments in the wrong order. +/// +/// cbindgen:ignore +#[no_mangle] +pub unsafe extern "C" fn __pathrs_inroot_symlink_v1( + root_fd: CBorrowedFd<'_>, + path: *const c_char, + target: *const c_char, +) -> c_int { + pathrs_inroot_symlink(root_fd, target, path) +} +utils::symver! { + // The old version of pathrs_inroot_symlink had "target" and "linkpath" + // flipped. + fn __pathrs_inroot_symlink_v1 <- (pathrs_inroot_symlink, version = "LIBPATHRS_0.2"); // This symbol was renamed in libpathrs 0.2. For backward compatibility with // pre-symbol-versioned builds of libpathrs, it needs to be a default so // that loaders will pick it when searching for the unversioned name. - fn pathrs_inroot_symlink <- (pathrs_symlink, version = "LIBPATHRS_0.1", default); + fn __pathrs_inroot_symlink_v1 <- (pathrs_symlink, version = "LIBPATHRS_0.1", default); } /// Create a hardlink within the rootfs referenced by root_fd. Both the hardlink @@ -657,22 +675,40 @@ utils::symver! { #[no_mangle] pub unsafe extern "C" fn pathrs_inroot_hardlink( root_fd: CBorrowedFd<'_>, - path: *const c_char, target: *const c_char, + linkpath: *const c_char, ) -> c_int { || -> Result<_, Error> { let root_fd = root_fd.try_as_borrowed_fd()?; let root = RootRef::from_fd(root_fd); - let path = unsafe { utils::parse_path(path)? }; // SAFETY: C caller guarantees path is safe. let target = unsafe { utils::parse_path(target)? }; // SAFETY: C caller guarantees path is safe. - root.create(path, &InodeType::Hardlink(target.into())) + let linkpath = unsafe { utils::parse_path(linkpath)? }; // SAFETY: C caller guarantees path is safe. + root.create(linkpath, &InodeType::Hardlink(target.into())) }() .into_c_return() } utils::symver! { - fn pathrs_inroot_hardlink <- (pathrs_inroot_hardlink, version = "LIBPATHRS_0.2", default); + fn pathrs_inroot_hardlink <- (pathrs_inroot_hardlink, version = "LIBPATHRS_0.3", default); +} + +/// A compatibility shim for `pathrs_inroot_hardlink`, which previously took its +/// arguments in the wrong order. +/// +/// cbindgen:ignore +#[no_mangle] +pub unsafe extern "C" fn __pathrs_inroot_hardlink_v1( + root_fd: CBorrowedFd<'_>, + path: *const c_char, + target: *const c_char, +) -> c_int { + pathrs_inroot_hardlink(root_fd, target, path) +} +utils::symver! { + // The old version of pathrs_inroot_hardlink had "target" and "linkpath" + // flipped. + fn __pathrs_inroot_hardlink_v1 <- (pathrs_inroot_hardlink, version = "LIBPATHRS_0.2"); // This symbol was renamed in libpathrs 0.2. For backward compatibility with // pre-symbol-versioned builds of libpathrs, it needs to be a default so // that loaders will pick it when searching for the unversioned name. - fn pathrs_inroot_hardlink <- (pathrs_hardlink, version = "LIBPATHRS_0.1", default); + fn __pathrs_inroot_hardlink_v1 <- (pathrs_hardlink, version = "LIBPATHRS_0.1", default); } diff --git a/src/tests/capi/root.rs b/src/tests/capi/root.rs index 3bf6fdc..d5a3601 100644 --- a/src/tests/capi/root.rs +++ b/src/tests/capi/root.rs @@ -139,8 +139,8 @@ impl CapiRoot { unsafe { capi::core::pathrs_inroot_symlink( root_fd.into(), - path.as_ptr(), target.as_ptr(), + path.as_ptr(), ) } } @@ -149,8 +149,8 @@ impl CapiRoot { unsafe { capi::core::pathrs_inroot_hardlink( root_fd.into(), - path.as_ptr(), target.as_ptr(), + path.as_ptr(), ) } }