Coding style fix.
[uftps.git] / list_dir.c
blobe1ca7ddd626345aef6feb0c47af8a6c9356f70fd
1 /*
2 * User FTP Server
3 * Author : C2H5OH
4 * License: GPL v2
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
13 * In particular:
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
19 * found:
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
36 * to execute CWD.
38 * Also note that most clients will appreciate listings where all its items are
39 * stat()-able.
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/socket.h>
44 #include <netinet/in.h>
45 #include <unistd.h>
46 #include <dirent.h>
47 #include <time.h>
48 #include <string.h>
49 #include <stdio.h>
51 #include "uftps.h"
53 /* Month names */
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)
62 int err;
63 DIR *dir;
64 struct dirent *dentry;
65 struct sockaddr_in saddr;
66 struct stat st;
67 struct tm t;
68 socklen_t saddr_len = sizeof(saddr);
70 if (S_passive_mode)
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 */
76 if (S_arg[0] == '-')
77 dir = opendir(".");
78 else
79 dir = opendir(expanded_arg());
80 } else {
81 dir = opendir(".");
84 send_reply(S_cmd_sk, "150 Sending directory list.\r\n");
85 if (dir == NULL)
86 goto finish;
88 /* Skip "." and "..", under Linux they are always the first two */
89 readdir(dir);
90 readdir(dir);
92 do {
93 dentry = readdir(dir);
94 if (dentry == NULL)
95 break;
97 err = stat(dentry->d_name, &st);
98 if (err == -1)
99 continue;
101 if (full_list) {
102 /* LIST */
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,
109 dentry->d_name);
110 } else {
111 /* NLST */
112 snprintf(AuxBuf, LINE_SIZE, "%s%s", dentry->d_name,
113 (dentry->d_type == DT_DIR ? "/\r\n"
114 : "\r\n"));
117 send_reply(S_data_sk, AuxBuf);
119 } while (1);
120 closedir(dir);
122 finish:
123 send_reply(S_cmd_sk, "226 Directory list sent.\r\n");
124 close(S_data_sk);
125 S_data_sk = -1;
126 S_passive_mode = 0;