• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
dirtype(char type)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 
ftp_readdir(struct inode * inode,struct dirent * dirent)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