From e41a5efcb5477ca94195aed734f2b37ef12e77c5 Mon Sep 17 00:00:00 2001 From: Marius Gerbershagen Date: Sat, 10 Aug 2024 15:07:01 +0200 Subject: [PATCH] avoid unnecessary network requests when reading directories on emscripten If we call stat in order to find out if a filename points to a directory or an ordinary file, the emscripten stdlib may need to do a network request to find out the size of the file even though we don't care about that. This happens for files created with FS.createLazyFile() by emscripten. By using readlink/opendir when possible we avoid that. --- src/c/unixfsys.d | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/c/unixfsys.d b/src/c/unixfsys.d index 570b07c8d..058ef4edf 100644 --- a/src/c/unixfsys.d +++ b/src/c/unixfsys.d @@ -250,6 +250,41 @@ file_kind(ecl_filename_char *filename, bool follow_links) { else output = @':file'; ecl_enable_interrupts(); +#elif defined(EMSCRIPTEN) && defined(HAVE_DIRENT_H) + /* We don't want to call stat unless we have to on emscripten + * because getting the size of a file may involve a network call for + * lazy loading files. Since we don't care about the size but only + * the kind of file we have, we can use other functions to get + * the information. */ + ecl_stat_struct buf; + DIR *dir; + if (!follow_links) { + char buffer; + if (readlink(filename, &buffer, 1) >= 0) + return @':link'; + else if (errno == ENOENT) + return ECL_NIL; + } + dir = opendir(filename); + if (dir != NULL) { + closedir(dir); + output = @':directory'; + } else if (errno == ENOENT) + output = ECL_NIL; + else if (errno == ENOTDIR) + output = @':file'; + else if (safe_stat(filename, &buf) < 0) + output = ECL_NIL; + else if (S_ISDIR(buf.st_mode)) + output = @':directory'; + else if (S_ISREG(buf.st_mode)) + output = @':file'; +# ifdef S_ISFIFO + else if (S_ISFIFO(buf.st_mode)) + output = @':fifo'; +# endif + else + output = @':special'; #else ecl_stat_struct buf; # ifdef HAVE_LSTAT @@ -296,6 +331,9 @@ si_readlink(cl_object filename) { ecl_disable_interrupts(); written = readlink(ecl_filename_self(filename), output, size); ecl_enable_interrupts(); + if (written == -1) { + return ECL_NIL; + } size += 256; } while (written == size-256); output[written] = '\0';