psftpcommon.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. /*
  2. * psftpcommon.c: front-end functionality shared between both file
  3. * transfer tools across platforms. (As opposed to sftpcommon.c, which
  4. * has *protocol*-level common code.)
  5. */
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include "putty.h"
  9. #include "ssh/sftp.h"
  10. #include "psftp.h"
  11. #define MAX_NAMES_MEMORY ((size_t)8 << 20)
  12. /*
  13. * qsort comparison routine for fxp_name structures. Sorts by real
  14. * file name.
  15. */
  16. int sftp_name_compare(const void *av, const void *bv)
  17. {
  18. const struct fxp_name *const *a = (const struct fxp_name *const *) av;
  19. const struct fxp_name *const *b = (const struct fxp_name *const *) bv;
  20. return strcmp((*a)->filename, (*b)->filename);
  21. }
  22. struct list_directory_from_sftp_ctx {
  23. size_t nnames, namesize, total_memory;
  24. struct fxp_name **names;
  25. bool sorting;
  26. };
  27. struct list_directory_from_sftp_ctx *list_directory_from_sftp_new(void)
  28. {
  29. struct list_directory_from_sftp_ctx *ctx =
  30. snew(struct list_directory_from_sftp_ctx);
  31. memset(ctx, 0, sizeof(*ctx));
  32. ctx->sorting = true;
  33. return ctx;
  34. }
  35. void list_directory_from_sftp_free(struct list_directory_from_sftp_ctx *ctx)
  36. {
  37. for (size_t i = 0; i < ctx->nnames; i++)
  38. fxp_free_name(ctx->names[i]);
  39. sfree(ctx->names);
  40. sfree(ctx);
  41. }
  42. void list_directory_from_sftp_feed(struct list_directory_from_sftp_ctx *ctx,
  43. struct fxp_name *name)
  44. {
  45. if (ctx->sorting) {
  46. /*
  47. * Accumulate these filenames into an array that we'll sort -
  48. * unless the array gets _really_ big, in which case, to avoid
  49. * consuming all the client's memory, we fall back to
  50. * outputting the directory listing unsorted.
  51. */
  52. size_t this_name_memory =
  53. sizeof(*ctx->names) + sizeof(**ctx->names) +
  54. strlen(name->filename) +
  55. strlen(name->longname);
  56. if (MAX_NAMES_MEMORY - ctx->total_memory < this_name_memory) {
  57. list_directory_from_sftp_warn_unsorted();
  58. /* Output all the previously stored names. */
  59. for (size_t i = 0; i < ctx->nnames; i++) {
  60. list_directory_from_sftp_print(ctx->names[i]);
  61. fxp_free_name(ctx->names[i]);
  62. }
  63. /* Don't store further names in that array. */
  64. sfree(ctx->names);
  65. ctx->names = NULL;
  66. ctx->nnames = 0;
  67. ctx->namesize = 0;
  68. ctx->sorting = false;
  69. /* And don't forget to output the name passed in this
  70. * actual function call. */
  71. list_directory_from_sftp_print(name);
  72. } else {
  73. sgrowarray(ctx->names, ctx->namesize, ctx->nnames);
  74. ctx->names[ctx->nnames++] = fxp_dup_name(name);
  75. ctx->total_memory += this_name_memory;
  76. }
  77. } else {
  78. list_directory_from_sftp_print(name);
  79. }
  80. }
  81. void list_directory_from_sftp_finish(struct list_directory_from_sftp_ctx *ctx)
  82. {
  83. if (ctx->nnames > 0) {
  84. assert(ctx->sorting);
  85. qsort(ctx->names, ctx->nnames, sizeof(*ctx->names), sftp_name_compare);
  86. for (size_t i = 0; i < ctx->nnames; i++)
  87. list_directory_from_sftp_print(ctx->names[i]);
  88. }
  89. }