authorgravatar for tauoverpi@yandex.comTau <tauoverpi@yandex.com> 2021-01-25 07:23:03+01:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-21 12:04:40+02:00
log840331ee48e54b1ce4a3c8196f90eec73ce6deea
tree674cd1223b59a58f7db0f944a65980cc97e3c56a
parentc70832bc411388c3e9749013d7cf99704ff95a36

Rebase link(at) properly


4 files changed, 188 insertions(+), 0 deletions(-)

lib/std/c.zig+2
...@@ -100,6 +100,8 @@ pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: u64)...@@ -100,6 +100,8 @@ pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: u64)
100pub extern "c" fn mmap(addr: ?*align(page_size) c_void, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: u64) *c_void;100pub extern "c" fn mmap(addr: ?*align(page_size) c_void, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: u64) *c_void;
101pub extern "c" fn munmap(addr: *align(page_size) c_void, len: usize) c_int;101pub extern "c" fn munmap(addr: *align(page_size) c_void, len: usize) c_int;
102pub extern "c" fn mprotect(addr: *align(page_size) c_void, len: usize, prot: c_uint) c_int;102pub extern "c" fn mprotect(addr: *align(page_size) c_void, len: usize, prot: c_uint) c_int;
103pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: c_int) c_int;
104pub extern "c" fn linkat(oldfd: fd_t, oldpath: [*:0]const u8, newfd: fd_t, newpath: [*:0]const u8, flags: c_int) c_int;
103pub extern "c" fn unlink(path: [*:0]const u8) c_int;105pub extern "c" fn unlink(path: [*:0]const u8) c_int;
104pub extern "c" fn unlinkat(dirfd: fd_t, path: [*:0]const u8, flags: c_uint) c_int;106pub extern "c" fn unlinkat(dirfd: fd_t, path: [*:0]const u8, flags: c_uint) c_int;
105pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;107pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
lib/std/os.zig+86
...@@ -1634,6 +1634,92 @@ pub fn symlinkatZ(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:...@@ -1634,6 +1634,92 @@ pub fn symlinkatZ(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:
1634 }1634 }
1635}1635}
16361636
1637pub const LinkError = UnexpectedError || error{
1638 AccessDenied,
1639 DiskQuota,
1640 PathAlreadyExists,
1641 FileSystem,
1642 SymLinkLoop,
1643 LinkQuotaExceeded,
1644 NameTooLong,
1645 FileNotFound,
1646 SystemResources,
1647 NoSpaceLeft,
1648 ReadOnlyFileSystem,
1649 NotSameFileSystem,
1650};
1651
1652pub fn linkZ(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: i32) LinkError!void {
1653 switch (errno(system.link(oldpath, newpath, flags))) {
1654 0 => return,
1655 EACCES => return error.AccessDenied,
1656 EDQUOT => return error.DiskQuota,
1657 EEXIST => return error.PathAlreadyExists,
1658 EFAULT => unreachable,
1659 EIO => return error.FileSystem,
1660 ELOOP => return error.SymLinkLoop,
1661 EMLINK => return error.LinkQuotaExceeded,
1662 ENAMETOOLONG => return error.NameTooLong,
1663 ENOENT => return error.FileNotFound,
1664 ENOMEM => return error.SystemResources,
1665 ENOSPC => return error.NoSpaceLeft,
1666 EPERM => return error.AccessDenied,
1667 EROFS => return error.ReadOnlyFileSystem,
1668 EXDEV => return error.NotSameFileSystem,
1669 EINVAL => unreachable,
1670 else => |err| return unexpectedErrno(err),
1671 }
1672}
1673
1674pub fn link(oldpath: []const u8, newpath: []const u8, flags: i32) LinkError!void {
1675 const old = try toPosixPath(oldpath);
1676 const new = try toPosixPath(newpath);
1677 return try linkZ(&old, &new, flags);
1678}
1679
1680pub const LinkatError = LinkError || error{NotDir};
1681
1682pub fn linkatZ(
1683 olddir: fd_t,
1684 oldpath: [*:0]const u8,
1685 newdir: fd_t,
1686 newpath: [*:0]const u8,
1687 flags: i32,
1688) LinkatError!void {
1689 switch (errno(system.linkat(olddir, oldpath, newdir, newpath, flags))) {
1690 0 => return,
1691 EACCES => return error.AccessDenied,
1692 EDQUOT => return error.DiskQuota,
1693 EEXIST => return error.PathAlreadyExists,
1694 EFAULT => unreachable,
1695 EIO => return error.FileSystem,
1696 ELOOP => return error.SymLinkLoop,
1697 EMLINK => return error.LinkQuotaExceeded,
1698 ENAMETOOLONG => return error.NameTooLong,
1699 ENOENT => return error.FileNotFound,
1700 ENOMEM => return error.SystemResources,
1701 ENOSPC => return error.NoSpaceLeft,
1702 ENOTDIR => return error.NotDir,
1703 EPERM => return error.AccessDenied,
1704 EROFS => return error.ReadOnlyFileSystem,
1705 EXDEV => return error.NotSameFileSystem,
1706 EINVAL => unreachable,
1707 else => |err| return unexpectedErrno(err),
1708 }
1709}
1710
1711pub fn linkat(
1712 olddir: fd_t,
1713 oldpath: []const u8,
1714 newdir: fd_t,
1715 newpath: []const u8,
1716 flags: i32,
1717) LinkatError!void {
1718 const old = try toPosixPath(oldpath);
1719 const new = try toPosixPath(newpath);
1720 return try linkatZ(olddir, &old, newdir, &new, flags);
1721}
1722
1637pub const UnlinkError = error{1723pub const UnlinkError = error{
1638 FileNotFound,1724 FileNotFound,
16391725
lib/std/os/linux.zig+31
...@@ -634,6 +634,37 @@ pub fn tgkill(tgid: pid_t, tid: pid_t, sig: i32) usize {...@@ -634,6 +634,37 @@ pub fn tgkill(tgid: pid_t, tid: pid_t, sig: i32) usize {
634 return syscall2(.tgkill, @bitCast(usize, @as(isize, tgid)), @bitCast(usize, @as(isize, tid)), @bitCast(usize, @as(isize, sig)));634 return syscall2(.tgkill, @bitCast(usize, @as(isize, tgid)), @bitCast(usize, @as(isize, tid)), @bitCast(usize, @as(isize, sig)));
635}635}
636636
637pub fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: i32) usize {
638 if (@hasField(SYS, "link")) {
639 return syscall3(
640 .link,
641 @ptrToInt(oldpath),
642 @ptrToInt(newpath),
643 @bitCast(usize, @as(isize, flags)),
644 );
645 } else {
646 return syscall5(
647 .linkat,
648 @bitCast(usize, @as(isize, AT_FDCWD)),
649 @ptrToInt(oldpath),
650 @bitCast(usize, @as(isize, AT_FDCWD)),
651 @ptrToInt(newpath),
652 @bitCast(usize, @as(isize, flags)),
653 );
654 }
655}
656
657pub fn linkat(oldfd: fd_t, oldpath: [*:0]const u8, newfd: fd_t, newpath: [*:0]const u8, flags: i32) usize {
658 return syscall5(
659 .linkat,
660 @bitCast(usize, @as(isize, oldfd)),
661 @ptrToInt(oldpath),
662 @bitCast(usize, @as(isize, newfd)),
663 @ptrToInt(newpath),
664 @bitCast(usize, @as(isize, flags)),
665 );
666}
667
637pub fn unlink(path: [*:0]const u8) usize {668pub fn unlink(path: [*:0]const u8) usize {
638 if (@hasField(SYS, "unlink")) {669 if (@hasField(SYS, "unlink")) {
639 return syscall1(.unlink, @ptrToInt(path));670 return syscall1(.unlink, @ptrToInt(path));
lib/std/os/test.zig+69
...@@ -189,6 +189,75 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {...@@ -189,6 +189,75 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
189 expect(mem.eql(u8, target_path, given));189 expect(mem.eql(u8, target_path, given));
190}190}
191191
192test "link with relative paths" {
193 if (builtin.os.tag != .linux) return error.SkipZigTest;
194 var cwd = fs.cwd();
195
196 cwd.deleteFile("example.txt") catch {};
197 cwd.deleteFile("new.txt") catch {};
198
199 try cwd.writeFile("example.txt", "example");
200 try os.link("example.txt", "new.txt", 0);
201
202 const efd = try cwd.openFile("example.txt", .{});
203 defer efd.close();
204
205 const nfd = try cwd.openFile("new.txt", .{});
206 defer nfd.close();
207
208 {
209 const estat = try os.fstat(efd.handle);
210 const nstat = try os.fstat(nfd.handle);
211
212 testing.expectEqual(estat.ino, nstat.ino);
213 testing.expectEqual(@as(usize, 2), nstat.nlink);
214 }
215
216 try os.unlink("new.txt");
217
218 {
219 const estat = try os.fstat(efd.handle);
220 testing.expectEqual(@as(usize, 1), estat.nlink);
221 }
222
223 try cwd.deleteFile("example.txt");
224}
225
226test "linkat with different directories" {
227 if (builtin.os.tag != .linux) return error.SkipZigTest;
228 var cwd = fs.cwd();
229 var tmp = tmpDir(.{});
230
231 cwd.deleteFile("example.txt") catch {};
232 tmp.dir.deleteFile("new.txt") catch {};
233
234 try cwd.writeFile("example.txt", "example");
235 try os.linkat(cwd.fd, "example.txt", tmp.dir.fd, "new.txt", 0);
236
237 const efd = try cwd.openFile("example.txt", .{});
238 defer efd.close();
239
240 const nfd = try tmp.dir.openFile("new.txt", .{});
241
242 {
243 defer nfd.close();
244 const estat = try os.fstat(efd.handle);
245 const nstat = try os.fstat(nfd.handle);
246
247 testing.expectEqual(estat.ino, nstat.ino);
248 testing.expectEqual(@as(usize, 2), nstat.nlink);
249 }
250
251 try os.unlinkat(tmp.dir.fd, "new.txt", 0);
252
253 {
254 const estat = try os.fstat(efd.handle);
255 testing.expectEqual(@as(usize, 1), estat.nlink);
256 }
257
258 try cwd.deleteFile("example.txt");
259}
260
192test "fstatat" {261test "fstatat" {
193 // enable when `fstat` and `fstatat` are implemented on Windows262 // enable when `fstat` and `fstatat` are implemented on Windows
194 if (builtin.os.tag == .windows) return error.SkipZigTest;263 if (builtin.os.tag == .windows) return error.SkipZigTest;