Welcome to mirror list, hosted at ThFree Co, Russian Federation.

psftpcommon.c - github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: e6c8e2d872a215b822798e21d80ef6120f21a941 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/*
 * 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]);
    }
}