diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c index 0162e176..f69de622 100644 --- a/src/libopensc/ctx.c +++ b/src/libopensc/ctx.c @@ -24,6 +24,9 @@ #include #include #include +#include +#include /* for mkdir */ +#include int _sc_add_reader(struct sc_context *ctx, struct sc_reader *reader) { @@ -461,3 +464,39 @@ int sc_get_cache_dir(struct sc_context *ctx, char *buf, size_t bufsize) return SC_ERROR_BUFFER_TOO_SMALL; return 0; } + +int sc_make_cache_dir(struct sc_context *ctx) +{ + char dirname[PATH_MAX], *sp; + int r, j, namelen; + + if ((r = sc_get_cache_dir(ctx, dirname, sizeof(dirname))) < 0) + return r; + namelen = strlen(dirname); + + while (1) { + if (mkdir(dirname, 0700) >= 0) + break; + if (errno != ENOENT + || (sp = strrchr(dirname, '/')) == NULL + || sp == dirname) + goto failed; + *sp = '\0'; + } + + /* We may have stripped one or more path components from + * the directory name. Restore them */ + while (1) { + j = strlen(dirname); + if (j >= namelen) + break; + dirname[j] = '/'; + if (mkdir(dirname, 0700) < 0) + goto failed; + } + return 0; + + /* for lack of a better return code */ +failed: error(ctx, "failed to create cache directory\n"); + return SC_ERROR_INTERNAL; +} diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 8f59ad85..bdfa0719 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -765,6 +765,7 @@ int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen); int sc_bin_to_hex(const u8 *, size_t, char *, size_t, int separator); int sc_get_cache_dir(struct sc_context *ctx, char *buf, size_t bufsize); +int sc_make_cache_dir(struct sc_context *ctx); int sc_enum_apps(struct sc_card *card); const struct sc_app_info * sc_find_app_by_aid(struct sc_card *card, diff --git a/src/libopensc/pkcs15-cache.c b/src/libopensc/pkcs15-cache.c index 90a9253d..d9f9b946 100644 --- a/src/libopensc/pkcs15-cache.c +++ b/src/libopensc/pkcs15-cache.c @@ -28,13 +28,15 @@ #include #endif #include +#include +#include #include static int generate_cache_filename(struct sc_pkcs15_card *p15card, const struct sc_path *path, char *buf, size_t bufsize) { - char dir[80]; + char dir[PATH_MAX]; char pathname[SC_MAX_PATH_SIZE*2+1]; int i, r; const u8 *pathptr; @@ -123,7 +125,7 @@ int sc_pkcs15_cache_file(struct sc_pkcs15_card *p15card, const struct sc_path *path, const u8 *buf, size_t bufsize) { - char fname[160]; + char fname[PATH_MAX]; int r; FILE *f; size_t c; @@ -131,9 +133,19 @@ int sc_pkcs15_cache_file(struct sc_pkcs15_card *p15card, r = generate_cache_filename(p15card, path, fname, sizeof(fname)); if (r != 0) return r; + f = fopen(fname, "wb"); + /* If the open failed because the cache directory does + * not exist, create it and a re-try the fopen() call. + */ + if (f == NULL && errno == ENOENT) { + if ((r = sc_make_cache_dir(p15card->card->ctx)) < 0) + return r; + f = fopen(fname, "wb"); + } if (f == NULL) return 0; + c = fwrite(buf, 1, bufsize, f); fclose(f); if (c != bufsize) {