source: EcnlProtoTool/trunk/mrbgems/mruby-io/src/file.c@ 321

Last change on this file since 321 was 321, checked in by coas-nagasima, 7 years ago

文字コードを設定

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 11.2 KB
Line 
1/*
2** file.c - File 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
11#if MRUBY_RELEASE_NO < 10000
12#include "error.h"
13#else
14#include "mruby/error.h"
15#endif
16
17#include <sys/types.h>
18#include <sys/stat.h>
19
20#include <fcntl.h>
21#include <limits.h>
22
23#include <errno.h>
24#include <stdlib.h>
25#include <string.h>
26#if defined(_WIN32) || defined(_WIN64)
27 #define NULL_FILE "NUL"
28 #define UNLINK _unlink
29 #define GETCWD _getcwd
30 #define CHMOD(a, b) 0
31 #define MAXPATHLEN 1024
32 #if !defined(PATH_MAX)
33 #define PATH_MAX _MAX_PATH
34 #endif
35 #define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
36 #include <direct.h>
37#else
38 #define NULL_FILE "/dev/null"
39 #include <unistd.h>
40 #define UNLINK unlink
41 #define GETCWD getcwd
42 #define CHMOD(a, b) chmod(a,b)
43 #include <sys/file.h>
44 #include <libgen.h>
45 #include <sys/param.h>
46 #include <pwd.h>
47#endif
48#if defined(__NEWLIB__)
49 #define _MAX_DIR 253
50 #define _MAX_DRIVE 2
51 #define PATH_MAX (_MAX_DRIVE + _MAX_DIR)
52 #define MAXPATHLEN (_MAX_DRIVE + _MAX_DIR)
53#endif
54
55#define FILE_SEPARATOR "/"
56
57#if defined(_WIN32) || defined(_WIN64)
58 #define PATH_SEPARATOR ";"
59 #define FILE_ALT_SEPARATOR "\\"
60#else
61 #define PATH_SEPARATOR ":"
62#endif
63
64#ifndef LOCK_SH
65#define LOCK_SH 1
66#endif
67#ifndef LOCK_EX
68#define LOCK_EX 2
69#endif
70#ifndef LOCK_NB
71#define LOCK_NB 4
72#endif
73#ifndef LOCK_UN
74#define LOCK_UN 8
75#endif
76
77#define STAT(p, s) stat(p, s)
78
79
80mrb_value
81mrb_file_s_umask(mrb_state *mrb, mrb_value klass)
82{
83#if defined(_WIN32) || defined(_WIN64) || defined(__NEWLIB__)
84 /* nothing to do on windows */
85 return mrb_fixnum_value(0);
86
87#else
88 mrb_int mask, omask;
89 if (mrb_get_args(mrb, "|i", &mask) == 0) {
90 omask = umask(0);
91 umask(omask);
92 } else {
93 omask = umask(mask);
94 }
95 return mrb_fixnum_value(omask);
96#endif
97}
98
99static mrb_value
100mrb_file_s_unlink(mrb_state *mrb, mrb_value obj)
101{
102 mrb_value *argv;
103 mrb_value pathv;
104 mrb_int argc, i;
105 const char *path;
106
107 mrb_get_args(mrb, "*", &argv, &argc);
108 for (i = 0; i < argc; i++) {
109 pathv = mrb_convert_type(mrb, argv[i], MRB_TT_STRING, "String", "to_str");
110 path = mrb_string_value_cstr(mrb, &pathv);
111 if (UNLINK(path) < 0) {
112 mrb_sys_fail(mrb, path);
113 }
114 }
115 return mrb_fixnum_value(argc);
116}
117
118static mrb_value
119mrb_file_s_rename(mrb_state *mrb, mrb_value obj)
120{
121 mrb_value from, to;
122 const char *src, *dst;
123
124 mrb_get_args(mrb, "SS", &from, &to);
125 src = mrb_string_value_cstr(mrb, &from);
126 dst = mrb_string_value_cstr(mrb, &to);
127 if (rename(src, dst) < 0) {
128 if (CHMOD(dst, 0666) == 0 && UNLINK(dst) == 0 && rename(src, dst) == 0) {
129 return mrb_fixnum_value(0);
130 }
131 mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to)));
132 }
133 return mrb_fixnum_value(0);
134}
135
136static mrb_value
137mrb_file_dirname(mrb_state *mrb, mrb_value klass)
138{
139#if defined(_WIN32) || defined(_WIN64)
140 char dname[_MAX_DIR], vname[_MAX_DRIVE];
141 char buffer[_MAX_DRIVE + _MAX_DIR];
142 char *path;
143 size_t ridx;
144 mrb_value s;
145 mrb_get_args(mrb, "S", &s);
146 path = mrb_str_to_cstr(mrb, s);
147 _splitpath((const char*)path, vname, dname, NULL, NULL);
148 snprintf(buffer, _MAX_DRIVE + _MAX_DIR, "%s%s", vname, dname);
149 ridx = strlen(buffer);
150 if (ridx == 0) {
151 strncpy(buffer, ".", 2); /* null terminated */
152 } else if (ridx > 1) {
153 ridx--;
154 while (ridx > 0 && (buffer[ridx] == '/' || buffer[ridx] == '\\')) {
155 buffer[ridx] = '\0'; /* remove last char */
156 ridx--;
157 }
158 }
159 return mrb_str_new_cstr(mrb, buffer);
160#else
161 char *dname, *path;
162 mrb_value s;
163 mrb_get_args(mrb, "S", &s);
164 path = mrb_str_to_cstr(mrb, s);
165
166 if ((dname = dirname(path)) == NULL) {
167 mrb_sys_fail(mrb, "dirname");
168 }
169#endif
170 return mrb_str_new_cstr(mrb, dname);
171}
172
173static mrb_value
174mrb_file_basename(mrb_state *mrb, mrb_value klass)
175{
176#if defined(_WIN32) || defined(_WIN64)
177 char bname[_MAX_DIR];
178 char extname[_MAX_EXT];
179 char *path;
180 size_t ridx;
181 char buffer[_MAX_DIR + _MAX_EXT];
182 mrb_value s;
183 mrb_get_args(mrb, "S", &s);
184 path = mrb_str_to_cstr(mrb, s);
185 ridx = strlen(path);
186 if (ridx > 0) {
187 ridx--;
188 while (ridx > 0 && (path[ridx] == '/' || path[ridx] == '\\')) {
189 path[ridx] = '\0';
190 ridx--;
191 }
192 if (strncmp(path, "/", 2) == 0) {
193 return mrb_str_new_cstr(mrb, path);
194 }
195 }
196 _splitpath((const char*)path, NULL, NULL, bname, extname);
197 snprintf(buffer, _MAX_DIR + _MAX_EXT, "%s%s", bname, extname);
198 return mrb_str_new_cstr(mrb, buffer);
199#else
200 char *bname, *path;
201 mrb_value s;
202 mrb_get_args(mrb, "S", &s);
203 path = mrb_str_to_cstr(mrb, s);
204 if ((bname = basename(path)) == NULL) {
205 mrb_sys_fail(mrb, "basename");
206 }
207 return mrb_str_new_cstr(mrb, bname);
208#endif
209}
210
211static mrb_value
212mrb_file_realpath(mrb_state *mrb, mrb_value klass)
213{
214 mrb_value pathname, dir_string, s, result;
215 int argc;
216 char *cpath;
217
218 argc = mrb_get_args(mrb, "S|S", &pathname, &dir_string);
219 if (argc == 2) {
220 s = mrb_str_dup(mrb, dir_string);
221 s = mrb_str_append(mrb, s, mrb_str_new_cstr(mrb, FILE_SEPARATOR));
222 s = mrb_str_append(mrb, s, pathname);
223 pathname = s;
224 }
225 cpath = mrb_str_to_cstr(mrb, pathname);
226 result = mrb_str_buf_new(mrb, PATH_MAX);
227 if (realpath(cpath, RSTRING_PTR(result)) == NULL)
228 mrb_sys_fail(mrb, cpath);
229 mrb_str_resize(mrb, result, strlen(RSTRING_PTR(result)));
230 return result;
231}
232
233mrb_value
234mrb_file__getwd(mrb_state *mrb, mrb_value klass)
235{
236 mrb_value path;
237
238 path = mrb_str_buf_new(mrb, MAXPATHLEN);
239 if (GETCWD(RSTRING_PTR(path), MAXPATHLEN) == NULL) {
240 mrb_sys_fail(mrb, "getcwd(2)");
241 }
242 mrb_str_resize(mrb, path, strlen(RSTRING_PTR(path)));
243 return path;
244}
245
246static int
247mrb_file_is_absolute_path(const char *path)
248{
249 return (path[0] == '/');
250}
251
252static mrb_value
253mrb_file__gethome(mrb_state *mrb, mrb_value klass)
254{
255#if !defined(_WIN32) && !defined(_WIN64) && !defined(__NEWLIB__)
256 mrb_value username;
257 int argc;
258 char *home;
259
260 argc = mrb_get_args(mrb, "|S", &username);
261 if (argc == 0) {
262 home = getenv("HOME");
263 if (home == NULL) {
264 return mrb_nil_value();
265 }
266 if (!mrb_file_is_absolute_path(home)) {
267 mrb_raise(mrb, E_ARGUMENT_ERROR, "non-absolute home");
268 }
269 } else {
270 const char *cuser = mrb_str_to_cstr(mrb, username);
271 struct passwd *pwd = getpwnam(cuser);
272 if (pwd == NULL) {
273 return mrb_nil_value();
274 }
275 home = pwd->pw_dir;
276 if (!mrb_file_is_absolute_path(home)) {
277 mrb_raisef(mrb, E_ARGUMENT_ERROR, "non-absolute home of ~%S", username);
278 }
279 }
280 return mrb_str_new_cstr(mrb, home);
281#else
282
283 return mrb_nil_value();
284#endif
285}
286
287mrb_value
288mrb_file_flock(mrb_state *mrb, mrb_value self)
289{
290#if defined(_WIN32) || defined(_WIN64) || defined(sun) || defined(__NEWLIB__)
291 mrb_raise(mrb, E_NOTIMP_ERROR, "flock is not supported on Illumos/Solaris/Windows");
292#else
293 mrb_int operation;
294 int fd;
295
296 mrb_get_args(mrb, "i", &operation);
297 fd = mrb_fixnum(mrb_io_fileno(mrb, self));
298
299 while (flock(fd, operation) == -1) {
300 switch (errno) {
301 case EINTR:
302 /* retry */
303 break;
304 case EAGAIN: /* NetBSD */
305#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
306 case EWOULDBLOCK: /* FreeBSD OpenBSD Linux */
307#endif
308 if (operation & LOCK_NB) {
309 return mrb_false_value();
310 }
311 /* FALLTHRU - should not happen */
312 default:
313 mrb_sys_fail(mrb, "flock failed");
314 break;
315 }
316 }
317#endif
318 return mrb_fixnum_value(0);
319}
320
321static mrb_value
322mrb_file_s_symlink(mrb_state *mrb, mrb_value klass)
323{
324#if defined(_WIN32) || defined(_WIN64) || defined(__NEWLIB__)
325 mrb_raise(mrb, E_NOTIMP_ERROR, "symlink is not supported on this platform");
326#else
327 mrb_value from, to;
328 const char *src, *dst;
329 int ai = mrb_gc_arena_save(mrb);
330
331 mrb_get_args(mrb, "SS", &from, &to);
332 src = mrb_str_to_cstr(mrb, from);
333 dst = mrb_str_to_cstr(mrb, to);
334
335 if (symlink(src, dst) == -1) {
336 mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to)));
337 }
338 mrb_gc_arena_restore(mrb, ai);
339#endif
340 return mrb_fixnum_value(0);
341}
342
343static mrb_value
344mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) {
345 mrb_int mode;
346 mrb_int argc, i;
347 mrb_value *filenames;
348 int ai = mrb_gc_arena_save(mrb);
349
350 mrb_get_args(mrb, "i*", &mode, &filenames, &argc);
351 for (i = 0; i < argc; i++) {
352 char *path = mrb_str_to_cstr(mrb, filenames[i]);
353 if (CHMOD(path, mode) == -1) {
354 mrb_sys_fail(mrb, path);
355 }
356 }
357
358 mrb_gc_arena_restore(mrb, ai);
359 return mrb_fixnum_value(argc);
360}
361
362static mrb_value
363mrb_file_s_readlink(mrb_state *mrb, mrb_value klass) {
364#if defined(_WIN32) || defined(_WIN64) || defined(__NEWLIB__)
365 mrb_raise(mrb, E_NOTIMP_ERROR, "readlink is not supported on this platform");
366 return mrb_nil_value(); // unreachable
367#else
368 char *path, *buf;
369 size_t bufsize = 100;
370 ssize_t rc;
371 mrb_value ret;
372 int ai = mrb_gc_arena_save(mrb);
373
374 mrb_get_args(mrb, "z", &path);
375
376 buf = (char *)mrb_malloc(mrb, bufsize);
377 while ((rc = readlink(path, buf, bufsize)) == bufsize && rc != -1) {
378 bufsize *= 2;
379 buf = (char *)mrb_realloc(mrb, buf, bufsize);
380 }
381 if (rc == -1) {
382 mrb_free(mrb, buf);
383 mrb_sys_fail(mrb, path);
384 }
385 ret = mrb_str_new(mrb, buf, rc);
386 mrb_free(mrb, buf);
387
388 mrb_gc_arena_restore(mrb, ai);
389 return ret;
390#endif
391}
392
393void
394mrb_init_file(mrb_state *mrb)
395{
396 struct RClass *io, *file, *cnst;
397
398 io = mrb_class_get(mrb, "IO");
399 file = mrb_define_class(mrb, "File", io);
400 MRB_SET_INSTANCE_TT(file, MRB_TT_DATA);
401 mrb_define_class_method(mrb, file, "umask", mrb_file_s_umask, MRB_ARGS_REQ(1));
402 mrb_define_class_method(mrb, file, "delete", mrb_file_s_unlink, MRB_ARGS_ANY());
403 mrb_define_class_method(mrb, file, "unlink", mrb_file_s_unlink, MRB_ARGS_ANY());
404 mrb_define_class_method(mrb, file, "rename", mrb_file_s_rename, MRB_ARGS_REQ(2));
405 mrb_define_class_method(mrb, file, "symlink", mrb_file_s_symlink, MRB_ARGS_REQ(2));
406 mrb_define_class_method(mrb, file, "chmod", mrb_file_s_chmod, MRB_ARGS_REQ(1) | MRB_ARGS_REST());
407 mrb_define_class_method(mrb, file, "readlink", mrb_file_s_readlink, MRB_ARGS_REQ(1));
408
409 mrb_define_class_method(mrb, file, "dirname", mrb_file_dirname, MRB_ARGS_REQ(1));
410 mrb_define_class_method(mrb, file, "basename", mrb_file_basename, MRB_ARGS_REQ(1));
411 mrb_define_class_method(mrb, file, "realpath", mrb_file_realpath, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
412 mrb_define_class_method(mrb, file, "_getwd", mrb_file__getwd, MRB_ARGS_NONE());
413 mrb_define_class_method(mrb, file, "_gethome", mrb_file__gethome, MRB_ARGS_OPT(1));
414
415 mrb_define_method(mrb, file, "flock", mrb_file_flock, MRB_ARGS_REQ(1));
416
417 cnst = mrb_define_module_under(mrb, file, "Constants");
418 mrb_define_const(mrb, cnst, "LOCK_SH", mrb_fixnum_value(LOCK_SH));
419 mrb_define_const(mrb, cnst, "LOCK_EX", mrb_fixnum_value(LOCK_EX));
420 mrb_define_const(mrb, cnst, "LOCK_UN", mrb_fixnum_value(LOCK_UN));
421 mrb_define_const(mrb, cnst, "LOCK_NB", mrb_fixnum_value(LOCK_NB));
422 mrb_define_const(mrb, cnst, "SEPARATOR", mrb_str_new_cstr(mrb, FILE_SEPARATOR));
423 mrb_define_const(mrb, cnst, "PATH_SEPARATOR", mrb_str_new_cstr(mrb, PATH_SEPARATOR));
424#if defined(_WIN32) || defined(_WIN64)
425 mrb_define_const(mrb, cnst, "ALT_SEPARATOR", mrb_str_new_cstr(mrb, FILE_ALT_SEPARATOR));
426#else
427 mrb_define_const(mrb, cnst, "ALT_SEPARATOR", mrb_nil_value());
428#endif
429 mrb_define_const(mrb, cnst, "NULL", mrb_str_new_cstr(mrb, NULL_FILE));
430
431}
Note: See TracBrowser for help on using the repository browser.