123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- /*
- * psftpcommon.c: front-end functionality shared between both file
- * transfer tools across platforms. (As opposed to sftpcommon.c, which
- * has *protocol*-level common code.)
- */
- #include <stdlib.h>
- #include <string.h>
- #include "putty.h"
- #include "ssh/sftp.h"
- #include "psftp.h"
- #define MAX_NAMES_MEMORY ((size_t)8 << 20)
- /*
- * qsort comparison routine for fxp_name structures. Sorts by real
- * file name.
- */
- int sftp_name_compare(const void *av, const void *bv)
- {
- const struct fxp_name *const *a = (const struct fxp_name *const *) av;
- const struct fxp_name *const *b = (const struct fxp_name *const *) bv;
- return strcmp((*a)->filename, (*b)->filename);
- }
- struct list_directory_from_sftp_ctx {
- size_t nnames, namesize, total_memory;
- struct fxp_name **names;
- bool sorting;
- };
- struct list_directory_from_sftp_ctx *list_directory_from_sftp_new(void)
- {
- struct list_directory_from_sftp_ctx *ctx =
- snew(struct list_directory_from_sftp_ctx);
- memset(ctx, 0, sizeof(*ctx));
- ctx->sorting = true;
- return ctx;
- }
- void list_directory_from_sftp_free(struct list_directory_from_sftp_ctx *ctx)
- {
- for (size_t i = 0; i < ctx->nnames; i++)
- fxp_free_name(ctx->names[i]);
- sfree(ctx->names);
- sfree(ctx);
- }
- void list_directory_from_sftp_feed(struct list_directory_from_sftp_ctx *ctx,
- struct fxp_name *name)
- {
- if (ctx->sorting) {
- /*
- * Accumulate these filenames into an array that we'll sort -
- * unless the array gets _really_ big, in which case, to avoid
- * consuming all the client's memory, we fall back to
- * outputting the directory listing unsorted.
- */
- size_t this_name_memory =
- sizeof(*ctx->names) + sizeof(**ctx->names) +
- strlen(name->filename) +
- strlen(name->longname);
- if (MAX_NAMES_MEMORY - ctx->total_memory < this_name_memory) {
- list_directory_from_sftp_warn_unsorted();
- /* Output all the previously stored names. */
- for (size_t i = 0; i < ctx->nnames; i++) {
- list_directory_from_sftp_print(ctx->names[i]);
- fxp_free_name(ctx->names[i]);
- }
- /* Don't store further names in that array. */
- sfree(ctx->names);
- ctx->names = NULL;
- ctx->nnames = 0;
- ctx->namesize = 0;
- ctx->sorting = false;
- /* And don't forget to output the name passed in this
- * actual function call. */
- list_directory_from_sftp_print(name);
- } else {
- sgrowarray(ctx->names, ctx->namesize, ctx->nnames);
- ctx->names[ctx->nnames++] = fxp_dup_name(name);
- ctx->total_memory += this_name_memory;
- }
- } else {
- list_directory_from_sftp_print(name);
- }
- }
- void list_directory_from_sftp_finish(struct list_directory_from_sftp_ctx *ctx)
- {
- if (ctx->nnames > 0) {
- assert(ctx->sorting);
- qsort(ctx->names, ctx->nnames, sizeof(*ctx->names), sftp_name_compare);
- for (size_t i = 0; i < ctx->nnames; i++)
- list_directory_from_sftp_print(ctx->names[i]);
- }
- }
|