ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/enametoolong/enametoolong.C
Revision: 1.1
Committed: Wed May 7 09:20:48 2025 UTC (2 months, 1 week ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Log Message:
*** empty log message ***

File Contents

# Content
1 #undef _GNU_SOURCE
2 #define _GNU_SOURCE
3
4 #include <limits.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <sys/wait.h>
8 #include <dlfcn.h>
9 #include <errno.h>
10 #include <unistd.h>
11 #include <sys/socket.h>
12 #include <sys/socket.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <arpa/inet.h>
16
17 #include <unordered_map>
18 #include <mutex>
19
20 #define PATHBUFSIZE 4097
21 #define NAMEMAX 255
22 #define DEFAULT_SHORTENER "/root/enametoolong/shortener-prod"
23
24 static std::mutex shorten_mutex;
25
26 static int shortener_fd = -1;
27 static pid_t shortener_pid;
28
29 static void
30 die (const char *msg)
31 {
32 perror ("socketpair");
33 exit (EXIT_FAILURE);
34 }
35
36 static bool
37 xread (int fd, void *buf, size_t count)
38 {
39 while (count > 0)
40 {
41 ssize_t bytesRead = read (fd, buf, count);
42
43 if (bytesRead < 0)
44 {
45 if (errno == EINTR)
46 continue;
47
48 return false;
49 }
50 else if (bytesRead == 0)
51 return false;
52
53 buf = (char *)buf + bytesRead;
54 count -= bytesRead;
55 }
56
57 return true;
58 }
59
60 static bool
61 xwrite(int fd, const void *buf, size_t count)
62 {
63 while (count > 0)
64 {
65 ssize_t bytesWritten = send (fd, buf, count, MSG_NOSIGNAL);
66
67 if (bytesWritten < 0)
68 {
69 if (errno == EINTR)
70 continue;
71
72 return false;
73 }
74
75 buf = (char *)buf + bytesWritten;
76 count -= bytesWritten;
77 }
78
79 return true;
80 }
81
82 static void
83 shortener_open (void)
84 {
85 int sp[2];
86
87 if (socketpair (AF_UNIX, SOCK_STREAM, 0, sp) < 0)
88 die ("socketpair");
89
90 shortener_pid = vfork ();
91
92 if (shortener_pid < 0)
93 die ("vfork");
94
95 if (shortener_pid == 0)
96 {
97 dup2 (sp[1], 0);
98 dup2 (sp[1], 1);
99 close (sp[0]);
100
101 static const char *const argv[2] = { "-", 0 };
102 const char *shortener_path = secure_getenv ("ENAMETOOLONG_SHORTENER");
103 execve (shortener_path ? shortener_path : DEFAULT_SHORTENER, const_cast<char *const *>(argv), 0);
104 _exit (126);
105 }
106
107 close (sp[1]);
108
109 shortener_fd = sp[0];
110 }
111
112 static void
113 shortener_close (void)
114 {
115 if (shortener_fd < 0)
116 return;
117
118 close (shortener_fd);
119 shortener_fd = -1;
120
121 if (shortener_pid > 0)
122 {
123 int wstatus;
124 waitpid (shortener_pid, &wstatus, 0);
125 shortener_pid = -1;
126 }
127
128 sleep (1); // rate limit retries
129 }
130
131 static std::unordered_map<std::string, std::string> cache;
132
133 __attribute__ ((__cold__, __noinline__))
134 static const char *
135 shorten (const char *path)
136 {
137 std::lock_guard<std::mutex> guard (shorten_mutex);
138
139 std::string &shorter = cache[path];
140
141 if (shorter.size ())
142 return shorter.c_str ();
143
144 for (;;)
145 {
146 if (shortener_fd < 0)
147 shortener_open ();
148
149 uint32_t slen = strlen (path);
150 uint32_t nlen = htonl (slen);
151 xwrite (shortener_fd, &nlen, sizeof nlen);
152 xwrite (shortener_fd, path, slen);
153
154 if (xread (shortener_fd, &nlen, sizeof nlen))
155 {
156 nlen = ntohl (nlen);
157
158 if (nlen < PATHBUFSIZE)
159 {
160 shorter.resize (nlen);
161
162 if (xread (shortener_fd, shorter.data (), nlen))
163 return shorter.c_str ();
164 }
165 }
166
167 shortener_close ();
168 }
169 }
170
171 static bool
172 toolong (const char *path)
173 {
174 size_t clen = 0;
175
176 for (;;)
177 {
178 if (*path == '/')
179 clen = 0;
180 else if (!*path)
181 return false;
182 else if (++clen > NAMEMAX)
183 return true;
184
185 ++path;
186 }
187 }
188
189 #include "wrap.C"