Imported Upstream version 1.46.0
[platform/upstream/nghttp2.git] / third-party / mruby / mrbgems / mruby-io / test / mruby_io_test.c
1 #include <mruby/common.h>
2 #include <sys/types.h>
3 #include <errno.h>
4 #include <string.h>
5
6 #if defined(_WIN32) || defined(_WIN64)
7
8 #include <winsock.h>
9 #include <io.h>
10 #include <fcntl.h>
11 #include <direct.h>
12 #include <stdlib.h>
13 #include <malloc.h>
14
15 #if (!defined __MINGW64__) && (!defined __MINGW32__)
16 typedef int mode_t;
17 #endif
18
19 #define open _open
20 #define close _close
21
22 #if defined(_MSC_VER) || \
23     (defined(MRB_MINGW32_VERSION) && MRB_MINGW32_VERSION < 3021) || \
24     (defined(MRB_MINGW64_VERSION) && MRB_MINGW64_VERSION < 4000)
25 #include <sys/stat.h>
26
27 static int
28 mkstemp(char *p)
29 {
30   int fd;
31   char* fname = _mktemp(p);
32   if (fname == NULL)
33     return -1;
34   fd = open(fname, O_RDWR | O_CREAT | O_EXCL, _S_IREAD | _S_IWRITE);
35   if (fd >= 0)
36     return fd;
37   return -1;
38 }
39 #endif
40
41 static char*
42 mkdtemp(char *temp)
43 {
44   char *path = _mktemp(temp);
45   if (path[0] == 0) return NULL;
46   if (_mkdir(path) < 0) return NULL;
47   return path;
48 }
49
50 #define umask(mode) _umask(mode)
51 #define rmdir(path) _rmdir(path)
52 #else
53   #include <sys/socket.h>
54   #include <unistd.h>
55   #include <sys/un.h>
56   #include <fcntl.h>
57   #include <libgen.h>
58 #endif
59
60 #include <sys/stat.h>
61 #include <stdlib.h>
62
63 #include "mruby.h"
64 #include "mruby/array.h"
65 #include "mruby/error.h"
66 #include "mruby/string.h"
67 #include "mruby/variable.h"
68 #include <mruby/ext/io.h>
69
70 static mrb_value
71 mrb_io_test_io_setup(mrb_state *mrb, mrb_value self)
72 {
73 #define GVNAME(n) "$mrbtest_io_" #n "name"
74   enum {IDX_READ, IDX_WRITE, IDX_LINK, IDX_SOCKET, IDX_COUNT};
75   const char *gvnames[] = {GVNAME(rf), GVNAME(wf), GVNAME(symlink), GVNAME(socket)};
76   char *fnames[IDX_COUNT];
77   int fds[IDX_COUNT];
78   char msg[] = "mruby io test\n";
79   mode_t mask;
80   FILE *fp;
81   int i;
82 #if !defined(_WIN32) && !defined(_WIN64)
83   struct sockaddr_un sun0;
84 #endif
85
86   mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_msg"), mrb_str_new_cstr(mrb, msg));
87
88   mask = umask(077);
89   for (i = 0; i < IDX_COUNT; i++) {
90     mrb_value fname = mrb_str_new_capa(mrb, 0);
91 #if !defined(_WIN32) && !defined(_WIN64)
92     /*
93      * Workaround for not being able to bind a socket to some file systems
94      * (e.g. vboxsf, NFS). [#4981]
95      */
96     char *tmpdir = getenv("TMPDIR");
97     if (tmpdir && strlen(tmpdir) > 0) {
98       mrb_str_cat_cstr(mrb, fname, tmpdir);
99       if (*(RSTRING_END(fname)-1) != '/') mrb_str_cat_lit(mrb, fname, "/");
100     } else {
101       mrb_str_cat_lit(mrb, fname, "/tmp/");
102     }
103 #endif
104     mrb_str_cat_cstr(mrb, fname, gvnames[i]+1);
105     mrb_str_cat_cstr(mrb, fname, ".XXXXXXXX");
106     fnames[i] = RSTRING_PTR(fname);
107     fds[i] = mkstemp(fnames[i]);
108     if (fds[i] == -1) {
109       mrb_raise(mrb, E_RUNTIME_ERROR, "can't create temporary file");
110     }
111     close(fds[i]);
112     mrb_gv_set(mrb, mrb_intern_cstr(mrb, gvnames[i]), fname);
113   }
114   umask(mask);
115
116   fp = fopen(fnames[IDX_READ], "wb");
117   if (fp == NULL) {
118     mrb_raise(mrb, E_RUNTIME_ERROR, "can't open temporary file");
119     return mrb_nil_value();
120   }
121   fputs(msg, fp);
122   fclose(fp);
123
124   fp = fopen(fnames[IDX_WRITE], "wb");
125   if (fp == NULL) {
126     mrb_raise(mrb, E_RUNTIME_ERROR, "can't open temporary file");
127     return mrb_nil_value();
128   }
129   fclose(fp);
130
131 #if !defined(_WIN32) && !defined(_WIN64)
132   unlink(fnames[IDX_LINK]);
133   if (symlink(basename(fnames[IDX_READ]), fnames[IDX_LINK]) == -1) {
134     mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a symbolic link");
135   }
136
137   unlink(fnames[IDX_SOCKET]);
138   fds[IDX_SOCKET] = socket(AF_UNIX, SOCK_STREAM, 0);
139   if (fds[IDX_SOCKET] == -1) {
140     mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a socket");
141   }
142   sun0.sun_family = AF_UNIX;
143   strncpy(sun0.sun_path, fnames[IDX_SOCKET], sizeof(sun0.sun_path)-1);
144   sun0.sun_path[sizeof(sun0.sun_path)-1] = 0;
145   if (bind(fds[IDX_SOCKET], (struct sockaddr *)&sun0, sizeof(sun0)) == -1) {
146     mrb_raisef(mrb, E_RUNTIME_ERROR, "can't bind AF_UNIX socket to %s: %d",
147                sun0.sun_path,
148                errno);
149   }
150   close(fds[IDX_SOCKET]);
151 #endif
152
153   return mrb_true_value();
154 #undef GVNAME
155 }
156
157 static mrb_value
158 mrb_io_test_io_cleanup(mrb_state *mrb, mrb_value self)
159 {
160   mrb_value rfname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"));
161   mrb_value wfname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"));
162   mrb_value symlinkname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"));
163   mrb_value socketname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"));
164
165   if (mrb_string_p(rfname)) {
166     remove(RSTRING_PTR(rfname));
167   }
168   if (mrb_string_p(wfname)) {
169     remove(RSTRING_PTR(wfname));
170   }
171   if (mrb_string_p(symlinkname)) {
172     remove(RSTRING_PTR(symlinkname));
173   }
174   if (mrb_string_p(socketname)) {
175     remove(RSTRING_PTR(socketname));
176   }
177
178   mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"), mrb_nil_value());
179   mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"), mrb_nil_value());
180   mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"), mrb_nil_value());
181   mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"), mrb_nil_value());
182   mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_msg"), mrb_nil_value());
183
184   return mrb_nil_value();
185 }
186
187 static mrb_value
188 mrb_io_test_mkdtemp(mrb_state *mrb, mrb_value klass)
189 {
190   mrb_value str;
191   char *cp;
192
193   mrb_get_args(mrb, "S", &str);
194   cp = mrb_str_to_cstr(mrb, str);
195   if (mkdtemp(cp) == NULL) {
196     mrb_sys_fail(mrb, "mkdtemp");
197   }
198   return mrb_str_new_cstr(mrb, cp);
199 }
200
201 static mrb_value
202 mrb_io_test_rmdir(mrb_state *mrb, mrb_value klass)
203 {
204   const char *cp;
205
206   mrb_get_args(mrb, "z", &cp);
207   if (rmdir(cp) == -1) {
208     mrb_sys_fail(mrb, "rmdir");
209   }
210   return mrb_true_value();
211 }
212
213 static mrb_value
214 mrb_io_win_p(mrb_state *mrb, mrb_value klass)
215 {
216 #if defined(_WIN32) || defined(_WIN64)
217 # if defined(__CYGWIN__) || defined(__CYGWIN32__)
218   return mrb_false_value();
219 # else
220   return mrb_true_value();
221 # endif
222 #else
223   return mrb_false_value();
224 #endif
225 }
226
227 #ifdef MRB_WITH_IO_PREAD_PWRITE
228 # define MRB_WITH_IO_PREAD_PWRITE_ENABLED TRUE
229 #else
230 # define MRB_WITH_IO_PREAD_PWRITE_ENABLED FALSE
231 #endif
232
233 void
234 mrb_mruby_io_gem_test(mrb_state* mrb)
235 {
236   struct RClass *io_test = mrb_define_module(mrb, "MRubyIOTestUtil");
237   mrb_define_class_method(mrb, io_test, "io_test_setup", mrb_io_test_io_setup, MRB_ARGS_NONE());
238   mrb_define_class_method(mrb, io_test, "io_test_cleanup", mrb_io_test_io_cleanup, MRB_ARGS_NONE());
239
240   mrb_define_class_method(mrb, io_test, "mkdtemp", mrb_io_test_mkdtemp, MRB_ARGS_REQ(1));
241   mrb_define_class_method(mrb, io_test, "rmdir", mrb_io_test_rmdir, MRB_ARGS_REQ(1));
242   mrb_define_class_method(mrb, io_test, "win?", mrb_io_win_p, MRB_ARGS_NONE());
243
244   mrb_define_const(mrb, io_test, "MRB_WITH_IO_PREAD_PWRITE", mrb_bool_value(MRB_WITH_IO_PREAD_PWRITE_ENABLED));
245 }