Imported Upstream version 1.46.0
[platform/upstream/nghttp2.git] / third-party / mruby / mrbgems / mruby-io / src / file_test.c
1 /*
2 ** file_test.c - FileTest class
3 */
4
5 #include "mruby.h"
6 #include "mruby/class.h"
7 #include "mruby/data.h"
8 #include "mruby/string.h"
9 #include "mruby/ext/io.h"
10 #include "mruby/error.h"
11
12 #include <sys/types.h>
13 #include <sys/stat.h>
14
15 #if defined(_WIN32) || defined(_WIN64)
16   #define LSTAT stat
17   #include <winsock.h>
18 #else
19   #define LSTAT lstat
20   #include <sys/file.h>
21   #include <sys/param.h>
22   #include <sys/wait.h>
23   #include <libgen.h>
24   #include <pwd.h>
25   #include <unistd.h>
26 #endif
27
28 #include <fcntl.h>
29
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 extern struct mrb_data_type mrb_io_type;
35
36 static int
37 mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat)
38 {
39   if (mrb_obj_is_kind_of(mrb, obj, mrb_class_get(mrb, "IO"))) {
40     struct mrb_io *fptr;
41     fptr = (struct mrb_io *)mrb_data_get_ptr(mrb, obj, &mrb_io_type);
42
43     if (fptr && fptr->fd >= 0) {
44       return fstat(fptr->fd, st);
45     }
46
47     mrb_raise(mrb, E_IO_ERROR, "closed stream");
48     return -1;
49   }
50   else {
51     char *path = mrb_locale_from_utf8(RSTRING_CSTR(mrb, obj), -1);
52     int ret;
53     if (do_lstat) {
54       ret = LSTAT(path, st);
55     } else {
56       ret = stat(path, st);
57     }
58     mrb_locale_free(path);
59     return ret;
60   }
61 }
62
63 static int
64 mrb_stat(mrb_state *mrb, mrb_value obj, struct stat *st)
65 {
66   return mrb_stat0(mrb, obj, st, 0);
67 }
68
69 static int
70 mrb_lstat(mrb_state *mrb, mrb_value obj, struct stat *st)
71 {
72   return mrb_stat0(mrb, obj, st, 1);
73 }
74
75 /*
76  * Document-method: directory?
77  *
78  * call-seq:
79  *   File.directory?(file_name)   ->  true or false
80  *
81  * Returns <code>true</code> if the named file is a directory,
82  * or a symlink that points at a directory, and <code>false</code>
83  * otherwise.
84  *
85  *    File.directory?(".")
86  */
87
88 static mrb_value
89 mrb_filetest_s_directory_p(mrb_state *mrb, mrb_value klass)
90 {
91 #ifndef S_ISDIR
92 #   define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
93 #endif
94
95   struct stat st;
96   mrb_value obj = mrb_get_arg1(mrb);
97
98   if (mrb_stat(mrb, obj, &st) < 0)
99     return mrb_false_value();
100   if (S_ISDIR(st.st_mode))
101     return mrb_true_value();
102
103   return mrb_false_value();
104 }
105
106 /*
107  * call-seq:
108  *   File.pipe?(file_name)   ->  true or false
109  *
110  * Returns <code>true</code> if the named file is a pipe.
111  */
112
113 static mrb_value
114 mrb_filetest_s_pipe_p(mrb_state *mrb, mrb_value klass)
115 {
116 #if defined(_WIN32) || defined(_WIN64)
117   mrb_raise(mrb, E_NOTIMP_ERROR, "pipe is not supported on this platform");
118 #else
119 #ifdef S_IFIFO
120 #  ifndef S_ISFIFO
121 #    define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
122 #  endif
123
124   struct stat st;
125   mrb_value obj = mrb_get_arg1(mrb);
126
127   if (mrb_stat(mrb, obj, &st) < 0)
128     return mrb_false_value();
129   if (S_ISFIFO(st.st_mode))
130     return mrb_true_value();
131
132 #endif
133   return mrb_false_value();
134 #endif
135 }
136
137 /*
138  * call-seq:
139  *   File.symlink?(file_name)   ->  true or false
140  *
141  * Returns <code>true</code> if the named file is a symbolic link.
142  */
143
144 static mrb_value
145 mrb_filetest_s_symlink_p(mrb_state *mrb, mrb_value klass)
146 {
147 #if defined(_WIN32) || defined(_WIN64)
148   mrb_raise(mrb, E_NOTIMP_ERROR, "symlink is not supported on this platform");
149 #else
150 #ifndef S_ISLNK
151 #  ifdef _S_ISLNK
152 #    define S_ISLNK(m) _S_ISLNK(m)
153 #  else
154 #    ifdef _S_IFLNK
155 #      define S_ISLNK(m) (((m) & S_IFMT) == _S_IFLNK)
156 #    else
157 #      ifdef S_IFLNK
158 #        define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
159 #      endif
160 #    endif
161 #  endif
162 #endif
163
164 #ifdef S_ISLNK
165   struct stat st;
166   mrb_value obj = mrb_get_arg1(mrb);
167
168   if (mrb_lstat(mrb, obj, &st) == -1)
169     return mrb_false_value();
170   if (S_ISLNK(st.st_mode))
171     return mrb_true_value();
172 #endif
173
174   return mrb_false_value();
175 #endif
176 }
177
178 /*
179  * call-seq:
180  *   File.socket?(file_name)   ->  true or false
181  *
182  * Returns <code>true</code> if the named file is a socket.
183  */
184
185 static mrb_value
186 mrb_filetest_s_socket_p(mrb_state *mrb, mrb_value klass)
187 {
188 #if defined(_WIN32) || defined(_WIN64)
189   mrb_raise(mrb, E_NOTIMP_ERROR, "socket is not supported on this platform");
190 #else
191 #ifndef S_ISSOCK
192 #  ifdef _S_ISSOCK
193 #    define S_ISSOCK(m) _S_ISSOCK(m)
194 #  else
195 #    ifdef _S_IFSOCK
196 #      define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
197 #    else
198 #      ifdef S_IFSOCK
199 #        define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
200 #      endif
201 #    endif
202 #  endif
203 #endif
204
205 #ifdef S_ISSOCK
206   struct stat st;
207   mrb_value obj = mrb_get_arg1(mrb);
208
209   if (mrb_stat(mrb, obj, &st) < 0)
210     return mrb_false_value();
211   if (S_ISSOCK(st.st_mode))
212     return mrb_true_value();
213 #endif
214
215   return mrb_false_value();
216 #endif
217 }
218
219 /*
220  * call-seq:
221  *    File.exist?(file_name)    ->  true or false
222  *    File.exists?(file_name)   ->  true or false
223  *
224  * Return <code>true</code> if the named file exists.
225  */
226
227 static mrb_value
228 mrb_filetest_s_exist_p(mrb_state *mrb, mrb_value klass)
229 {
230   struct stat st;
231   mrb_value obj = mrb_get_arg1(mrb);
232
233   if (mrb_stat(mrb, obj, &st) < 0)
234     return mrb_false_value();
235
236   return mrb_true_value();
237 }
238
239 /*
240  * call-seq:
241  *    File.file?(file_name)   -> true or false
242  *
243  * Returns <code>true</code> if the named file exists and is a
244  * regular file.
245  */
246
247 static mrb_value
248 mrb_filetest_s_file_p(mrb_state *mrb, mrb_value klass)
249 {
250 #ifndef S_ISREG
251 #   define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
252 #endif
253
254   struct stat st;
255   mrb_value obj = mrb_get_arg1(mrb);
256
257   if (mrb_stat(mrb, obj, &st) < 0)
258     return mrb_false_value();
259   if (S_ISREG(st.st_mode))
260     return mrb_true_value();
261
262   return mrb_false_value();
263 }
264
265 /*
266  * call-seq:
267  *    File.zero?(file_name)   -> true or false
268  *
269  * Returns <code>true</code> if the named file exists and has
270  * a zero size.
271  */
272
273 static mrb_value
274 mrb_filetest_s_zero_p(mrb_state *mrb, mrb_value klass)
275 {
276   struct stat st;
277   mrb_value obj = mrb_get_arg1(mrb);
278
279   if (mrb_stat(mrb, obj, &st) < 0)
280     return mrb_false_value();
281   if (st.st_size == 0)
282     return mrb_true_value();
283
284   return mrb_false_value();
285 }
286
287 /*
288  * call-seq:
289  *    File.size(file_name)   -> integer
290  *
291  * Returns the size of <code>file_name</code>.
292  *
293  * _file_name_ can be an IO object.
294  */
295
296 static mrb_value
297 mrb_filetest_s_size(mrb_state *mrb, mrb_value klass)
298 {
299   struct stat st;
300   mrb_value obj = mrb_get_arg1(mrb);
301
302   if (mrb_stat(mrb, obj, &st) < 0)
303     mrb_sys_fail(mrb, "mrb_stat");
304
305   return mrb_fixnum_value(st.st_size);
306 }
307
308 /*
309  * call-seq:
310  *    File.size?(file_name)   -> Integer or nil
311  *
312  * Returns +nil+ if +file_name+ doesn't exist or has zero size, the size of the
313  * file otherwise.
314  */
315
316 static mrb_value
317 mrb_filetest_s_size_p(mrb_state *mrb, mrb_value klass)
318 {
319   struct stat st;
320   mrb_value obj = mrb_get_arg1(mrb);
321
322   if (mrb_stat(mrb, obj, &st) < 0)
323     return mrb_nil_value();
324   if (st.st_size == 0)
325     return mrb_nil_value();
326
327   return mrb_fixnum_value(st.st_size);
328 }
329
330 void
331 mrb_init_file_test(mrb_state *mrb)
332 {
333   struct RClass *f;
334
335   f = mrb_define_class(mrb, "FileTest", mrb->object_class);
336
337   mrb_define_class_method(mrb, f, "directory?", mrb_filetest_s_directory_p, MRB_ARGS_REQ(1));
338   mrb_define_class_method(mrb, f, "exist?",     mrb_filetest_s_exist_p,     MRB_ARGS_REQ(1));
339   mrb_define_class_method(mrb, f, "exists?",    mrb_filetest_s_exist_p,     MRB_ARGS_REQ(1));
340   mrb_define_class_method(mrb, f, "file?",      mrb_filetest_s_file_p,      MRB_ARGS_REQ(1));
341   mrb_define_class_method(mrb, f, "pipe?",      mrb_filetest_s_pipe_p,      MRB_ARGS_REQ(1));
342   mrb_define_class_method(mrb, f, "size",       mrb_filetest_s_size,        MRB_ARGS_REQ(1));
343   mrb_define_class_method(mrb, f, "size?",      mrb_filetest_s_size_p,      MRB_ARGS_REQ(1));
344   mrb_define_class_method(mrb, f, "socket?",    mrb_filetest_s_socket_p,    MRB_ARGS_REQ(1));
345   mrb_define_class_method(mrb, f, "symlink?",   mrb_filetest_s_symlink_p,   MRB_ARGS_REQ(1));
346   mrb_define_class_method(mrb, f, "zero?",      mrb_filetest_s_zero_p,      MRB_ARGS_REQ(1));
347 }