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
29 static const char const month
[12][4] = {
30 "Jan\0", "Feb\0", "Mar\0", "Apr\0", "May\0", "Jun\0", "Jul\0", "Aug\0",
31 "Sep\0", "Oct\0", "Nov\0", "Dec\0"
36 * Send a listing line of length "len", contained in "str" over the socket "sk".
37 * Return 0 when all "len" bytes has been transferred or -1 if there was an
38 * error or less bytes were sent.
40 static int send_data_line (int sk
, const char *str
, int len
)
46 b
= send(sk
, &str
[l
], len
- l
, 0);
49 error("Sending listing data");
61 * LIST and NLST commands implementation. The boolean argument enables LIST
62 * mode, otherwise NSLT listing is sent.
64 * To make Mozilla Firefox list the directory contents correctly, some research
65 * work had to be done. That concluded in:
67 * http://cr.yp.to/ftp.html
71 * http://cr.yp.to/ftp/list/binls.html
73 * Only files or subdirectories are shown, the rest of items (symlinks, named
74 * pipes, sockets...) are ignored. The following line is sent when a file is
77 * -rw-r--r-- 1 ftp ftp 999 Mon 88 7777 filename
79 * In case of a subdirectory, the line is:
81 * drwxr-xr-x 1 ftp ftp 999 Mon 88 7777 dirname
83 * Where '999' is the item size, 'Mon 88 7777' is the month, day and year,
84 * respectively, of the last modification date. Some servers display the hour
85 * and minute when the distance between current time and last modification time
86 * is less than six months. We don't do that as it is considered irrelevant.
87 * To obtain a more precise value for the last modification time, let the client
88 * send an MDTM command.
90 * Note that most clients will appreciate listings where all its items are
93 void list_dir (int full_list
)
97 struct dirent
*dentry
;
102 /* Workaround for Konqueror and Nautilus */
103 if (SS
.arg
!= NULL
&& SS
.arg
[0] == '-')
107 dir
= opendir(SS
.arg
);
110 error("Opening directory '%s'", SS
.arg
);
111 reply_c("550 Could not open directory.\r\n");
115 /* Prepare the argument for the listing, see below */
118 SS
.arg
[len
- 1] = '/';
122 e
= open_data_channel();
129 reply_c("150 Sending directory list.\r\n");
132 dentry
= readdir(dir
);
137 * Due to the chroot emulation, each dentry needs to be
138 * prepended by the expanded argument (stored in the auxiliary
139 * buffer) after checking bounds. Otherwise, the stat() call
142 l
= strlen(dentry
->d_name
);
143 if (len
+ l
>= LINE_SIZE
)
144 fatal("Path overflow in LIST/NLST");
145 strcpy(&SS
.arg
[len
- 1], dentry
->d_name
);
147 debug("Stating %s", SS
.arg
);
148 e
= lstat(SS
.arg
, &s
);
149 if (e
== -1 || (!S_ISDIR(s
.st_mode
) && !S_ISREG(s
.st_mode
)))
151 debug("Dentry %s skipped", SS
.arg
);
158 gmtime_r(&(s
.st_mtime
), &t
);
159 l
= snprintf(item
, 512,
160 "%s 1 ftp ftp %13lld %s %3d %4d %s\r\n",
161 (S_ISDIR(s
.st_mode
) ? "dr-xr-xr-x"
162 : "-r--r--r--"), (long long) s
.st_size
,
163 month
[t
.tm_mon
], t
.tm_mday
, t
.tm_year
+ 1900,
169 l
= snprintf(item
, 512, "%s%s", dentry
->d_name
,
170 (S_ISDIR(s
.st_mode
) ? "/\r\n" : "\r\n"));
173 e
= send_data_line(SS
.data_sk
, item
, l
);
177 reply_c("226 Directory list sent.\r\n");
179 reply_c("426 Connection closed, transfer aborted.\r\n");