1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15: #ifdef _WIN32
16: #include "missing/file.h"
17: #endif
18:
19: #include "ruby/ruby.h"
20: #include "ruby/io.h"
21: #include "ruby/signal.h"
22: #include "ruby/util.h"
23: #include "dln.h"
24:
25: #ifdef HAVE_UNISTD_H
26: #include <unistd.h>
27: #endif
28:
29: #ifdef HAVE_SYS_FILE_H
30: # include <sys/file.h>
31: #else
32: int flock(int, int);
33: #endif
34:
35: #ifdef HAVE_SYS_PARAM_H
36: # include <sys/param.h>
37: #endif
38: #ifndef MAXPATHLEN
39: # define MAXPATHLEN 1024
40: #endif
41:
42: #include <ctype.h>
43:
44: #include <time.h>
45:
46: #ifdef HAVE_UTIME_H
47: #include <utime.h>
48: #elif defined HAVE_SYS_UTIME_H
49: #include <sys/utime.h>
50: #endif
51:
52: #ifdef HAVE_PWD_H
53: #include <pwd.h>
54: #endif
55:
56: #include <sys/types.h>
57: #include <sys/stat.h>
58:
59: #ifdef HAVE_SYS_MKDEV_H
60: #include <sys/mkdev.h>
61: #endif
62:
63: #if !defined HAVE_LSTAT && !defined lstat
64: #define lstat stat
65: #endif
66:
67: #ifdef __BEOS__
68: static int
69: be_chown(const char *path, uid_t owner, gid_t group)
70: {
71: if (owner == -1 || group == -1) {
72: struct stat st;
73: if (stat(path, &st) < 0) return -1;
74: if (owner == -1) owner = st.st_uid;
75: if (group == -1) group = st.st_gid;
76: }
77: return chown(path, owner, group);
78: }
79: #define chown be_chown
80: static int
81: be_fchown(int fd, uid_t owner, gid_t group)
82: {
83: if (owner == -1 || group == -1) {
84: struct stat st;
85: if (fstat(fd, &st) < 0) return -1;
86: if (owner == -1) owner = st.st_uid;
87: if (group == -1) group = st.st_gid;
88: }
89: return fchown(fd, owner, group);
90: }
91: #define fchown be_fchown
92: #endif
93:
94: VALUE rb_cFile;
95: VALUE rb_mFileTest;
96: VALUE rb_cStat;
97:
98: static VALUE
99: rb_get_path_check(VALUE obj, int check)
100: {
101: VALUE tmp;
102: static ID to_path;
103:
104: if (check) rb_check_safe_obj(obj);
105: tmp = rb_check_string_type(obj);
106: if (!NIL_P(tmp)) goto exit;
107:
108: if (!to_path) {
109: to_path = rb_intern("to_path");
110: }
111: if (rb_respond_to(obj, to_path)) {
112: tmp = rb_funcall(obj, to_path, 0, 0);
113: }
114: else {
115: tmp = obj;
116: }
117: exit:
118: StringValueCStr(tmp);
119: if (check && obj != tmp) {
120: rb_check_safe_obj(tmp);
121: }
122: return rb_str_new4(tmp);
123: }
124:
125: VALUE
126: rb_get_path_no_checksafe(VALUE obj)
127: {
128: return rb_get_path_check(obj, 0);
129: }
130:
131: VALUE
132: rb_get_path(VALUE obj)
133: {
134: return rb_get_path_check(obj, 1);
135: }
136:
137: static long
138: apply2files(void (*func)(const char *, void *), VALUE vargs, void *arg)
139: {
140: long i;
141: volatile VALUE path;
142:
143: rb_secure(4);
144: for (i=0; i<RARRAY_LEN(vargs); i++) {
145: path = rb_get_path(RARRAY_PTR(vargs)[i]);
146: (*func)(StringValueCStr(path), arg);
147: }
148:
149: return RARRAY_LEN(vargs);
150: }
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164: static VALUE
165: rb_file_path(VALUE obj)
166: {
167: rb_io_t *fptr;
168:
169: fptr = RFILE(rb_io_taint_check(obj))->fptr;
170: rb_io_check_initialized(fptr);
171: if (!fptr->path) return Qnil;
172: return rb_tainted_str_new2(fptr->path);
173: }
174:
175: static VALUE
176: stat_new_0(VALUE klass, struct stat *st)
177: {
178: struct stat *nst = 0;
179:
180: if (st) {
181: nst = ALLOC(struct stat);
182: *nst = *st;
183: }
184: return Data_Wrap_Struct(klass, NULL, free, nst);
185: }
186:
187: static VALUE
188: stat_new(struct stat *st)
189: {
190: return stat_new_0(rb_cStat, st);
191: }
192:
193: static struct stat*
194: get_stat(VALUE self)
195: {
196: struct stat* st;
197: Data_Get_Struct(self, struct stat, st);
198: if (!st) rb_raise(rb_eTypeError, "uninitialized File::Stat");
199: return st;
200: }
201:
202: static struct timespec stat_mtimespec(struct stat *st);
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217: static VALUE
218: rb_stat_cmp(VALUE self, VALUE other)
219: {
220: if (rb_obj_is_kind_of(other, rb_obj_class(self))) {
221: struct timespec ts1 = stat_mtimespec(get_stat(self));
222: struct timespec ts2 = stat_mtimespec(get_stat(other));
223: if (ts1.tv_sec == ts2.tv_sec) {
224: if (ts1.tv_nsec == ts2.tv_nsec) return INT2FIX(0);
225: if (ts1.tv_nsec < ts2.tv_nsec) return INT2FIX(-1);
226: return INT2FIX(1);
227: }
228: if (ts1.tv_sec < ts2.tv_sec) return INT2FIX(-1);
229: return INT2FIX(1);
230: }
231: return Qnil;
232: }
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244: static VALUE
245: rb_stat_dev(VALUE self)
246: {
247: return INT2NUM(get_stat(self)->st_dev);
248: }
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261: static VALUE
262: rb_stat_dev_major(VALUE self)
263: {
264: #if defined(major)
265: long dev = get_stat(self)->st_dev;
266: return ULONG2NUM(major(dev));
267: #else
268: return Qnil;
269: #endif
270: }
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283: static VALUE
284: rb_stat_dev_minor(VALUE self)
285: {
286: #if defined(minor)
287: long dev = get_stat(self)->st_dev;
288: return ULONG2NUM(minor(dev));
289: #else
290: return Qnil;
291: #endif
292: }
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305: static VALUE
306: rb_stat_ino(VALUE self)
307: {
308: #ifdef HUGE_ST_INO
309: return ULL2NUM(get_stat(self)->st_ino);
310: #else
311: return ULONG2NUM(get_stat(self)->st_ino);
312: #endif
313: }
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325:
326:
327:
328: static VALUE
329: rb_stat_mode(VALUE self)
330: {
331: #ifdef __BORLANDC__
332: return UINT2NUM((unsigned short)(get_stat(self)->st_mode));
333: #else
334: return UINT2NUM(get_stat(self)->st_mode);
335: #endif
336: }
337:
338:
339:
340:
341:
342:
343:
344:
345:
346:
347:
348:
349:
350: static VALUE
351: rb_stat_nlink(VALUE self)
352: {
353: return UINT2NUM(get_stat(self)->st_nlink);
354: }
355:
356:
357:
358:
359:
360:
361:
362:
363:
364:
365:
366:
367: static VALUE
368: rb_stat_uid(VALUE self)
369: {
370: return UIDT2NUM(get_stat(self)->st_uid);
371: }
372:
373:
374:
375:
376:
377:
378:
379:
380:
381:
382:
383: static VALUE
384: rb_stat_gid(VALUE self)
385: {
386: return GIDT2NUM(get_stat(self)->st_gid);
387: }
388:
389:
390:
391:
392:
393:
394:
395:
396:
397:
398:
399:
400:
401:
402: static VALUE
403: rb_stat_rdev(VALUE self)
404: {
405: #ifdef HAVE_ST_RDEV
406: return ULONG2NUM(get_stat(self)->st_rdev);
407: #else
408: return Qnil;
409: #endif
410: }
411:
412:
413:
414:
415:
416:
417:
418:
419:
420:
421:
422:
423: static VALUE
424: rb_stat_rdev_major(VALUE self)
425: {
426: #if defined(HAVE_ST_RDEV) && defined(major)
427: long rdev = get_stat(self)->st_rdev;
428: return ULONG2NUM(major(rdev));
429: #else
430: return Qnil;
431: #endif
432: }
433:
434:
435:
436:
437:
438:
439:
440:
441:
442:
443:
444:
445: static VALUE
446: rb_stat_rdev_minor(VALUE self)
447: {
448: #if defined(HAVE_ST_RDEV) && defined(minor)
449: long rdev = get_stat(self)->st_rdev;
450: return ULONG2NUM(minor(rdev));
451: #else
452: return Qnil;
453: #endif
454: }
455:
456:
457:
458:
459:
460:
461:
462:
463:
464:
465: static VALUE
466: rb_stat_size(VALUE self)
467: {
468: return OFFT2NUM(get_stat(self)->st_size);
469: }
470:
471:
472:
473:
474:
475:
476:
477:
478:
479:
480:
481:
482: static VALUE
483: rb_stat_blksize(VALUE self)
484: {
485: #ifdef HAVE_ST_BLKSIZE
486: return ULONG2NUM(get_stat(self)->st_blksize);
487: #else
488: return Qnil;
489: #endif
490: }
491:
492:
493:
494:
495:
496:
497:
498:
499:
500:
501:
502:
503: static VALUE
504: rb_stat_blocks(VALUE self)
505: {
506: #ifdef HAVE_ST_BLOCKS
507: return ULONG2NUM(get_stat(self)->st_blocks);
508: #else
509: return Qnil;
510: #endif
511: }
512:
513: static struct timespec
514: stat_atimespec(struct stat *st)
515: {
516: struct timespec ts;
517: ts.tv_sec = st->st_atime;
518: #if defined(HAVE_STRUCT_STAT_ST_ATIM)
519: ts.tv_nsec = st->st_atim.tv_nsec;
520: #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
521: ts.tv_nsec = st->st_atimespec.tv_nsec;
522: #elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
523: ts.tv_nsec = st->st_atimensec;
524: #else
525: ts.tv_nsec = 0;
526: #endif
527: return ts;
528: }
529:
530: static VALUE
531: stat_atime(struct stat *st)
532: {
533: struct timespec ts = stat_atimespec(st);
534: return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
535: }
536:
537: static struct timespec
538: stat_mtimespec(struct stat *st)
539: {
540: struct timespec ts;
541: ts.tv_sec = st->st_mtime;
542: #if defined(HAVE_STRUCT_STAT_ST_MTIM)
543: ts.tv_nsec = st->st_mtim.tv_nsec;
544: #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
545: ts.tv_nsec = st->st_mtimespec.tv_nsec;
546: #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
547: ts.tv_nsec = st->st_mtimensec;
548: #else
549: ts.tv_nsec = 0;
550: #endif
551: return ts;
552: }
553:
554: static VALUE
555: stat_mtime(struct stat *st)
556: {
557: struct timespec ts = stat_mtimespec(st);
558: return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
559: }
560:
561: static struct timespec
562: stat_ctimespec(struct stat *st)
563: {
564: struct timespec ts;
565: ts.tv_sec = st->st_ctime;
566: #if defined(HAVE_STRUCT_STAT_ST_CTIM)
567: ts.tv_nsec = st->st_ctim.tv_nsec;
568: #elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
569: ts.tv_nsec = st->st_ctimespec.tv_nsec;
570: #elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
571: ts.tv_nsec = st->st_ctimensec;
572: #else
573: ts.tv_nsec = 0;
574: #endif
575: return ts;
576: }
577:
578: static VALUE
579: stat_ctime(struct stat *st)
580: {
581: struct timespec ts = stat_ctimespec(st);
582: return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
583: }
584:
585:
586:
587:
588:
589:
590:
591:
592:
593:
594:
595:
596: static VALUE
597: rb_stat_atime(VALUE self)
598: {
599: return stat_atime(get_stat(self));
600: }
601:
602:
603:
604:
605:
606:
607:
608:
609:
610:
611:
612: static VALUE
613: rb_stat_mtime(VALUE self)
614: {
615: return stat_mtime(get_stat(self));
616: }
617:
618:
619:
620:
621:
622:
623:
624:
625:
626:
627:
628:
629:
630: static VALUE
631: rb_stat_ctime(VALUE self)
632: {
633: return stat_ctime(get_stat(self));
634: }
635:
636:
637:
638:
639:
640:
641:
642:
643:
644:
645:
646:
647:
648: