mirror of
https://github.com/ziglang/zig.git
synced 2026-01-04 20:43:19 +00:00
Rebase link(at) properly
This commit is contained in:
parent
c70832bc41
commit
840331ee48
@ -100,6 +100,8 @@ pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: u64)
|
||||
pub 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;
|
||||
pub extern "c" fn munmap(addr: *align(page_size) c_void, len: usize) c_int;
|
||||
pub extern "c" fn mprotect(addr: *align(page_size) c_void, len: usize, prot: c_uint) c_int;
|
||||
pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: c_int) c_int;
|
||||
pub extern "c" fn linkat(oldfd: fd_t, oldpath: [*:0]const u8, newfd: fd_t, newpath: [*:0]const u8, flags: c_int) c_int;
|
||||
pub extern "c" fn unlink(path: [*:0]const u8) c_int;
|
||||
pub extern "c" fn unlinkat(dirfd: fd_t, path: [*:0]const u8, flags: c_uint) c_int;
|
||||
pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
|
||||
|
||||
@ -1634,6 +1634,92 @@ pub fn symlinkatZ(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:
|
||||
}
|
||||
}
|
||||
|
||||
pub const LinkError = UnexpectedError || error{
|
||||
AccessDenied,
|
||||
DiskQuota,
|
||||
PathAlreadyExists,
|
||||
FileSystem,
|
||||
SymLinkLoop,
|
||||
LinkQuotaExceeded,
|
||||
NameTooLong,
|
||||
FileNotFound,
|
||||
SystemResources,
|
||||
NoSpaceLeft,
|
||||
ReadOnlyFileSystem,
|
||||
NotSameFileSystem,
|
||||
};
|
||||
|
||||
pub fn linkZ(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: i32) LinkError!void {
|
||||
switch (errno(system.link(oldpath, newpath, flags))) {
|
||||
0 => return,
|
||||
EACCES => return error.AccessDenied,
|
||||
EDQUOT => return error.DiskQuota,
|
||||
EEXIST => return error.PathAlreadyExists,
|
||||
EFAULT => unreachable,
|
||||
EIO => return error.FileSystem,
|
||||
ELOOP => return error.SymLinkLoop,
|
||||
EMLINK => return error.LinkQuotaExceeded,
|
||||
ENAMETOOLONG => return error.NameTooLong,
|
||||
ENOENT => return error.FileNotFound,
|
||||
ENOMEM => return error.SystemResources,
|
||||
ENOSPC => return error.NoSpaceLeft,
|
||||
EPERM => return error.AccessDenied,
|
||||
EROFS => return error.ReadOnlyFileSystem,
|
||||
EXDEV => return error.NotSameFileSystem,
|
||||
EINVAL => unreachable,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn link(oldpath: []const u8, newpath: []const u8, flags: i32) LinkError!void {
|
||||
const old = try toPosixPath(oldpath);
|
||||
const new = try toPosixPath(newpath);
|
||||
return try linkZ(&old, &new, flags);
|
||||
}
|
||||
|
||||
pub const LinkatError = LinkError || error{NotDir};
|
||||
|
||||
pub fn linkatZ(
|
||||
olddir: fd_t,
|
||||
oldpath: [*:0]const u8,
|
||||
newdir: fd_t,
|
||||
newpath: [*:0]const u8,
|
||||
flags: i32,
|
||||
) LinkatError!void {
|
||||
switch (errno(system.linkat(olddir, oldpath, newdir, newpath, flags))) {
|
||||
0 => return,
|
||||
EACCES => return error.AccessDenied,
|
||||
EDQUOT => return error.DiskQuota,
|
||||
EEXIST => return error.PathAlreadyExists,
|
||||
EFAULT => unreachable,
|
||||
EIO => return error.FileSystem,
|
||||
ELOOP => return error.SymLinkLoop,
|
||||
EMLINK => return error.LinkQuotaExceeded,
|
||||
ENAMETOOLONG => return error.NameTooLong,
|
||||
ENOENT => return error.FileNotFound,
|
||||
ENOMEM => return error.SystemResources,
|
||||
ENOSPC => return error.NoSpaceLeft,
|
||||
ENOTDIR => return error.NotDir,
|
||||
EPERM => return error.AccessDenied,
|
||||
EROFS => return error.ReadOnlyFileSystem,
|
||||
EXDEV => return error.NotSameFileSystem,
|
||||
EINVAL => unreachable,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn linkat(
|
||||
olddir: fd_t,
|
||||
oldpath: []const u8,
|
||||
newdir: fd_t,
|
||||
newpath: []const u8,
|
||||
flags: i32,
|
||||
) LinkatError!void {
|
||||
const old = try toPosixPath(oldpath);
|
||||
const new = try toPosixPath(newpath);
|
||||
return try linkatZ(olddir, &old, newdir, &new, flags);
|
||||
}
|
||||
|
||||
pub const UnlinkError = error{
|
||||
FileNotFound,
|
||||
|
||||
|
||||
@ -634,6 +634,37 @@ pub fn tgkill(tgid: pid_t, tid: pid_t, sig: i32) usize {
|
||||
return syscall2(.tgkill, @bitCast(usize, @as(isize, tgid)), @bitCast(usize, @as(isize, tid)), @bitCast(usize, @as(isize, sig)));
|
||||
}
|
||||
|
||||
pub fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: i32) usize {
|
||||
if (@hasField(SYS, "link")) {
|
||||
return syscall3(
|
||||
.link,
|
||||
@ptrToInt(oldpath),
|
||||
@ptrToInt(newpath),
|
||||
@bitCast(usize, @as(isize, flags)),
|
||||
);
|
||||
} else {
|
||||
return syscall5(
|
||||
.linkat,
|
||||
@bitCast(usize, @as(isize, AT_FDCWD)),
|
||||
@ptrToInt(oldpath),
|
||||
@bitCast(usize, @as(isize, AT_FDCWD)),
|
||||
@ptrToInt(newpath),
|
||||
@bitCast(usize, @as(isize, flags)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn linkat(oldfd: fd_t, oldpath: [*:0]const u8, newfd: fd_t, newpath: [*:0]const u8, flags: i32) usize {
|
||||
return syscall5(
|
||||
.linkat,
|
||||
@bitCast(usize, @as(isize, oldfd)),
|
||||
@ptrToInt(oldpath),
|
||||
@bitCast(usize, @as(isize, newfd)),
|
||||
@ptrToInt(newpath),
|
||||
@bitCast(usize, @as(isize, flags)),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn unlink(path: [*:0]const u8) usize {
|
||||
if (@hasField(SYS, "unlink")) {
|
||||
return syscall1(.unlink, @ptrToInt(path));
|
||||
|
||||
@ -189,6 +189,75 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
|
||||
expect(mem.eql(u8, target_path, given));
|
||||
}
|
||||
|
||||
test "link with relative paths" {
|
||||
if (builtin.os.tag != .linux) return error.SkipZigTest;
|
||||
var cwd = fs.cwd();
|
||||
|
||||
cwd.deleteFile("example.txt") catch {};
|
||||
cwd.deleteFile("new.txt") catch {};
|
||||
|
||||
try cwd.writeFile("example.txt", "example");
|
||||
try os.link("example.txt", "new.txt", 0);
|
||||
|
||||
const efd = try cwd.openFile("example.txt", .{});
|
||||
defer efd.close();
|
||||
|
||||
const nfd = try cwd.openFile("new.txt", .{});
|
||||
defer nfd.close();
|
||||
|
||||
{
|
||||
const estat = try os.fstat(efd.handle);
|
||||
const nstat = try os.fstat(nfd.handle);
|
||||
|
||||
testing.expectEqual(estat.ino, nstat.ino);
|
||||
testing.expectEqual(@as(usize, 2), nstat.nlink);
|
||||
}
|
||||
|
||||
try os.unlink("new.txt");
|
||||
|
||||
{
|
||||
const estat = try os.fstat(efd.handle);
|
||||
testing.expectEqual(@as(usize, 1), estat.nlink);
|
||||
}
|
||||
|
||||
try cwd.deleteFile("example.txt");
|
||||
}
|
||||
|
||||
test "linkat with different directories" {
|
||||
if (builtin.os.tag != .linux) return error.SkipZigTest;
|
||||
var cwd = fs.cwd();
|
||||
var tmp = tmpDir(.{});
|
||||
|
||||
cwd.deleteFile("example.txt") catch {};
|
||||
tmp.dir.deleteFile("new.txt") catch {};
|
||||
|
||||
try cwd.writeFile("example.txt", "example");
|
||||
try os.linkat(cwd.fd, "example.txt", tmp.dir.fd, "new.txt", 0);
|
||||
|
||||
const efd = try cwd.openFile("example.txt", .{});
|
||||
defer efd.close();
|
||||
|
||||
const nfd = try tmp.dir.openFile("new.txt", .{});
|
||||
|
||||
{
|
||||
defer nfd.close();
|
||||
const estat = try os.fstat(efd.handle);
|
||||
const nstat = try os.fstat(nfd.handle);
|
||||
|
||||
testing.expectEqual(estat.ino, nstat.ino);
|
||||
testing.expectEqual(@as(usize, 2), nstat.nlink);
|
||||
}
|
||||
|
||||
try os.unlinkat(tmp.dir.fd, "new.txt", 0);
|
||||
|
||||
{
|
||||
const estat = try os.fstat(efd.handle);
|
||||
testing.expectEqual(@as(usize, 1), estat.nlink);
|
||||
}
|
||||
|
||||
try cwd.deleteFile("example.txt");
|
||||
}
|
||||
|
||||
test "fstatat" {
|
||||
// enable when `fstat` and `fstatat` are implemented on Windows
|
||||
if (builtin.os.tag == .windows) return error.SkipZigTest;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user