Home | History | Annotate | Download | only in pxe
      1 /* ----------------------------------------------------------------------- *
      2  *
      3  *   Copyright 2011 Intel Corporation; author: H. Peter Anvin
      4  *
      5  *   This program is free software; you can redistribute it and/or modify
      6  *   it under the terms of the GNU General Public License as published by
      7  *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
      8  *   Boston MA 02110-1301, USA; either version 2 of the License, or
      9  *   (at your option) any later version; incorporated herein by reference.
     10  *
     11  * ----------------------------------------------------------------------- */
     12 
     13 /*
     14  * ftp_readdir.c
     15  */
     16 #include <inttypes.h>
     17 #include <string.h>
     18 #include <stdlib.h>
     19 #include <ctype.h>
     20 #include <dprintf.h>
     21 #include "pxe.h"
     22 
     23 static int dirtype(char type)
     24 {
     25     switch (type) {
     26     case 'f':
     27 	return DT_FIFO;
     28     case 'c':
     29 	return DT_CHR;
     30     case 'd':
     31 	return DT_DIR;
     32     case 'b':
     33 	return DT_BLK;
     34     case '-':
     35     case '0' ... '9':		/* Some DOS FTP stacks */
     36 	return DT_REG;
     37     case 'l':
     38 	return DT_LNK;
     39     case 's':
     40 	return DT_SOCK;
     41     default:
     42 	return DT_UNKNOWN;
     43     }
     44 }
     45 
     46 int ftp_readdir(struct inode *inode, struct dirent *dirent)
     47 {
     48     char bufs[2][FILENAME_MAX + 1];
     49     int nbuf = 0;
     50     char *buf = bufs[nbuf];
     51     char *p = buf;
     52     char *name = NULL;
     53     char type;
     54     int c;
     55     int dt;
     56     bool was_cr = false;
     57     bool first = true;
     58 
     59     for (;;) {
     60 	type = 0;
     61 
     62 	for (;;) {
     63 	    c = pxe_getc(inode);
     64 	    if (c == -1)
     65 		return -1;	/* Nothing else there */
     66 
     67 	    if (c == '\r') {
     68 		was_cr = true;
     69 		continue;
     70 	    }
     71 	    if (was_cr) {
     72 		if (c == '\n') {
     73 		    if (!name) {
     74 			*p = '\0';
     75 			name = buf;
     76 		    }
     77 		    break;	/* End of line */
     78 		}
     79 		else if (c == '\0')
     80 		    c = '\r';
     81 	    }
     82 	    was_cr = false;
     83 
     84 	    if (c == ' ' || c == '\t') {
     85 		if (!name) {
     86 		    *p = '\0';
     87 		    if (first) {
     88 			if (p == buf) {
     89 			    /* Name started with whitespace - skip line */
     90 			    name = buf;
     91 			} else if ((p = strchr(buf, ';'))) {
     92 			    /* VMS/Multinet format */
     93 			    if (p > buf+4 && !memcmp(p-4, ".DIR", 4)) {
     94 				type = 'd';
     95 				p -= 4;
     96 			    } else {
     97 				type = 'f';
     98 			    }
     99 			    *p = '\0';
    100 			    name = buf;
    101 			} else {
    102 			    type = buf[0];
    103 			}
    104 			first = false;
    105 		    } else {
    106 			/* Not the first word */
    107 			if ((type >= '0' && type <= '9') &&
    108 			    !strcmp(buf, "<DIR>")) {
    109 			    /* Some DOS FTP servers */
    110 			    type = 'd';
    111 			} else if (type == 'l' && !strcmp(buf, "->")) {
    112 			    /* The name was the previous word */
    113 			    name = bufs[nbuf ^ 1];
    114 			}
    115 		    }
    116 		    nbuf ^= 1;
    117 		    p = buf = bufs[nbuf];
    118 		}
    119 	    } else {
    120 		if (!name && p < buf + FILENAME_MAX)
    121 		    *p++ = c;
    122 	    }
    123 	}
    124 
    125 	dt = dirtype(type);
    126 	if (dt != DT_UNKNOWN) {
    127 	    size_t len = strlen(name);
    128 
    129 	    if (len <= NAME_MAX) {
    130 		dirent->d_type = dt;
    131 		dirent->d_ino = 0;	/* Not applicable */
    132 		dirent->d_off = 0;	/* Not applicable */
    133 		dirent->d_reclen = offsetof(struct dirent, d_name) + len+1;
    134 		memcpy(dirent->d_name, name, len+1);
    135 		return 0;
    136 	    }
    137 	}
    138 
    139 	/* Otherwise try the next line... */
    140     }
    141 }
    142