2 * User FTP Server, Share folders over FTP without being root.
3 * Copyright (C) 2008 Isaac Jurado
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option) any later
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 * LIST and NLST commands implementation.
24 * To make Mozilla Firefox list the directory contents correctly, some research
25 * work had to be done. That concluded in:
27 * http://cr.yp.to/ftp.html
31 * http://cr.yp.to/ftp/list/binls.html
33 * Only files or subdirectories are shown, the rest of items (symlinks, named
34 * pipes, sockets...) are ignored. The following line is sent when a file is
37 * -rw-r--r-- 1 ftp ftp 999 Mon 88 7777 filename
39 * In case of a subdirectory, the line is:
41 * drwxr-xr-x 1 ftp ftp 999 Mon 88 7777 dirname
43 * Where '999' is the item size, 'Mon 88 7777' is the month, day and year,
44 * respectively, of the last modification date. Some servers display the hour
45 * and minute when the distance between current time and last modification time
46 * is less than six months. We don't do that as it is considered irrelevant.
47 * To obtain a more precise value for the last modification time, let the client
48 * send a MDTM command.
50 * Note that when, for some reason, directory listing is not possible, an empty
51 * list is sent. So this error is not detected from the client, until it tries
54 * Also note that most clients will appreciate listings where all its items are
58 #include <sys/types.h>
60 #include <sys/socket.h>
61 #include <netinet/in.h>
70 static char month
[12][4] = {
71 "Jan\0", "Feb\0", "Mar\0", "Apr\0", "May\0", "Jun\0", "Jul\0", "Aug\0",
72 "Sep\0", "Oct\0", "Nov\0", "Dec\0"
77 * Temporary workaround
79 static void send_data (int sk
, const char *str
, int len
)
84 b
= write(sk
, str
, len
);
94 void list_dir (int full_list
)
98 struct dirent
*dentry
;
99 struct sockaddr_in saddr
;
102 socklen_t saddr_len
= sizeof(saddr
);
106 SS
.data_sk
= accept(SS
.passive_sk
, (struct sockaddr
*) &saddr
,
109 /* Workaround for Konqueror and Nautilus */
110 if (SS
.arg
!= NULL
&& SS
.arg
[0] == '-')
114 dir
= opendir(SS
.arg
);
117 SS
.arg
[len
- 1] = '/';
121 reply_c("150 Sending directory list.\r\n");
126 dentry
= readdir(dir
);
130 strcpy(&SS
.arg
[len
- 1], dentry
->d_name
);
131 debug("Stating '%s'", SS
.arg
);
132 err
= stat(SS
.arg
, &st
);
139 gmtime_r(&(st
.st_mtime
), &t
);
140 l
= snprintf(item
, 512,
141 "%s 1 ftp ftp %13lld %s %3d %4d %s\r\n",
142 (S_ISDIR(st
.st_mode
) ? "dr-xr-xr-x"
143 : "-r--r--r--"), (long long) st
.st_size
,
144 month
[t
.tm_mon
], t
.tm_mday
, t
.tm_year
+ 1900,
150 l
= snprintf(item
, 512, "%s%s", dentry
->d_name
,
151 (dentry
->d_type
== DT_DIR
? "/\r\n"
155 send_data(SS
.data_sk
, item
, l
);
161 reply_c("226 Directory list sent.\r\n");