View | Details | Raw Unified | Return to bug 51409
Collapse All | Expand All

(-)modules/ftp/ftp_commands.c (-17 / +67 lines)
Lines 24-29 Link Here
24
#include "mod_ftp.h"
24
#include "mod_ftp.h"
25
#include "ftp_internal.h"
25
#include "ftp_internal.h"
26
#include "apr_version.h"
26
#include <apr_version.h>
27
#include "apr_network_io.h"
27
#include <apr_getopt.h>
28
#include <apr_network_io.h>
29
#include <apr_strings.h>
28
#include "http_vhost.h"
30
#include "http_vhost.h"
29
31
Lines 665-686 static int common_list(request_rec *r, c Link Here
665
    apr_status_t rv;
667
    apr_status_t rv;
666
    apr_size_t nbytes;
668
    apr_size_t nbytes;
667
    char *varg = apr_pstrdup(r->pool, arg);
668
    const char *test, *sl;
669
    const char *test, *sl;
669
    int res;
670
    int res;
670
    int decend = 0;
671
    int decend = 0;
672
    apr_getopt_t *options;
673
    char **argv, option;
674
    const char *optval;
675
    char * const *p;
676
    int argc;
677
    /* Sort by name ascending by default */
678
    int reverse = 0;
679
    enum ftp_sort sortby = SORT_BY_NAME; /* Why not SORT_NONE? */
680
681
    /* TODO: improve error reporting with detailed status explanation */
682
    if ((res = apr_tokenize_to_argv(arg, &argv, r->pool))) {
683
        ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
684
	    "Attempt to tokenize string `%s' failed", arg);
685
	return res;
686
    }
687
    for (p = argv, argc = 0; *p; p++)
688
	argc++;
671
689
672
    while (*varg == '-')
690
    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Split `%s' into %d word%s",
673
    {
691
        arg, argc, argc == 1 ? "" : "s");
674
        if (ftp_parse2(r->pool, varg, &word, &varg, FTP_KEEP_WHITESPACE)) {
692
675
            varg = word;
693
    /*
676
            break;
694
     * apr_getopt ignores argv[0] thinking, it is the program's name,
677
        }
695
     * but we want it to start with it, so we shift argv and argc by one:
678
        /* More Cowbell!  TODO: expand the accepted dash patterns */
696
     */
679
        if (ap_strchr(word, 'l')) {
697
    if ((res = apr_getopt_init(&options, r->pool, argc + 1, (const char **)argv - 1))) {
698
        ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
699
	    "apr_getopt_init failed");
700
	return res;
701
    }
702
703
    /* Disable apr_getopt's own error-reporting: */
704
    options->errfn = NULL;
705
706
    while (apr_getopt(options, "Slrtcu", &option, &optval) != APR_EOF) {
707
        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Checking option `%c'", option);
708
        switch(option) {
709
        case 'l':
680
            dashl = 1;
710
            dashl = 1;
681
        }
711
            continue;
682
        /* -- 'end of dash-opts' by convention allows patterns like '-*' */
712
        case 'r':
683
        if (ap_strchr(word + 1, '-')) {
713
            reverse = 1;
684
            break;
714
            continue;
715
        case 't':
716
	    sortby = SORT_BY_MTIME;
717
            continue;
718
        case 'c':
719
	    sortby = SORT_BY_CTIME;
720
            continue;
721
        case 'u':
722
	    sortby = SORT_BY_ATIME;
723
            continue;
724
        case 'S':
725
            sortby = SORT_BY_SIZE;
726
            continue;
727
        default:
728
            /* TODO: communicate this back to the client too */
729
            ap_log_rerror(APLOG_MARK, APLOG_WARNING | APLOG_NOERRNO, 0, r,
730
                "Ignoring unrecognized listing option `%c'", option);
685
        }
731
        }
686
    }
732
    }
Lines 696-700 static int common_list(request_rec *r, c Link Here
696
    }
748
    }
697
749
698
    arg = varg;
750
    arg = argv[options->ind - 1] ? argv[options->ind - 1] : "";
751
752
    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "%s-listing `%s', "
753
        "sorting by %d (%sscending)", is_list ? "Long" : "Short",
754
         arg ? arg : "nill!", (int)sortby, reverse ? "de" : "a");
699
755
700
    if (is_list && (ap_strchr_c(arg, '*') != NULL))
756
    if (is_list && (ap_strchr_c(arg, '*') != NULL))
Lines 768-772 static int common_list(request_rec *r, c Link Here
768
824
769
    /* Construct the sorted array of directory contents */
825
    /* Construct the sorted array of directory contents */
770
    if ((direntry = ftp_direntry_get(r, pattern)) == NULL) {
826
    if ((direntry = ftp_direntry_get(r, pattern, sortby, reverse)) == NULL) {
771
        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOSUCHFILE,
827
        fc->response_notes = apr_psprintf(r->pool, FTP_MSG_NOSUCHFILE,
772
                                 ftp_escape_control_text(arg, r->pool));
828
                                 ftp_escape_control_text(arg, r->pool));
(-)modules/ftp/ftp_internal.h (-1 / +12 lines)
Lines 160-163 typedef enum { Link Here
160
} ftp_loginlimit_t;
160
} ftp_loginlimit_t;
161
161
162
enum ftp_sort {
163
	SORT_BY_NAME,
164
	SORT_BY_MTIME,
165
	SORT_BY_ATIME,
166
	SORT_BY_CTIME,
167
	SORT_BY_SIZE,
168
	SORT_NONE
169
};
170
162
/* Directory entry structure.  Used for directory listings */
171
/* Directory entry structure.  Used for directory listings */
163
typedef struct ftp_direntry
172
typedef struct ftp_direntry
Lines 170-173 typedef struct ftp_direntry Link Here
170
    apr_off_t size; 
179
    apr_off_t size; 
171
    apr_off_t csize;
180
    apr_off_t csize;
181
    apr_time_t atime, mtime, ctime;
172
    apr_int32_t  nlink;
182
    apr_int32_t  nlink;
173
    struct ftp_direntry *child; /* For descending */
183
    struct ftp_direntry *child; /* For descending */
Lines 254-258 int ftp_limitlogin_loggedout(conn_rec *c Link Here
254
int ftp_eprt_decode(apr_int32_t *family, char **addr, apr_port_t *port,
264
int ftp_eprt_decode(apr_int32_t *family, char **addr, apr_port_t *port,
255
                    char *arg);
265
                    char *arg);
256
struct ftp_direntry *ftp_direntry_get(request_rec *r, const char *pattern);
266
struct ftp_direntry *ftp_direntry_get(request_rec *r, const char *pattern,
267
                                      enum ftp_sort sortby, int reverse);
257
268
258
void ftp_set_authorization(request_rec *r);
269
void ftp_set_authorization(request_rec *r);
(-)modules/ftp/ftp_util.c (-6 / +51 lines)
Lines 210-213 static struct ftp_direntry *ftp_direntry Link Here
210
        dirent->size = rr->finfo.size;
210
        dirent->size = rr->finfo.size;
211
        dirent->csize = rr->finfo.csize;
211
        dirent->csize = rr->finfo.csize;
212
        dirent->ctime = rr->finfo.ctime;
213
        dirent->atime = rr->finfo.atime;
214
        dirent->mtime = rr->finfo.mtime;
212
        dirent->modestring = apr_pstrdup(r->pool,
215
        dirent->modestring = apr_pstrdup(r->pool,
213
                                         ftp_modestring_get(
216
                                         ftp_modestring_get(
Lines 267-272 static struct ftp_direntry *ftp_direntry Link Here
267
 *          be greater than d2.
270
 *          be greater than d2.
268
 */
271
 */
269
static int ftp_dsortf(struct ftp_direntry ** d1,
272
static int ftp_dsortf(const struct ftp_direntry ** d1,
270
                          struct ftp_direntry ** d2)
273
                      const struct ftp_direntry ** d2)
271
{
274
{
272
    /* Simple sort based on filename */
275
    /* Simple sort based on filename */
Lines 274-277 static int ftp_dsortf(struct ftp_direntr Link Here
274
}
277
}
275
278
279
static int ftp_dsortf_desc(const struct ftp_direntry ** d1,
280
                           const struct ftp_direntry ** d2)
281
{
282
    /* Simple sort based on filename, descending */
283
    return strcmp((*d2)->name, (*d1)->name);
284
}
285
286
#define FTP_DSORT_NUM(field)	\
287
static int ftp_dsort_##field(const struct ftp_direntry ** d1,	\
288
                             const struct ftp_direntry ** d2)	\
289
{	\
290
    if ((*d1)->field == (*d2)->field)	\
291
        return 0;	\
292
    return (*d1)->field < (*d2)->field ? 1 : -1;	\
293
}	\
294
static int ftp_dsort_desc_##field(const struct ftp_direntry ** d1,	\
295
                                  const struct ftp_direntry ** d2)	\
296
{	\
297
    if ((*d1)->field == (*d2)->field)	\
298
        return 0;	\
299
    return (*d1)->field > (*d2)->field ? 1 : -1;	\
300
}
301
302
FTP_DSORT_NUM(mtime)
303
FTP_DSORT_NUM(ctime)
304
FTP_DSORT_NUM(atime)
305
FTP_DSORT_NUM(size)
306
276
/* ftp_direntry_get: Return an array of ftp_direntry structures based
307
/* ftp_direntry_get: Return an array of ftp_direntry structures based
277
 *                   on the uri stored in the request rec.  An extra
308
 *                   on the uri stored in the request rec.  An extra
Lines 283-287 static int ftp_dsortf(struct ftp_direntr Link Here
283
 * Returns: The sorted array of directory entries on success, NULL otherwise
310
 * Returns: The sorted array of directory entries on success, NULL otherwise
284
 */
311
 */
285
struct ftp_direntry *ftp_direntry_get(request_rec *r, const char *pattern)
312
struct ftp_direntry *ftp_direntry_get(request_rec *r, const char *pattern,
313
                                      enum ftp_sort sortby, int reverse)
286
{
314
{
287
    struct ftp_direntry *p, *head, *current, **a;
315
    struct ftp_direntry *p, *head, *current, **a;
Lines 293-296 struct ftp_direntry *ftp_direntry_get(re Link Here
293
    const char *path, *search;
321
    const char *path, *search;
294
322
323
    int (*compar[])(const struct ftp_direntry **,
324
                    const struct ftp_direntry **) = {
325
        /* The order here must match the enum ftp_sort! */
326
        ftp_dsortf, ftp_dsortf_desc,
327
	ftp_dsort_mtime, ftp_dsort_desc_mtime,
328
	ftp_dsort_atime, ftp_dsort_desc_atime,
329
	ftp_dsort_ctime, ftp_dsort_desc_ctime,
330
	ftp_dsort_size, ftp_dsort_desc_size
331
    };
332
295
    /*
333
    /*
296
     * The actual search pattern, used to determine if we should recurse into
334
     * The actual search pattern, used to determine if we should recurse into
Lines 374-378 struct ftp_direntry *ftp_direntry_get(re Link Here
374
            const char *newpattern = apr_pstrcat(r->pool, fname,
412
            const char *newpattern = apr_pstrcat(r->pool, fname,
375
                                                 "/*", NULL);
413
                                                 "/*", NULL);
376
            p->child = ftp_direntry_get(r, newpattern);
414
            p->child = ftp_direntry_get(r, newpattern, sortby, reverse);
377
        }
415
        }
378
        else {
416
        else {
Lines 396-401 struct ftp_direntry *ftp_direntry_get(re Link Here
396
        }
434
        }
397
        num = i;
435
        num = i;
398
        qsort((void *) a, num, sizeof(struct ftp_direntry *),
436
	if (sortby != SORT_NONE) {
399
              (int (*) (const void *, const void *)) ftp_dsortf);
437
            qsort((void *) a, num, sizeof(struct ftp_direntry *),
438
                  (int (*)(const void *,
439
                           const void *))compar[sortby * 2 + reverse]);
440
        }
400
441
401
        /* Re-construct the list from the sorted list */
442
        /* Re-construct the list from the sorted list */

Return to bug 51409