ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/enametoolong/enametoolong.C
Revision: 1.2
Committed: Wed Dec 24 15:26:21 2025 UTC (6 months, 2 weeks ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +23 -0 lines
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 <stdlib.h>
15 #include <string.h>
16 #include <arpa/inet.h>
17
18 #include <string>
19 #include <unordered_map>
20 #include <mutex>
21
22 #define PATHBUFSIZE 4097
23 #define NAMEMAX 255
24 #define DEFAULT_SHORTENER "/root/enametoolong/shortener-prod"
25
26 static std::mutex shorten_mutex;
27
28 static int shortener_fd = -1;
29 static pid_t shortener_pid;
30
31 static void
32 die (const char *msg)
33 {
34 perror ("socketpair");
35 exit (EXIT_FAILURE);
36 }
37
38 static bool
39 xread (int fd, void *buf, size_t count)
40 {
41 while (count > 0)
42 {
43 ssize_t bytesRead = read (fd, buf, count);
44
45 if (bytesRead < 0)
46 {
47 if (errno == EINTR)
48 continue;
49
50 return false;
51 }
52 else if (bytesRead == 0)
53 return false;
54
55 buf = (char *)buf + bytesRead;
56 count -= bytesRead;
57 }
58
59 return true;
60 }
61
62 static bool
63 xwrite(int fd, const void *buf, size_t count)
64 {
65 while (count > 0)
66 {
67 ssize_t bytesWritten = send (fd, buf, count, MSG_NOSIGNAL);
68
69 if (bytesWritten < 0)
70 {
71 if (errno == EINTR)
72 continue;
73
74 return false;
75 }
76
77 buf = (char *)buf + bytesWritten;
78 count -= bytesWritten;
79 }
80
81 return true;
82 }
83
84 static void
85 shortener_open (void)
86 {
87 int sp[2];
88
89 if (socketpair (AF_UNIX, SOCK_STREAM, 0, sp) < 0)
90 die ("socketpair");
91
92 shortener_pid = vfork ();
93
94 if (shortener_pid < 0)
95 die ("vfork");
96
97 if (shortener_pid == 0)
98 {
99 dup2 (sp[1], 0);
100 dup2 (sp[1], 1);
101 close (sp[0]);
102
103 static const char *const argv[2] = { "-", 0 };
104 const char *shortener_path = secure_getenv ("ENAMETOOLONG_SHORTENER");
105 execve (shortener_path ? shortener_path : DEFAULT_SHORTENER, const_cast<char *const *>(argv), 0);
106 _exit (126);
107 }
108
109 close (sp[1]);
110
111 shortener_fd = sp[0];
112 }
113
114 static void
115 shortener_close (void)
116 {
117 if (shortener_fd < 0)
118 return;
119
120 close (shortener_fd);
121 shortener_fd = -1;
122
123 if (shortener_pid > 0)
124 {
125 int wstatus;
126 waitpid (shortener_pid, &wstatus, 0);
127 shortener_pid = -1;
128 }
129
130 sleep (1); // rate limit retries
131 }
132
133 static std::unordered_map<std::string, std::string> cache;
134
135 __attribute__ ((__cold__, __noinline__))
136 static const char *
137 shorten (const char *path)
138 {
139 std::lock_guard<std::mutex> guard (shorten_mutex);
140
141 std::string &shorter = cache[path];
142
143 if (shorter.size ())
144 return shorter.c_str ();
145
146 for (;;)
147 {
148 if (shortener_fd < 0)
149 shortener_open ();
150
151 uint32_t slen = strlen (path);
152 uint32_t nlen = htonl (slen);
153 xwrite (shortener_fd, &nlen, sizeof nlen);
154 xwrite (shortener_fd, path, slen);
155
156 if (xread (shortener_fd, &nlen, sizeof nlen))
157 {
158 nlen = ntohl (nlen);
159
160 if (nlen < PATHBUFSIZE)
161 {
162 shorter.resize (nlen);
163
164 if (xread (shortener_fd, shorter.data (), nlen))
165 return shorter.c_str ();
166 }
167 }
168
169 shortener_close ();
170 }
171 }
172
173 static bool
174 toolong (const char *path)
175 {
176 size_t clen = 0;
177
178 for (;;)
179 {
180 if (*path == '/')
181 clen = 0;
182 else if (!*path)
183 return false;
184 else if (++clen > NAMEMAX)
185 return true;
186
187 ++path;
188 }
189 }
190
191 // paths starting with the MAGIC_PREFIX return the shortened
192 // version of the part after the prefix (a relative path)
193 // in readlink and readlinkat.
194
195 #define MAGIC_PREFIX "/dev/enametoolong/"
196
197 static ssize_t
198 magic_readlink (const char *path, char *buf, size_t len)
199 {
200 size_t slen = strlen (path);
201 slen -= sizeof (MAGIC_PREFIX) - 1;
202 path += sizeof (MAGIC_PREFIX) - 1;
203 strncpy (buf, path, len < slen ? len : slen);
204 return slen;
205 }
206
207 #define MAGIC_READLINK(path, buf, len) \
208 if (strncmp (path, MAGIC_PREFIX, sizeof (MAGIC_PREFIX) - 1) == 0) \
209 return magic_readlink (path, buf, len);
210
211 #include "wrap.C"
212