diff options
author | 2023-02-17 21:41:58 -0800 | |
---|---|---|
committer | 2023-02-17 21:41:58 -0800 | |
commit | 1106c8e2f26ec5f521e33b132594b0741e9caaa3 (patch) | |
tree | 0f3d0139125f25094432f849b3971f1231264317 | |
parent | 20d9483cd068358d364cd91e518dfb852521cd8b (diff) | |
download | bun-1106c8e2f26ec5f521e33b132594b0741e9caaa3.tar.gz bun-1106c8e2f26ec5f521e33b132594b0741e9caaa3.tar.zst bun-1106c8e2f26ec5f521e33b132594b0741e9caaa3.zip |
More correct filesystem flags parsing
-rw-r--r-- | src/bun.js/node/types.zig | 104 |
1 files changed, 55 insertions, 49 deletions
diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig index d5ed86f4a..fbae5b3e1 100644 --- a/src/bun.js/node/types.zig +++ b/src/bun.js/node/types.zig @@ -970,61 +970,67 @@ pub const FileSystemFlags = enum(Mode) { } if (val.isNumber()) { - const number = val.toInt32(); - return @intToEnum(FileSystemFlags, number); + const number = val.coerce(i32, ctx); + return @intToEnum(FileSystemFlags, @intCast(Mode, @max(number, 0))); } const jsType = val.jsType(); if (jsType.isStringLike()) { - var zig_str = JSC.ZigString.init(""); - val.toZigString(&zig_str, ctx.ptr()); - - var buf: [4]u8 = .{ 0, 0, 0, 0 }; - @memcpy(&buf, zig_str.ptr, @min(buf.len, zig_str.len)); - const Matcher = strings.ExactSizeMatcher(4); - - // https://github.com/nodejs/node/blob/8c3637cd35cca352794e2c128f3bc5e6b6c41380/lib/internal/fs/utils.js#L565 - const flags = switch (Matcher.match(buf[0..4])) { - Matcher.case("r") => O_RDONLY, - Matcher.case("rs"), Matcher.case("sr") => O_RDONLY | O_SYNC, - Matcher.case("r+") => O_RDWR, - Matcher.case("rs+"), Matcher.case("sr+") => O_RDWR | O_SYNC, - - Matcher.case("w") => O_TRUNC | O_CREAT | O_WRONLY, - Matcher.case("wx"), Matcher.case("xw") => O_TRUNC | O_CREAT | O_WRONLY | O_EXCL, - - Matcher.case("w+") => O_TRUNC | O_CREAT | O_RDWR, - Matcher.case("wx+"), Matcher.case("xw+") => O_TRUNC | O_CREAT | O_RDWR | O_EXCL, - - Matcher.case("a") => O_APPEND | O_CREAT | O_WRONLY, - Matcher.case("ax"), Matcher.case("xa") => O_APPEND | O_CREAT | O_WRONLY | O_EXCL, - Matcher.case("as"), Matcher.case("sa") => O_APPEND | O_CREAT | O_WRONLY | O_SYNC, - - Matcher.case("a+") => O_APPEND | O_CREAT | O_RDWR, - Matcher.case("ax+"), Matcher.case("xa+") => O_APPEND | O_CREAT | O_RDWR | O_EXCL, - Matcher.case("as+"), Matcher.case("sa+") => O_APPEND | O_CREAT | O_RDWR | O_SYNC, - - Matcher.case("") => { - JSC.throwInvalidArguments( - "Invalid flag: string can't be empty", - .{}, - ctx, - exception, - ); - return null; - }, - else => { - JSC.throwInvalidArguments( - "Invalid flag. Learn more at https://nodejs.org/api/fs.html#fs_file_system_flags", - .{}, - ctx, - exception, - ); - return null; - }, + const str = val.getZigString(ctx); + if (str.isEmpty()) { + JSC.throwInvalidArguments( + "Expected flags to be a non-empty string. Learn more at https://nodejs.org/api/fs.html#fs_file_system_flags", + .{}, + ctx, + exception, + ); + return null; + } + + const flags = brk: { + switch (str.is16Bit()) { + inline else => |is_16bit| { + const chars = if (is_16bit) str.utf16SliceAligned() else str.slice(); + + if (std.ascii.isDigit(@truncate(u8, chars[0]))) { + // node allows "0o644" as a string :( + if (is_16bit) { + const slice = str.toSlice(bun.default_allocator); + defer slice.deinit(); + + break :brk std.fmt.parseInt(Mode, slice.slice(), 10) catch null; + } else { + break :brk std.fmt.parseInt(Mode, chars, 10) catch null; + } + } + + var flags: Mode = 0; + for (chars) |c| { + flags |= switch (c) { + 'R', 'r' => O_RDONLY, + 'W', 'w' => O_WRONLY | O_CREAT | O_TRUNC, + 'A', 'a' => O_WRONLY | O_CREAT | O_APPEND, + '+' => O_RDWR, + 'X', 'x' => O_WRONLY | O_CREAT | O_EXCL, + 'S', 's' => O_SYNC, + else => break :brk null, + }; + } + + break :brk flags; + }, + } + } orelse { + JSC.throwInvalidArguments( + "Invalid flag. Learn more at https://nodejs.org/api/fs.html#fs_file_system_flags", + .{}, + ctx, + exception, + ); + return null; }; - return @intToEnum(FileSystemFlags, flags); + return @intToEnum(FileSystemFlags, @intCast(Mode, flags)); } return null; |