passenger 5.0.8 → 5.0.9
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of passenger might be problematic. Click here for more details.
- checksums.yaml +8 -8
- checksums.yaml.gz.asc +7 -7
- data.tar.gz.asc +7 -7
- data/.editorconfig +20 -0
- data/CHANGELOG +21 -0
- data/bin/passenger-install-apache2-module +3 -1
- data/build/agents.rb +7 -5
- data/build/basics.rb +3 -3
- data/build/common_library.rb +52 -30
- data/build/cxx_tests.rb +20 -13
- data/build/misc.rb +5 -5
- data/doc/Design and Architecture.html +1 -1
- data/doc/Design and Architecture.txt +1 -1
- data/doc/Packaging.html +4 -4
- data/doc/Packaging.txt.md +4 -4
- data/doc/Users guide Apache.html +22 -9
- data/doc/Users guide Apache.idmap.txt +4 -2
- data/doc/Users guide Apache.txt +2 -0
- data/doc/Users guide Nginx.html +22 -9
- data/doc/Users guide Nginx.idmap.txt +4 -2
- data/doc/Users guide Nginx.txt +2 -0
- data/doc/Users guide Standalone.html +14 -9
- data/doc/Users guide Standalone.idmap.txt +4 -2
- data/doc/users_guide_snippets/installation.txt +10 -6
- data/ext/apache2/Hooks.cpp +13 -2
- data/ext/common/ApplicationPool2/Pool/Inspection.h +8 -3
- data/ext/common/BackgroundEventLoop.cpp +249 -67
- data/ext/common/BackgroundEventLoop.h +5 -5
- data/ext/common/Constants.h +1 -1
- data/ext/common/InstanceDirectory.h +8 -6
- data/ext/common/ServerKit/Context.h +8 -2
- data/ext/common/ServerKit/FileBufferedChannel.h +262 -226
- data/ext/common/ServerKit/HeaderTable.h +28 -3
- data/ext/common/ServerKit/HttpHeaderParser.h +37 -13
- data/ext/common/ServerKit/HttpServer.h +17 -1
- data/ext/common/ServerKit/Implementation.cpp +2 -0
- data/ext/common/ServerKit/Server.h +25 -28
- data/ext/common/Utils/IOUtils.cpp +11 -0
- data/ext/common/Utils/ProcessMetricsCollector.h +4 -0
- data/ext/common/Utils/StrIntUtils.cpp +11 -7
- data/ext/common/Utils/StrIntUtils.h +1 -1
- data/ext/common/Utils/StrIntUtilsNoStrictAliasing.cpp +21 -16
- data/ext/common/agents/Base.cpp +6 -0
- data/ext/common/agents/Base.h +2 -0
- data/ext/common/agents/HelperAgent/AdminServer.h +25 -25
- data/ext/common/agents/HelperAgent/Main.cpp +37 -12
- data/ext/common/agents/HelperAgent/RequestHandler.h +18 -20
- data/ext/common/agents/HelperAgent/RequestHandler/AppResponse.h +4 -0
- data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +10 -6
- data/ext/common/agents/HelperAgent/RequestHandler/Hooks.cpp +2 -0
- data/ext/common/agents/HelperAgent/RequestHandler/InitRequest.cpp +1 -1
- data/ext/common/agents/HelperAgent/RequestHandler/SendRequest.cpp +1 -1
- data/ext/common/agents/HelperAgent/RequestHandler/Utils.cpp +9 -2
- data/ext/common/agents/HelperAgent/ResponseCache.h +11 -11
- data/ext/common/agents/LoggingAgent/AdminServer.h +8 -8
- data/ext/common/agents/LoggingAgent/Main.cpp +6 -5
- data/ext/common/agents/Watchdog/AdminServer.h +13 -13
- data/ext/common/agents/Watchdog/Main.cpp +8 -3
- data/ext/libuv/.gitignore +72 -0
- data/ext/libuv/AUTHORS +199 -0
- data/ext/libuv/ChangeLog +2023 -0
- data/ext/libuv/LICENSE +46 -0
- data/ext/libuv/Makefile.am +336 -0
- data/ext/libuv/README.md +197 -0
- data/ext/libuv/checksparse.sh +233 -0
- data/ext/libuv/common.gypi +210 -0
- data/ext/libuv/configure.ac +67 -0
- data/ext/libuv/gyp_uv.py +96 -0
- data/ext/libuv/include/android-ifaddrs.h +54 -0
- data/ext/libuv/include/pthread-fixes.h +72 -0
- data/ext/libuv/include/tree.h +768 -0
- data/ext/libuv/include/uv-aix.h +32 -0
- data/ext/libuv/include/uv-bsd.h +34 -0
- data/ext/libuv/include/uv-darwin.h +61 -0
- data/ext/libuv/include/uv-errno.h +418 -0
- data/ext/libuv/include/uv-linux.h +34 -0
- data/ext/libuv/include/uv-sunos.h +44 -0
- data/ext/libuv/include/uv-threadpool.h +37 -0
- data/ext/libuv/include/uv-unix.h +383 -0
- data/ext/libuv/include/uv-version.h +39 -0
- data/ext/libuv/include/uv.h +1455 -0
- data/ext/libuv/libuv.pc.in +11 -0
- data/ext/libuv/m4/.gitignore +4 -0
- data/ext/libuv/m4/as_case.m4 +21 -0
- data/ext/libuv/m4/libuv-check-flags.m4 +319 -0
- data/ext/libuv/src/fs-poll.c +255 -0
- data/ext/libuv/src/heap-inl.h +245 -0
- data/ext/libuv/src/inet.c +313 -0
- data/ext/libuv/src/queue.h +92 -0
- data/ext/libuv/src/threadpool.c +303 -0
- data/ext/libuv/src/unix/aix.c +1240 -0
- data/ext/libuv/src/unix/android-ifaddrs.c +703 -0
- data/ext/libuv/src/unix/async.c +284 -0
- data/ext/libuv/src/unix/atomic-ops.h +60 -0
- data/ext/libuv/src/unix/core.c +985 -0
- data/ext/libuv/src/unix/darwin-proctitle.c +206 -0
- data/ext/libuv/src/unix/darwin.c +331 -0
- data/ext/libuv/src/unix/dl.c +83 -0
- data/ext/libuv/src/unix/freebsd.c +435 -0
- data/ext/libuv/src/unix/fs.c +1189 -0
- data/ext/libuv/src/unix/fsevents.c +899 -0
- data/ext/libuv/src/unix/getaddrinfo.c +202 -0
- data/ext/libuv/src/unix/getnameinfo.c +120 -0
- data/ext/libuv/src/unix/internal.h +314 -0
- data/ext/libuv/src/unix/kqueue.c +418 -0
- data/ext/libuv/src/unix/linux-core.c +876 -0
- data/ext/libuv/src/unix/linux-inotify.c +257 -0
- data/ext/libuv/src/unix/linux-syscalls.c +471 -0
- data/ext/libuv/src/unix/linux-syscalls.h +158 -0
- data/ext/libuv/src/unix/loop-watcher.c +63 -0
- data/ext/libuv/src/unix/loop.c +135 -0
- data/ext/libuv/src/unix/netbsd.c +368 -0
- data/ext/libuv/src/unix/openbsd.c +384 -0
- data/ext/libuv/src/unix/pipe.c +288 -0
- data/ext/libuv/src/unix/poll.c +113 -0
- data/ext/libuv/src/unix/process.c +551 -0
- data/ext/libuv/src/unix/proctitle.c +102 -0
- data/ext/libuv/src/unix/pthread-fixes.c +103 -0
- data/ext/libuv/src/unix/signal.c +465 -0
- data/ext/libuv/src/unix/spinlock.h +53 -0
- data/ext/libuv/src/unix/stream.c +1598 -0
- data/ext/libuv/src/unix/sunos.c +763 -0
- data/ext/libuv/src/unix/tcp.c +327 -0
- data/ext/libuv/src/unix/thread.c +519 -0
- data/ext/libuv/src/unix/timer.c +172 -0
- data/ext/libuv/src/unix/tty.c +265 -0
- data/ext/libuv/src/unix/udp.c +833 -0
- data/ext/libuv/src/uv-common.c +544 -0
- data/ext/libuv/src/uv-common.h +214 -0
- data/ext/libuv/src/version.c +49 -0
- data/ext/libuv/uv.gyp +487 -0
- data/ext/nginx/ContentHandler.c +21 -10
- data/ext/nginx/ngx_http_passenger_module.c +7 -0
- data/ext/oxt/implementation.cpp +9 -2
- data/ext/oxt/initialize.hpp +5 -1
- data/lib/phusion_passenger.rb +3 -3
- data/lib/phusion_passenger/admin_tools/instance.rb +10 -6
- data/lib/phusion_passenger/admin_tools/instance_registry.rb +6 -2
- data/lib/phusion_passenger/packaging.rb +3 -4
- data/lib/phusion_passenger/platform_info.rb +13 -1
- data/lib/phusion_passenger/platform_info/apache.rb +15 -4
- data/lib/phusion_passenger/platform_info/apache_detector.rb +5 -1
- data/lib/phusion_passenger/rack/thread_handler_extension.rb +184 -99
- data/lib/phusion_passenger/request_handler/thread_handler.rb +13 -6
- data/lib/phusion_passenger/standalone/start_command.rb +2 -2
- data/resources/templates/apache2/apache_install_broken.txt.erb +2 -1
- metadata +99 -22
- metadata.gz.asc +7 -7
- data/ext/libeio/Changes +0 -76
- data/ext/libeio/LICENSE +0 -36
- data/ext/libeio/Makefile.am +0 -15
- data/ext/libeio/Makefile.in +0 -694
- data/ext/libeio/aclocal.m4 +0 -9418
- data/ext/libeio/autogen.sh +0 -3
- data/ext/libeio/config.guess +0 -1540
- data/ext/libeio/config.h.in +0 -136
- data/ext/libeio/config.sub +0 -1779
- data/ext/libeio/configure +0 -14822
- data/ext/libeio/configure.ac +0 -22
- data/ext/libeio/demo.c +0 -194
- data/ext/libeio/ecb.h +0 -714
- data/ext/libeio/eio.c +0 -2818
- data/ext/libeio/eio.h +0 -414
- data/ext/libeio/install-sh +0 -520
- data/ext/libeio/libeio.m4 +0 -195
- data/ext/libeio/ltmain.sh +0 -9636
- data/ext/libeio/missing +0 -376
- data/ext/libeio/xthread.h +0 -166
data/ext/libeio/eio.c
DELETED
@@ -1,2818 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* libeio implementation
|
3
|
-
*
|
4
|
-
* Copyright (c) 2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann <libeio@schmorp.de>
|
5
|
-
* All rights reserved.
|
6
|
-
*
|
7
|
-
* Redistribution and use in source and binary forms, with or without modifica-
|
8
|
-
* tion, are permitted provided that the following conditions are met:
|
9
|
-
*
|
10
|
-
* 1. Redistributions of source code must retain the above copyright notice,
|
11
|
-
* this list of conditions and the following disclaimer.
|
12
|
-
*
|
13
|
-
* 2. Redistributions in binary form must reproduce the above copyright
|
14
|
-
* notice, this list of conditions and the following disclaimer in the
|
15
|
-
* documentation and/or other materials provided with the distribution.
|
16
|
-
*
|
17
|
-
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
18
|
-
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
19
|
-
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
20
|
-
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
21
|
-
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
22
|
-
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
23
|
-
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
24
|
-
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
25
|
-
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
26
|
-
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
-
*
|
28
|
-
* Alternatively, the contents of this file may be used under the terms of
|
29
|
-
* the GNU General Public License ("GPL") version 2 or any later version,
|
30
|
-
* in which case the provisions of the GPL are applicable instead of
|
31
|
-
* the above. If you wish to allow the use of your version of this file
|
32
|
-
* only under the terms of the GPL and not to allow others to use your
|
33
|
-
* version of this file under the BSD license, indicate your decision
|
34
|
-
* by deleting the provisions above and replace them with the notice
|
35
|
-
* and other provisions required by the GPL. If you do not delete the
|
36
|
-
* provisions above, a recipient may use your version of this file under
|
37
|
-
* either the BSD or the GPL.
|
38
|
-
*/
|
39
|
-
|
40
|
-
#ifndef _WIN32
|
41
|
-
# include "config.h"
|
42
|
-
#endif
|
43
|
-
|
44
|
-
#include "eio.h"
|
45
|
-
#include "ecb.h"
|
46
|
-
|
47
|
-
#ifdef EIO_STACKSIZE
|
48
|
-
# define X_STACKSIZE EIO_STACKSIZE
|
49
|
-
#endif
|
50
|
-
#include "xthread.h"
|
51
|
-
|
52
|
-
#include <errno.h>
|
53
|
-
#include <stddef.h>
|
54
|
-
#include <stdlib.h>
|
55
|
-
#include <string.h>
|
56
|
-
#include <errno.h>
|
57
|
-
#include <sys/types.h>
|
58
|
-
#include <sys/stat.h>
|
59
|
-
#include <limits.h>
|
60
|
-
#include <fcntl.h>
|
61
|
-
#include <assert.h>
|
62
|
-
|
63
|
-
/* intptr_t comes from unistd.h, says POSIX/UNIX/tradition */
|
64
|
-
/* intptr_t only comes from stdint.h, says idiot openbsd coder */
|
65
|
-
#if HAVE_STDINT_H
|
66
|
-
# include <stdint.h>
|
67
|
-
#endif
|
68
|
-
|
69
|
-
#ifndef ECANCELED
|
70
|
-
# define ECANCELED EDOM
|
71
|
-
#endif
|
72
|
-
#ifndef ELOOP
|
73
|
-
# define ELOOP EDOM
|
74
|
-
#endif
|
75
|
-
|
76
|
-
#if !defined(ENOTSOCK) && defined(WSAENOTSOCK)
|
77
|
-
# define ENOTSOCK WSAENOTSOCK
|
78
|
-
#endif
|
79
|
-
|
80
|
-
static void eio_destroy (eio_req *req);
|
81
|
-
|
82
|
-
#ifndef EIO_FINISH
|
83
|
-
# define EIO_FINISH(req) ((req)->finish) ? (req)->finish (req) : 0
|
84
|
-
#endif
|
85
|
-
|
86
|
-
#ifndef EIO_DESTROY
|
87
|
-
# define EIO_DESTROY(req) do { if ((req)->destroy) (req)->destroy (req); } while (0)
|
88
|
-
#endif
|
89
|
-
|
90
|
-
#ifndef EIO_FEED
|
91
|
-
# define EIO_FEED(req) do { if ((req)->feed ) (req)->feed (req); } while (0)
|
92
|
-
#endif
|
93
|
-
|
94
|
-
#ifndef EIO_FD_TO_WIN32_HANDLE
|
95
|
-
# define EIO_FD_TO_WIN32_HANDLE(fd) _get_osfhandle (fd)
|
96
|
-
#endif
|
97
|
-
#ifndef EIO_WIN32_HANDLE_TO_FD
|
98
|
-
# define EIO_WIN32_HANDLE_TO_FD(handle) _open_osfhandle (handle, 0)
|
99
|
-
#endif
|
100
|
-
|
101
|
-
#define EIO_ERRNO(errval,retval) ((errno = errval), retval)
|
102
|
-
|
103
|
-
#define EIO_ENOSYS() EIO_ERRNO (ENOSYS, -1)
|
104
|
-
|
105
|
-
#ifdef _WIN32
|
106
|
-
|
107
|
-
#undef PAGESIZE
|
108
|
-
#define PAGESIZE 4096 /* GetSystemInfo? */
|
109
|
-
|
110
|
-
/* TODO: look at how perl does stat (non-sloppy), unlink (ro-files), utime, link */
|
111
|
-
|
112
|
-
#ifdef EIO_STRUCT_STATI64
|
113
|
-
/* look at perl's non-sloppy stat */
|
114
|
-
#define stat(path,buf) _stati64 (path,buf)
|
115
|
-
#define fstat(fd,buf) _fstati64 (fd,buf)
|
116
|
-
#endif
|
117
|
-
#define lstat(path,buf) stat (path,buf)
|
118
|
-
#define fsync(fd) (FlushFileBuffers ((HANDLE)EIO_FD_TO_WIN32_HANDLE (fd)) ? 0 : EIO_ERRNO (EBADF, -1))
|
119
|
-
#define mkdir(path,mode) _mkdir (path)
|
120
|
-
#define link(old,neu) (CreateHardLink (neu, old, 0) ? 0 : EIO_ERRNO (ENOENT, -1))
|
121
|
-
|
122
|
-
#define chmod(path,mode) _chmod (path, mode)
|
123
|
-
#define dup(fd) _dup (fd)
|
124
|
-
#define dup2(fd1,fd2) _dup2 (fd1, fd2)
|
125
|
-
|
126
|
-
#define fchmod(fd,mode) EIO_ENOSYS ()
|
127
|
-
#define chown(path,uid,gid) EIO_ENOSYS ()
|
128
|
-
#define fchown(fd,uid,gid) EIO_ENOSYS ()
|
129
|
-
#define truncate(path,offs) EIO_ENOSYS () /* far-miss: SetEndOfFile */
|
130
|
-
#define ftruncate(fd,offs) EIO_ENOSYS () /* near-miss: SetEndOfFile */
|
131
|
-
#define mknod(path,mode,dev) EIO_ENOSYS ()
|
132
|
-
#define sync() EIO_ENOSYS ()
|
133
|
-
#define readlink(path,buf,s) EIO_ENOSYS ()
|
134
|
-
#define statvfs(path,buf) EIO_ENOSYS ()
|
135
|
-
#define fstatvfs(fd,buf) EIO_ENOSYS ()
|
136
|
-
|
137
|
-
#define pread(fd,buf,count,offset) eio__pread (fd, buf, count, offset)
|
138
|
-
#define pwrite(fd,buf,count,offset) eio__pwrite (fd, buf, count, offset)
|
139
|
-
|
140
|
-
#if __GNUC__
|
141
|
-
typedef long long eio_off_t; /* signed for compatibility to msvc */
|
142
|
-
#else
|
143
|
-
typedef __int64 eio_off_t; /* unsigned not supported by msvc */
|
144
|
-
#endif
|
145
|
-
|
146
|
-
static eio_ssize_t
|
147
|
-
eio__pread (int fd, void *buf, eio_ssize_t count, eio_off_t offset)
|
148
|
-
{
|
149
|
-
OVERLAPPED o = { 0 };
|
150
|
-
DWORD got;
|
151
|
-
|
152
|
-
o.Offset = offset;
|
153
|
-
o.OffsetHigh = offset >> 32;
|
154
|
-
|
155
|
-
return ReadFile ((HANDLE)EIO_FD_TO_WIN32_HANDLE (fd), buf, count, &got, &o)
|
156
|
-
? got : -1;
|
157
|
-
}
|
158
|
-
|
159
|
-
static eio_ssize_t
|
160
|
-
eio__pwrite (int fd, void *buf, eio_ssize_t count, eio_off_t offset)
|
161
|
-
{
|
162
|
-
OVERLAPPED o = { 0 };
|
163
|
-
DWORD got;
|
164
|
-
|
165
|
-
o.Offset = offset;
|
166
|
-
o.OffsetHigh = offset >> 32;
|
167
|
-
|
168
|
-
return WriteFile ((HANDLE)EIO_FD_TO_WIN32_HANDLE (fd), buf, count, &got, &o)
|
169
|
-
? got : -1;
|
170
|
-
}
|
171
|
-
|
172
|
-
/* rename() uses MoveFile, which fails to overwrite */
|
173
|
-
#define rename(old,neu) eio__rename (old, neu)
|
174
|
-
|
175
|
-
static int
|
176
|
-
eio__rename (const char *old, const char *neu)
|
177
|
-
{
|
178
|
-
if (MoveFileEx (old, neu, MOVEFILE_REPLACE_EXISTING))
|
179
|
-
return 0;
|
180
|
-
|
181
|
-
/* should steal _dosmaperr */
|
182
|
-
switch (GetLastError ())
|
183
|
-
{
|
184
|
-
case ERROR_FILE_NOT_FOUND:
|
185
|
-
case ERROR_PATH_NOT_FOUND:
|
186
|
-
case ERROR_INVALID_DRIVE:
|
187
|
-
case ERROR_NO_MORE_FILES:
|
188
|
-
case ERROR_BAD_NETPATH:
|
189
|
-
case ERROR_BAD_NET_NAME:
|
190
|
-
case ERROR_BAD_PATHNAME:
|
191
|
-
case ERROR_FILENAME_EXCED_RANGE:
|
192
|
-
errno = ENOENT;
|
193
|
-
break;
|
194
|
-
|
195
|
-
default:
|
196
|
-
errno = EACCES;
|
197
|
-
break;
|
198
|
-
}
|
199
|
-
|
200
|
-
return -1;
|
201
|
-
}
|
202
|
-
|
203
|
-
/* we could even stat and see if it exists */
|
204
|
-
static int
|
205
|
-
symlink (const char *old, const char *neu)
|
206
|
-
{
|
207
|
-
#if WINVER >= 0x0600
|
208
|
-
if (CreateSymbolicLink (neu, old, 1))
|
209
|
-
return 0;
|
210
|
-
|
211
|
-
if (CreateSymbolicLink (neu, old, 0))
|
212
|
-
return 0;
|
213
|
-
#endif
|
214
|
-
|
215
|
-
return EIO_ERRNO (ENOENT, -1);
|
216
|
-
}
|
217
|
-
|
218
|
-
/* POSIX API only */
|
219
|
-
#define CreateHardLink(neu,old,flags) 0
|
220
|
-
#define CreateSymbolicLink(neu,old,flags) 0
|
221
|
-
|
222
|
-
struct statvfs
|
223
|
-
{
|
224
|
-
int dummy;
|
225
|
-
};
|
226
|
-
|
227
|
-
#define DT_DIR EIO_DT_DIR
|
228
|
-
#define DT_REG EIO_DT_REG
|
229
|
-
#define D_NAME(entp) entp.cFileName
|
230
|
-
#define D_TYPE(entp) (entp.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? DT_DIR : DT_REG)
|
231
|
-
|
232
|
-
#else
|
233
|
-
|
234
|
-
#include <sys/time.h>
|
235
|
-
#include <sys/select.h>
|
236
|
-
#include <sys/statvfs.h>
|
237
|
-
#include <unistd.h>
|
238
|
-
#include <signal.h>
|
239
|
-
#include <dirent.h>
|
240
|
-
|
241
|
-
#if _POSIX_MEMLOCK || _POSIX_MEMLOCK_RANGE || _POSIX_MAPPED_FILES
|
242
|
-
#include <sys/mman.h>
|
243
|
-
#endif
|
244
|
-
|
245
|
-
#define D_NAME(entp) entp->d_name
|
246
|
-
|
247
|
-
/* POSIX_SOURCE is useless on bsd's, and XOPEN_SOURCE is unreliable there, too */
|
248
|
-
#if __FreeBSD__ || __NetBSD__ || __OpenBSD__
|
249
|
-
#define _DIRENT_HAVE_D_TYPE /* sigh */
|
250
|
-
#define D_INO(de) (de)->d_fileno
|
251
|
-
#define D_NAMLEN(de) (de)->d_namlen
|
252
|
-
#elif __linux || defined d_ino || _XOPEN_SOURCE >= 600
|
253
|
-
#define D_INO(de) (de)->d_ino
|
254
|
-
#endif
|
255
|
-
|
256
|
-
#ifdef _D_EXACT_NAMLEN
|
257
|
-
#undef D_NAMLEN
|
258
|
-
#define D_NAMLEN(de) _D_EXACT_NAMLEN (de)
|
259
|
-
#endif
|
260
|
-
|
261
|
-
#ifdef _DIRENT_HAVE_D_TYPE
|
262
|
-
#define D_TYPE(de) (de)->d_type
|
263
|
-
#endif
|
264
|
-
|
265
|
-
#ifndef EIO_STRUCT_DIRENT
|
266
|
-
#define EIO_STRUCT_DIRENT struct dirent
|
267
|
-
#endif
|
268
|
-
|
269
|
-
#endif
|
270
|
-
|
271
|
-
#if HAVE_UTIMES
|
272
|
-
# include <utime.h>
|
273
|
-
#endif
|
274
|
-
|
275
|
-
#if HAVE_SYS_SYSCALL_H
|
276
|
-
# include <sys/syscall.h>
|
277
|
-
#endif
|
278
|
-
|
279
|
-
#if HAVE_SYS_PRCTL_H
|
280
|
-
# include <sys/prctl.h>
|
281
|
-
#endif
|
282
|
-
|
283
|
-
#if HAVE_SENDFILE
|
284
|
-
# if __linux
|
285
|
-
# include <sys/sendfile.h>
|
286
|
-
# elif __FreeBSD__ || defined __APPLE__
|
287
|
-
# include <sys/socket.h>
|
288
|
-
# include <sys/uio.h>
|
289
|
-
# elif __hpux
|
290
|
-
# include <sys/socket.h>
|
291
|
-
# elif __solaris
|
292
|
-
# include <sys/sendfile.h>
|
293
|
-
# else
|
294
|
-
# error sendfile support requested but not available
|
295
|
-
# endif
|
296
|
-
#endif
|
297
|
-
|
298
|
-
#ifndef D_TYPE
|
299
|
-
# define D_TYPE(de) 0
|
300
|
-
#endif
|
301
|
-
#ifndef D_INO
|
302
|
-
# define D_INO(de) 0
|
303
|
-
#endif
|
304
|
-
#ifndef D_NAMLEN
|
305
|
-
# define D_NAMLEN(entp) strlen (D_NAME (entp))
|
306
|
-
#endif
|
307
|
-
|
308
|
-
/* used for struct dirent, AIX doesn't provide it */
|
309
|
-
#ifndef NAME_MAX
|
310
|
-
# define NAME_MAX 4096
|
311
|
-
#endif
|
312
|
-
|
313
|
-
/* used for readlink etc. */
|
314
|
-
#ifndef PATH_MAX
|
315
|
-
# define PATH_MAX 4096
|
316
|
-
#endif
|
317
|
-
|
318
|
-
/* buffer size for various temporary buffers */
|
319
|
-
#define EIO_BUFSIZE 65536
|
320
|
-
|
321
|
-
#define dBUF \
|
322
|
-
char *eio_buf = malloc (EIO_BUFSIZE); \
|
323
|
-
errno = ENOMEM; \
|
324
|
-
if (!eio_buf) \
|
325
|
-
return -1
|
326
|
-
|
327
|
-
#define FUBd \
|
328
|
-
free (eio_buf)
|
329
|
-
|
330
|
-
#define EIO_TICKS ((1000000 + 1023) >> 10)
|
331
|
-
|
332
|
-
/*****************************************************************************/
|
333
|
-
|
334
|
-
struct tmpbuf
|
335
|
-
{
|
336
|
-
void *ptr;
|
337
|
-
int len;
|
338
|
-
};
|
339
|
-
|
340
|
-
static void *
|
341
|
-
tmpbuf_get (struct tmpbuf *buf, int len)
|
342
|
-
{
|
343
|
-
if (buf->len < len)
|
344
|
-
{
|
345
|
-
free (buf->ptr);
|
346
|
-
buf->ptr = malloc (buf->len = len);
|
347
|
-
}
|
348
|
-
|
349
|
-
return buf->ptr;
|
350
|
-
}
|
351
|
-
|
352
|
-
struct tmpbuf;
|
353
|
-
|
354
|
-
#if _POSIX_VERSION >= 200809L
|
355
|
-
#define HAVE_AT 1
|
356
|
-
#define WD2FD(wd) ((wd) ? (wd)->fd : AT_FDCWD)
|
357
|
-
#ifndef O_SEARCH
|
358
|
-
#define O_SEARCH O_RDONLY
|
359
|
-
#endif
|
360
|
-
#else
|
361
|
-
#define HAVE_AT 0
|
362
|
-
static const char *wd_expand (struct tmpbuf *tmpbuf, eio_wd wd, const char *path);
|
363
|
-
#endif
|
364
|
-
|
365
|
-
struct eio_pwd
|
366
|
-
{
|
367
|
-
#if HAVE_AT
|
368
|
-
int fd;
|
369
|
-
#endif
|
370
|
-
int len;
|
371
|
-
char str[1]; /* actually, a 0-terminated canonical path */
|
372
|
-
};
|
373
|
-
|
374
|
-
/*****************************************************************************/
|
375
|
-
|
376
|
-
#define ETP_PRI_MIN EIO_PRI_MIN
|
377
|
-
#define ETP_PRI_MAX EIO_PRI_MAX
|
378
|
-
|
379
|
-
struct etp_worker;
|
380
|
-
|
381
|
-
#define ETP_REQ eio_req
|
382
|
-
#define ETP_DESTROY(req) eio_destroy (req)
|
383
|
-
static int eio_finish (eio_req *req);
|
384
|
-
#define ETP_FINISH(req) eio_finish (req)
|
385
|
-
static void eio_execute (struct etp_worker *self, eio_req *req);
|
386
|
-
#define ETP_EXECUTE(wrk,req) eio_execute (wrk,req)
|
387
|
-
|
388
|
-
/*****************************************************************************/
|
389
|
-
|
390
|
-
#define ETP_NUM_PRI (ETP_PRI_MAX - ETP_PRI_MIN + 1)
|
391
|
-
|
392
|
-
/* calculate time difference in ~1/EIO_TICKS of a second */
|
393
|
-
ecb_inline int
|
394
|
-
tvdiff (struct timeval *tv1, struct timeval *tv2)
|
395
|
-
{
|
396
|
-
return (tv2->tv_sec - tv1->tv_sec ) * EIO_TICKS
|
397
|
-
+ ((tv2->tv_usec - tv1->tv_usec) >> 10);
|
398
|
-
}
|
399
|
-
|
400
|
-
static unsigned int started, idle, wanted = 4;
|
401
|
-
|
402
|
-
static void (*want_poll_cb) (void);
|
403
|
-
static void (*done_poll_cb) (void);
|
404
|
-
|
405
|
-
static unsigned int max_poll_time; /* reslock */
|
406
|
-
static unsigned int max_poll_reqs; /* reslock */
|
407
|
-
|
408
|
-
static unsigned int nreqs; /* reqlock */
|
409
|
-
static unsigned int nready; /* reqlock */
|
410
|
-
static unsigned int npending; /* reqlock */
|
411
|
-
static unsigned int max_idle = 4; /* maximum number of threads that can idle indefinitely */
|
412
|
-
static unsigned int idle_timeout = 10; /* number of seconds after which an idle threads exit */
|
413
|
-
|
414
|
-
static xmutex_t wrklock;
|
415
|
-
static xmutex_t reslock;
|
416
|
-
static xmutex_t reqlock;
|
417
|
-
static xcond_t reqwait;
|
418
|
-
|
419
|
-
typedef struct etp_worker
|
420
|
-
{
|
421
|
-
struct tmpbuf tmpbuf;
|
422
|
-
|
423
|
-
/* locked by wrklock */
|
424
|
-
struct etp_worker *prev, *next;
|
425
|
-
|
426
|
-
xthread_t tid;
|
427
|
-
|
428
|
-
#ifdef ETP_WORKER_COMMON
|
429
|
-
ETP_WORKER_COMMON
|
430
|
-
#endif
|
431
|
-
} etp_worker;
|
432
|
-
|
433
|
-
static etp_worker wrk_first; /* NOT etp */
|
434
|
-
|
435
|
-
#define ETP_WORKER_LOCK(wrk) X_LOCK (wrklock)
|
436
|
-
#define ETP_WORKER_UNLOCK(wrk) X_UNLOCK (wrklock)
|
437
|
-
|
438
|
-
/* worker threads management */
|
439
|
-
|
440
|
-
static void
|
441
|
-
etp_worker_clear (etp_worker *wrk)
|
442
|
-
{
|
443
|
-
}
|
444
|
-
|
445
|
-
static void ecb_cold
|
446
|
-
etp_worker_free (etp_worker *wrk)
|
447
|
-
{
|
448
|
-
free (wrk->tmpbuf.ptr);
|
449
|
-
|
450
|
-
wrk->next->prev = wrk->prev;
|
451
|
-
wrk->prev->next = wrk->next;
|
452
|
-
|
453
|
-
free (wrk);
|
454
|
-
}
|
455
|
-
|
456
|
-
static unsigned int
|
457
|
-
etp_nreqs (void)
|
458
|
-
{
|
459
|
-
int retval;
|
460
|
-
if (WORDACCESS_UNSAFE) X_LOCK (reqlock);
|
461
|
-
retval = nreqs;
|
462
|
-
if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock);
|
463
|
-
return retval;
|
464
|
-
}
|
465
|
-
|
466
|
-
static unsigned int
|
467
|
-
etp_nready (void)
|
468
|
-
{
|
469
|
-
unsigned int retval;
|
470
|
-
|
471
|
-
if (WORDACCESS_UNSAFE) X_LOCK (reqlock);
|
472
|
-
retval = nready;
|
473
|
-
if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock);
|
474
|
-
|
475
|
-
return retval;
|
476
|
-
}
|
477
|
-
|
478
|
-
static unsigned int
|
479
|
-
etp_npending (void)
|
480
|
-
{
|
481
|
-
unsigned int retval;
|
482
|
-
|
483
|
-
if (WORDACCESS_UNSAFE) X_LOCK (reqlock);
|
484
|
-
retval = npending;
|
485
|
-
if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock);
|
486
|
-
|
487
|
-
return retval;
|
488
|
-
}
|
489
|
-
|
490
|
-
static unsigned int
|
491
|
-
etp_nthreads (void)
|
492
|
-
{
|
493
|
-
unsigned int retval;
|
494
|
-
|
495
|
-
if (WORDACCESS_UNSAFE) X_LOCK (reqlock);
|
496
|
-
retval = started;
|
497
|
-
if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock);
|
498
|
-
|
499
|
-
return retval;
|
500
|
-
}
|
501
|
-
|
502
|
-
/*
|
503
|
-
* a somewhat faster data structure might be nice, but
|
504
|
-
* with 8 priorities this actually needs <20 insns
|
505
|
-
* per shift, the most expensive operation.
|
506
|
-
*/
|
507
|
-
typedef struct {
|
508
|
-
ETP_REQ *qs[ETP_NUM_PRI], *qe[ETP_NUM_PRI]; /* qstart, qend */
|
509
|
-
int size;
|
510
|
-
} etp_reqq;
|
511
|
-
|
512
|
-
static etp_reqq req_queue;
|
513
|
-
static etp_reqq res_queue;
|
514
|
-
|
515
|
-
static void ecb_noinline ecb_cold
|
516
|
-
reqq_init (etp_reqq *q)
|
517
|
-
{
|
518
|
-
int pri;
|
519
|
-
|
520
|
-
for (pri = 0; pri < ETP_NUM_PRI; ++pri)
|
521
|
-
q->qs[pri] = q->qe[pri] = 0;
|
522
|
-
|
523
|
-
q->size = 0;
|
524
|
-
}
|
525
|
-
|
526
|
-
static int ecb_noinline
|
527
|
-
reqq_push (etp_reqq *q, ETP_REQ *req)
|
528
|
-
{
|
529
|
-
int pri = req->pri;
|
530
|
-
req->next = 0;
|
531
|
-
|
532
|
-
if (q->qe[pri])
|
533
|
-
{
|
534
|
-
q->qe[pri]->next = req;
|
535
|
-
q->qe[pri] = req;
|
536
|
-
}
|
537
|
-
else
|
538
|
-
q->qe[pri] = q->qs[pri] = req;
|
539
|
-
|
540
|
-
return q->size++;
|
541
|
-
}
|
542
|
-
|
543
|
-
static ETP_REQ * ecb_noinline
|
544
|
-
reqq_shift (etp_reqq *q)
|
545
|
-
{
|
546
|
-
int pri;
|
547
|
-
|
548
|
-
if (!q->size)
|
549
|
-
return 0;
|
550
|
-
|
551
|
-
--q->size;
|
552
|
-
|
553
|
-
for (pri = ETP_NUM_PRI; pri--; )
|
554
|
-
{
|
555
|
-
eio_req *req = q->qs[pri];
|
556
|
-
|
557
|
-
if (req)
|
558
|
-
{
|
559
|
-
if (!(q->qs[pri] = (eio_req *)req->next))
|
560
|
-
q->qe[pri] = 0;
|
561
|
-
|
562
|
-
return req;
|
563
|
-
}
|
564
|
-
}
|
565
|
-
|
566
|
-
abort ();
|
567
|
-
}
|
568
|
-
|
569
|
-
static int ecb_cold
|
570
|
-
etp_init (void (*want_poll)(void), void (*done_poll)(void))
|
571
|
-
{
|
572
|
-
X_MUTEX_CREATE (wrklock);
|
573
|
-
X_MUTEX_CREATE (reslock);
|
574
|
-
X_MUTEX_CREATE (reqlock);
|
575
|
-
X_COND_CREATE (reqwait);
|
576
|
-
|
577
|
-
reqq_init (&req_queue);
|
578
|
-
reqq_init (&res_queue);
|
579
|
-
|
580
|
-
wrk_first.next =
|
581
|
-
wrk_first.prev = &wrk_first;
|
582
|
-
|
583
|
-
started = 0;
|
584
|
-
idle = 0;
|
585
|
-
nreqs = 0;
|
586
|
-
nready = 0;
|
587
|
-
npending = 0;
|
588
|
-
|
589
|
-
want_poll_cb = want_poll;
|
590
|
-
done_poll_cb = done_poll;
|
591
|
-
|
592
|
-
return 0;
|
593
|
-
}
|
594
|
-
|
595
|
-
static void ecb_cold etp_end_thread (void);
|
596
|
-
|
597
|
-
static int
|
598
|
-
etp_deinit ()
|
599
|
-
{
|
600
|
-
while (started > 0)
|
601
|
-
etp_end_thread ();
|
602
|
-
|
603
|
-
return 0;
|
604
|
-
}
|
605
|
-
|
606
|
-
X_THREAD_PROC (etp_proc);
|
607
|
-
|
608
|
-
static void ecb_cold
|
609
|
-
etp_start_thread (void)
|
610
|
-
{
|
611
|
-
etp_worker *wrk = calloc (1, sizeof (etp_worker));
|
612
|
-
|
613
|
-
/*TODO*/
|
614
|
-
assert (("unable to allocate worker thread data", wrk));
|
615
|
-
|
616
|
-
X_LOCK (wrklock);
|
617
|
-
|
618
|
-
if (xthread_create (&wrk->tid, etp_proc, (void *)wrk))
|
619
|
-
{
|
620
|
-
wrk->prev = &wrk_first;
|
621
|
-
wrk->next = wrk_first.next;
|
622
|
-
wrk_first.next->prev = wrk;
|
623
|
-
wrk_first.next = wrk;
|
624
|
-
++started;
|
625
|
-
}
|
626
|
-
else
|
627
|
-
free (wrk);
|
628
|
-
|
629
|
-
X_UNLOCK (wrklock);
|
630
|
-
}
|
631
|
-
|
632
|
-
static void
|
633
|
-
etp_maybe_start_thread (void)
|
634
|
-
{
|
635
|
-
if (ecb_expect_true (etp_nthreads () >= wanted))
|
636
|
-
return;
|
637
|
-
|
638
|
-
/* todo: maybe use idle here, but might be less exact */
|
639
|
-
if (ecb_expect_true (0 <= (int)etp_nthreads () + (int)etp_npending () - (int)etp_nreqs ()))
|
640
|
-
return;
|
641
|
-
|
642
|
-
etp_start_thread ();
|
643
|
-
}
|
644
|
-
|
645
|
-
static void ecb_cold
|
646
|
-
etp_end_thread (void)
|
647
|
-
{
|
648
|
-
eio_req *req = calloc (1, sizeof (eio_req)); /* will be freed by worker */
|
649
|
-
|
650
|
-
req->type = -1;
|
651
|
-
req->pri = ETP_PRI_MAX - ETP_PRI_MIN;
|
652
|
-
|
653
|
-
X_LOCK (reqlock);
|
654
|
-
reqq_push (&req_queue, req);
|
655
|
-
X_COND_SIGNAL (reqwait);
|
656
|
-
X_UNLOCK (reqlock);
|
657
|
-
|
658
|
-
X_LOCK (wrklock);
|
659
|
-
--started;
|
660
|
-
X_UNLOCK (wrklock);
|
661
|
-
}
|
662
|
-
|
663
|
-
static int
|
664
|
-
etp_poll (void)
|
665
|
-
{
|
666
|
-
unsigned int maxreqs;
|
667
|
-
unsigned int maxtime;
|
668
|
-
struct timeval tv_start, tv_now;
|
669
|
-
|
670
|
-
X_LOCK (reslock);
|
671
|
-
maxreqs = max_poll_reqs;
|
672
|
-
maxtime = max_poll_time;
|
673
|
-
X_UNLOCK (reslock);
|
674
|
-
|
675
|
-
if (maxtime)
|
676
|
-
gettimeofday (&tv_start, 0);
|
677
|
-
|
678
|
-
for (;;)
|
679
|
-
{
|
680
|
-
ETP_REQ *req;
|
681
|
-
|
682
|
-
etp_maybe_start_thread ();
|
683
|
-
|
684
|
-
X_LOCK (reslock);
|
685
|
-
req = reqq_shift (&res_queue);
|
686
|
-
|
687
|
-
if (req)
|
688
|
-
{
|
689
|
-
--npending;
|
690
|
-
|
691
|
-
if (!res_queue.size && done_poll_cb)
|
692
|
-
done_poll_cb ();
|
693
|
-
}
|
694
|
-
|
695
|
-
X_UNLOCK (reslock);
|
696
|
-
|
697
|
-
if (!req)
|
698
|
-
return 0;
|
699
|
-
|
700
|
-
X_LOCK (reqlock);
|
701
|
-
--nreqs;
|
702
|
-
X_UNLOCK (reqlock);
|
703
|
-
|
704
|
-
if (ecb_expect_false (req->type == EIO_GROUP && req->size))
|
705
|
-
{
|
706
|
-
req->int1 = 1; /* mark request as delayed */
|
707
|
-
continue;
|
708
|
-
}
|
709
|
-
else
|
710
|
-
{
|
711
|
-
int res = ETP_FINISH (req);
|
712
|
-
if (ecb_expect_false (res))
|
713
|
-
return res;
|
714
|
-
}
|
715
|
-
|
716
|
-
if (ecb_expect_false (maxreqs && !--maxreqs))
|
717
|
-
break;
|
718
|
-
|
719
|
-
if (maxtime)
|
720
|
-
{
|
721
|
-
gettimeofday (&tv_now, 0);
|
722
|
-
|
723
|
-
if (tvdiff (&tv_start, &tv_now) >= maxtime)
|
724
|
-
break;
|
725
|
-
}
|
726
|
-
}
|
727
|
-
|
728
|
-
errno = EAGAIN;
|
729
|
-
return -1;
|
730
|
-
}
|
731
|
-
|
732
|
-
static void
|
733
|
-
etp_cancel (ETP_REQ *req)
|
734
|
-
{
|
735
|
-
req->cancelled = 1;
|
736
|
-
|
737
|
-
eio_grp_cancel (req);
|
738
|
-
}
|
739
|
-
|
740
|
-
static void
|
741
|
-
etp_submit (ETP_REQ *req)
|
742
|
-
{
|
743
|
-
req->pri -= ETP_PRI_MIN;
|
744
|
-
|
745
|
-
if (ecb_expect_false (req->pri < ETP_PRI_MIN - ETP_PRI_MIN)) req->pri = ETP_PRI_MIN - ETP_PRI_MIN;
|
746
|
-
if (ecb_expect_false (req->pri > ETP_PRI_MAX - ETP_PRI_MIN)) req->pri = ETP_PRI_MAX - ETP_PRI_MIN;
|
747
|
-
|
748
|
-
if (ecb_expect_false (req->type == EIO_GROUP))
|
749
|
-
{
|
750
|
-
/* I hope this is worth it :/ */
|
751
|
-
X_LOCK (reqlock);
|
752
|
-
++nreqs;
|
753
|
-
X_UNLOCK (reqlock);
|
754
|
-
|
755
|
-
X_LOCK (reslock);
|
756
|
-
|
757
|
-
++npending;
|
758
|
-
|
759
|
-
if (!reqq_push (&res_queue, req) && want_poll_cb)
|
760
|
-
want_poll_cb ();
|
761
|
-
|
762
|
-
X_UNLOCK (reslock);
|
763
|
-
}
|
764
|
-
else
|
765
|
-
{
|
766
|
-
X_LOCK (reqlock);
|
767
|
-
++nreqs;
|
768
|
-
++nready;
|
769
|
-
reqq_push (&req_queue, req);
|
770
|
-
X_COND_SIGNAL (reqwait);
|
771
|
-
X_UNLOCK (reqlock);
|
772
|
-
|
773
|
-
etp_maybe_start_thread ();
|
774
|
-
}
|
775
|
-
}
|
776
|
-
|
777
|
-
static void ecb_cold
|
778
|
-
etp_set_max_poll_time (double nseconds)
|
779
|
-
{
|
780
|
-
if (WORDACCESS_UNSAFE) X_LOCK (reslock);
|
781
|
-
max_poll_time = nseconds * EIO_TICKS;
|
782
|
-
if (WORDACCESS_UNSAFE) X_UNLOCK (reslock);
|
783
|
-
}
|
784
|
-
|
785
|
-
static void ecb_cold
|
786
|
-
etp_set_max_poll_reqs (unsigned int maxreqs)
|
787
|
-
{
|
788
|
-
if (WORDACCESS_UNSAFE) X_LOCK (reslock);
|
789
|
-
max_poll_reqs = maxreqs;
|
790
|
-
if (WORDACCESS_UNSAFE) X_UNLOCK (reslock);
|
791
|
-
}
|
792
|
-
|
793
|
-
static void ecb_cold
|
794
|
-
etp_set_max_idle (unsigned int nthreads)
|
795
|
-
{
|
796
|
-
if (WORDACCESS_UNSAFE) X_LOCK (reqlock);
|
797
|
-
max_idle = nthreads;
|
798
|
-
if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock);
|
799
|
-
}
|
800
|
-
|
801
|
-
static void ecb_cold
|
802
|
-
etp_set_idle_timeout (unsigned int seconds)
|
803
|
-
{
|
804
|
-
if (WORDACCESS_UNSAFE) X_LOCK (reqlock);
|
805
|
-
idle_timeout = seconds;
|
806
|
-
if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock);
|
807
|
-
}
|
808
|
-
|
809
|
-
static void ecb_cold
|
810
|
-
etp_set_min_parallel (unsigned int nthreads)
|
811
|
-
{
|
812
|
-
if (wanted < nthreads)
|
813
|
-
wanted = nthreads;
|
814
|
-
}
|
815
|
-
|
816
|
-
static void ecb_cold
|
817
|
-
etp_set_max_parallel (unsigned int nthreads)
|
818
|
-
{
|
819
|
-
if (wanted > nthreads)
|
820
|
-
wanted = nthreads;
|
821
|
-
|
822
|
-
while (started > wanted)
|
823
|
-
etp_end_thread ();
|
824
|
-
}
|
825
|
-
|
826
|
-
/*****************************************************************************/
|
827
|
-
|
828
|
-
static void
|
829
|
-
grp_try_feed (eio_req *grp)
|
830
|
-
{
|
831
|
-
while (grp->size < grp->int2 && !EIO_CANCELLED (grp))
|
832
|
-
{
|
833
|
-
grp->flags &= ~EIO_FLAG_GROUPADD;
|
834
|
-
|
835
|
-
EIO_FEED (grp);
|
836
|
-
|
837
|
-
/* stop if no progress has been made */
|
838
|
-
if (!(grp->flags & EIO_FLAG_GROUPADD))
|
839
|
-
{
|
840
|
-
grp->feed = 0;
|
841
|
-
break;
|
842
|
-
}
|
843
|
-
}
|
844
|
-
}
|
845
|
-
|
846
|
-
static int
|
847
|
-
grp_dec (eio_req *grp)
|
848
|
-
{
|
849
|
-
--grp->size;
|
850
|
-
|
851
|
-
/* call feeder, if applicable */
|
852
|
-
grp_try_feed (grp);
|
853
|
-
|
854
|
-
/* finish, if done */
|
855
|
-
if (!grp->size && grp->int1)
|
856
|
-
return eio_finish (grp);
|
857
|
-
else
|
858
|
-
return 0;
|
859
|
-
}
|
860
|
-
|
861
|
-
static void
|
862
|
-
eio_destroy (eio_req *req)
|
863
|
-
{
|
864
|
-
if ((req)->flags & EIO_FLAG_PTR1_FREE) free (req->ptr1);
|
865
|
-
if ((req)->flags & EIO_FLAG_PTR2_FREE) free (req->ptr2);
|
866
|
-
|
867
|
-
EIO_DESTROY (req);
|
868
|
-
}
|
869
|
-
|
870
|
-
static int
|
871
|
-
eio_finish (eio_req *req)
|
872
|
-
{
|
873
|
-
int res = EIO_FINISH (req);
|
874
|
-
|
875
|
-
if (req->grp)
|
876
|
-
{
|
877
|
-
int res2;
|
878
|
-
eio_req *grp = req->grp;
|
879
|
-
|
880
|
-
/* unlink request */
|
881
|
-
if (req->grp_next) req->grp_next->grp_prev = req->grp_prev;
|
882
|
-
if (req->grp_prev) req->grp_prev->grp_next = req->grp_next;
|
883
|
-
|
884
|
-
if (grp->grp_first == req)
|
885
|
-
grp->grp_first = req->grp_next;
|
886
|
-
|
887
|
-
res2 = grp_dec (grp);
|
888
|
-
|
889
|
-
if (!res)
|
890
|
-
res = res2;
|
891
|
-
}
|
892
|
-
|
893
|
-
eio_destroy (req);
|
894
|
-
|
895
|
-
return res;
|
896
|
-
}
|
897
|
-
|
898
|
-
void
|
899
|
-
eio_grp_cancel (eio_req *grp)
|
900
|
-
{
|
901
|
-
for (grp = grp->grp_first; grp; grp = grp->grp_next)
|
902
|
-
eio_cancel (grp);
|
903
|
-
}
|
904
|
-
|
905
|
-
void
|
906
|
-
eio_cancel (eio_req *req)
|
907
|
-
{
|
908
|
-
etp_cancel (req);
|
909
|
-
}
|
910
|
-
|
911
|
-
void
|
912
|
-
eio_submit (eio_req *req)
|
913
|
-
{
|
914
|
-
etp_submit (req);
|
915
|
-
}
|
916
|
-
|
917
|
-
unsigned int
|
918
|
-
eio_nreqs (void)
|
919
|
-
{
|
920
|
-
return etp_nreqs ();
|
921
|
-
}
|
922
|
-
|
923
|
-
unsigned int
|
924
|
-
eio_nready (void)
|
925
|
-
{
|
926
|
-
return etp_nready ();
|
927
|
-
}
|
928
|
-
|
929
|
-
unsigned int
|
930
|
-
eio_npending (void)
|
931
|
-
{
|
932
|
-
return etp_npending ();
|
933
|
-
}
|
934
|
-
|
935
|
-
unsigned int ecb_cold
|
936
|
-
eio_nthreads (void)
|
937
|
-
{
|
938
|
-
return etp_nthreads ();
|
939
|
-
}
|
940
|
-
|
941
|
-
void ecb_cold
|
942
|
-
eio_set_max_poll_time (double nseconds)
|
943
|
-
{
|
944
|
-
etp_set_max_poll_time (nseconds);
|
945
|
-
}
|
946
|
-
|
947
|
-
void ecb_cold
|
948
|
-
eio_set_max_poll_reqs (unsigned int maxreqs)
|
949
|
-
{
|
950
|
-
etp_set_max_poll_reqs (maxreqs);
|
951
|
-
}
|
952
|
-
|
953
|
-
void ecb_cold
|
954
|
-
eio_set_max_idle (unsigned int nthreads)
|
955
|
-
{
|
956
|
-
etp_set_max_idle (nthreads);
|
957
|
-
}
|
958
|
-
|
959
|
-
void ecb_cold
|
960
|
-
eio_set_idle_timeout (unsigned int seconds)
|
961
|
-
{
|
962
|
-
etp_set_idle_timeout (seconds);
|
963
|
-
}
|
964
|
-
|
965
|
-
void ecb_cold
|
966
|
-
eio_set_min_parallel (unsigned int nthreads)
|
967
|
-
{
|
968
|
-
etp_set_min_parallel (nthreads);
|
969
|
-
}
|
970
|
-
|
971
|
-
void ecb_cold
|
972
|
-
eio_set_max_parallel (unsigned int nthreads)
|
973
|
-
{
|
974
|
-
etp_set_max_parallel (nthreads);
|
975
|
-
}
|
976
|
-
|
977
|
-
int eio_poll (void)
|
978
|
-
{
|
979
|
-
return etp_poll ();
|
980
|
-
}
|
981
|
-
|
982
|
-
/*****************************************************************************/
|
983
|
-
/* work around various missing functions */
|
984
|
-
|
985
|
-
#ifndef HAVE_UTIMES
|
986
|
-
|
987
|
-
# undef utimes
|
988
|
-
# define utimes(path,times) eio__utimes (path, times)
|
989
|
-
|
990
|
-
static int
|
991
|
-
eio__utimes (const char *filename, const struct timeval times[2])
|
992
|
-
{
|
993
|
-
if (times)
|
994
|
-
{
|
995
|
-
struct utimbuf buf;
|
996
|
-
|
997
|
-
buf.actime = times[0].tv_sec;
|
998
|
-
buf.modtime = times[1].tv_sec;
|
999
|
-
|
1000
|
-
return utime (filename, &buf);
|
1001
|
-
}
|
1002
|
-
else
|
1003
|
-
return utime (filename, 0);
|
1004
|
-
}
|
1005
|
-
|
1006
|
-
#endif
|
1007
|
-
|
1008
|
-
#ifndef HAVE_FUTIMES
|
1009
|
-
|
1010
|
-
# undef futimes
|
1011
|
-
# define futimes(fd,times) eio__futimes (fd, times)
|
1012
|
-
|
1013
|
-
static int
|
1014
|
-
eio__futimes (int fd, const struct timeval tv[2])
|
1015
|
-
{
|
1016
|
-
errno = ENOSYS;
|
1017
|
-
return -1;
|
1018
|
-
}
|
1019
|
-
|
1020
|
-
#endif
|
1021
|
-
|
1022
|
-
#if !HAVE_FDATASYNC
|
1023
|
-
# undef fdatasync
|
1024
|
-
# define fdatasync(fd) fsync (fd)
|
1025
|
-
#endif
|
1026
|
-
|
1027
|
-
static int
|
1028
|
-
eio__syncfs (int fd)
|
1029
|
-
{
|
1030
|
-
int res;
|
1031
|
-
|
1032
|
-
#if HAVE_SYS_SYNCFS
|
1033
|
-
res = (int)syscall (__NR_syncfs, (int)(fd));
|
1034
|
-
#else
|
1035
|
-
res = EIO_ENOSYS ();
|
1036
|
-
#endif
|
1037
|
-
|
1038
|
-
if (res < 0 && errno == ENOSYS && fd >= 0)
|
1039
|
-
sync ();
|
1040
|
-
|
1041
|
-
return res;
|
1042
|
-
}
|
1043
|
-
|
1044
|
-
/* sync_file_range always needs emulation */
|
1045
|
-
static int
|
1046
|
-
eio__sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags)
|
1047
|
-
{
|
1048
|
-
#if HAVE_SYNC_FILE_RANGE
|
1049
|
-
int res;
|
1050
|
-
|
1051
|
-
if (EIO_SYNC_FILE_RANGE_WAIT_BEFORE != SYNC_FILE_RANGE_WAIT_BEFORE
|
1052
|
-
|| EIO_SYNC_FILE_RANGE_WRITE != SYNC_FILE_RANGE_WRITE
|
1053
|
-
|| EIO_SYNC_FILE_RANGE_WAIT_AFTER != SYNC_FILE_RANGE_WAIT_AFTER)
|
1054
|
-
{
|
1055
|
-
flags = 0
|
1056
|
-
| (flags & EIO_SYNC_FILE_RANGE_WAIT_BEFORE ? SYNC_FILE_RANGE_WAIT_BEFORE : 0)
|
1057
|
-
| (flags & EIO_SYNC_FILE_RANGE_WRITE ? SYNC_FILE_RANGE_WRITE : 0)
|
1058
|
-
| (flags & EIO_SYNC_FILE_RANGE_WAIT_AFTER ? SYNC_FILE_RANGE_WAIT_AFTER : 0);
|
1059
|
-
}
|
1060
|
-
|
1061
|
-
res = sync_file_range (fd, offset, nbytes, flags);
|
1062
|
-
|
1063
|
-
if (!res || errno != ENOSYS)
|
1064
|
-
return res;
|
1065
|
-
#endif
|
1066
|
-
|
1067
|
-
/* even though we could play tricks with the flags, it's better to always
|
1068
|
-
* call fdatasync, as that matches the expectation of its users best */
|
1069
|
-
return fdatasync (fd);
|
1070
|
-
}
|
1071
|
-
|
1072
|
-
static int
|
1073
|
-
eio__fallocate (int fd, int mode, off_t offset, size_t len)
|
1074
|
-
{
|
1075
|
-
#if HAVE_LINUX_FALLOCATE
|
1076
|
-
return fallocate (fd, mode, offset, len);
|
1077
|
-
#else
|
1078
|
-
return EIO_ENOSYS ();
|
1079
|
-
#endif
|
1080
|
-
}
|
1081
|
-
|
1082
|
-
#if !HAVE_READAHEAD
|
1083
|
-
# undef readahead
|
1084
|
-
# define readahead(fd,offset,count) eio__readahead (fd, offset, count, self)
|
1085
|
-
|
1086
|
-
static eio_ssize_t
|
1087
|
-
eio__readahead (int fd, off_t offset, size_t count, etp_worker *self)
|
1088
|
-
{
|
1089
|
-
size_t todo = count;
|
1090
|
-
dBUF;
|
1091
|
-
|
1092
|
-
while (todo > 0)
|
1093
|
-
{
|
1094
|
-
size_t len = todo < EIO_BUFSIZE ? todo : EIO_BUFSIZE;
|
1095
|
-
|
1096
|
-
pread (fd, eio_buf, len, offset);
|
1097
|
-
offset += len;
|
1098
|
-
todo -= len;
|
1099
|
-
}
|
1100
|
-
|
1101
|
-
FUBd;
|
1102
|
-
|
1103
|
-
/* linux's readahead basically only fails for EBADF or EINVAL (not mmappable) */
|
1104
|
-
/* but not for e.g. EIO or eof, so we also never fail */
|
1105
|
-
return 0;
|
1106
|
-
}
|
1107
|
-
|
1108
|
-
#endif
|
1109
|
-
|
1110
|
-
/* sendfile always needs emulation */
|
1111
|
-
static eio_ssize_t
|
1112
|
-
eio__sendfile (int ofd, int ifd, off_t offset, size_t count)
|
1113
|
-
{
|
1114
|
-
eio_ssize_t written = 0;
|
1115
|
-
eio_ssize_t res;
|
1116
|
-
|
1117
|
-
if (!count)
|
1118
|
-
return 0;
|
1119
|
-
|
1120
|
-
for (;;)
|
1121
|
-
{
|
1122
|
-
#ifdef __APPLE__
|
1123
|
-
# undef HAVE_SENDFILE /* broken, as everything on os x */
|
1124
|
-
#endif
|
1125
|
-
#if HAVE_SENDFILE
|
1126
|
-
# if __linux
|
1127
|
-
off_t soffset = offset;
|
1128
|
-
res = sendfile (ofd, ifd, &soffset, count);
|
1129
|
-
|
1130
|
-
# elif __FreeBSD__
|
1131
|
-
/*
|
1132
|
-
* Of course, the freebsd sendfile is a dire hack with no thoughts
|
1133
|
-
* wasted on making it similar to other I/O functions.
|
1134
|
-
*/
|
1135
|
-
off_t sbytes;
|
1136
|
-
res = sendfile (ifd, ofd, offset, count, 0, &sbytes, 0);
|
1137
|
-
|
1138
|
-
#if 0 /* according to the manpage, this is correct, but broken behaviour */
|
1139
|
-
/* freebsd' sendfile will return 0 on success */
|
1140
|
-
/* freebsd 8 documents it as only setting *sbytes on EINTR and EAGAIN, but */
|
1141
|
-
/* not on e.g. EIO or EPIPE - sounds broken */
|
1142
|
-
if ((res < 0 && (errno == EAGAIN || errno == EINTR) && sbytes) || res == 0)
|
1143
|
-
res = sbytes;
|
1144
|
-
#endif
|
1145
|
-
|
1146
|
-
/* according to source inspection, this is correct, and useful behaviour */
|
1147
|
-
if (sbytes)
|
1148
|
-
res = sbytes;
|
1149
|
-
|
1150
|
-
# elif defined __APPLE__
|
1151
|
-
off_t sbytes = count;
|
1152
|
-
res = sendfile (ifd, ofd, offset, &sbytes, 0, 0);
|
1153
|
-
|
1154
|
-
/* according to the manpage, sbytes is always valid */
|
1155
|
-
if (sbytes)
|
1156
|
-
res = sbytes;
|
1157
|
-
|
1158
|
-
# elif __hpux
|
1159
|
-
res = sendfile (ofd, ifd, offset, count, 0, 0);
|
1160
|
-
|
1161
|
-
# elif __solaris
|
1162
|
-
struct sendfilevec vec;
|
1163
|
-
size_t sbytes;
|
1164
|
-
|
1165
|
-
vec.sfv_fd = ifd;
|
1166
|
-
vec.sfv_flag = 0;
|
1167
|
-
vec.sfv_off = offset;
|
1168
|
-
vec.sfv_len = count;
|
1169
|
-
|
1170
|
-
res = sendfilev (ofd, &vec, 1, &sbytes);
|
1171
|
-
|
1172
|
-
if (res < 0 && sbytes)
|
1173
|
-
res = sbytes;
|
1174
|
-
|
1175
|
-
# endif
|
1176
|
-
|
1177
|
-
#elif defined (_WIN32) && 0
|
1178
|
-
/* does not work, just for documentation of what would need to be done */
|
1179
|
-
/* actually, cannot be done like this, as TransmitFile changes the file offset, */
|
1180
|
-
/* libeio guarantees that the file offset does not change, and windows */
|
1181
|
-
/* has no way to get an independent handle to the same file description */
|
1182
|
-
HANDLE h = TO_SOCKET (ifd);
|
1183
|
-
SetFilePointer (h, offset, 0, FILE_BEGIN);
|
1184
|
-
res = TransmitFile (TO_SOCKET (ofd), h, count, 0, 0, 0, 0);
|
1185
|
-
|
1186
|
-
#else
|
1187
|
-
res = EIO_ENOSYS ();
|
1188
|
-
#endif
|
1189
|
-
|
1190
|
-
/* we assume sendfile can copy at least 128mb in one go */
|
1191
|
-
if (res <= 128 * 1024 * 1024)
|
1192
|
-
{
|
1193
|
-
if (res > 0)
|
1194
|
-
written += res;
|
1195
|
-
|
1196
|
-
if (written)
|
1197
|
-
return written;
|
1198
|
-
|
1199
|
-
break;
|
1200
|
-
}
|
1201
|
-
else
|
1202
|
-
{
|
1203
|
-
/* if we requested more, then probably the kernel was lazy */
|
1204
|
-
written += res;
|
1205
|
-
offset += res;
|
1206
|
-
count -= res;
|
1207
|
-
|
1208
|
-
if (!count)
|
1209
|
-
return written;
|
1210
|
-
}
|
1211
|
-
}
|
1212
|
-
|
1213
|
-
if (res < 0
|
1214
|
-
&& (errno == ENOSYS || errno == EINVAL || errno == ENOTSOCK
|
1215
|
-
/* BSDs */
|
1216
|
-
#ifdef ENOTSUP /* sigh, if the steenking pile called openbsd would only try to at least compile posix code... */
|
1217
|
-
|| errno == ENOTSUP
|
1218
|
-
#endif
|
1219
|
-
#ifdef EOPNOTSUPP /* windows */
|
1220
|
-
|| errno == EOPNOTSUPP /* BSDs */
|
1221
|
-
#endif
|
1222
|
-
#if __solaris
|
1223
|
-
|| errno == EAFNOSUPPORT || errno == EPROTOTYPE
|
1224
|
-
#endif
|
1225
|
-
)
|
1226
|
-
)
|
1227
|
-
{
|
1228
|
-
/* emulate sendfile. this is a major pain in the ass */
|
1229
|
-
dBUF;
|
1230
|
-
|
1231
|
-
res = 0;
|
1232
|
-
|
1233
|
-
while (count)
|
1234
|
-
{
|
1235
|
-
eio_ssize_t cnt;
|
1236
|
-
|
1237
|
-
cnt = pread (ifd, eio_buf, count > EIO_BUFSIZE ? EIO_BUFSIZE : count, offset);
|
1238
|
-
|
1239
|
-
if (cnt <= 0)
|
1240
|
-
{
|
1241
|
-
if (cnt && !res) res = -1;
|
1242
|
-
break;
|
1243
|
-
}
|
1244
|
-
|
1245
|
-
cnt = write (ofd, eio_buf, cnt);
|
1246
|
-
|
1247
|
-
if (cnt <= 0)
|
1248
|
-
{
|
1249
|
-
if (cnt && !res) res = -1;
|
1250
|
-
break;
|
1251
|
-
}
|
1252
|
-
|
1253
|
-
offset += cnt;
|
1254
|
-
res += cnt;
|
1255
|
-
count -= cnt;
|
1256
|
-
}
|
1257
|
-
|
1258
|
-
FUBd;
|
1259
|
-
}
|
1260
|
-
|
1261
|
-
return res;
|
1262
|
-
}
|
1263
|
-
|
1264
|
-
#ifdef PAGESIZE
|
1265
|
-
# define eio_pagesize() PAGESIZE
|
1266
|
-
#else
|
1267
|
-
static intptr_t
|
1268
|
-
eio_pagesize (void)
|
1269
|
-
{
|
1270
|
-
static intptr_t page;
|
1271
|
-
|
1272
|
-
if (!page)
|
1273
|
-
page = sysconf (_SC_PAGESIZE);
|
1274
|
-
|
1275
|
-
return page;
|
1276
|
-
}
|
1277
|
-
#endif
|
1278
|
-
|
1279
|
-
static void
|
1280
|
-
eio_page_align (void **addr, size_t *length)
|
1281
|
-
{
|
1282
|
-
intptr_t mask = eio_pagesize () - 1;
|
1283
|
-
|
1284
|
-
/* round down addr */
|
1285
|
-
intptr_t adj = mask & (intptr_t)*addr;
|
1286
|
-
|
1287
|
-
*addr = (void *)((intptr_t)*addr - adj);
|
1288
|
-
*length += adj;
|
1289
|
-
|
1290
|
-
/* round up length */
|
1291
|
-
*length = (*length + mask) & ~mask;
|
1292
|
-
}
|
1293
|
-
|
1294
|
-
#if !_POSIX_MEMLOCK
|
1295
|
-
# define eio__mlockall(a) EIO_ENOSYS ()
|
1296
|
-
#else
|
1297
|
-
|
1298
|
-
static int
|
1299
|
-
eio__mlockall (int flags)
|
1300
|
-
{
|
1301
|
-
#if __GLIBC__ == 2 && __GLIBC_MINOR__ <= 7
|
1302
|
-
extern int mallopt (int, int);
|
1303
|
-
mallopt (-6, 238); /* http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=473812 */
|
1304
|
-
#endif
|
1305
|
-
|
1306
|
-
if (EIO_MCL_CURRENT != MCL_CURRENT
|
1307
|
-
|| EIO_MCL_FUTURE != MCL_FUTURE)
|
1308
|
-
{
|
1309
|
-
flags = 0
|
1310
|
-
| (flags & EIO_MCL_CURRENT ? MCL_CURRENT : 0)
|
1311
|
-
| (flags & EIO_MCL_FUTURE ? MCL_FUTURE : 0);
|
1312
|
-
}
|
1313
|
-
|
1314
|
-
return mlockall (flags);
|
1315
|
-
}
|
1316
|
-
#endif
|
1317
|
-
|
1318
|
-
#if !_POSIX_MEMLOCK_RANGE
|
1319
|
-
# define eio__mlock(a,b) EIO_ENOSYS ()
|
1320
|
-
#else
|
1321
|
-
|
1322
|
-
static int
|
1323
|
-
eio__mlock (void *addr, size_t length)
|
1324
|
-
{
|
1325
|
-
eio_page_align (&addr, &length);
|
1326
|
-
|
1327
|
-
return mlock (addr, length);
|
1328
|
-
}
|
1329
|
-
|
1330
|
-
#endif
|
1331
|
-
|
1332
|
-
#if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO)
|
1333
|
-
# define eio__msync(a,b,c) EIO_ENOSYS ()
|
1334
|
-
#else
|
1335
|
-
|
1336
|
-
static int
|
1337
|
-
eio__msync (void *mem, size_t len, int flags)
|
1338
|
-
{
|
1339
|
-
eio_page_align (&mem, &len);
|
1340
|
-
|
1341
|
-
if (EIO_MS_ASYNC != MS_SYNC
|
1342
|
-
|| EIO_MS_INVALIDATE != MS_INVALIDATE
|
1343
|
-
|| EIO_MS_SYNC != MS_SYNC)
|
1344
|
-
{
|
1345
|
-
flags = 0
|
1346
|
-
| (flags & EIO_MS_ASYNC ? MS_ASYNC : 0)
|
1347
|
-
| (flags & EIO_MS_INVALIDATE ? MS_INVALIDATE : 0)
|
1348
|
-
| (flags & EIO_MS_SYNC ? MS_SYNC : 0);
|
1349
|
-
}
|
1350
|
-
|
1351
|
-
return msync (mem, len, flags);
|
1352
|
-
}
|
1353
|
-
|
1354
|
-
#endif
|
1355
|
-
|
1356
|
-
static int
|
1357
|
-
eio__mtouch (eio_req *req)
|
1358
|
-
{
|
1359
|
-
void *mem = req->ptr2;
|
1360
|
-
size_t len = req->size;
|
1361
|
-
int flags = req->int1;
|
1362
|
-
|
1363
|
-
eio_page_align (&mem, &len);
|
1364
|
-
|
1365
|
-
{
|
1366
|
-
intptr_t addr = (intptr_t)mem;
|
1367
|
-
intptr_t end = addr + len;
|
1368
|
-
intptr_t page = eio_pagesize ();
|
1369
|
-
|
1370
|
-
if (addr < end)
|
1371
|
-
if (flags & EIO_MT_MODIFY) /* modify */
|
1372
|
-
do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len && !EIO_CANCELLED (req));
|
1373
|
-
else
|
1374
|
-
do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len && !EIO_CANCELLED (req));
|
1375
|
-
}
|
1376
|
-
|
1377
|
-
return 0;
|
1378
|
-
}
|
1379
|
-
|
1380
|
-
/*****************************************************************************/
|
1381
|
-
/* requests implemented outside eio_execute, because they are so large */
|
1382
|
-
|
1383
|
-
static void
|
1384
|
-
eio__lseek (eio_req *req)
|
1385
|
-
{
|
1386
|
-
/* this usually gets optimised away completely, or your compiler sucks, */
|
1387
|
-
/* or the whence constants really are not 0, 1, 2 */
|
1388
|
-
int whence = req->int2 == EIO_SEEK_SET ? SEEK_SET
|
1389
|
-
: req->int2 == EIO_SEEK_CUR ? SEEK_CUR
|
1390
|
-
: req->int2 == EIO_SEEK_END ? SEEK_END
|
1391
|
-
: req->int2;
|
1392
|
-
|
1393
|
-
req->offs = lseek (req->int1, req->offs, whence);
|
1394
|
-
req->result = req->offs == (off_t)-1 ? -1 : 0;
|
1395
|
-
}
|
1396
|
-
|
1397
|
-
/* result will always end up in tmpbuf, there is always space for adding a 0-byte */
|
1398
|
-
static int
|
1399
|
-
eio__realpath (struct tmpbuf *tmpbuf, eio_wd wd, const char *path)
|
1400
|
-
{
|
1401
|
-
const char *rel = path;
|
1402
|
-
char *res;
|
1403
|
-
char *tmp1, *tmp2;
|
1404
|
-
#if SYMLOOP_MAX > 32
|
1405
|
-
int symlinks = SYMLOOP_MAX;
|
1406
|
-
#else
|
1407
|
-
int symlinks = 32;
|
1408
|
-
#endif
|
1409
|
-
|
1410
|
-
errno = EINVAL;
|
1411
|
-
if (!rel)
|
1412
|
-
return -1;
|
1413
|
-
|
1414
|
-
errno = ENOENT;
|
1415
|
-
if (!*rel)
|
1416
|
-
return -1;
|
1417
|
-
|
1418
|
-
res = tmpbuf_get (tmpbuf, PATH_MAX * 3);
|
1419
|
-
tmp1 = res + PATH_MAX;
|
1420
|
-
tmp2 = tmp1 + PATH_MAX;
|
1421
|
-
|
1422
|
-
#if 0 /* disabled, the musl way to do things is just too racy */
|
1423
|
-
#if __linux && defined(O_NONBLOCK) && defined(O_NOATIME)
|
1424
|
-
/* on linux we may be able to ask the kernel */
|
1425
|
-
{
|
1426
|
-
int fd = open (rel, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_NOATIME);
|
1427
|
-
|
1428
|
-
if (fd >= 0)
|
1429
|
-
{
|
1430
|
-
sprintf (tmp1, "/proc/self/fd/%d", fd);
|
1431
|
-
req->result = readlink (tmp1, res, PATH_MAX);
|
1432
|
-
close (fd);
|
1433
|
-
|
1434
|
-
/* here we should probably stat the open file and the disk file, to make sure they still match */
|
1435
|
-
|
1436
|
-
if (req->result > 0)
|
1437
|
-
goto done;
|
1438
|
-
}
|
1439
|
-
else if (errno == ELOOP || errno == ENAMETOOLONG || errno == ENOENT || errno == ENOTDIR || errno == EIO)
|
1440
|
-
return;
|
1441
|
-
}
|
1442
|
-
#endif
|
1443
|
-
#endif
|
1444
|
-
|
1445
|
-
if (*rel != '/')
|
1446
|
-
{
|
1447
|
-
int len;
|
1448
|
-
|
1449
|
-
errno = ENOENT;
|
1450
|
-
if (wd == EIO_INVALID_WD)
|
1451
|
-
return -1;
|
1452
|
-
|
1453
|
-
if (wd == EIO_CWD)
|
1454
|
-
{
|
1455
|
-
if (!getcwd (res, PATH_MAX))
|
1456
|
-
return -1;
|
1457
|
-
|
1458
|
-
len = strlen (res);
|
1459
|
-
}
|
1460
|
-
else
|
1461
|
-
memcpy (res, wd->str, len = wd->len);
|
1462
|
-
|
1463
|
-
if (res [1]) /* only use if not / */
|
1464
|
-
res += len;
|
1465
|
-
}
|
1466
|
-
|
1467
|
-
while (*rel)
|
1468
|
-
{
|
1469
|
-
eio_ssize_t len, linklen;
|
1470
|
-
const char *beg = rel;
|
1471
|
-
|
1472
|
-
while (*rel && *rel != '/')
|
1473
|
-
++rel;
|
1474
|
-
|
1475
|
-
len = rel - beg;
|
1476
|
-
|
1477
|
-
if (!len) /* skip slashes */
|
1478
|
-
{
|
1479
|
-
++rel;
|
1480
|
-
continue;
|
1481
|
-
}
|
1482
|
-
|
1483
|
-
if (beg [0] == '.')
|
1484
|
-
{
|
1485
|
-
if (len == 1)
|
1486
|
-
continue; /* . - nop */
|
1487
|
-
|
1488
|
-
if (beg [1] == '.' && len == 2)
|
1489
|
-
{
|
1490
|
-
/* .. - back up one component, if possible */
|
1491
|
-
|
1492
|
-
while (res != tmpbuf->ptr)
|
1493
|
-
if (*--res == '/')
|
1494
|
-
break;
|
1495
|
-
|
1496
|
-
continue;
|
1497
|
-
}
|
1498
|
-
}
|
1499
|
-
|
1500
|
-
errno = ENAMETOOLONG;
|
1501
|
-
if (res + 1 + len + 1 >= tmp1)
|
1502
|
-
return -1;
|
1503
|
-
|
1504
|
-
/* copy one component */
|
1505
|
-
*res = '/';
|
1506
|
-
memcpy (res + 1, beg, len);
|
1507
|
-
|
1508
|
-
/* zero-terminate, for readlink */
|
1509
|
-
res [len + 1] = 0;
|
1510
|
-
|
1511
|
-
/* now check if it's a symlink */
|
1512
|
-
linklen = readlink (tmpbuf->ptr, tmp1, PATH_MAX);
|
1513
|
-
|
1514
|
-
if (linklen < 0)
|
1515
|
-
{
|
1516
|
-
if (errno != EINVAL)
|
1517
|
-
return -1;
|
1518
|
-
|
1519
|
-
/* it's a normal directory. hopefully */
|
1520
|
-
res += len + 1;
|
1521
|
-
}
|
1522
|
-
else
|
1523
|
-
{
|
1524
|
-
/* yay, it was a symlink - build new path in tmp2 */
|
1525
|
-
int rellen = strlen (rel);
|
1526
|
-
|
1527
|
-
errno = ENAMETOOLONG;
|
1528
|
-
if (linklen + 1 + rellen >= PATH_MAX)
|
1529
|
-
return -1;
|
1530
|
-
|
1531
|
-
errno = ELOOP;
|
1532
|
-
if (!--symlinks)
|
1533
|
-
return -1;
|
1534
|
-
|
1535
|
-
if (*tmp1 == '/')
|
1536
|
-
res = tmpbuf->ptr; /* symlink resolves to an absolute path */
|
1537
|
-
|
1538
|
-
/* we need to be careful, as rel might point into tmp2 already */
|
1539
|
-
memmove (tmp2 + linklen + 1, rel, rellen + 1);
|
1540
|
-
tmp2 [linklen] = '/';
|
1541
|
-
memcpy (tmp2, tmp1, linklen);
|
1542
|
-
|
1543
|
-
rel = tmp2;
|
1544
|
-
}
|
1545
|
-
}
|
1546
|
-
|
1547
|
-
/* special case for the lone root path */
|
1548
|
-
if (res == tmpbuf->ptr)
|
1549
|
-
*res++ = '/';
|
1550
|
-
|
1551
|
-
return res - (char *)tmpbuf->ptr;
|
1552
|
-
}
|
1553
|
-
|
1554
|
-
static signed char
|
1555
|
-
eio_dent_cmp (const eio_dirent *a, const eio_dirent *b)
|
1556
|
-
{
|
1557
|
-
return a->score - b->score ? a->score - b->score /* works because our signed char is always 0..100 */
|
1558
|
-
: a->inode < b->inode ? -1
|
1559
|
-
: a->inode > b->inode ? 1
|
1560
|
-
: 0;
|
1561
|
-
}
|
1562
|
-
|
1563
|
-
#define EIO_DENT_CMP(i,op,j) eio_dent_cmp (&i, &j) op 0
|
1564
|
-
|
1565
|
-
#define EIO_SORT_CUTOFF 30 /* quite high, but performs well on many filesystems */
|
1566
|
-
#define EIO_SORT_FAST 60 /* when to only use insertion sort */
|
1567
|
-
|
1568
|
-
static void
|
1569
|
-
eio_dent_radix_sort (eio_dirent *dents, int size, signed char score_bits, eio_ino_t inode_bits)
|
1570
|
-
{
|
1571
|
-
unsigned char bits [9 + sizeof (eio_ino_t) * 8];
|
1572
|
-
unsigned char *bit = bits;
|
1573
|
-
|
1574
|
-
assert (CHAR_BIT == 8);
|
1575
|
-
assert (sizeof (eio_dirent) * 8 < 256);
|
1576
|
-
assert (offsetof (eio_dirent, inode)); /* we use bit #0 as sentinel */
|
1577
|
-
assert (offsetof (eio_dirent, score)); /* we use bit #0 as sentinel */
|
1578
|
-
|
1579
|
-
if (size <= EIO_SORT_FAST)
|
1580
|
-
return;
|
1581
|
-
|
1582
|
-
/* first prepare an array of bits to test in our radix sort */
|
1583
|
-
/* try to take endianness into account, as well as differences in eio_ino_t sizes */
|
1584
|
-
/* inode_bits must contain all inodes ORed together */
|
1585
|
-
/* which is used to skip bits that are 0 everywhere, which is very common */
|
1586
|
-
{
|
1587
|
-
eio_ino_t endianness;
|
1588
|
-
int i, j;
|
1589
|
-
|
1590
|
-
/* we store the byte offset of byte n into byte n of "endianness" */
|
1591
|
-
for (i = 0; i < sizeof (eio_ino_t); ++i)
|
1592
|
-
((unsigned char *)&endianness)[i] = i;
|
1593
|
-
|
1594
|
-
*bit++ = 0;
|
1595
|
-
|
1596
|
-
for (i = 0; i < sizeof (eio_ino_t); ++i)
|
1597
|
-
{
|
1598
|
-
/* shifting off the byte offsets out of "endianness" */
|
1599
|
-
int offs = (offsetof (eio_dirent, inode) + (endianness & 0xff)) * 8;
|
1600
|
-
endianness >>= 8;
|
1601
|
-
|
1602
|
-
for (j = 0; j < 8; ++j)
|
1603
|
-
if (inode_bits & (((eio_ino_t)1) << (i * 8 + j)))
|
1604
|
-
*bit++ = offs + j;
|
1605
|
-
}
|
1606
|
-
|
1607
|
-
for (j = 0; j < 8; ++j)
|
1608
|
-
if (score_bits & (1 << j))
|
1609
|
-
*bit++ = offsetof (eio_dirent, score) * 8 + j;
|
1610
|
-
}
|
1611
|
-
|
1612
|
-
/* now actually do the sorting (a variant of MSD radix sort) */
|
1613
|
-
{
|
1614
|
-
eio_dirent *base_stk [9 + sizeof (eio_ino_t) * 8], *base;
|
1615
|
-
eio_dirent *end_stk [9 + sizeof (eio_ino_t) * 8], *end;
|
1616
|
-
unsigned char *bit_stk [9 + sizeof (eio_ino_t) * 8];
|
1617
|
-
int stk_idx = 0;
|
1618
|
-
|
1619
|
-
base_stk [stk_idx] = dents;
|
1620
|
-
end_stk [stk_idx] = dents + size;
|
1621
|
-
bit_stk [stk_idx] = bit - 1;
|
1622
|
-
|
1623
|
-
do
|
1624
|
-
{
|
1625
|
-
base = base_stk [stk_idx];
|
1626
|
-
end = end_stk [stk_idx];
|
1627
|
-
bit = bit_stk [stk_idx];
|
1628
|
-
|
1629
|
-
for (;;)
|
1630
|
-
{
|
1631
|
-
unsigned char O = *bit >> 3;
|
1632
|
-
unsigned char M = 1 << (*bit & 7);
|
1633
|
-
|
1634
|
-
eio_dirent *a = base;
|
1635
|
-
eio_dirent *b = end;
|
1636
|
-
|
1637
|
-
if (b - a < EIO_SORT_CUTOFF)
|
1638
|
-
break;
|
1639
|
-
|
1640
|
-
/* now bit-partition the array on the bit */
|
1641
|
-
/* this ugly asymmetric loop seems to perform much better than typical */
|
1642
|
-
/* partition algos found in the literature */
|
1643
|
-
do
|
1644
|
-
if (!(((unsigned char *)a)[O] & M))
|
1645
|
-
++a;
|
1646
|
-
else if (!(((unsigned char *)--b)[O] & M))
|
1647
|
-
{
|
1648
|
-
eio_dirent tmp = *a; *a = *b; *b = tmp;
|
1649
|
-
++a;
|
1650
|
-
}
|
1651
|
-
while (b > a);
|
1652
|
-
|
1653
|
-
/* next bit, or stop, if no bits left in this path */
|
1654
|
-
if (!*--bit)
|
1655
|
-
break;
|
1656
|
-
|
1657
|
-
base_stk [stk_idx] = a;
|
1658
|
-
end_stk [stk_idx] = end;
|
1659
|
-
bit_stk [stk_idx] = bit;
|
1660
|
-
++stk_idx;
|
1661
|
-
|
1662
|
-
end = a;
|
1663
|
-
}
|
1664
|
-
}
|
1665
|
-
while (stk_idx--);
|
1666
|
-
}
|
1667
|
-
}
|
1668
|
-
|
1669
|
-
static void
|
1670
|
-
eio_dent_insertion_sort (eio_dirent *dents, int size)
|
1671
|
-
{
|
1672
|
-
/* first move the smallest element to the front, to act as a sentinel */
|
1673
|
-
{
|
1674
|
-
int i;
|
1675
|
-
eio_dirent *min = dents;
|
1676
|
-
|
1677
|
-
/* the radix pre-pass ensures that the minimum element is in the first EIO_SORT_CUTOFF + 1 elements */
|
1678
|
-
for (i = size > EIO_SORT_FAST ? EIO_SORT_CUTOFF + 1 : size; --i; )
|
1679
|
-
if (EIO_DENT_CMP (dents [i], <, *min))
|
1680
|
-
min = &dents [i];
|
1681
|
-
|
1682
|
-
/* swap elements 0 and j (minimum) */
|
1683
|
-
{
|
1684
|
-
eio_dirent tmp = *dents; *dents = *min; *min = tmp;
|
1685
|
-
}
|
1686
|
-
}
|
1687
|
-
|
1688
|
-
/* then do standard insertion sort, assuming that all elements are >= dents [0] */
|
1689
|
-
{
|
1690
|
-
eio_dirent *i, *j;
|
1691
|
-
|
1692
|
-
for (i = dents + 1; i < dents + size; ++i)
|
1693
|
-
{
|
1694
|
-
eio_dirent value = *i;
|
1695
|
-
|
1696
|
-
for (j = i - 1; EIO_DENT_CMP (*j, >, value); --j)
|
1697
|
-
j [1] = j [0];
|
1698
|
-
|
1699
|
-
j [1] = value;
|
1700
|
-
}
|
1701
|
-
}
|
1702
|
-
}
|
1703
|
-
|
1704
|
-
static void
|
1705
|
-
eio_dent_sort (eio_dirent *dents, int size, signed char score_bits, eio_ino_t inode_bits)
|
1706
|
-
{
|
1707
|
-
if (size <= 1)
|
1708
|
-
return; /* our insertion sort relies on size > 0 */
|
1709
|
-
|
1710
|
-
/* first we use a radix sort, but only for dirs >= EIO_SORT_FAST */
|
1711
|
-
/* and stop sorting when the partitions are <= EIO_SORT_CUTOFF */
|
1712
|
-
eio_dent_radix_sort (dents, size, score_bits, inode_bits);
|
1713
|
-
|
1714
|
-
/* use an insertion sort at the end, or for small arrays, */
|
1715
|
-
/* as insertion sort is more efficient for small partitions */
|
1716
|
-
eio_dent_insertion_sort (dents, size);
|
1717
|
-
}
|
1718
|
-
|
1719
|
-
/* read a full directory */
|
1720
|
-
static void
|
1721
|
-
eio__scandir (eio_req *req, etp_worker *self)
|
1722
|
-
{
|
1723
|
-
char *name, *names;
|
1724
|
-
int namesalloc = 4096 - sizeof (void *) * 4;
|
1725
|
-
int namesoffs = 0;
|
1726
|
-
int flags = req->int1;
|
1727
|
-
eio_dirent *dents = 0;
|
1728
|
-
int dentalloc = 128;
|
1729
|
-
int dentoffs = 0;
|
1730
|
-
eio_ino_t inode_bits = 0;
|
1731
|
-
#ifdef _WIN32
|
1732
|
-
HANDLE dirp;
|
1733
|
-
WIN32_FIND_DATA entp;
|
1734
|
-
#else
|
1735
|
-
DIR *dirp;
|
1736
|
-
EIO_STRUCT_DIRENT *entp;
|
1737
|
-
#endif
|
1738
|
-
|
1739
|
-
req->result = -1;
|
1740
|
-
|
1741
|
-
if (!(flags & EIO_READDIR_DENTS))
|
1742
|
-
flags &= ~(EIO_READDIR_DIRS_FIRST | EIO_READDIR_STAT_ORDER);
|
1743
|
-
|
1744
|
-
#ifdef _WIN32
|
1745
|
-
{
|
1746
|
-
int len = strlen ((const char *)req->ptr1);
|
1747
|
-
char *path = malloc (MAX_PATH);
|
1748
|
-
const char *fmt;
|
1749
|
-
const char *reqpath = wd_expand (&self->tmpbuf, req->wd, req->ptr1);
|
1750
|
-
|
1751
|
-
if (!len)
|
1752
|
-
fmt = "./*";
|
1753
|
-
else if (reqpath[len - 1] == '/' || reqpath[len - 1] == '\\')
|
1754
|
-
fmt = "%s*";
|
1755
|
-
else
|
1756
|
-
fmt = "%s/*";
|
1757
|
-
|
1758
|
-
_snprintf (path, MAX_PATH, fmt, reqpath);
|
1759
|
-
dirp = FindFirstFile (path, &entp);
|
1760
|
-
free (path);
|
1761
|
-
|
1762
|
-
if (dirp == INVALID_HANDLE_VALUE)
|
1763
|
-
{
|
1764
|
-
/* should steal _dosmaperr */
|
1765
|
-
switch (GetLastError ())
|
1766
|
-
{
|
1767
|
-
case ERROR_FILE_NOT_FOUND:
|
1768
|
-
req->result = 0;
|
1769
|
-
break;
|
1770
|
-
|
1771
|
-
case ERROR_INVALID_NAME:
|
1772
|
-
case ERROR_PATH_NOT_FOUND:
|
1773
|
-
case ERROR_NO_MORE_FILES:
|
1774
|
-
errno = ENOENT;
|
1775
|
-
break;
|
1776
|
-
|
1777
|
-
case ERROR_NOT_ENOUGH_MEMORY:
|
1778
|
-
errno = ENOMEM;
|
1779
|
-
break;
|
1780
|
-
|
1781
|
-
default:
|
1782
|
-
errno = EINVAL;
|
1783
|
-
break;
|
1784
|
-
}
|
1785
|
-
|
1786
|
-
return;
|
1787
|
-
}
|
1788
|
-
}
|
1789
|
-
#else
|
1790
|
-
#if HAVE_AT
|
1791
|
-
if (req->wd)
|
1792
|
-
{
|
1793
|
-
int fd = openat (WD2FD (req->wd), req->ptr1, O_CLOEXEC | O_SEARCH | O_DIRECTORY);
|
1794
|
-
|
1795
|
-
if (fd < 0)
|
1796
|
-
return;
|
1797
|
-
|
1798
|
-
dirp = fdopendir (fd);
|
1799
|
-
|
1800
|
-
if (!dirp)
|
1801
|
-
close (fd);
|
1802
|
-
}
|
1803
|
-
else
|
1804
|
-
dirp = opendir (req->ptr1);
|
1805
|
-
#else
|
1806
|
-
dirp = opendir (wd_expand (&self->tmpbuf, req->wd, req->ptr1));
|
1807
|
-
#endif
|
1808
|
-
|
1809
|
-
if (!dirp)
|
1810
|
-
return;
|
1811
|
-
#endif
|
1812
|
-
|
1813
|
-
if (req->flags & EIO_FLAG_PTR1_FREE)
|
1814
|
-
free (req->ptr1);
|
1815
|
-
|
1816
|
-
req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE;
|
1817
|
-
req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0;
|
1818
|
-
req->ptr2 = names = malloc (namesalloc);
|
1819
|
-
|
1820
|
-
if (!names || (flags && !dents))
|
1821
|
-
return;
|
1822
|
-
|
1823
|
-
for (;;)
|
1824
|
-
{
|
1825
|
-
int done;
|
1826
|
-
|
1827
|
-
#ifdef _WIN32
|
1828
|
-
done = !dirp;
|
1829
|
-
#else
|
1830
|
-
errno = 0;
|
1831
|
-
entp = readdir (dirp);
|
1832
|
-
done = !entp;
|
1833
|
-
#endif
|
1834
|
-
|
1835
|
-
if (done)
|
1836
|
-
{
|
1837
|
-
#ifndef _WIN32
|
1838
|
-
int old_errno = errno;
|
1839
|
-
closedir (dirp);
|
1840
|
-
errno = old_errno;
|
1841
|
-
|
1842
|
-
if (errno)
|
1843
|
-
break;
|
1844
|
-
#endif
|
1845
|
-
|
1846
|
-
/* sort etc. */
|
1847
|
-
req->int1 = flags;
|
1848
|
-
req->result = dentoffs;
|
1849
|
-
|
1850
|
-
if (flags & EIO_READDIR_STAT_ORDER)
|
1851
|
-
eio_dent_sort (dents, dentoffs, flags & EIO_READDIR_DIRS_FIRST ? 7 : 0, inode_bits);
|
1852
|
-
else if (flags & EIO_READDIR_DIRS_FIRST)
|
1853
|
-
if (flags & EIO_READDIR_FOUND_UNKNOWN)
|
1854
|
-
eio_dent_sort (dents, dentoffs, 7, inode_bits); /* sort by score and inode */
|
1855
|
-
else
|
1856
|
-
{
|
1857
|
-
/* in this case, all is known, and we just put dirs first and sort them */
|
1858
|
-
eio_dirent *oth = dents + dentoffs;
|
1859
|
-
eio_dirent *dir = dents;
|
1860
|
-
|
1861
|
-
/* now partition dirs to the front, and non-dirs to the back */
|
1862
|
-
/* by walking from both sides and swapping if necessary */
|
1863
|
-
while (oth > dir)
|
1864
|
-
{
|
1865
|
-
if (dir->type == EIO_DT_DIR)
|
1866
|
-
++dir;
|
1867
|
-
else if ((--oth)->type == EIO_DT_DIR)
|
1868
|
-
{
|
1869
|
-
eio_dirent tmp = *dir; *dir = *oth; *oth = tmp;
|
1870
|
-
|
1871
|
-
++dir;
|
1872
|
-
}
|
1873
|
-
}
|
1874
|
-
|
1875
|
-
/* now sort the dirs only (dirs all have the same score) */
|
1876
|
-
eio_dent_sort (dents, dir - dents, 0, inode_bits);
|
1877
|
-
}
|
1878
|
-
|
1879
|
-
break;
|
1880
|
-
}
|
1881
|
-
|
1882
|
-
/* now add the entry to our list(s) */
|
1883
|
-
name = D_NAME (entp);
|
1884
|
-
|
1885
|
-
/* skip . and .. entries */
|
1886
|
-
if (name [0] != '.' || (name [1] && (name [1] != '.' || name [2])))
|
1887
|
-
{
|
1888
|
-
int len = D_NAMLEN (entp) + 1;
|
1889
|
-
|
1890
|
-
while (ecb_expect_false (namesoffs + len > namesalloc))
|
1891
|
-
{
|
1892
|
-
namesalloc *= 2;
|
1893
|
-
req->ptr2 = names = realloc (names, namesalloc);
|
1894
|
-
|
1895
|
-
if (!names)
|
1896
|
-
break;
|
1897
|
-
}
|
1898
|
-
|
1899
|
-
memcpy (names + namesoffs, name, len);
|
1900
|
-
|
1901
|
-
if (dents)
|
1902
|
-
{
|
1903
|
-
struct eio_dirent *ent;
|
1904
|
-
|
1905
|
-
if (ecb_expect_false (dentoffs == dentalloc))
|
1906
|
-
{
|
1907
|
-
dentalloc *= 2;
|
1908
|
-
req->ptr1 = dents = realloc (dents, dentalloc * sizeof (eio_dirent));
|
1909
|
-
|
1910
|
-
if (!dents)
|
1911
|
-
break;
|
1912
|
-
}
|
1913
|
-
|
1914
|
-
ent = dents + dentoffs;
|
1915
|
-
|
1916
|
-
ent->nameofs = namesoffs; /* rather dirtily we store the offset in the pointer */
|
1917
|
-
ent->namelen = len - 1;
|
1918
|
-
ent->inode = D_INO (entp);
|
1919
|
-
|
1920
|
-
inode_bits |= ent->inode;
|
1921
|
-
|
1922
|
-
switch (D_TYPE (entp))
|
1923
|
-
{
|
1924
|
-
default:
|
1925
|
-
ent->type = EIO_DT_UNKNOWN;
|
1926
|
-
flags |= EIO_READDIR_FOUND_UNKNOWN;
|
1927
|
-
break;
|
1928
|
-
|
1929
|
-
#ifdef DT_FIFO
|
1930
|
-
case DT_FIFO: ent->type = EIO_DT_FIFO; break;
|
1931
|
-
#endif
|
1932
|
-
#ifdef DT_CHR
|
1933
|
-
case DT_CHR: ent->type = EIO_DT_CHR; break;
|
1934
|
-
#endif
|
1935
|
-
#ifdef DT_MPC
|
1936
|
-
case DT_MPC: ent->type = EIO_DT_MPC; break;
|
1937
|
-
#endif
|
1938
|
-
#ifdef DT_DIR
|
1939
|
-
case DT_DIR: ent->type = EIO_DT_DIR; break;
|
1940
|
-
#endif
|
1941
|
-
#ifdef DT_NAM
|
1942
|
-
case DT_NAM: ent->type = EIO_DT_NAM; break;
|
1943
|
-
#endif
|
1944
|
-
#ifdef DT_BLK
|
1945
|
-
case DT_BLK: ent->type = EIO_DT_BLK; break;
|
1946
|
-
#endif
|
1947
|
-
#ifdef DT_MPB
|
1948
|
-
case DT_MPB: ent->type = EIO_DT_MPB; break;
|
1949
|
-
#endif
|
1950
|
-
#ifdef DT_REG
|
1951
|
-
case DT_REG: ent->type = EIO_DT_REG; break;
|
1952
|
-
#endif
|
1953
|
-
#ifdef DT_NWK
|
1954
|
-
case DT_NWK: ent->type = EIO_DT_NWK; break;
|
1955
|
-
#endif
|
1956
|
-
#ifdef DT_CMP
|
1957
|
-
case DT_CMP: ent->type = EIO_DT_CMP; break;
|
1958
|
-
#endif
|
1959
|
-
#ifdef DT_LNK
|
1960
|
-
case DT_LNK: ent->type = EIO_DT_LNK; break;
|
1961
|
-
#endif
|
1962
|
-
#ifdef DT_SOCK
|
1963
|
-
case DT_SOCK: ent->type = EIO_DT_SOCK; break;
|
1964
|
-
#endif
|
1965
|
-
#ifdef DT_DOOR
|
1966
|
-
case DT_DOOR: ent->type = EIO_DT_DOOR; break;
|
1967
|
-
#endif
|
1968
|
-
#ifdef DT_WHT
|
1969
|
-
case DT_WHT: ent->type = EIO_DT_WHT; break;
|
1970
|
-
#endif
|
1971
|
-
}
|
1972
|
-
|
1973
|
-
ent->score = 7;
|
1974
|
-
|
1975
|
-
if (flags & EIO_READDIR_DIRS_FIRST)
|
1976
|
-
{
|
1977
|
-
if (ent->type == EIO_DT_UNKNOWN)
|
1978
|
-
{
|
1979
|
-
if (*name == '.') /* leading dots are likely directories, and, in any case, rare */
|
1980
|
-
ent->score = 1;
|
1981
|
-
else if (!strchr (name, '.')) /* absence of dots indicate likely dirs */
|
1982
|
-
ent->score = len <= 2 ? 4 - len : len <= 4 ? 4 : len <= 7 ? 5 : 6; /* shorter == more likely dir, but avoid too many classes */
|
1983
|
-
}
|
1984
|
-
else if (ent->type == EIO_DT_DIR)
|
1985
|
-
ent->score = 0;
|
1986
|
-
}
|
1987
|
-
}
|
1988
|
-
|
1989
|
-
namesoffs += len;
|
1990
|
-
++dentoffs;
|
1991
|
-
}
|
1992
|
-
|
1993
|
-
if (EIO_CANCELLED (req))
|
1994
|
-
{
|
1995
|
-
errno = ECANCELED;
|
1996
|
-
break;
|
1997
|
-
}
|
1998
|
-
|
1999
|
-
#ifdef _WIN32
|
2000
|
-
if (!FindNextFile (dirp, &entp))
|
2001
|
-
{
|
2002
|
-
FindClose (dirp);
|
2003
|
-
dirp = 0;
|
2004
|
-
}
|
2005
|
-
#endif
|
2006
|
-
}
|
2007
|
-
}
|
2008
|
-
|
2009
|
-
/*****************************************************************************/
|
2010
|
-
/* working directory stuff */
|
2011
|
-
/* various deficiencies in the posix 2008 api force us to */
|
2012
|
-
/* keep the absolute path in string form at all times */
|
2013
|
-
/* fuck yeah. */
|
2014
|
-
|
2015
|
-
#if !HAVE_AT
|
2016
|
-
|
2017
|
-
/* a bit like realpath, but usually faster because it doesn'T have to return */
|
2018
|
-
/* an absolute or canonical path */
|
2019
|
-
static const char *
|
2020
|
-
wd_expand (struct tmpbuf *tmpbuf, eio_wd wd, const char *path)
|
2021
|
-
{
|
2022
|
-
if (!wd || *path == '/')
|
2023
|
-
return path;
|
2024
|
-
|
2025
|
-
if (path [0] == '.' && !path [1])
|
2026
|
-
return wd->str;
|
2027
|
-
|
2028
|
-
{
|
2029
|
-
int l1 = wd->len;
|
2030
|
-
int l2 = strlen (path);
|
2031
|
-
|
2032
|
-
char *res = tmpbuf_get (tmpbuf, l1 + l2 + 2);
|
2033
|
-
|
2034
|
-
memcpy (res, wd->str, l1);
|
2035
|
-
res [l1] = '/';
|
2036
|
-
memcpy (res + l1 + 1, path, l2 + 1);
|
2037
|
-
|
2038
|
-
return res;
|
2039
|
-
}
|
2040
|
-
}
|
2041
|
-
|
2042
|
-
#endif
|
2043
|
-
|
2044
|
-
static eio_wd
|
2045
|
-
eio__wd_open_sync (struct tmpbuf *tmpbuf, eio_wd wd, const char *path)
|
2046
|
-
{
|
2047
|
-
int fd;
|
2048
|
-
eio_wd res;
|
2049
|
-
int len = eio__realpath (tmpbuf, wd, path);
|
2050
|
-
|
2051
|
-
if (len < 0)
|
2052
|
-
return EIO_INVALID_WD;
|
2053
|
-
|
2054
|
-
#if HAVE_AT
|
2055
|
-
fd = openat (WD2FD (wd), path, O_CLOEXEC | O_SEARCH | O_DIRECTORY);
|
2056
|
-
|
2057
|
-
if (fd < 0)
|
2058
|
-
return EIO_INVALID_WD;
|
2059
|
-
#endif
|
2060
|
-
|
2061
|
-
res = malloc (sizeof (*res) + len); /* one extra 0-byte */
|
2062
|
-
|
2063
|
-
#if HAVE_AT
|
2064
|
-
res->fd = fd;
|
2065
|
-
#endif
|
2066
|
-
|
2067
|
-
res->len = len;
|
2068
|
-
memcpy (res->str, tmpbuf->ptr, len);
|
2069
|
-
res->str [len] = 0;
|
2070
|
-
|
2071
|
-
return res;
|
2072
|
-
}
|
2073
|
-
|
2074
|
-
eio_wd
|
2075
|
-
eio_wd_open_sync (eio_wd wd, const char *path)
|
2076
|
-
{
|
2077
|
-
struct tmpbuf tmpbuf = { 0 };
|
2078
|
-
wd = eio__wd_open_sync (&tmpbuf, wd, path);
|
2079
|
-
free (tmpbuf.ptr);
|
2080
|
-
|
2081
|
-
return wd;
|
2082
|
-
}
|
2083
|
-
|
2084
|
-
void
|
2085
|
-
eio_wd_close_sync (eio_wd wd)
|
2086
|
-
{
|
2087
|
-
if (wd != EIO_INVALID_WD && wd != EIO_CWD)
|
2088
|
-
{
|
2089
|
-
#if HAVE_AT
|
2090
|
-
close (wd->fd);
|
2091
|
-
#endif
|
2092
|
-
free (wd);
|
2093
|
-
}
|
2094
|
-
}
|
2095
|
-
|
2096
|
-
#if HAVE_AT
|
2097
|
-
|
2098
|
-
/* they forgot these */
|
2099
|
-
|
2100
|
-
static int
|
2101
|
-
eio__truncateat (int dirfd, const char *path, off_t length)
|
2102
|
-
{
|
2103
|
-
int fd = openat (dirfd, path, O_WRONLY | O_CLOEXEC);
|
2104
|
-
int res;
|
2105
|
-
|
2106
|
-
if (fd < 0)
|
2107
|
-
return fd;
|
2108
|
-
|
2109
|
-
res = ftruncate (fd, length);
|
2110
|
-
close (fd);
|
2111
|
-
return res;
|
2112
|
-
}
|
2113
|
-
|
2114
|
-
static int
|
2115
|
-
eio__statvfsat (int dirfd, const char *path, struct statvfs *buf)
|
2116
|
-
{
|
2117
|
-
int fd = openat (dirfd, path, O_SEARCH | O_CLOEXEC);
|
2118
|
-
int res;
|
2119
|
-
|
2120
|
-
if (fd < 0)
|
2121
|
-
return fd;
|
2122
|
-
|
2123
|
-
res = fstatvfs (fd, buf);
|
2124
|
-
close (fd);
|
2125
|
-
return res;
|
2126
|
-
|
2127
|
-
}
|
2128
|
-
|
2129
|
-
#endif
|
2130
|
-
|
2131
|
-
/*****************************************************************************/
|
2132
|
-
|
2133
|
-
#define ALLOC(len) \
|
2134
|
-
if (!req->ptr2) \
|
2135
|
-
{ \
|
2136
|
-
X_LOCK (wrklock); \
|
2137
|
-
req->flags |= EIO_FLAG_PTR2_FREE; \
|
2138
|
-
X_UNLOCK (wrklock); \
|
2139
|
-
req->ptr2 = malloc (len); \
|
2140
|
-
if (!req->ptr2) \
|
2141
|
-
{ \
|
2142
|
-
errno = ENOMEM; \
|
2143
|
-
req->result = -1; \
|
2144
|
-
break; \
|
2145
|
-
} \
|
2146
|
-
}
|
2147
|
-
|
2148
|
-
static void ecb_noinline ecb_cold
|
2149
|
-
etp_proc_init (void)
|
2150
|
-
{
|
2151
|
-
#if HAVE_PRCTL_SET_NAME
|
2152
|
-
/* provide a more sensible "thread name" */
|
2153
|
-
char name[16 + 1];
|
2154
|
-
const int namelen = sizeof (name) - 1;
|
2155
|
-
int len;
|
2156
|
-
|
2157
|
-
prctl (PR_GET_NAME, (unsigned long)name, 0, 0, 0);
|
2158
|
-
name [namelen] = 0;
|
2159
|
-
len = strlen (name);
|
2160
|
-
strcpy (name + (len <= namelen - 4 ? len : namelen - 4), "/eio");
|
2161
|
-
prctl (PR_SET_NAME, (unsigned long)name, 0, 0, 0);
|
2162
|
-
#endif
|
2163
|
-
}
|
2164
|
-
|
2165
|
-
X_THREAD_PROC (etp_proc)
|
2166
|
-
{
|
2167
|
-
ETP_REQ *req;
|
2168
|
-
struct timespec ts;
|
2169
|
-
etp_worker *self = (etp_worker *)thr_arg;
|
2170
|
-
|
2171
|
-
etp_proc_init ();
|
2172
|
-
|
2173
|
-
/* try to distribute timeouts somewhat evenly */
|
2174
|
-
ts.tv_nsec = ((unsigned long)self & 1023UL) * (1000000000UL / 1024UL);
|
2175
|
-
|
2176
|
-
for (;;)
|
2177
|
-
{
|
2178
|
-
ts.tv_sec = 0;
|
2179
|
-
|
2180
|
-
X_LOCK (reqlock);
|
2181
|
-
|
2182
|
-
for (;;)
|
2183
|
-
{
|
2184
|
-
req = reqq_shift (&req_queue);
|
2185
|
-
|
2186
|
-
if (req)
|
2187
|
-
break;
|
2188
|
-
|
2189
|
-
if (ts.tv_sec == 1) /* no request, but timeout detected, let's quit */
|
2190
|
-
{
|
2191
|
-
X_UNLOCK (reqlock);
|
2192
|
-
X_LOCK (wrklock);
|
2193
|
-
--started;
|
2194
|
-
X_UNLOCK (wrklock);
|
2195
|
-
goto quit;
|
2196
|
-
}
|
2197
|
-
|
2198
|
-
++idle;
|
2199
|
-
|
2200
|
-
if (idle <= max_idle)
|
2201
|
-
/* we are allowed to idle, so do so without any timeout */
|
2202
|
-
X_COND_WAIT (reqwait, reqlock);
|
2203
|
-
else
|
2204
|
-
{
|
2205
|
-
/* initialise timeout once */
|
2206
|
-
if (!ts.tv_sec)
|
2207
|
-
ts.tv_sec = time (0) + idle_timeout;
|
2208
|
-
|
2209
|
-
if (X_COND_TIMEDWAIT (reqwait, reqlock, ts) == ETIMEDOUT)
|
2210
|
-
ts.tv_sec = 1; /* assuming this is not a value computed above.,.. */
|
2211
|
-
}
|
2212
|
-
|
2213
|
-
--idle;
|
2214
|
-
}
|
2215
|
-
|
2216
|
-
--nready;
|
2217
|
-
|
2218
|
-
X_UNLOCK (reqlock);
|
2219
|
-
|
2220
|
-
if (req->type < 0)
|
2221
|
-
goto quit;
|
2222
|
-
|
2223
|
-
ETP_EXECUTE (self, req);
|
2224
|
-
|
2225
|
-
X_LOCK (reslock);
|
2226
|
-
|
2227
|
-
++npending;
|
2228
|
-
|
2229
|
-
if (!reqq_push (&res_queue, req) && want_poll_cb)
|
2230
|
-
want_poll_cb ();
|
2231
|
-
|
2232
|
-
etp_worker_clear (self);
|
2233
|
-
|
2234
|
-
X_UNLOCK (reslock);
|
2235
|
-
}
|
2236
|
-
|
2237
|
-
quit:
|
2238
|
-
free (req);
|
2239
|
-
|
2240
|
-
X_LOCK (wrklock);
|
2241
|
-
etp_worker_free (self);
|
2242
|
-
X_UNLOCK (wrklock);
|
2243
|
-
|
2244
|
-
return 0;
|
2245
|
-
}
|
2246
|
-
|
2247
|
-
/*****************************************************************************/
|
2248
|
-
|
2249
|
-
int ecb_cold
|
2250
|
-
eio_init (void (*want_poll)(void), void (*done_poll)(void))
|
2251
|
-
{
|
2252
|
-
return etp_init (want_poll, done_poll);
|
2253
|
-
}
|
2254
|
-
|
2255
|
-
int ecb_cold
|
2256
|
-
eio_deinit ()
|
2257
|
-
{
|
2258
|
-
return etp_deinit ();
|
2259
|
-
}
|
2260
|
-
|
2261
|
-
ecb_inline void
|
2262
|
-
eio_api_destroy (eio_req *req)
|
2263
|
-
{
|
2264
|
-
free (req);
|
2265
|
-
}
|
2266
|
-
|
2267
|
-
#define REQ(rtype) \
|
2268
|
-
eio_req *req; \
|
2269
|
-
\
|
2270
|
-
req = (eio_req *)calloc (1, sizeof *req); \
|
2271
|
-
if (!req) \
|
2272
|
-
return 0; \
|
2273
|
-
\
|
2274
|
-
req->type = rtype; \
|
2275
|
-
req->pri = pri; \
|
2276
|
-
req->finish = cb; \
|
2277
|
-
req->data = data; \
|
2278
|
-
req->destroy = eio_api_destroy;
|
2279
|
-
|
2280
|
-
#define SEND eio_submit (req); return req
|
2281
|
-
|
2282
|
-
#define PATH \
|
2283
|
-
req->flags |= EIO_FLAG_PTR1_FREE; \
|
2284
|
-
req->ptr1 = strdup (path); \
|
2285
|
-
if (!req->ptr1) \
|
2286
|
-
{ \
|
2287
|
-
eio_api_destroy (req); \
|
2288
|
-
return 0; \
|
2289
|
-
}
|
2290
|
-
|
2291
|
-
static void
|
2292
|
-
eio_execute (etp_worker *self, eio_req *req)
|
2293
|
-
{
|
2294
|
-
#if HAVE_AT
|
2295
|
-
int dirfd;
|
2296
|
-
#else
|
2297
|
-
const char *path;
|
2298
|
-
#endif
|
2299
|
-
|
2300
|
-
if (ecb_expect_false (EIO_CANCELLED (req)))
|
2301
|
-
{
|
2302
|
-
req->result = -1;
|
2303
|
-
req->errorno = ECANCELED;
|
2304
|
-
return;
|
2305
|
-
}
|
2306
|
-
|
2307
|
-
if (ecb_expect_false (req->wd == EIO_INVALID_WD))
|
2308
|
-
{
|
2309
|
-
req->result = -1;
|
2310
|
-
req->errorno = ENOENT;
|
2311
|
-
return;
|
2312
|
-
}
|
2313
|
-
|
2314
|
-
if (req->type >= EIO_OPEN)
|
2315
|
-
{
|
2316
|
-
#if HAVE_AT
|
2317
|
-
dirfd = WD2FD (req->wd);
|
2318
|
-
#else
|
2319
|
-
path = wd_expand (&self->tmpbuf, req->wd, req->ptr1);
|
2320
|
-
#endif
|
2321
|
-
}
|
2322
|
-
|
2323
|
-
switch (req->type)
|
2324
|
-
{
|
2325
|
-
case EIO_WD_OPEN: req->wd = eio__wd_open_sync (&self->tmpbuf, req->wd, req->ptr1);
|
2326
|
-
req->result = req->wd == EIO_INVALID_WD ? -1 : 0;
|
2327
|
-
break;
|
2328
|
-
case EIO_WD_CLOSE: req->result = 0;
|
2329
|
-
eio_wd_close_sync (req->wd); break;
|
2330
|
-
|
2331
|
-
case EIO_SEEK: eio__lseek (req); break;
|
2332
|
-
case EIO_READ: ALLOC (req->size);
|
2333
|
-
req->result = req->offs >= 0
|
2334
|
-
? pread (req->int1, req->ptr2, req->size, req->offs)
|
2335
|
-
: read (req->int1, req->ptr2, req->size); break;
|
2336
|
-
case EIO_WRITE: req->result = req->offs >= 0
|
2337
|
-
? pwrite (req->int1, req->ptr2, req->size, req->offs)
|
2338
|
-
: write (req->int1, req->ptr2, req->size); break;
|
2339
|
-
|
2340
|
-
case EIO_READAHEAD: req->result = readahead (req->int1, req->offs, req->size); break;
|
2341
|
-
case EIO_SENDFILE: req->result = eio__sendfile (req->int1, req->int2, req->offs, req->size); break;
|
2342
|
-
|
2343
|
-
#if HAVE_AT
|
2344
|
-
|
2345
|
-
case EIO_STAT: ALLOC (sizeof (EIO_STRUCT_STAT));
|
2346
|
-
req->result = fstatat (dirfd, req->ptr1, (EIO_STRUCT_STAT *)req->ptr2, 0); break;
|
2347
|
-
case EIO_LSTAT: ALLOC (sizeof (EIO_STRUCT_STAT));
|
2348
|
-
req->result = fstatat (dirfd, req->ptr1, (EIO_STRUCT_STAT *)req->ptr2, AT_SYMLINK_NOFOLLOW); break;
|
2349
|
-
case EIO_CHOWN: req->result = fchownat (dirfd, req->ptr1, req->int2, req->int3, 0); break;
|
2350
|
-
case EIO_CHMOD: req->result = fchmodat (dirfd, req->ptr1, (mode_t)req->int2, 0); break;
|
2351
|
-
case EIO_TRUNCATE: req->result = eio__truncateat (dirfd, req->ptr1, req->offs); break;
|
2352
|
-
case EIO_OPEN: req->result = openat (dirfd, req->ptr1, req->int1, (mode_t)req->int2); break;
|
2353
|
-
|
2354
|
-
case EIO_UNLINK: req->result = unlinkat (dirfd, req->ptr1, 0); break;
|
2355
|
-
case EIO_RMDIR: req->result = unlinkat (dirfd, req->ptr1, AT_REMOVEDIR); break;
|
2356
|
-
case EIO_MKDIR: req->result = mkdirat (dirfd, req->ptr1, (mode_t)req->int2); break;
|
2357
|
-
case EIO_RENAME: req->result = renameat (dirfd, req->ptr1, WD2FD ((eio_wd)req->int3), req->ptr2); break;
|
2358
|
-
case EIO_LINK: req->result = linkat (dirfd, req->ptr1, WD2FD ((eio_wd)req->int3), req->ptr2, 0); break;
|
2359
|
-
case EIO_SYMLINK: req->result = symlinkat (req->ptr1, dirfd, req->ptr2); break;
|
2360
|
-
case EIO_MKNOD: req->result = mknodat (dirfd, req->ptr1, (mode_t)req->int2, (dev_t)req->offs); break;
|
2361
|
-
case EIO_READLINK: ALLOC (PATH_MAX);
|
2362
|
-
req->result = readlinkat (dirfd, req->ptr1, req->ptr2, PATH_MAX); break;
|
2363
|
-
case EIO_STATVFS: ALLOC (sizeof (EIO_STRUCT_STATVFS));
|
2364
|
-
req->result = eio__statvfsat (dirfd, req->ptr1, (EIO_STRUCT_STATVFS *)req->ptr2); break;
|
2365
|
-
case EIO_UTIME:
|
2366
|
-
case EIO_FUTIME:
|
2367
|
-
{
|
2368
|
-
struct timespec ts[2];
|
2369
|
-
struct timespec *times;
|
2370
|
-
|
2371
|
-
if (req->nv1 != -1. || req->nv2 != -1.)
|
2372
|
-
{
|
2373
|
-
ts[0].tv_sec = req->nv1;
|
2374
|
-
ts[0].tv_nsec = (req->nv1 - ts[0].tv_sec) * 1e9;
|
2375
|
-
ts[1].tv_sec = req->nv2;
|
2376
|
-
ts[1].tv_nsec = (req->nv2 - ts[1].tv_sec) * 1e9;
|
2377
|
-
|
2378
|
-
times = ts;
|
2379
|
-
}
|
2380
|
-
else
|
2381
|
-
times = 0;
|
2382
|
-
|
2383
|
-
req->result = req->type == EIO_FUTIME
|
2384
|
-
? futimens (req->int1, times)
|
2385
|
-
: utimensat (dirfd, req->ptr1, times, 0);
|
2386
|
-
}
|
2387
|
-
break;
|
2388
|
-
|
2389
|
-
#else
|
2390
|
-
|
2391
|
-
case EIO_STAT: ALLOC (sizeof (EIO_STRUCT_STAT));
|
2392
|
-
req->result = stat (path , (EIO_STRUCT_STAT *)req->ptr2); break;
|
2393
|
-
case EIO_LSTAT: ALLOC (sizeof (EIO_STRUCT_STAT));
|
2394
|
-
req->result = lstat (path , (EIO_STRUCT_STAT *)req->ptr2); break;
|
2395
|
-
case EIO_CHOWN: req->result = chown (path , req->int2, req->int3); break;
|
2396
|
-
case EIO_CHMOD: req->result = chmod (path , (mode_t)req->int2); break;
|
2397
|
-
case EIO_TRUNCATE: req->result = truncate (path , req->offs); break;
|
2398
|
-
case EIO_OPEN: req->result = open (path , req->int1, (mode_t)req->int2); break;
|
2399
|
-
|
2400
|
-
case EIO_UNLINK: req->result = unlink (path ); break;
|
2401
|
-
case EIO_RMDIR: req->result = rmdir (path ); break;
|
2402
|
-
case EIO_MKDIR: req->result = mkdir (path , (mode_t)req->int2); break;
|
2403
|
-
case EIO_RENAME: req->result = rename (path , req->ptr2); break;
|
2404
|
-
case EIO_LINK: req->result = link (path , req->ptr2); break;
|
2405
|
-
case EIO_SYMLINK: req->result = symlink (path , req->ptr2); break;
|
2406
|
-
case EIO_MKNOD: req->result = mknod (path , (mode_t)req->int2, (dev_t)req->offs); break;
|
2407
|
-
case EIO_READLINK: ALLOC (PATH_MAX);
|
2408
|
-
req->result = readlink (path, req->ptr2, PATH_MAX); break;
|
2409
|
-
case EIO_STATVFS: ALLOC (sizeof (EIO_STRUCT_STATVFS));
|
2410
|
-
req->result = statvfs (path , (EIO_STRUCT_STATVFS *)req->ptr2); break;
|
2411
|
-
|
2412
|
-
case EIO_UTIME:
|
2413
|
-
case EIO_FUTIME:
|
2414
|
-
{
|
2415
|
-
struct timeval tv[2];
|
2416
|
-
struct timeval *times;
|
2417
|
-
|
2418
|
-
if (req->nv1 != -1. || req->nv2 != -1.)
|
2419
|
-
{
|
2420
|
-
tv[0].tv_sec = req->nv1;
|
2421
|
-
tv[0].tv_usec = (req->nv1 - tv[0].tv_sec) * 1e6;
|
2422
|
-
tv[1].tv_sec = req->nv2;
|
2423
|
-
tv[1].tv_usec = (req->nv2 - tv[1].tv_sec) * 1e6;
|
2424
|
-
|
2425
|
-
times = tv;
|
2426
|
-
}
|
2427
|
-
else
|
2428
|
-
times = 0;
|
2429
|
-
|
2430
|
-
req->result = req->type == EIO_FUTIME
|
2431
|
-
? futimes (req->int1, times)
|
2432
|
-
: utimes (req->ptr1, times);
|
2433
|
-
}
|
2434
|
-
break;
|
2435
|
-
|
2436
|
-
#endif
|
2437
|
-
|
2438
|
-
case EIO_REALPATH: if (0 <= (req->result = eio__realpath (&self->tmpbuf, req->wd, req->ptr1)))
|
2439
|
-
{
|
2440
|
-
ALLOC (req->result);
|
2441
|
-
memcpy (req->ptr2, self->tmpbuf.ptr, req->result);
|
2442
|
-
}
|
2443
|
-
break;
|
2444
|
-
|
2445
|
-
case EIO_FSTAT: ALLOC (sizeof (EIO_STRUCT_STAT));
|
2446
|
-
req->result = fstat (req->int1, (EIO_STRUCT_STAT *)req->ptr2); break;
|
2447
|
-
|
2448
|
-
case EIO_FSTATVFS: ALLOC (sizeof (EIO_STRUCT_STATVFS));
|
2449
|
-
req->result = fstatvfs (req->int1, (EIO_STRUCT_STATVFS *)req->ptr2); break;
|
2450
|
-
|
2451
|
-
case EIO_FCHOWN: req->result = fchown (req->int1, req->int2, req->int3); break;
|
2452
|
-
case EIO_FCHMOD: req->result = fchmod (req->int1, (mode_t)req->int2); break;
|
2453
|
-
case EIO_FTRUNCATE: req->result = ftruncate (req->int1, req->offs); break;
|
2454
|
-
|
2455
|
-
case EIO_CLOSE: req->result = close (req->int1); break;
|
2456
|
-
case EIO_DUP2: req->result = dup2 (req->int1, req->int2); break;
|
2457
|
-
case EIO_SYNC: req->result = 0; sync (); break;
|
2458
|
-
case EIO_FSYNC: req->result = fsync (req->int1); break;
|
2459
|
-
case EIO_FDATASYNC: req->result = fdatasync (req->int1); break;
|
2460
|
-
case EIO_SYNCFS: req->result = eio__syncfs (req->int1); break;
|
2461
|
-
case EIO_SYNC_FILE_RANGE: req->result = eio__sync_file_range (req->int1, req->offs, req->size, req->int2); break;
|
2462
|
-
case EIO_MSYNC: req->result = eio__msync (req->ptr2, req->size, req->int1); break;
|
2463
|
-
case EIO_MTOUCH: req->result = eio__mtouch (req); break;
|
2464
|
-
case EIO_MLOCK: req->result = eio__mlock (req->ptr2, req->size); break;
|
2465
|
-
case EIO_MLOCKALL: req->result = eio__mlockall (req->int1); break;
|
2466
|
-
case EIO_FALLOCATE: req->result = eio__fallocate (req->int1, req->int2, req->offs, req->size); break;
|
2467
|
-
|
2468
|
-
case EIO_READDIR: eio__scandir (req, self); break;
|
2469
|
-
|
2470
|
-
case EIO_BUSY:
|
2471
|
-
#ifdef _WIN32
|
2472
|
-
Sleep (req->nv1 * 1e3);
|
2473
|
-
#else
|
2474
|
-
{
|
2475
|
-
struct timeval tv;
|
2476
|
-
|
2477
|
-
tv.tv_sec = req->nv1;
|
2478
|
-
tv.tv_usec = (req->nv1 - tv.tv_sec) * 1e6;
|
2479
|
-
|
2480
|
-
req->result = select (0, 0, 0, 0, &tv);
|
2481
|
-
}
|
2482
|
-
#endif
|
2483
|
-
break;
|
2484
|
-
|
2485
|
-
case EIO_GROUP:
|
2486
|
-
abort (); /* handled in eio_request */
|
2487
|
-
|
2488
|
-
case EIO_NOP:
|
2489
|
-
req->result = 0;
|
2490
|
-
break;
|
2491
|
-
|
2492
|
-
case EIO_CUSTOM:
|
2493
|
-
req->feed (req);
|
2494
|
-
break;
|
2495
|
-
|
2496
|
-
default:
|
2497
|
-
req->result = EIO_ENOSYS ();
|
2498
|
-
break;
|
2499
|
-
}
|
2500
|
-
|
2501
|
-
req->errorno = errno;
|
2502
|
-
}
|
2503
|
-
|
2504
|
-
#ifndef EIO_NO_WRAPPERS
|
2505
|
-
|
2506
|
-
eio_req *eio_wd_open (const char *path, int pri, eio_cb cb, void *data)
|
2507
|
-
{
|
2508
|
-
REQ (EIO_WD_OPEN); PATH; SEND;
|
2509
|
-
}
|
2510
|
-
|
2511
|
-
eio_req *eio_wd_close (eio_wd wd, int pri, eio_cb cb, void *data)
|
2512
|
-
{
|
2513
|
-
REQ (EIO_WD_CLOSE); req->wd = wd; SEND;
|
2514
|
-
}
|
2515
|
-
|
2516
|
-
eio_req *eio_nop (int pri, eio_cb cb, void *data)
|
2517
|
-
{
|
2518
|
-
REQ (EIO_NOP); SEND;
|
2519
|
-
}
|
2520
|
-
|
2521
|
-
eio_req *eio_busy (double delay, int pri, eio_cb cb, void *data)
|
2522
|
-
{
|
2523
|
-
REQ (EIO_BUSY); req->nv1 = delay; SEND;
|
2524
|
-
}
|
2525
|
-
|
2526
|
-
eio_req *eio_sync (int pri, eio_cb cb, void *data)
|
2527
|
-
{
|
2528
|
-
REQ (EIO_SYNC); SEND;
|
2529
|
-
}
|
2530
|
-
|
2531
|
-
eio_req *eio_fsync (int fd, int pri, eio_cb cb, void *data)
|
2532
|
-
{
|
2533
|
-
REQ (EIO_FSYNC); req->int1 = fd; SEND;
|
2534
|
-
}
|
2535
|
-
|
2536
|
-
eio_req *eio_msync (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data)
|
2537
|
-
{
|
2538
|
-
REQ (EIO_MSYNC); req->ptr2 = addr; req->size = length; req->int1 = flags; SEND;
|
2539
|
-
}
|
2540
|
-
|
2541
|
-
eio_req *eio_fdatasync (int fd, int pri, eio_cb cb, void *data)
|
2542
|
-
{
|
2543
|
-
REQ (EIO_FDATASYNC); req->int1 = fd; SEND;
|
2544
|
-
}
|
2545
|
-
|
2546
|
-
eio_req *eio_syncfs (int fd, int pri, eio_cb cb, void *data)
|
2547
|
-
{
|
2548
|
-
REQ (EIO_SYNCFS); req->int1 = fd; SEND;
|
2549
|
-
}
|
2550
|
-
|
2551
|
-
eio_req *eio_sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags, int pri, eio_cb cb, void *data)
|
2552
|
-
{
|
2553
|
-
REQ (EIO_SYNC_FILE_RANGE); req->int1 = fd; req->offs = offset; req->size = nbytes; req->int2 = flags; SEND;
|
2554
|
-
}
|
2555
|
-
|
2556
|
-
eio_req *eio_mtouch (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data)
|
2557
|
-
{
|
2558
|
-
REQ (EIO_MTOUCH); req->ptr2 = addr; req->size = length; req->int1 = flags; SEND;
|
2559
|
-
}
|
2560
|
-
|
2561
|
-
eio_req *eio_mlock (void *addr, size_t length, int pri, eio_cb cb, void *data)
|
2562
|
-
{
|
2563
|
-
REQ (EIO_MLOCK); req->ptr2 = addr; req->size = length; SEND;
|
2564
|
-
}
|
2565
|
-
|
2566
|
-
eio_req *eio_mlockall (int flags, int pri, eio_cb cb, void *data)
|
2567
|
-
{
|
2568
|
-
REQ (EIO_MLOCKALL); req->int1 = flags; SEND;
|
2569
|
-
}
|
2570
|
-
|
2571
|
-
eio_req *eio_fallocate (int fd, int mode, off_t offset, size_t len, int pri, eio_cb cb, void *data)
|
2572
|
-
{
|
2573
|
-
REQ (EIO_FALLOCATE); req->int1 = fd; req->int2 = mode; req->offs = offset; req->size = len; SEND;
|
2574
|
-
}
|
2575
|
-
|
2576
|
-
eio_req *eio_close (int fd, int pri, eio_cb cb, void *data)
|
2577
|
-
{
|
2578
|
-
REQ (EIO_CLOSE); req->int1 = fd; SEND;
|
2579
|
-
}
|
2580
|
-
|
2581
|
-
eio_req *eio_readahead (int fd, off_t offset, size_t length, int pri, eio_cb cb, void *data)
|
2582
|
-
{
|
2583
|
-
REQ (EIO_READAHEAD); req->int1 = fd; req->offs = offset; req->size = length; SEND;
|
2584
|
-
}
|
2585
|
-
|
2586
|
-
eio_req *eio_seek (int fd, off_t offset, int whence, int pri, eio_cb cb, void *data)
|
2587
|
-
{
|
2588
|
-
REQ (EIO_SEEK); req->int1 = fd; req->offs = offset; req->int2 = whence; SEND;
|
2589
|
-
}
|
2590
|
-
|
2591
|
-
eio_req *eio_read (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data)
|
2592
|
-
{
|
2593
|
-
REQ (EIO_READ); req->int1 = fd; req->offs = offset; req->size = length; req->ptr2 = buf; SEND;
|
2594
|
-
}
|
2595
|
-
|
2596
|
-
eio_req *eio_write (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data)
|
2597
|
-
{
|
2598
|
-
REQ (EIO_WRITE); req->int1 = fd; req->offs = offset; req->size = length; req->ptr2 = buf; SEND;
|
2599
|
-
}
|
2600
|
-
|
2601
|
-
eio_req *eio_fstat (int fd, int pri, eio_cb cb, void *data)
|
2602
|
-
{
|
2603
|
-
REQ (EIO_FSTAT); req->int1 = fd; SEND;
|
2604
|
-
}
|
2605
|
-
|
2606
|
-
eio_req *eio_fstatvfs (int fd, int pri, eio_cb cb, void *data)
|
2607
|
-
{
|
2608
|
-
REQ (EIO_FSTATVFS); req->int1 = fd; SEND;
|
2609
|
-
}
|
2610
|
-
|
2611
|
-
eio_req *eio_futime (int fd, double atime, double mtime, int pri, eio_cb cb, void *data)
|
2612
|
-
{
|
2613
|
-
REQ (EIO_FUTIME); req->int1 = fd; req->nv1 = atime; req->nv2 = mtime; SEND;
|
2614
|
-
}
|
2615
|
-
|
2616
|
-
eio_req *eio_ftruncate (int fd, off_t offset, int pri, eio_cb cb, void *data)
|
2617
|
-
{
|
2618
|
-
REQ (EIO_FTRUNCATE); req->int1 = fd; req->offs = offset; SEND;
|
2619
|
-
}
|
2620
|
-
|
2621
|
-
eio_req *eio_fchmod (int fd, mode_t mode, int pri, eio_cb cb, void *data)
|
2622
|
-
{
|
2623
|
-
REQ (EIO_FCHMOD); req->int1 = fd; req->int2 = (long)mode; SEND;
|
2624
|
-
}
|
2625
|
-
|
2626
|
-
eio_req *eio_fchown (int fd, eio_uid_t uid, eio_gid_t gid, int pri, eio_cb cb, void *data)
|
2627
|
-
{
|
2628
|
-
REQ (EIO_FCHOWN); req->int1 = fd; req->int2 = (long)uid; req->int3 = (long)gid; SEND;
|
2629
|
-
}
|
2630
|
-
|
2631
|
-
eio_req *eio_dup2 (int fd, int fd2, int pri, eio_cb cb, void *data)
|
2632
|
-
{
|
2633
|
-
REQ (EIO_DUP2); req->int1 = fd; req->int2 = fd2; SEND;
|
2634
|
-
}
|
2635
|
-
|
2636
|
-
eio_req *eio_sendfile (int out_fd, int in_fd, off_t in_offset, size_t length, int pri, eio_cb cb, void *data)
|
2637
|
-
{
|
2638
|
-
REQ (EIO_SENDFILE); req->int1 = out_fd; req->int2 = in_fd; req->offs = in_offset; req->size = length; SEND;
|
2639
|
-
}
|
2640
|
-
|
2641
|
-
eio_req *eio_open (const char *path, int flags, mode_t mode, int pri, eio_cb cb, void *data)
|
2642
|
-
{
|
2643
|
-
REQ (EIO_OPEN); PATH; req->int1 = flags; req->int2 = (long)mode; SEND;
|
2644
|
-
}
|
2645
|
-
|
2646
|
-
eio_req *eio_utime (const char *path, double atime, double mtime, int pri, eio_cb cb, void *data)
|
2647
|
-
{
|
2648
|
-
REQ (EIO_UTIME); PATH; req->nv1 = atime; req->nv2 = mtime; SEND;
|
2649
|
-
}
|
2650
|
-
|
2651
|
-
eio_req *eio_truncate (const char *path, off_t offset, int pri, eio_cb cb, void *data)
|
2652
|
-
{
|
2653
|
-
REQ (EIO_TRUNCATE); PATH; req->offs = offset; SEND;
|
2654
|
-
}
|
2655
|
-
|
2656
|
-
eio_req *eio_chown (const char *path, eio_uid_t uid, eio_gid_t gid, int pri, eio_cb cb, void *data)
|
2657
|
-
{
|
2658
|
-
REQ (EIO_CHOWN); PATH; req->int2 = (long)uid; req->int3 = (long)gid; SEND;
|
2659
|
-
}
|
2660
|
-
|
2661
|
-
eio_req *eio_chmod (const char *path, mode_t mode, int pri, eio_cb cb, void *data)
|
2662
|
-
{
|
2663
|
-
REQ (EIO_CHMOD); PATH; req->int2 = (long)mode; SEND;
|
2664
|
-
}
|
2665
|
-
|
2666
|
-
eio_req *eio_mkdir (const char *path, mode_t mode, int pri, eio_cb cb, void *data)
|
2667
|
-
{
|
2668
|
-
REQ (EIO_MKDIR); PATH; req->int2 = (long)mode; SEND;
|
2669
|
-
}
|
2670
|
-
|
2671
|
-
static eio_req *
|
2672
|
-
eio__1path (int type, const char *path, int pri, eio_cb cb, void *data)
|
2673
|
-
{
|
2674
|
-
REQ (type); PATH; SEND;
|
2675
|
-
}
|
2676
|
-
|
2677
|
-
eio_req *eio_readlink (const char *path, int pri, eio_cb cb, void *data)
|
2678
|
-
{
|
2679
|
-
return eio__1path (EIO_READLINK, path, pri, cb, data);
|
2680
|
-
}
|
2681
|
-
|
2682
|
-
eio_req *eio_realpath (const char *path, int pri, eio_cb cb, void *data)
|
2683
|
-
{
|
2684
|
-
return eio__1path (EIO_REALPATH, path, pri, cb, data);
|
2685
|
-
}
|
2686
|
-
|
2687
|
-
eio_req *eio_stat (const char *path, int pri, eio_cb cb, void *data)
|
2688
|
-
{
|
2689
|
-
return eio__1path (EIO_STAT, path, pri, cb, data);
|
2690
|
-
}
|
2691
|
-
|
2692
|
-
eio_req *eio_lstat (const char *path, int pri, eio_cb cb, void *data)
|
2693
|
-
{
|
2694
|
-
return eio__1path (EIO_LSTAT, path, pri, cb, data);
|
2695
|
-
}
|
2696
|
-
|
2697
|
-
eio_req *eio_statvfs (const char *path, int pri, eio_cb cb, void *data)
|
2698
|
-
{
|
2699
|
-
return eio__1path (EIO_STATVFS, path, pri, cb, data);
|
2700
|
-
}
|
2701
|
-
|
2702
|
-
eio_req *eio_unlink (const char *path, int pri, eio_cb cb, void *data)
|
2703
|
-
{
|
2704
|
-
return eio__1path (EIO_UNLINK, path, pri, cb, data);
|
2705
|
-
}
|
2706
|
-
|
2707
|
-
eio_req *eio_rmdir (const char *path, int pri, eio_cb cb, void *data)
|
2708
|
-
{
|
2709
|
-
return eio__1path (EIO_RMDIR, path, pri, cb, data);
|
2710
|
-
}
|
2711
|
-
|
2712
|
-
eio_req *eio_readdir (const char *path, int flags, int pri, eio_cb cb, void *data)
|
2713
|
-
{
|
2714
|
-
REQ (EIO_READDIR); PATH; req->int1 = flags; SEND;
|
2715
|
-
}
|
2716
|
-
|
2717
|
-
eio_req *eio_mknod (const char *path, mode_t mode, dev_t dev, int pri, eio_cb cb, void *data)
|
2718
|
-
{
|
2719
|
-
REQ (EIO_MKNOD); PATH; req->int2 = (long)mode; req->offs = (off_t)dev; SEND;
|
2720
|
-
}
|
2721
|
-
|
2722
|
-
static eio_req *
|
2723
|
-
eio__2path (int type, const char *path, const char *new_path, int pri, eio_cb cb, void *data)
|
2724
|
-
{
|
2725
|
-
REQ (type); PATH;
|
2726
|
-
|
2727
|
-
req->flags |= EIO_FLAG_PTR2_FREE;
|
2728
|
-
req->ptr2 = strdup (new_path);
|
2729
|
-
if (!req->ptr2)
|
2730
|
-
{
|
2731
|
-
eio_api_destroy (req);
|
2732
|
-
return 0;
|
2733
|
-
}
|
2734
|
-
|
2735
|
-
SEND;
|
2736
|
-
}
|
2737
|
-
|
2738
|
-
eio_req *eio_link (const char *path, const char *new_path, int pri, eio_cb cb, void *data)
|
2739
|
-
{
|
2740
|
-
return eio__2path (EIO_LINK, path, new_path, pri, cb, data);
|
2741
|
-
}
|
2742
|
-
|
2743
|
-
eio_req *eio_symlink (const char *path, const char *new_path, int pri, eio_cb cb, void *data)
|
2744
|
-
{
|
2745
|
-
return eio__2path (EIO_SYMLINK, path, new_path, pri, cb, data);
|
2746
|
-
}
|
2747
|
-
|
2748
|
-
eio_req *eio_rename (const char *path, const char *new_path, int pri, eio_cb cb, void *data)
|
2749
|
-
{
|
2750
|
-
return eio__2path (EIO_RENAME, path, new_path, pri, cb, data);
|
2751
|
-
}
|
2752
|
-
|
2753
|
-
eio_req *eio_custom (void (*execute)(eio_req *), int pri, eio_cb cb, void *data)
|
2754
|
-
{
|
2755
|
-
REQ (EIO_CUSTOM); req->feed = execute; SEND;
|
2756
|
-
}
|
2757
|
-
|
2758
|
-
#endif
|
2759
|
-
|
2760
|
-
eio_req *eio_grp (eio_cb cb, void *data)
|
2761
|
-
{
|
2762
|
-
const int pri = EIO_PRI_MAX;
|
2763
|
-
|
2764
|
-
REQ (EIO_GROUP); SEND;
|
2765
|
-
}
|
2766
|
-
|
2767
|
-
#undef REQ
|
2768
|
-
#undef PATH
|
2769
|
-
#undef SEND
|
2770
|
-
|
2771
|
-
/*****************************************************************************/
|
2772
|
-
/* grp functions */
|
2773
|
-
|
2774
|
-
void
|
2775
|
-
eio_grp_feed (eio_req *grp, void (*feed)(eio_req *req), int limit)
|
2776
|
-
{
|
2777
|
-
grp->int2 = limit;
|
2778
|
-
grp->feed = feed;
|
2779
|
-
|
2780
|
-
grp_try_feed (grp);
|
2781
|
-
}
|
2782
|
-
|
2783
|
-
void
|
2784
|
-
eio_grp_limit (eio_req *grp, int limit)
|
2785
|
-
{
|
2786
|
-
grp->int2 = limit;
|
2787
|
-
|
2788
|
-
grp_try_feed (grp);
|
2789
|
-
}
|
2790
|
-
|
2791
|
-
void
|
2792
|
-
eio_grp_add (eio_req *grp, eio_req *req)
|
2793
|
-
{
|
2794
|
-
assert (("cannot add requests to IO::AIO::GRP after the group finished", grp->int1 != 2));
|
2795
|
-
|
2796
|
-
grp->flags |= EIO_FLAG_GROUPADD;
|
2797
|
-
|
2798
|
-
++grp->size;
|
2799
|
-
req->grp = grp;
|
2800
|
-
|
2801
|
-
req->grp_prev = 0;
|
2802
|
-
req->grp_next = grp->grp_first;
|
2803
|
-
|
2804
|
-
if (grp->grp_first)
|
2805
|
-
grp->grp_first->grp_prev = req;
|
2806
|
-
|
2807
|
-
grp->grp_first = req;
|
2808
|
-
}
|
2809
|
-
|
2810
|
-
/*****************************************************************************/
|
2811
|
-
/* misc garbage */
|
2812
|
-
|
2813
|
-
eio_ssize_t
|
2814
|
-
eio_sendfile_sync (int ofd, int ifd, off_t offset, size_t count)
|
2815
|
-
{
|
2816
|
-
return eio__sendfile (ofd, ifd, offset, count);
|
2817
|
-
}
|
2818
|
-
|