diff --git a/.gitignore b/.gitignore index 6d8accf..d6147f1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,6 @@ test compile_commands.json .quickmarks +.firecmds .DS_Store diff --git a/include/cli.h b/include/cli.h index e43028b..8ef002f 100644 --- a/include/cli.h +++ b/include/cli.h @@ -4,7 +4,7 @@ #include #include -#define LASER_VERSION "1.7.2" +#define LASER_VERSION "1.7.3" typedef struct laser_opts { diff --git a/include/laser_pwuid.h b/include/laser_pwuid.h new file mode 100644 index 0000000..94f3bb2 --- /dev/null +++ b/include/laser_pwuid.h @@ -0,0 +1,23 @@ +#ifndef LASER_PWUID_H +#define LASER_PWUID_H + +#include + +struct laser_uid +{ + uid_t uid; + char *name; // we don need the whole passwd struct +}; + +// i doubt you have more than this many users on your system +#define LASER_UID_CACHE_SIZE 64 +struct laser_uid_cache +{ + struct laser_uid uid_cache[LASER_UID_CACHE_SIZE]; + size_t uid_cache_count; +}; + +struct laser_uid *laser_getpwuid(uid_t uid); +void laser_pwuid_free_cache(void); + +#endif diff --git a/src/laser.c b/src/laser.c index 3ab7b8c..0b84c97 100644 --- a/src/laser.c +++ b/src/laser.c @@ -3,6 +3,7 @@ #include "filetypes/checktypes.h" #include "git/lgit.h" #include "init_lua.h" +#include "laser_pwuid.h" #include "logger.h" #include "lua_filters.h" #include "utils.h" @@ -14,6 +15,9 @@ #define BLOCK_SIZE 512 #define BRANCH_SIZE 8 +#define INITIAL_ENTRIES_CAPACITY 16 +#define ENTRIES_GROWTH_FACTOR 2 + static ssize_t longest_ownername = 0; static size_t current_dir_total_size = 0; @@ -92,7 +96,7 @@ void laser_process_single_file(laser_opts opts) if (opts.show_git->show_git_status) lgit_getGitStatus(opts, &entry, opts.dir); - char *ownername = getpwuid(entry.s.st_uid)->pw_name; + char *ownername = laser_getpwuid(entry.s.st_uid)->name; longest_ownername = strlen(ownername); // this has to be the longest name // cus it be the ownly name @@ -123,7 +127,6 @@ static void laser_list_directory(laser_opts opts, int depth) } static void laser_process_entries(laser_opts opts, int depth, char *indent) - { DIR *dir = opendir(opts.dir); if (dir == NULL) @@ -138,9 +141,11 @@ static void laser_process_entries(laser_opts opts, int depth, char *indent) strerror(errno)); struct laser_dirent **entries = NULL; + size_t entries_capacity = 0; if (opts.sort) { - entries = malloc(sizeof(struct laser_dirent *)); + entries_capacity = INITIAL_ENTRIES_CAPACITY; + entries = malloc(sizeof(*entries) * entries_capacity); if (entries == NULL) laser_logger_fatal(1, "Failed to allocate entries struct: %s", strerror(errno)); @@ -155,7 +160,7 @@ static void laser_process_entries(laser_opts opts, int depth, char *indent) exit(1); } - int entry_count = 0; + size_t entry_count = 0; int entry_ignored = 0; char full_path[LASER_PATH_MAX]; while ((entry->d = readdir(dir)) != NULL) @@ -222,23 +227,25 @@ static void laser_process_entries(laser_opts opts, int depth, char *indent) current_dir_total_size += entry->s.st_size; } - char *ownername = getpwuid(entry->s.st_uid)->pw_name; + char *ownername = laser_getpwuid(entry->s.st_uid)->name; ssize_t ownername_len = strlen(ownername); if (ownername_len > longest_ownername) longest_ownername = ownername_len; if (!opts.sort) { - // we dunno what dir is gon be last laser_handle_entry(entry, full_path, indent, depth, opts, 0); continue; } - entries = realloc(entries, (entry_count + 1) * - sizeof(struct laser_dirent *)); - if (entries == NULL) - laser_logger_fatal(1, "Failed to realloc entries: %s", - strerror(errno)); + if (entry_count >= entries_capacity) + { + entries_capacity += ENTRIES_GROWTH_FACTOR; + entries = realloc(entries, sizeof(*entries) * entries_capacity); + if (entries == NULL) + laser_logger_fatal(1, "Failed to realloc entries: %s", + strerror(errno)); + } size_t entry_size = sizeof(struct laser_dirent) + offsetof(struct dirent, d_name) + @@ -276,9 +283,9 @@ static void laser_process_entries(laser_opts opts, int depth, char *indent) laser_sort(entries, entry_count, sizeof(struct laser_dirent *), laser_cmp_dirent, NULL); - for (int i = 0; i < entry_count; i++) + for (size_t i = 0; i < entry_count; i++) { - int is_last = (i == entry_count - 1); + size_t is_last = (i == entry_count - 1); snprintf(full_path, sizeof(full_path), "%s/%s", opts.dir, entries[i]->d->d_name); @@ -420,7 +427,7 @@ static void laser_print_long_entry(struct laser_dirent *entry, lua_pushinteger(L, entry->s.st_mtime); lua_setfield(L, -2, "mtime"); - lua_pushstring(L, getpwuid(entry->s.st_uid)->pw_name); + lua_pushstring(L, laser_getpwuid(entry->s.st_uid)->name); lua_setfield(L, -2, "owner"); lua_pushstring(L, S_ISDIR(entry->s.st_mode) ? "d" : S_ISLNK(entry->s.st_mode) ? "l" @@ -494,11 +501,6 @@ static off_t laser_git_dir_size(struct laser_dirent *ent, char *fp) if (!S_ISDIR(ent->s.st_mode)) return -1; - off_t s = 0; - - struct laser_dirent e; - char full_path[LASER_PATH_MAX]; - DIR *dir = opendir(fp); if (dir == NULL) { @@ -507,14 +509,28 @@ static off_t laser_git_dir_size(struct laser_dirent *ent, char *fp) return -1; } + off_t s = 0; + + struct laser_dirent e; + size_t fp_len = strlen(fp); + + char full_path[LASER_PATH_MAX]; + memcpy(full_path, fp, fp_len); + full_path[fp_len] = '/'; + while ((e.d = readdir(dir)) != NULL) { if (strcmp(e.d->d_name, ".") == 0 || strcmp(e.d->d_name, "..") == 0) continue; - snprintf(full_path, sizeof(full_path), "%s/%s", fp, e.d->d_name); + // first +1 is to ensure that / is added + memcpy(full_path + fp_len + 1, e.d->d_name, strlen(e.d->d_name) + 1); if (stat(full_path, &e.s) == -1) { + // just ignore Eror NO ENTry + if (errno == ENOENT) + continue; + laser_logger_error("couldn't stat %s, %s\n", full_path, strerror(errno)); continue; diff --git a/src/laser_pwuid.c b/src/laser_pwuid.c new file mode 100644 index 0000000..1286470 --- /dev/null +++ b/src/laser_pwuid.c @@ -0,0 +1,50 @@ +#include "laser_pwuid.h" +#include "logger.h" +#include +#include +#include + +static struct laser_uid_cache uid_cache = {.uid_cache_count = 0}; + +// to free the allocated memory by the cache you have to call the +// `laser_pwuid_free_cache` function at the end of the program run, you +// SHOULDN'T be manually freeing this memory!! +struct laser_uid *laser_getpwuid(uid_t uid) +{ + for (size_t i = 0; i < uid_cache.uid_cache_count; i++) + { + if (uid_cache.uid_cache[i].uid == uid) + return &uid_cache.uid_cache[i]; + } + + struct passwd *pw = getpwuid(uid); + if (!pw) + laser_logger_fatal(1, "getpwuid failed: %s", strerror(errno)); + + // if there is not space (which shouldn't happen cuz if it does then that's + // impressive, how many users have you got???) then just return NULL + if (uid_cache.uid_cache_count >= LASER_UID_CACHE_SIZE) + return NULL; + + struct laser_uid *entry = &uid_cache.uid_cache[uid_cache.uid_cache_count]; + uid_cache.uid_cache_count++; + + entry->uid = uid; + entry->name = strdup(pw->pw_name); + if (!entry->name) + laser_logger_fatal(1, "failed to allocate memory for uid name: %s", + strerror(errno)); + + return entry; +} + +void laser_pwuid_free_cache(void) +{ + for (size_t i = 0; i < uid_cache.uid_cache_count; i++) + { + if (uid_cache.uid_cache[i].name) + free(uid_cache.uid_cache[i].name); + } + + uid_cache.uid_cache_count = 0; +} diff --git a/src/lua_filters.c b/src/lua_filters.c index 8796897..28ef22f 100644 --- a/src/lua_filters.c +++ b/src/lua_filters.c @@ -1,4 +1,5 @@ #include "lua_filters.h" +#include "laser_pwuid.h" #include "logger.h" int lua_filters_apply(laser_opts opts, struct laser_dirent *entry) @@ -20,7 +21,7 @@ int lua_filters_apply(laser_opts opts, struct laser_dirent *entry) lua_pushinteger(L, entry->s.st_mtime); lua_setfield(L, -2, "mtime"); - lua_pushstring(L, getpwuid(entry->s.st_uid)->pw_name); + lua_pushstring(L, laser_getpwuid(entry->s.st_uid)->name); lua_setfield(L, -2, "owner"); lua_pushstring(L, S_ISDIR(entry->s.st_mode) ? "d" diff --git a/src/main.c b/src/main.c index 4a4906e..b219a5a 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,7 @@ #include "colors.h" #include "init_lua.h" #include "laser.h" +#include "laser_pwuid.h" #include "logger.h" #include #include @@ -77,6 +78,7 @@ int main(int argc, char **argv) clean: laser_cli_destroy_opts(opts); laser_lua_destroy(); + laser_pwuid_free_cache(); git_libgit2_shutdown(); return 0;