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 * LIST and NLST commands implementation. The boolean argument enables LIST
37 * mode, otherwise NSLT listing is sent.
39 * To make Mozilla Firefox list the directory contents correctly, some research
40 * work had to be done. That concluded in:
42 * http://cr.yp.to/ftp.html
46 * http://cr.yp.to/ftp/list/binls.html
48 * Only files or subdirectories are shown, the rest of items (symlinks, named
49 * pipes, sockets...) are ignored. The following line is sent when a file is
52 * -rw-r--r-- 1 ftp ftp 999 Mon 88 7777 filename
54 * In case of a subdirectory, the line is:
56 * drwxr-xr-x 1 ftp ftp 999 Mon 88 7777 dirname
58 * Where '999' is the item size, 'Mon 88 7777' is the month, day and year,
59 * respectively, of the last modification date. Some servers display the hour
60 * and minute when the distance between current time and last modification time
61 * is less than six months. We don't do that as it is considered irrelevant.
62 * To obtain a more precise value for the last modification time, let the client
63 * send an MDTM command.
65 * Note that most clients will appreciate listings where all its items are
68 void list_dir (int full_list
)
72 struct dirent
*dentry
;
77 /* Workaround for Konqueror and Nautilus */
78 if (SS
.arg
!= NULL
&& SS
.arg
[0] == '-')
82 dir
= opendir(SS
.arg
);
85 error("Opening directory '%s'", SS
.arg
);
86 reply_c("550 Could not open directory.\r\n");
90 /* Prepare the argument for the listing, see below */
93 SS
.arg
[len
- 1] = '/';
97 e
= open_data_channel();
104 reply_c("150 Sending directory list.\r\n");
107 dentry
= readdir(dir
);
112 * Due to the chroot emulation, each dentry needs to be
113 * prepended by the expanded argument (stored in the auxiliary
114 * buffer) after checking bounds. Otherwise, the stat() call
117 l
= strlen(dentry
->d_name
);
118 if (len
+ l
>= LINE_SIZE
)
119 fatal("Path overflow in LIST/NLST");
120 strcpy(&SS
.arg
[len
- 1], dentry
->d_name
);
122 debug("Stating %s", SS
.arg
);
123 e
= lstat(SS
.arg
, &s
);
124 if (e
== -1 || (!S_ISDIR(s
.st_mode
) && !S_ISREG(s
.st_mode
)))
126 debug("Dentry %s skipped", SS
.arg
);
133 gmtime_r(&(s
.st_mtime
), &t
);
134 l
= snprintf(item
, 512,
135 "%s 1 ftp ftp %13lld %s %3d %4d %s\r\n",
136 (S_ISDIR(s
.st_mode
) ? "dr-xr-xr-x"
137 : "-r--r--r--"), (long long) s
.st_size
,
138 month
[t
.tm_mon
], t
.tm_mday
, t
.tm_year
+ 1900,
144 l
= snprintf(item
, 512, "%s%s", dentry
->d_name
,
145 (S_ISDIR(s
.st_mode
) ? "/\r\n" : "\r\n"));
148 e
= data_reply(item
, l
);
152 reply_c("226 Directory list sent.\r\n");
154 reply_c("426 Connection closed, transfer aborted.\r\n");