Skip to content

Commit 17e0756

Browse files
kevinxucshhvm-bot
authored andcommitted
Implemented UserFile file descriptor casting.
Summary: Implemented UserFile file descriptor casting by calling user defined function streamWrapper::stream_cast(int). Also in the function which converts File* to file descriptor, checks whether the casting function fd() returns -1, raise warning if so. Finally after all the castings for read / write / except array are done, check whether any file descriptors are successfully casted, if not, raise warning and return false. Passing vfsstream selectStream test. Closes #4320 Reviewed By: @JoelMarcey Differential Revision: D1700515 Signature: t1:1700515:1417906904:ef75237addf5559d512ae99d959a2a7df9a3b304
1 parent 37f0d70 commit 17e0756

File tree

7 files changed

+91
-5
lines changed

7 files changed

+91
-5
lines changed

hphp/runtime/base/file.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ struct File : SweepableResourceData {
7575
const String& o_getResourceName() const { return s_resource_name; }
7676
virtual bool isInvalid() const { return m_closed; }
7777

78-
int fd() const { return m_fd;}
78+
virtual int fd() const { return m_fd;}
7979
bool valid() const { return m_fd >= 0;}
8080
const std::string getName() const { return m_name;}
8181

hphp/runtime/base/user-file.cpp

+66
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ namespace HPHP {
3838
#define PHP_LOCK_UN 3
3939
#define PHP_LOCK_NB 4
4040

41+
/* coerce the stream into some other form */
42+
/* cast as a stdio FILE * */
43+
#define PHP_STREAM_AS_STDIO 0
44+
/* cast as a POSIX fd or socketd */
45+
#define PHP_STREAM_AS_FD 1
46+
/* cast as a socketd */
47+
#define PHP_STREAM_AS_SOCKETD 2
48+
/* cast as fd/socket for select purposes */
49+
#define PHP_STREAM_AS_FD_FOR_SELECT 3
50+
4151
StaticString s_stream_open("stream_open");
4252
StaticString s_stream_close("stream_close");
4353
StaticString s_stream_read("stream_read");
@@ -50,6 +60,7 @@ StaticString s_stream_truncate("stream_truncate");
5060
StaticString s_stream_lock("stream_lock");
5161
StaticString s_stream_stat("stream_stat");
5262
StaticString s_stream_metadata("stream_metadata");
63+
StaticString s_stream_cast("stream_cast");
5364
StaticString s_url_stat("url_stat");
5465
StaticString s_unlink("unlink");
5566
StaticString s_rename("rename");
@@ -76,6 +87,7 @@ UserFile::UserFile(Class *cls, const Variant& context /*= null */) : UserFSNode(
7687
m_Mkdir = lookupMethod(s_mkdir.get());
7788
m_Rmdir = lookupMethod(s_rmdir.get());
7889
m_StreamMetadata = lookupMethod(s_stream_metadata.get());
90+
m_StreamCast = lookupMethod(s_stream_cast.get());
7991

8092
m_isLocal = true;
8193

@@ -98,6 +110,60 @@ void UserFile::sweep() {
98110

99111
///////////////////////////////////////////////////////////////////////////////
100112

113+
Resource UserFile::invokeCast(int castas) {
114+
bool invoked = false;
115+
Variant ret = invoke(
116+
m_StreamCast,
117+
s_stream_cast,
118+
PackedArrayInit(1)
119+
.append(castas)
120+
.toArray(),
121+
invoked
122+
);
123+
124+
if (!invoked) {
125+
raise_warning(
126+
"%s::stream_cast is not implemented!",
127+
m_cls->name()->data()
128+
);
129+
return Resource();
130+
}
131+
if (ret.toBoolean() == false) {
132+
return Resource();
133+
}
134+
Resource handle = ret.toResource();
135+
File *f = handle.getTyped<File>(true, true);
136+
if (!f) {
137+
raise_warning(
138+
"%s::stream_cast must return a stream resource",
139+
m_cls->name()->data()
140+
);
141+
return Resource();
142+
}
143+
if (f == this) {
144+
raise_warning(
145+
"%s::stream_cast must not return itself",
146+
m_cls->name()->data()
147+
);
148+
return Resource();
149+
}
150+
151+
return handle;
152+
}
153+
154+
int UserFile::fd() const {
155+
Resource handle = const_cast<UserFile*>(this)->invokeCast(
156+
PHP_STREAM_AS_FD_FOR_SELECT);
157+
if (handle.isNull()) {
158+
raise_warning(
159+
"cannot represent a stream of type user-space as a file descriptor"
160+
);
161+
return -1;
162+
}
163+
File *f = handle.getTyped<File>();
164+
return f->fd();
165+
}
166+
101167
///////////////////////////////////////////////////////////////////////////////
102168

103169
bool UserFile::openImpl(const String& filename, const String& mode,

hphp/runtime/base/user-file.h

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ class UserFile : public File, public UserFSNode {
3333
// overriding ResourceData
3434
const String& o_getClassNameHook() const { return classnameof(); }
3535

36+
virtual int fd() const;
37+
3638
virtual bool open(const String& filename, const String& mode) {
3739
return openImpl(filename, mode, 0);
3840
}
@@ -74,6 +76,7 @@ class UserFile : public File, public UserFSNode {
7476
int urlStat(const String& path, struct stat* stat_sb, int flags = 0);
7577
bool flushImpl(bool strict);
7678
bool invokeMetadata(const Array& args, const char* funcName);
79+
Resource invokeCast(int castas);
7780

7881
protected:
7982
const Func* m_StreamOpen;
@@ -88,6 +91,7 @@ class UserFile : public File, public UserFSNode {
8891
const Func* m_StreamLock;
8992
const Func* m_StreamStat;
9093
const Func* m_StreamMetadata;
94+
const Func* m_StreamCast;
9195
const Func* m_UrlStat;
9296
const Func* m_Unlink;
9397
const Func* m_Rename;

hphp/runtime/ext/sockets/ext_sockets.cpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,12 @@ static void sock_array_to_fd_set(const Array& sockets, pollfd *fds, int &nfds,
235235
assert(fds);
236236
for (ArrayIter iter(sockets); iter; ++iter) {
237237
File *sock = iter.second().toResource().getTyped<File>();
238+
int intfd = sock->fd();
239+
if (intfd < 0) {
240+
continue;
241+
}
238242
pollfd &fd = fds[nfds++];
239-
fd.fd = sock->fd();
243+
fd.fd = intfd;
240244
fd.events = flag;
241245
fd.revents = 0;
242246
}
@@ -849,6 +853,11 @@ Variant HHVM_FUNCTION(socket_select,
849853
if (!except.isNull()) {
850854
sock_array_to_fd_set(except.toArray(), fds, count, POLLPRI);
851855
}
856+
if (!count) {
857+
raise_warning("no resource arrays were passed to select");
858+
free(fds);
859+
return false;
860+
}
852861

853862
IOStatusHelper io("socket_select");
854863
int timeout_ms = -1;

hphp/test/frameworks/results/vfsstream.expect

+1-1
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ org\bovigo\vfs\vfsStreamWrapperQuotaTestCase::writeMoreThanQotaWritesOnlyUpToQuo
609609
org\bovigo\vfs\vfsStreamWrapperQuotaTestCase::writeUpToQotaWritesEverything
610610
.
611611
org\bovigo\vfs\vfsStreamWrapperSelectStreamTestCase::selectStream
612-
F
612+
.
613613
org\bovigo\vfs\vfsStreamWrapperSetOptionTestCase::removeBlockingDoesNotWork
614614
.
615615
org\bovigo\vfs\vfsStreamWrapperSetOptionTestCase::setBlockingDoesNotWork

hphp/test/slow/streams/stream_wrapper_register.php

-2
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,10 @@ public function url_stat($path, $flags) {
159159
feof($fp);
160160
fread($fp, 1);
161161

162-
/** We don't have anything like stream_cast
163162
$r = array($fp);
164163
$w = null;
165164
$e = null;
166165
stream_select($r, $w, $e, 0);
167-
*/
168166

169167
fflush($fp);
170168
flock($fp, LOCK_SH);

hphp/test/slow/streams/stream_wrapper_register.php.expect renamed to hphp/test/slow/streams/stream_wrapper_register.php.expectf

+9
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ array(1) {
2323
[0]=>
2424
int(8192)
2525
}
26+
string(11) "stream_cast"
27+
array(1) {
28+
[0]=>
29+
int(3)
30+
}
31+
32+
Warning: cannot represent a stream of type user-space as a file descriptor in %s/test/slow/streams/stream_wrapper_register.php on line %d
33+
34+
Warning: no resource arrays were passed to select in %s/test/slow/streams/stream_wrapper_register.php on line %d
2635
string(12) "stream_flush"
2736
array(0) {
2837
}

0 commit comments

Comments
 (0)