From bae92d8701f866a99ebf32c136f0de752922e915 Mon Sep 17 00:00:00 2001 From: konect-V <66421869+konect-V@users.noreply.github.com> Date: Mon, 17 Jun 2024 16:46:24 +0200 Subject: [PATCH] Add update system for store | Bug fix for curl and fat32 --- .vscode/settings.json | 3 +- patches/curl/curl.patch | 93 ++++++++- .../core/apps/datetime/target/amd64/makefile | 2 +- sources/core/apps/init/target/amd64/makefile | 2 +- sources/core/apps/ip/target/amd64/makefile | 2 +- sources/core/apps/llm/target/amd64/makefile | 2 +- sources/core/apps/store/source/core/core.c | 11 +- .../apps/store/source/download/download.c | 4 +- .../apps/store/source/download/download.h | 2 +- .../core/apps/store/source/install/install.c | 6 +- .../core/apps/store/source/install/install.h | 2 +- sources/core/apps/store/source/untar/untar.c | 4 + .../core/apps/store/source/update/update.c | 197 ++++++++++++++++++ .../core/apps/store/source/update/update.h | 14 ++ sources/core/apps/store/target/amd64/makefile | 2 +- .../core/apps/weather/target/amd64/makefile | 2 +- sources/core/modules/fat32/source/core.c | 20 +- 17 files changed, 337 insertions(+), 31 deletions(-) create mode 100644 sources/core/apps/store/source/update/update.c create mode 100644 sources/core/apps/store/source/update/update.h diff --git a/.vscode/settings.json b/.vscode/settings.json index e512a3a9e..580d696ee 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -203,7 +203,8 @@ "curl_memory.h": "c", "apps.h": "c", "download.h": "c", - "stdlib.h": "c" + "stdlib.h": "c", + "update.h": "c" }, "files.exclude": { "bundled": true, diff --git a/patches/curl/curl.patch b/patches/curl/curl.patch index 31bda0eff..7664cf6ca 100644 --- a/patches/curl/curl.patch +++ b/patches/curl/curl.patch @@ -1,11 +1,12 @@ -From 09dd7f9cdae6821aa50fee1e70054021b6e3d2fa Mon Sep 17 00:00:00 2001 +From 7696a5a455df17e54a74f2508b289c340f46c928 Mon Sep 17 00:00:00 2001 From: konect-V <66421869+konect-V@users.noreply.github.com> -Date: Fri, 31 May 2024 16:03:34 +0200 -Subject: [PATCH 1/1] Port curl to kot +Date: Mon, 17 Jun 2024 13:11:56 +0200 +Subject: [PATCH 1/1] Port to Kot --- - config.sub | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) + config.sub | 2 +- + lib/vtls/openssl.c | 68 ---------------------------------------------- + 2 files changed, 1 insertion(+), 69 deletions(-) diff --git a/config.sub b/config.sub index dba16e8..dc0d387 100755 @@ -20,6 +21,84 @@ index dba16e8..dc0d387 100755 | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \ | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \ | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ +diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c +index a3953f6..f805048 100644 +--- a/lib/vtls/openssl.c ++++ b/lib/vtls/openssl.c +@@ -1890,74 +1890,6 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data) + DEBUGASSERT(backend); + + if(backend->handle) { +- /* Send the TLS shutdown if we are still connected *and* if +- * the peer did not already close the connection. */ +- if(cf->next && cf->next->connected && !connssl->peer_closed) { +- char buf[1024]; +- int nread, err; +- long sslerr; +- +- /* Maybe the server has already sent a close notify alert. +- Read it to avoid an RST on the TCP connection. */ +- ERR_clear_error(); +- nread = SSL_read(backend->handle, buf, (int)sizeof(buf)); +- err = SSL_get_error(backend->handle, nread); +- if(!nread && err == SSL_ERROR_ZERO_RETURN) { +- CURLcode result; +- ssize_t n; +- size_t blen = sizeof(buf); +- CURL_TRC_CF(data, cf, "peer has shutdown TLS"); +- /* SSL_read() will not longer touch the socket, let's receive +- * directly from the next filter to see if the underlying +- * connection has also been closed. */ +- n = Curl_conn_cf_recv(cf->next, data, buf, blen, &result); +- if(!n) { +- connssl->peer_closed = TRUE; +- CURL_TRC_CF(data, cf, "peer closed connection"); +- } +- } +- ERR_clear_error(); +- if(connssl->peer_closed) { +- /* As the peer closed, we do not expect it to read anything more we +- * may send. It may be harmful, leading to TCP RST and delaying +- * a lingering close. Just leave. */ +- CURL_TRC_CF(data, cf, "not from sending TLS shutdown on " +- "connection closed by peer"); +- } +- else if(SSL_shutdown(backend->handle) == 1) { +- CURL_TRC_CF(data, cf, "SSL shutdown finished"); +- } +- else { +- nread = SSL_read(backend->handle, buf, (int)sizeof(buf)); +- err = SSL_get_error(backend->handle, nread); +- switch(err) { +- case SSL_ERROR_NONE: /* this is not an error */ +- case SSL_ERROR_ZERO_RETURN: /* no more data */ +- CURL_TRC_CF(data, cf, "SSL shutdown, EOF from server"); +- break; +- case SSL_ERROR_WANT_READ: +- /* SSL has send its notify and now wants to read the reply +- * from the server. We are not really interested in that. */ +- CURL_TRC_CF(data, cf, "SSL shutdown sent"); +- break; +- case SSL_ERROR_WANT_WRITE: +- CURL_TRC_CF(data, cf, "SSL shutdown send blocked"); +- break; +- default: +- sslerr = ERR_get_error(); +- CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s', errno %d", +- (sslerr ? +- ossl_strerror(sslerr, buf, sizeof(buf)) : +- SSL_ERROR_to_str(err)), +- SOCKERRNO); +- break; +- } +- } +- +- ERR_clear_error(); +- SSL_set_connect_state(backend->handle); +- } +- + SSL_free(backend->handle); + backend->handle = NULL; + } -- -2.34.1 - +2.43.0 diff --git a/sources/core/apps/datetime/target/amd64/makefile b/sources/core/apps/datetime/target/amd64/makefile index 96b195338..2fc827336 100644 --- a/sources/core/apps/datetime/target/amd64/makefile +++ b/sources/core/apps/datetime/target/amd64/makefile @@ -13,7 +13,7 @@ BIN = bin/usr/bin LIB = lib # Tools Config -CFLAGS = +CFLAGS = -Werror LDFLAGS = -Wall \ -lc diff --git a/sources/core/apps/init/target/amd64/makefile b/sources/core/apps/init/target/amd64/makefile index 69c5d701d..fa7cc970c 100644 --- a/sources/core/apps/init/target/amd64/makefile +++ b/sources/core/apps/init/target/amd64/makefile @@ -12,7 +12,7 @@ BIN = bin/system/init LIB = lib # Tools Config -CFLAGS = +CFLAGS = -Werror LDFLAGS = -Wall \ -lc diff --git a/sources/core/apps/ip/target/amd64/makefile b/sources/core/apps/ip/target/amd64/makefile index ea579c952..c2058d716 100644 --- a/sources/core/apps/ip/target/amd64/makefile +++ b/sources/core/apps/ip/target/amd64/makefile @@ -13,7 +13,7 @@ BIN = bin/usr/bin LIB = lib # Tools Config -CFLAGS = +CFLAGS = -Werror LDFLAGS = -Wall \ -lc diff --git a/sources/core/apps/llm/target/amd64/makefile b/sources/core/apps/llm/target/amd64/makefile index 24dcfaf44..ae7a35bdb 100644 --- a/sources/core/apps/llm/target/amd64/makefile +++ b/sources/core/apps/llm/target/amd64/makefile @@ -13,7 +13,7 @@ BIN = bin/usr/bin LIB = lib # Tools Config -CFLAGS = +CFLAGS = -Werror LDFLAGS = -Wall \ -lc diff --git a/sources/core/apps/store/source/core/core.c b/sources/core/apps/store/source/core/core.c index cb59e9096..9cc975be8 100644 --- a/sources/core/apps/store/source/core/core.c +++ b/sources/core/apps/store/source/core/core.c @@ -1,9 +1,11 @@ #include #include #include +#include #include #include "../apps/apps.h" +#include "../update/update.h" #include "../install/install.h" void print_help(){ @@ -54,7 +56,7 @@ int main(int argc, char *argv[]){ fgets(allow_install, sizeof(allow_install), stdin); allow_install[strcspn(allow_install, "\n")] = 0; if(!strcmp("Y", allow_install)){ - install_app(curl, apps_available[index_to_install]->url, apps_available[index_to_install]->name); + install_app(curl, apps_available[index_to_install]->url, apps_available[index_to_install]->name, false); }else{ printf("Cancel the installation\n"); } @@ -80,7 +82,7 @@ int main(int argc, char *argv[]){ fgets(allow_install, sizeof(allow_install), stdin); allow_install[strcspn(allow_install, "\n")] = 0; if(!strcmp("Y", allow_install)){ - install_app(curl, url, name); + install_app(curl, url, name, false); }else{ printf("Cancel the installation\n"); } @@ -102,7 +104,7 @@ int main(int argc, char *argv[]){ fgets(allow_install, sizeof(allow_install), stdin); allow_install[strcspn(allow_install, "\n")] = 0; if(!strcmp("Y", allow_install)){ - install_app(curl, url, name); + install_app(curl, url, name, false); }else{ printf("Cancel the installation\n"); } @@ -110,6 +112,9 @@ int main(int argc, char *argv[]){ }else{ printf("Can't find %s in the store. Did you spell it correctly?\n", name); } + }else if(!strcmp(argv[1], "--update") && argc == 3){ + char* name = argv[2]; + update_app(curl, name); }else{ print_help(); } diff --git a/sources/core/apps/store/source/download/download.c b/sources/core/apps/store/source/download/download.c index 884a951b3..221733a41 100644 --- a/sources/core/apps/store/source/download/download.c +++ b/sources/core/apps/store/source/download/download.c @@ -33,8 +33,8 @@ static int progress_callback(void *clientp, curl_off_t dltotal, curl_off_t dlnow } -int download_file(CURL* curl, char* url, char* path){ - if(!is_file_exists(path)){ +int download_file(CURL* curl, char* url, char* path, bool force_download){ + if(!is_file_exists(path) || force_download){ printf("Initiating download of `%s` to `%s`\n", url, path); int r = -1; FILE* fp = fopen(path, "wb"); diff --git a/sources/core/apps/store/source/download/download.h b/sources/core/apps/store/source/download/download.h index 77891661b..edf519d14 100644 --- a/sources/core/apps/store/source/download/download.h +++ b/sources/core/apps/store/source/download/download.h @@ -4,6 +4,6 @@ #include #include -int download_file(CURL* curl, char* url, char* path); +int download_file(CURL* curl, char* url, char* path, bool force_download); #endif // DOWNLOAD_H \ No newline at end of file diff --git a/sources/core/apps/store/source/install/install.c b/sources/core/apps/store/source/install/install.c index 3e979ed6d..9047bc49b 100644 --- a/sources/core/apps/store/source/install/install.c +++ b/sources/core/apps/store/source/install/install.c @@ -22,7 +22,7 @@ static int create_dir_if_not_exist(char* path){ return 0; } -int install_app(CURL* curl, char* url, char* name){ +int install_app(CURL* curl, char* url, char* name, bool reinstall){ char* path_store = getenv("PATHSTORE"); create_dir_if_not_exist(path_store); @@ -37,7 +37,7 @@ int install_app(CURL* curl, char* url, char* name){ strcpy(path_store_app_info_json, path_store_app); strcat(path_store_app_info_json, "app-info.json"); - if(download_file(curl, url, path_store_app_info_json)){ + if(download_file(curl, url, path_store_app_info_json, reinstall)){ printf("Error: Aborting installation of %s!\n", name); free(path_store_app_info_json); @@ -82,7 +82,7 @@ int install_app(CURL* curl, char* url, char* name){ strcpy(path_store_installation_file, path_store_app); strcat(path_store_installation_file, installation_file_name); - if(download_file(curl, installation_file_url, path_store_installation_file)){ + if(download_file(curl, installation_file_url, path_store_installation_file, reinstall)){ printf("Error: Aborting installation of %s!\n", name); remove(path_store_app_info_json); diff --git a/sources/core/apps/store/source/install/install.h b/sources/core/apps/store/source/install/install.h index 0ced0bddd..0dae6bb1f 100644 --- a/sources/core/apps/store/source/install/install.h +++ b/sources/core/apps/store/source/install/install.h @@ -4,6 +4,6 @@ #include #include -int install_app(CURL* curl, char* url, char* name); +int install_app(CURL* curl, char* url, char* name, bool reinstall); #endif // INSTALL_H \ No newline at end of file diff --git a/sources/core/apps/store/source/untar/untar.c b/sources/core/apps/store/source/untar/untar.c index 460210d8a..2336caf6c 100644 --- a/sources/core/apps/store/source/untar/untar.c +++ b/sources/core/apps/store/source/untar/untar.c @@ -5,6 +5,10 @@ */ #include +#include +#include +#include +#include static int parseoct(const char *p, size_t n){ int i = 0; diff --git a/sources/core/apps/store/source/update/update.c b/sources/core/apps/store/source/update/update.c new file mode 100644 index 000000000..217ff3876 --- /dev/null +++ b/sources/core/apps/store/source/update/update.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "update.h" +#include "../install/install.h" + +static bool is_dir_exist(char* path){ + struct stat sb; + return (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)); +} + +static bool is_file_exists(char* path){ + struct stat sb; + return (stat(path, &sb) == 0); +} + +static size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp){ + fetch_app_info_t* buffer_info = (fetch_app_info_t*)userp; + size_t real_size = size * nmemb; + + buffer_info->size += real_size; + buffer_info->buffer = realloc(buffer_info->buffer, buffer_info->size); + + memcpy(&(buffer_info->buffer[buffer_info->size - real_size]), contents, real_size); + + return real_size; +} + +static int get_version_from_string(char* version_str){ + int x, y, z; + int len = strlen(version_str); + + for(int i = 0; i < len; i++){ + if(version_str[i] == '.'){ + continue; + } + if(version_str[i] < '0' || version_str[i] > '9'){ + return -1; + } + } + + sscanf(version_str, "%d.%d.%d", &x, &y, &z); + + const int x_shift = 16; + const int y_shift = 8; + const int x_mask = 0xFFFF0000; + const int y_mask = 0x0000FF00; + const int z_mask = 0x000000FF; + + int version_int = (x << x_shift) & x_mask; + version_int |= (y << y_shift) & y_mask; + version_int |= z & z_mask; + + return version_int; +} + +static int get_version_url(CURL* curl, char* url_info_path){ + fetch_app_info_t* buffer_info = malloc(sizeof(fetch_app_info_t)); + buffer_info->buffer = NULL; + buffer_info->size = 0; + curl_easy_setopt(curl, CURLOPT_URL, url_info_path); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer_info); + curl_easy_setopt(curl, CURLOPT_CAINFO, "/usr/etc/ssl/cert.pem"); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + CURLcode res = curl_easy_perform(curl); + + if(res != CURLE_OK){ + fprintf(stderr, "Error : curl_%s\n", curl_easy_strerror(res)); + free(buffer_info->buffer); + free(buffer_info); + return -1; + }else{ + cJSON* root = cJSON_Parse(buffer_info->buffer); + if(root != NULL){ + cJSON* version = cJSON_GetObjectItem(root, "version"); + if(version != NULL){ + if(cJSON_IsString(version) && (version->valuestring != NULL)){ + int ret = get_version_from_string(version->valuestring); + cJSON_Delete(root); + + free(buffer_info->buffer); + free(buffer_info); + return ret; + } + } + } + cJSON_Delete(root); + + free(buffer_info->buffer); + free(buffer_info); + } + + return -1; +} + +static int check_update(CURL* curl, char* app_info_path, char** url){ + FILE* fp = fopen(app_info_path, "r"); + + int version_local = 0; + int version_url = 0; + int n_version_get = 0; + + if(fp != NULL){ + fseek(fp, 0, SEEK_END); + size_t size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + void* buffer = malloc(size); + int len = fread(buffer, 1, size, fp); + fclose(fp); + + cJSON* root = cJSON_Parse(buffer); + if(root != NULL){ + cJSON* app_info_url = cJSON_GetObjectItem(root, "app_info_url"); + if(app_info_url != NULL){ + if(cJSON_IsString(app_info_url) && (app_info_url->valuestring != NULL)){ + version_url = get_version_url(curl, app_info_url->valuestring); + if(version_url > 0){ + n_version_get++; + } + + *url = malloc(strlen(app_info_url->valuestring) + 1); + strcpy(*url, app_info_url->valuestring); + } + } + cJSON* version = cJSON_GetObjectItem(root, "version"); + if(version != NULL){ + if(cJSON_IsString(version) && (version->valuestring != NULL)){ + version_local = get_version_from_string(version->valuestring); + if(version_local > 0){ + n_version_get++; + } + } + } + cJSON_Delete(root); + } + + free(buffer); + + if(n_version_get == 2){ + if(version_url > version_local){ + return 1; + }else{ + return 0; + } + }else{ + return -1; + } + }else{ + return -1; + } +} + +int update_app(CURL* curl, char* name){ + char* path_store = getenv("PATHSTORE"); + if(is_dir_exist(path_store)){ + char* path_store_app = malloc(strlen(path_store) + sizeof((char)'/') + strlen(name) + sizeof((char)'/') + 1); + strcpy(path_store_app, path_store); + strcat(path_store_app, "/"); + strcat(path_store_app, name); + strcat(path_store_app, "/"); + + if(is_dir_exist(path_store_app)){ + char* path_store_app_info_json = malloc(strlen(path_store_app) + strlen("app-info.json") + 1); + strcpy(path_store_app_info_json, path_store_app); + strcat(path_store_app_info_json, "app-info.json"); + + char* url = NULL; + int result = check_update(curl, path_store_app_info_json, &url); + + if(result == 0){ + printf("%s : is up-to-date\n", name); + }else if(result == 1 && url != NULL){ + printf("%s : is not up-to-date\n", name); + printf("Updating...\n"); + int r = install_app(curl, url, name, true); + if(!r){ + printf("Update finish with success\n"); + }else{ + printf("Update finish with error code : %d\n", r); + } + }else{ + printf("%s : is not installed corectly\n", name); + } + }else{ + printf("%s : is not installed\n", name); + } + }else{ + printf("%s : is not installed\n", name); + } +} \ No newline at end of file diff --git a/sources/core/apps/store/source/update/update.h b/sources/core/apps/store/source/update/update.h new file mode 100644 index 000000000..904d9ea7e --- /dev/null +++ b/sources/core/apps/store/source/update/update.h @@ -0,0 +1,14 @@ +#ifndef UPDATE_H +#define UPDATE_H + +typedef struct{ + char* buffer; + size_t size; +}fetch_app_info_t; + +#include +#include + +int update_app(CURL* curl, char* name); + +#endif // UPDATE_H \ No newline at end of file diff --git a/sources/core/apps/store/target/amd64/makefile b/sources/core/apps/store/target/amd64/makefile index 52e449cb8..e812be54a 100644 --- a/sources/core/apps/store/target/amd64/makefile +++ b/sources/core/apps/store/target/amd64/makefile @@ -13,7 +13,7 @@ BIN = bin/usr/bin LIB = lib # Tools Config -CFLAGS = +CFLAGS = -Werror LDFLAGS = -Wall \ -lc diff --git a/sources/core/apps/weather/target/amd64/makefile b/sources/core/apps/weather/target/amd64/makefile index 57b5946eb..c40ecef64 100644 --- a/sources/core/apps/weather/target/amd64/makefile +++ b/sources/core/apps/weather/target/amd64/makefile @@ -13,7 +13,7 @@ BIN = bin/usr/bin LIB = lib # Tools Config -CFLAGS = +CFLAGS = -Werror LDFLAGS = -Wall \ -lc diff --git a/sources/core/modules/fat32/source/core.c b/sources/core/modules/fat32/source/core.c index e65ebac75..0aaf21d41 100644 --- a/sources/core/modules/fat32/source/core.c +++ b/sources/core/modules/fat32/source/core.c @@ -157,11 +157,12 @@ static int fat_free_cluster(fat_context_t* ctx, uint32_t cluster){ } static int fat_free_all_following_clusters(fat_context_t* ctx, uint32_t cluster){ - uint32_t next_cluster = cluster; + uint32_t current_cluster = cluster; - while(next_cluster < 0x0FFFFFF8){ - fat_free_cluster(ctx, next_cluster); - next_cluster = fat_get_next_cluster(ctx, cluster); + while(current_cluster < 0x0FFFFFF8 && current_cluster != 0){ + uint32_t next_cluster = fat_get_next_cluster(ctx, current_cluster); + fat_free_cluster(ctx, current_cluster); + current_cluster = next_cluster; } return 0; @@ -378,7 +379,7 @@ static bool fat_is_need_lfn(char* name, bool is_file){ if(name[i] != to_upper(name[i])){ return true; } - } + } return false; } @@ -531,6 +532,8 @@ static int fat_find_entry_info(fat_context_t* ctx, uint32_t current_cluster, con last_entry_index_lfn = entry_index; + entry_name[LFN_NAME_SIZE * order] = '\0'; + for(uint8_t y = 0; y < order; y++){ lfn = (fat_long_entry_name_t*)fat_read_entry_with_cache(ctx, current_cluster, entry_index + y, cluster_buffer, &cluster_cache_id_count_from_base, &last_cluster_read); fat_parse_lfn(&entry_name[LFN_NAME_SIZE * (order - 1 - y)], lfn); @@ -569,7 +572,7 @@ static int fat_find_entry_info(fat_context_t* ctx, uint32_t current_cluster, con } static fat_short_entry_t* fat_find_entry(fat_context_t* ctx, uint32_t current_cluster, const char* name, void* cluster_buffer){ - char entry_name[256]; + char entry_name[257]; uint32_t cluster_cache_id_count_from_base = 0; uint32_t last_cluster_read = 0; @@ -585,6 +588,8 @@ static fat_short_entry_t* fat_find_entry(fat_context_t* ctx, uint32_t current_cl fat_long_entry_name_t* lfn = (fat_long_entry_name_t*)dir; uint8_t order = lfn->order & ~0x40; + entry_name[LFN_NAME_SIZE * order] = '\0'; + for(uint8_t y = 0; y < order; y++){ lfn = (fat_long_entry_name_t*)fat_read_entry_with_cache(ctx, current_cluster, entry_index + y, cluster_buffer, &cluster_cache_id_count_from_base, &last_cluster_read); fat_parse_lfn(&entry_name[LFN_NAME_SIZE * (order - 1 - y)], lfn); @@ -1209,6 +1214,8 @@ int fat_interface_dir_get_directory_entries(void* buffer, size_t max_size, size_ fat_long_entry_name_t* lfn = (fat_long_entry_name_t*)current_dir; uint8_t order = lfn->order & ~0x40; + entry->d_name[LFN_NAME_SIZE * order] = '\0'; + for(uint8_t y = 0; y < order; y++){ lfn = (fat_long_entry_name_t*)fat_read_entry_with_cache(internal_dir->ctx, cluster_base, entry_index + y, cluster_buffer, &cluster_cache_id_count_from_base, &last_cluster_read); fat_parse_lfn(&entry->d_name[LFN_NAME_SIZE * (order - 1 - y)], lfn); @@ -1435,7 +1442,6 @@ int fat_interface_stat(struct fs_t* ctx, const char* path, int flags, struct sta fat_short_entry_t* fat_entry = fat_find_entry_with_path_from_root(fat_ctx, path_convert, cluster_buffer); if(fat_entry != NULL){ - fat_entry = fat_find_entry_with_path_from_root(fat_ctx, path_convert, cluster_buffer); memset(statbuf, 0, sizeof(struct stat)); statbuf->st_mode = fat_entry->attributes.directory ? S_IFDIR : S_IFREG;