aboutsummaryrefslogtreecommitdiff
path: root/src/fs.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs.zig')
-rw-r--r--src/fs.zig147
1 files changed, 72 insertions, 75 deletions
diff --git a/src/fs.zig b/src/fs.zig
index d37706b45..4e043aaf8 100644
--- a/src/fs.zig
+++ b/src/fs.zig
@@ -179,29 +179,8 @@ pub const FileSystem = struct {
}
// entry.name only lives for the duration of the iteration
- var name: []u8 = undefined;
+ const name = try FileSystem.FilenameStore.instance.appendLowerCase(@TypeOf(entry.name), entry.name);
- switch (_kind) {
- .file => {
- name = FileSystem.FilenameStore.editableSlice(try FileSystem.FilenameStore.instance.append(@TypeOf(entry.name), entry.name));
- },
- .dir => {
- // FileSystem.FilenameStore here because it's not an absolute path
- // it's a path relative to the parent directory
- // so it's a tiny path like "foo" instead of "/bar/baz/foo"
- name = FileSystem.FilenameStore.editableSlice(try FileSystem.FilenameStore.instance.append(@TypeOf(entry.name), entry.name));
- },
- }
-
- for (name) |c, i| {
- name[i] = std.ascii.toLower(c);
- }
-
- var symlink: []u8 = "";
-
- if (entry.kind == std.fs.Dir.Entry.Kind.SymLink) {
- symlink = name;
- }
const index = try EntryStore.instance.append(Entry{
.base = name,
.dir = dir.dir,
@@ -211,7 +190,7 @@ pub const FileSystem = struct {
// for each entry was a big performance issue for that package.
.need_stat = entry.kind == .SymLink,
.cache = Entry.Cache{
- .symlink = symlink,
+ .symlink = "",
.kind = _kind,
},
});
@@ -332,8 +311,6 @@ pub const FileSystem = struct {
};
pub fn kind(entry: *Entry, fs: *Implementation) Kind {
- // entry.mutex.lock();
- // defer entry.mutex.unlock();
if (entry.need_stat) {
entry.need_stat = false;
entry.cache = fs.kind(entry.dir, entry.base) catch unreachable;
@@ -342,8 +319,6 @@ pub const FileSystem = struct {
}
pub fn symlink(entry: *Entry, fs: *Implementation) string {
- // entry.mutex.lock();
- // defer entry.mutex.unlock();
if (entry.need_stat) {
entry.need_stat = false;
entry.cache = fs.kind(entry.dir, entry.base) catch unreachable;
@@ -464,7 +439,7 @@ pub const FileSystem = struct {
entries_mutex: Mutex = Mutex.init(),
entries: *EntriesOption.Map,
allocator: *std.mem.Allocator,
- limiter: Limiter,
+ limiter: *Limiter,
cwd: string,
parent_fs: *FileSystem = undefined,
file_limit: usize = 32,
@@ -529,18 +504,28 @@ pub const FileSystem = struct {
return limit.cur;
}
+ threadlocal var _entries_option_map: *EntriesOption.Map = undefined;
+ threadlocal var _entries_option_map_loaded: bool = false;
+ var __limiter: Limiter = undefined;
pub fn init(
allocator: *std.mem.Allocator,
cwd: string,
) RealFS {
const file_limit = adjustUlimit();
+
+ if (!_entries_option_map_loaded) {
+ _entries_option_map = EntriesOption.Map.init(allocator);
+ _entries_option_map_loaded = true;
+ __limiter = Limiter.init(allocator, file_limit);
+ }
+
return RealFS{
- .entries = EntriesOption.Map.init(allocator),
+ .entries = _entries_option_map,
.allocator = allocator,
.cwd = cwd,
.file_limit = file_limit,
.file_quota = file_limit,
- .limiter = Limiter.init(allocator, file_limit),
+ .limiter = &__limiter,
};
}
@@ -637,7 +622,7 @@ pub const FileSystem = struct {
// This custom map implementation:
// - Preallocates a fixed amount of directory name space
// - Doesn't store directory names which don't exist.
- pub const Map = allocators.BSSMap(EntriesOption, Preallocate.Counts.dir_entry, false, 128);
+ pub const Map = allocators.TBSSMap(EntriesOption, Preallocate.Counts.dir_entry, false, 128);
};
// Limit the number of files open simultaneously to avoid ulimit issues
@@ -668,7 +653,7 @@ pub const FileSystem = struct {
};
pub fn openDir(fs: *RealFS, unsafe_dir_string: string) std.fs.File.OpenError!std.fs.Dir {
- return try std.fs.openDirAbsolute(unsafe_dir_string, std.fs.Dir.OpenDirOptions{ .iterate = true, .access_sub_paths = true, .no_follow = true });
+ return try std.fs.openDirAbsolute(unsafe_dir_string, std.fs.Dir.OpenDirOptions{ .iterate = true, .access_sub_paths = true, .no_follow = false });
}
fn readdir(
@@ -843,61 +828,39 @@ pub const FileSystem = struct {
pub fn kind(fs: *RealFS, _dir: string, base: string) !Entry.Cache {
var dir = _dir;
var combo = [2]string{ dir, base };
- var entry_path = path_handler.joinAbsString(fs.cwd, &combo, .auto);
+ var outpath: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+ var entry_path = path_handler.joinAbsStringBuf(fs.cwd, &outpath, &combo, .auto);
- fs.limiter.before();
- defer fs.limiter.after();
+ outpath[entry_path.len + 1] = 0;
+ outpath[entry_path.len] = 0;
- const file = try std.fs.openFileAbsolute(entry_path, .{ .read = true, .write = false });
- defer {
- if (fs.needToCloseFiles()) {
- file.close();
- }
- }
- var stat = try file.stat();
+ const absolute_path_c: [:0]const u8 = outpath[0..entry_path.len :0];
+ fs.limiter.before();
+ defer fs.limiter.after();
+ var stat = try C.lstat_absolute(absolute_path_c);
+ const is_symlink = stat.kind == std.fs.File.Kind.SymLink;
var _kind = stat.kind;
var cache = Entry.Cache{ .kind = Entry.Kind.file, .symlink = "" };
var symlink: []const u8 = "";
- if (_kind == .SymLink) {
- // windows has a max filepath of 255 chars
- // we give it a little longer for other platforms
- var out_buffer = std.mem.zeroes([512]u8);
- var out_slice = &out_buffer;
- symlink = entry_path;
- var links_walked: u8 = 0;
-
- while (links_walked < 255) : (links_walked += 1) {
- var link: string = try std.os.readlink(symlink, out_slice);
-
- if (!std.fs.path.isAbsolute(link)) {
- combo[0] = dir;
- combo[1] = link;
-
- link = path_handler.joinAbsStringBuf(fs.cwd, out_slice, &combo, .auto);
- }
- // TODO: do we need to clean the path?
- symlink = link;
-
- const file2 = std.fs.openFileAbsolute(symlink, std.fs.File.OpenFlags{ .read = true, .write = false }) catch return cache;
- // These ones we always close
- defer file2.close();
-
- const stat2 = file2.stat() catch return cache;
+ if (is_symlink) {
+ var file = try std.fs.openFileAbsoluteZ(absolute_path_c, .{ .read = true });
+ setMaxFd(file.handle);
- // Re-run "lstat" on the symlink target
- _kind = stat2.kind;
- if (_kind != .SymLink) {
- break;
+ defer {
+ if (fs.needToCloseFiles()) {
+ file.close();
}
- dir = std.fs.path.dirname(link) orelse return cache;
}
+ const _stat = try file.stat();
- if (links_walked > 255) {
- return cache;
- }
+ symlink = try std.os.getFdPath(file.handle, &outpath);
+
+ _kind = _stat.kind;
}
+ std.debug.assert(_kind != .SymLink);
+
if (_kind == .Directory) {
cache.kind = .dir;
} else {
@@ -931,6 +894,7 @@ pub const PathName = struct {
base: string,
dir: string,
ext: string,
+ filename: string,
// For readability, the names of certain automatically-generated symbols are
// derived from the file name. For example, instead of the CommonJS wrapper for
@@ -1004,6 +968,7 @@ pub const PathName = struct {
.dir = dir,
.base = base,
.ext = ext,
+ .filename = if (dir.len > 0) _path[dir.len + 1 ..] else _path,
};
}
};
@@ -1014,10 +979,42 @@ threadlocal var join_buf: [1024]u8 = undefined;
pub const Path = struct {
pretty: string,
text: string,
+ non_symlink: string = "",
namespace: string = "unspecified",
name: PathName,
is_disabled: bool = false,
+ // "/foo/bar/node_modules/react/index.js" => "index.js"
+ // "/foo/bar/node_modules/.pnpm/react@17.0.1/node_modules/react/index.js" => "index.js"
+ pub fn packageRelativePathString(this: *const Path, name: string) string {
+ // TODO: we don't need to print this buffer, this is inefficient
+ var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+ const search_path = std.fmt.bufPrint(&buffer, std.fs.path.sep_str ++ "node_modules" ++ std.fs.path.sep_str ++ "{s}" ++ std.fs.path.sep_str, .{name}) catch return this.text;
+ if (strings.lastIndexOf(this.canonicalNodeModuleText(), search_path)) |i| {
+ return this.canonicalNodeModuleText()[i + search_path.len ..];
+ }
+
+ return this.canonicalNodeModuleText();
+ }
+
+ pub fn nodeModulesRelativePathString(
+ this: *const Path,
+ name: string,
+ ) string {
+ // TODO: we don't need to print this buffer, this is inefficient
+ var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+ const search_path = std.fmt.bufPrint(&buffer, std.fs.path.sep_str ++ "node_modules" ++ std.fs.path.sep_str ++ "{s}" ++ std.fs.path.sep_str, .{name}) catch return this.text;
+ if (strings.lastIndexOf(this.canonicalNodeModuleText(), search_path)) |i| {
+ return this.canonicalNodeModuleText()[i + search_path.len - name.len - 1 ..];
+ }
+
+ return this.canonicalNodeModuleText();
+ }
+
+ pub inline fn canonicalNodeModuleText(this: *const Path) string {
+ return this.text;
+ }
+
pub fn jsonStringify(self: *const @This(), options: anytype, writer: anytype) !void {
return try std.json.stringify(self.text, options, writer);
}