6 * list_dir.c - LIST and NLST commands implementation.
8 * To make Mozilla Firefox list the directory contents correctly, some research
9 * work had to be done. That concluded in:
11 * http://cr.yp.to/ftp.html
15 * http://cr.yp.to/ftp/list/binls.html
17 * Only files or subdirectories are shown, the rest of items (symlinks, named
18 * pipes, sockets...) are ignored. The following line is sent when a file is
21 * -rw-r--r-- 1 ftp ftp 999 Mon 88 7777 filename
23 * In case of a subdirectory, the line is:
25 * drwxr-xr-x 1 ftp ftp 999 Mon 88 7777 dirname
27 * Where '999' is the item size, 'Mon 88 7777' is the month, day and year,
28 * respectively, of the last modification date. Some servers display the hour
29 * and minute when the distance between current time and last modification time
30 * is less than six months. We don't do that as it is considered irrelevant. To
31 * obtain a more precise value for the last modification time, let the client
32 * send a MDTM command.
34 * Note that when, for some reason, directory listing is not possible, an empty
35 * list is sent. So this error is not detected from the client, until it tries
38 * Also note that most clients will appreciate listings where all its items are
41 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <netinet/in.h>
54 static char month
[12][4] = {
55 "Jan\0", "Feb\0", "Mar\0", "Apr\0", "May\0", "Jun\0", "Jul\0", "Aug\0",
56 "Sep\0", "Oct\0", "Nov\0", "Dec\0"
60 void list_dir (int full_list
)
64 struct dirent
*dentry
;
65 struct sockaddr_in saddr
;
68 socklen_t saddr_len
= sizeof(saddr
);
71 S_data_sk
= accept(S_passive_bind_sk
,
72 (struct sockaddr
*) &saddr
, &saddr_len
);
74 if (S_arg
!= NULL
&& path_is_secure(S_arg
)) {
75 /* Workaround for Konqueror and Nautilus */
79 dir
= opendir(expanded_arg());
84 send_reply(S_cmd_sk
, "150 Sending directory list.\r\n");
88 /* Skip "." and "..", under Linux they are always the first two */
93 dentry
= readdir(dir
);
97 err
= stat(dentry
->d_name
, &st
);
103 gmtime_r(&(st
.st_mtime
), &t
);
104 snprintf(AuxBuf
, LINE_SIZE
,
105 "%s 1 ftp ftp %13lld %s %3d %4d %s\r\n",
106 (S_ISDIR(st
.st_mode
) ? "dr-xr-xr-x"
107 : "-r--r--r--"), (long long) st
.st_size
,
108 month
[t
.tm_mon
], t
.tm_mday
, t
.tm_year
+ 1900,
112 snprintf(AuxBuf
, LINE_SIZE
, "%s%s", dentry
->d_name
,
113 (dentry
->d_type
== DT_DIR
? "/\r\n"
117 send_reply(S_data_sk
, AuxBuf
);
123 send_reply(S_cmd_sk
, "226 Directory list sent.\r\n");