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 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
/* ----------------------------------------------------------------------- *
*
* Copyright 2011 Intel Corporation; author: H. Peter Anvin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston MA 02110-1301, USA; either version 2 of the License, or
* (at your option) any later version; incorporated herein by reference.
*
* ----------------------------------------------------------------------- */
/*
* ftp_readdir.c
*/
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <dprintf.h>
#include "pxe.h"
static int dirtype(char type)
{
switch (type) {
case 'f':
return DT_FIFO;
case 'c':
return DT_CHR;
case 'd':
return DT_DIR;
case 'b':
return DT_BLK;
case '-':
case '0' ... '9': /* Some DOS FTP stacks */
return DT_REG;
case 'l':
return DT_LNK;
case 's':
return DT_SOCK;
default:
return DT_UNKNOWN;
}
}
int ftp_readdir(struct inode *inode, struct dirent *dirent)
{
char bufs[2][FILENAME_MAX + 1];
int nbuf = 0;
char *buf = bufs[nbuf];
char *p = buf;
char *name = NULL;
char type;
int c;
int dt;
bool was_cr = false;
bool first = true;
for (;;) {
type = 0;
for (;;) {
c = pxe_getc(inode);
if (c == -1)
return -1; /* Nothing else there */
if (c == '\r') {
was_cr = true;
continue;
}
if (was_cr) {
if (c == '\n') {
if (!name) {
*p = '\0';
name = buf;
}
break; /* End of line */
}
else if (c == '\0')
c = '\r';
}
was_cr = false;
if (c == ' ' || c == '\t') {
if (!name) {
*p = '\0';
if (first) {
if (p == buf) {
/* Name started with whitespace - skip line */
name = buf;
} else if ((p = strchr(buf, ';'))) {
/* VMS/Multinet format */
if (p > buf+4 && !memcmp(p-4, ".DIR", 4)) {
type = 'd';
p -= 4;
} else {
type = 'f';
}
*p = '\0';
name = buf;
} else {
type = buf[0];
}
first = false;
} else {
/* Not the first word */
if ((type >= '0' && type <= '9') &&
!strcmp(buf, "<DIR>")) {
/* Some DOS FTP servers */
type = 'd';
} else if (type == 'l' && !strcmp(buf, "->")) {
/* The name was the previous word */
name = bufs[nbuf ^ 1];
}
}
nbuf ^= 1;
p = buf = bufs[nbuf];
}
} else {
if (!name && p < buf + FILENAME_MAX)
*p++ = c;
}
}
dt = dirtype(type);
if (dt != DT_UNKNOWN) {
size_t len = strlen(name);
if (len <= NAME_MAX) {
dirent->d_type = dt;
dirent->d_ino = 0; /* Not applicable */
dirent->d_off = 0; /* Not applicable */
dirent->d_reclen = offsetof(struct dirent, d_name) + len+1;
memcpy(dirent->d_name, name, len+1);
return 0;
}
}
/* Otherwise try the next line... */
}
}
|