blob: 6b87f77e522ede72e764fdb162286cbb8d314e26 [file] [log] [blame]
/* ----------------------------------------------------------------------- *
*
* 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... */
}
}