1 /*
2 Copyright (C) 2011-2014, Parrot Foundation.
3
4 =head1 NAME
5
6 src/platform/generic/file.c - Generic POSIX file functions
7
8 =head1 DESCRIPTION
9
10 This file implements OS-specific file functions for generic POSIX platforms.
11
12 =head2 Functions
13
14 =over 4
15
16 =cut
17
18 */
19
20 #include <dirent.h>
21 #include <unistd.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24
25 #include "parrot/parrot.h"
26
27 /* GH #655 apparently, strerror_r is thread-safe and should be used instead.*/
28 #define THROW(msg) Parrot_ex_throw_from_c_args(interp, NULL, \
29 EXCEPTION_EXTERNAL_ERROR, "%s failed: %s", (msg), strerror(errno))
30
31 /* HEADERIZER HFILE: none */
32
33 /* HEADERIZER BEGIN: static */
34 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
35
36 static void convert_stat_buf(
37 ARGIN(struct stat *stat_buf),
38 ARGOUT(Parrot_Stat_Buf *buf))
39 __attribute__nonnull__(1)
40 __attribute__nonnull__(2)
41 FUNC_MODIFIES(*buf);
42
43 static INTVAL stat_intval(PARROT_INTERP,
44 ARGIN(struct stat *statbuf),
45 INTVAL thing,
46 int status)
47 __attribute__nonnull__(1)
48 __attribute__nonnull__(2);
49
50 #define ASSERT_ARGS_convert_stat_buf __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
51 PARROT_ASSERT_ARG(stat_buf) \
52 , PARROT_ASSERT_ARG(buf))
53 #define ASSERT_ARGS_stat_intval __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
54 PARROT_ASSERT_ARG(interp) \
55 , PARROT_ASSERT_ARG(statbuf))
56 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
57 /* HEADERIZER END: static */
58
59 /*
60
61 =item C<STRING * Parrot_file_getcwd(PARROT_INTERP)>
62
63 Returns the current working directory.
64
65 =cut
66
67 */
68
69 PARROT_CANNOT_RETURN_NULL
70 STRING *
Parrot_file_getcwd(PARROT_INTERP)71 Parrot_file_getcwd(PARROT_INTERP)
72 {
73 STRING *result;
74 char *c_str;
75
76 #ifdef PATH_MAX
77 c_str = getcwd(NULL, PATH_MAX+1);
78 #else
79 c_str = getcwd(NULL, 0);
80 #endif
81
82 if (c_str == NULL)
83 THROW("getcwd");
84
85 result = Parrot_str_from_platform_cstring(interp, c_str);
86
87 free(c_str);
88
89 return result;
90 }
91
92 /*
93
94 =item C<void Parrot_file_mkdir(PARROT_INTERP, STRING *path, INTVAL mode)>
95
96 Creates a directory specified by C<path> with mode C<mode>.
97
98 =cut
99
100 */
101
102 void
Parrot_file_mkdir(PARROT_INTERP,ARGIN (STRING * path),INTVAL mode)103 Parrot_file_mkdir(PARROT_INTERP, ARGIN(STRING *path), INTVAL mode)
104 {
105 char *c_str = Parrot_str_to_platform_cstring(interp, path);
106 int result = mkdir(c_str, mode);
107
108 Parrot_str_free_cstring(c_str);
109
110 if (result)
111 THROW("mkdir");
112 }
113
114 /*
115
116 =item C<void Parrot_file_chdir(PARROT_INTERP, STRING *path)>
117
118 Changes the current working directory to the one specified by C<path>.
119
120 =cut
121
122 */
123
124 void
Parrot_file_chdir(PARROT_INTERP,ARGIN (STRING * path))125 Parrot_file_chdir(PARROT_INTERP, ARGIN(STRING *path))
126 {
127 char *c_str = Parrot_str_to_platform_cstring(interp, path);
128 int result = chdir(c_str);
129
130 Parrot_str_free_cstring(c_str);
131
132 if (result)
133 THROW("chdir");
134 }
135
136 /*
137
138 =item C<void Parrot_file_rmdir(PARROT_INTERP, STRING *path)>
139
140 Removes a directory specified by C<path>.
141
142 =cut
143
144 */
145
146 void
Parrot_file_rmdir(PARROT_INTERP,ARGIN (STRING * path))147 Parrot_file_rmdir(PARROT_INTERP, ARGIN(STRING *path))
148 {
149 char *c_str = Parrot_str_to_platform_cstring(interp, path);
150 int result = rmdir(c_str);
151
152 Parrot_str_free_cstring(c_str);
153
154 if (result)
155 THROW("rmdir");
156 }
157
158 /*
159
160 =item C<void Parrot_file_unlink(PARROT_INTERP, STRING *path)>
161
162 Removes a directory specified by C<path>.
163
164 =cut
165
166 */
167
168 void
Parrot_file_unlink(PARROT_INTERP,ARGIN (STRING * path))169 Parrot_file_unlink(PARROT_INTERP, ARGIN(STRING *path))
170 {
171 char *c_str = Parrot_str_to_platform_cstring(interp, path);
172 int result = unlink(c_str);
173
174 Parrot_str_free_cstring(c_str);
175
176 if (result)
177 THROW("unlink");
178 }
179
180 /*
181
182 =item C<static void convert_stat_buf(struct stat *stat_buf, Parrot_Stat_Buf
183 *buf)>
184
185 Converts a UNIX stat buffer to a Parrot stat buffer.
186
187 =cut
188
189 */
190
191 static void
convert_stat_buf(ARGIN (struct stat * stat_buf),ARGOUT (Parrot_Stat_Buf * buf))192 convert_stat_buf(ARGIN(struct stat *stat_buf), ARGOUT(Parrot_Stat_Buf *buf))
193 {
194 ASSERT_ARGS(convert_stat_buf)
195 #ifdef PARROT_HAS_STAT_ST_TIMESPEC_T
196 static const st_timespec_t zero = { 0, 0 };
197 #else
198 static const struct timespec zero = { 0, 0 };
199 #endif
200
201 INTVAL type;
202
203 switch (stat_buf->st_mode & S_IFMT) {
204 case S_IFREG:
205 type = STAT_TYPE_FILE;
206 break;
207 case S_IFDIR:
208 type = STAT_TYPE_DIRECTORY;
209 break;
210 case S_IFIFO:
211 type = STAT_TYPE_PIPE;
212 break;
213 case S_IFLNK:
214 type = STAT_TYPE_LINK;
215 break;
216 case S_IFCHR:
217 case S_IFBLK:
218 type = STAT_TYPE_DEVICE;
219 break;
220 default:
221 type = STAT_TYPE_UNKNOWN;
222 break;
223 }
224
225 buf->type = type;
226 buf->size = stat_buf->st_size;
227 buf->uid = stat_buf->st_uid;
228 buf->gid = stat_buf->st_gid;
229 buf->dev = stat_buf->st_dev;
230 buf->inode = stat_buf->st_ino;
231 buf->mode = stat_buf->st_mode & 0xffff;
232 buf->n_links = stat_buf->st_nlink;
233 #ifdef PARROT_HAS_BSD_STAT_EXTN
234 buf->block_size = stat_buf->st_blksize;
235 buf->blocks = stat_buf->st_blocks;
236 #else
237 buf->block_size = 0;
238 buf->blocks = stat_buf->st_size / 512;
239 #endif
240
241 buf->create_time = zero;
242 #ifdef PARROT_HAS_STAT_ATIM
243 buf->access_time = stat_buf->st_atim;
244 buf->modify_time = stat_buf->st_mtim;
245 buf->change_time = stat_buf->st_ctim;
246 #else
247 # ifdef PARROT_HAS_STAT_ATIMESPEC
248 buf->access_time = stat_buf->st_atimespec;
249 buf->modify_time = stat_buf->st_mtimespec;
250 buf->change_time = stat_buf->st_ctimespec;
251 # else
252 buf->access_time.tv_sec = stat_buf->st_atime;
253 buf->access_time.tv_nsec = 0;
254 buf->modify_time.tv_sec = stat_buf->st_mtime;
255 buf->modify_time.tv_nsec = 0;
256 buf->change_time.tv_sec = stat_buf->st_ctime;
257 buf->change_time.tv_nsec = 0;
258 # endif
259 #endif
260 }
261
262 /*
263
264 =item C<void Parrot_file_stat(PARROT_INTERP, STRING *file, Parrot_Stat_Buf
265 *buf)>
266
267 Stats file C<file>.
268
269 =cut
270
271 */
272
273 void
Parrot_file_stat(PARROT_INTERP,ARGIN (STRING * file),ARGOUT (Parrot_Stat_Buf * buf))274 Parrot_file_stat(PARROT_INTERP, ARGIN(STRING *file),
275 ARGOUT(Parrot_Stat_Buf *buf))
276 {
277 struct stat stat_buf;
278 char * const filename = Parrot_str_to_platform_cstring(interp, file);
279 const int status = stat(filename, &stat_buf);
280
281 Parrot_str_free_cstring(filename);
282
283 if (status)
284 THROW("stat");
285
286 convert_stat_buf(&stat_buf, buf);
287 }
288
289 /*
290
291 =item C<void Parrot_file_lstat(PARROT_INTERP, STRING *file, Parrot_Stat_Buf
292 *buf)>
293
294 lstats file C<file>.
295
296 =cut
297
298 */
299
300 void
Parrot_file_lstat(PARROT_INTERP,ARGIN (STRING * file),ARGOUT (Parrot_Stat_Buf * buf))301 Parrot_file_lstat(PARROT_INTERP, ARGIN(STRING *file),
302 ARGOUT(Parrot_Stat_Buf *buf))
303 {
304 struct stat stat_buf;
305 char * const filename = Parrot_str_to_platform_cstring(interp, file);
306 const int status = lstat(filename, &stat_buf);
307
308 Parrot_str_free_cstring(filename);
309
310 if (status)
311 THROW("stat");
312
313 convert_stat_buf(&stat_buf, buf);
314 }
315
316 /*
317
318 =item C<void Parrot_file_fstat(PARROT_INTERP, PIOHANDLE os_handle,
319 Parrot_Stat_Buf *buf)>
320
321 fstats file C<file>.
322
323 =cut
324
325 */
326
327 void
Parrot_file_fstat(PARROT_INTERP,PIOHANDLE os_handle,ARGOUT (Parrot_Stat_Buf * buf))328 Parrot_file_fstat(PARROT_INTERP, PIOHANDLE os_handle,
329 ARGOUT(Parrot_Stat_Buf *buf))
330 {
331 struct stat stat_buf;
332 const int status = fstat(os_handle, &stat_buf);
333
334 if (status)
335 THROW("stat");
336
337 convert_stat_buf(&stat_buf, buf);
338 }
339
340 /*
341
342 =item C<static INTVAL stat_intval(PARROT_INTERP, struct stat *statbuf, INTVAL
343 thing, int status)>
344
345 Stats the file, and returns the information specified by C<thing>. C<thing> can
346 be one of:
347
348 =over 4
349
350 =item * C<STAT_EXISTS>
351
352 =item * C<STAT_FILESIZE>
353
354 =item * C<STAT_ISDIR>
355
356 =item * C<STAT_ISREG>
357
358 =item * C<STAT_ISDEV>
359
360 =item * C<STAT_ISLNK>
361
362 if S_ISLNK is supported by the platform.
363
364 =item * C<STAT_ACCESSTIME>
365
366 =item * C<STAT_MODIFYTIME>
367
368 =item * C<STAT_CHANGETIME>
369
370 =item * C<STAT_UID>
371
372 =item * C<STAT_GID>
373
374 =item * C<STAT_PLATFORM_DEV>
375
376 =item * C<STAT_PLATFORM_INODE>
377
378 =item * C<STAT_PLATFORM_MODE>
379
380 =item * C<STAT_PLATFORM_NLINKS>
381
382 =item * C<STAT_PLATFORM_DEVTYPE>
383
384 =item * C<STAT_PLATFORM_MODE>
385
386 =item * C<STAT_PLATFORM_NLINKS>
387
388 =item * C<STAT_PLATFORM_DEVTYPE>
389
390 =item * C<STAT_PLATFORM_BLOCKSIZE>
391
392 if supported by the platform.
393
394 =item * C<STAT_PLATFORM_BLOCKS>
395
396 if supported by the platform.
397
398 =back
399
400 C<STAT_CREATETIME> and C<STAT_BACKUPTIME> are not supported and will return C<-1>.
401
402 =cut
403
404 */
405
406 static INTVAL
stat_intval(PARROT_INTERP,ARGIN (struct stat * statbuf),INTVAL thing,int status)407 stat_intval(PARROT_INTERP, ARGIN(struct stat *statbuf), INTVAL thing, int status)
408 {
409 ASSERT_ARGS(stat_intval)
410 INTVAL result = -1;
411
412 if (thing == STAT_EXISTS)
413 return status == 0;
414
415 if (status)
416 THROW("stat");
417
418 switch (thing) {
419 case STAT_FILESIZE:
420 result = statbuf->st_size;
421 break;
422 case STAT_ISDIR:
423 result = S_ISDIR(statbuf->st_mode);
424 break;
425 case STAT_ISREG:
426 result = S_ISREG(statbuf->st_mode);
427 break;
428 case STAT_ISDEV:
429 result = S_ISCHR(statbuf->st_mode) || S_ISBLK(statbuf->st_mode);
430 break;
431 case STAT_ISLNK:
432 #ifdef S_ISLNK
433 result = S_ISLNK(statbuf->st_mode);
434 #else
435 result = 0;
436 #endif
437 break;
438 case STAT_CREATETIME:
439 result = -1;
440 break;
441 case STAT_ACCESSTIME:
442 result = statbuf->st_atime;
443 break;
444 case STAT_MODIFYTIME:
445 result = statbuf->st_mtime;
446 break;
447 case STAT_CHANGETIME:
448 result = statbuf->st_ctime;
449 break;
450 case STAT_BACKUPTIME:
451 result = -1;
452 break;
453 case STAT_UID:
454 result = statbuf->st_uid;
455 break;
456 case STAT_GID:
457 result = statbuf->st_gid;
458 break;
459 case STAT_PLATFORM_DEV:
460 result = statbuf->st_dev;
461 break;
462 case STAT_PLATFORM_INODE:
463 result = statbuf->st_ino;
464 break;
465 case STAT_PLATFORM_MODE:
466 result = statbuf->st_mode;
467 break;
468 case STAT_PLATFORM_NLINKS:
469 result = statbuf->st_nlink;
470 break;
471 case STAT_PLATFORM_DEVTYPE:
472 result = statbuf->st_rdev;
473 break;
474 case STAT_PLATFORM_BLOCKSIZE:
475 #ifdef PARROT_HAS_BSD_STAT_EXTN
476 result = statbuf->st_blksize;
477 #else
478 Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_ARG_OP_NOT_HANDLED,
479 "STAT_PLATFORM_BLOCKSIZE not supported");
480 #endif
481 break;
482 case STAT_PLATFORM_BLOCKS:
483 #ifdef PARROT_HAS_BSD_STAT_EXTN
484 result = statbuf->st_blocks;
485 #else
486 Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_ARG_OP_NOT_HANDLED,
487 "STAT_PLATFORM_BLOCKS not supported");
488 #endif
489 break;
490 default:
491 break;
492 }
493
494 return result;
495 }
496
497 /*
498
499 =item C<INTVAL Parrot_file_stat_intval(PARROT_INTERP, STRING *file, INTVAL
500 thing)>
501
502 Returns the stat field given by C<thing> of file C<file>.
503
504 =cut
505
506 */
507
508 INTVAL
Parrot_file_stat_intval(PARROT_INTERP,STRING * file,INTVAL thing)509 Parrot_file_stat_intval(PARROT_INTERP, STRING *file, INTVAL thing)
510 {
511 struct stat statbuf;
512 char * const filename = Parrot_str_to_platform_cstring(interp, file);
513 const int status = stat(filename, &statbuf);
514
515 Parrot_str_free_cstring(filename);
516
517 return stat_intval(interp, &statbuf, thing, status);
518 }
519
520 /*
521
522 =item C<INTVAL Parrot_file_lstat_intval(PARROT_INTERP, STRING *file, INTVAL
523 thing)>
524
525 Returns the lstat field given by C<thing> of file C<file>.
526
527 =cut
528
529 */
530
531 INTVAL
Parrot_file_lstat_intval(PARROT_INTERP,STRING * file,INTVAL thing)532 Parrot_file_lstat_intval(PARROT_INTERP, STRING *file, INTVAL thing)
533 {
534 struct stat statbuf;
535 char * const filename = Parrot_str_to_platform_cstring(interp, file);
536 const int status = lstat(filename, &statbuf);
537
538 Parrot_str_free_cstring(filename);
539
540 return stat_intval(interp, &statbuf, thing, status);
541 }
542
543 /*
544
545 =item C<INTVAL Parrot_file_fstat_intval(PARROT_INTERP, PIOHANDLE file, INTVAL
546 thing)>
547
548 Returns the fstat field given by C<thing> from file handle C<file>.
549
550 =cut
551
552 */
553
554 INTVAL
Parrot_file_fstat_intval(PARROT_INTERP,PIOHANDLE file,INTVAL thing)555 Parrot_file_fstat_intval(PARROT_INTERP, PIOHANDLE file, INTVAL thing)
556 {
557 struct stat statbuf;
558 int status;
559
560 /* Everything needs the result of stat, so just go do it */
561 status = fstat(file, &statbuf);
562 return stat_intval(interp, &statbuf, thing, status);
563 }
564
565 /*
566
567 =item C<void Parrot_file_symlink(PARROT_INTERP, STRING *from, STRING *to)>
568
569 Creates a symlink
570
571 =cut
572
573 */
574
575 void
Parrot_file_symlink(PARROT_INTERP,ARGIN (STRING * from),ARGIN (STRING * to))576 Parrot_file_symlink(PARROT_INTERP, ARGIN(STRING *from), ARGIN(STRING *to))
577 {
578 char * const c_from = Parrot_str_to_platform_cstring(interp, from);
579 char * const c_to = Parrot_str_to_platform_cstring(interp, to);
580 const int result = symlink(c_from, c_to);
581
582 Parrot_str_free_cstring(c_from);
583 Parrot_str_free_cstring(c_to);
584
585 if (result)
586 THROW("symlink");
587 }
588
589 /*
590
591 =item C<STRING * Parrot_file_readlink(PARROT_INTERP, STRING *path)>
592
593 Reads a symlink.
594
595 =cut
596
597 XXX Throws a exception even for EINVAL (The named file is not a symbolic link).
598 Is this the best behavior?
599
600 */
601
602 PARROT_CANNOT_RETURN_NULL
603 STRING *
Parrot_file_readlink(PARROT_INTERP,ARGIN (STRING * path))604 Parrot_file_readlink(PARROT_INTERP, ARGIN(STRING *path))
605 {
606 char * const c_path = Parrot_str_to_platform_cstring(interp, path);
607 STRING *str = STRINGNULL;
608
609 #if defined(PATH_MAX) && PATH_MAX > 0
610 const int buf_size = PATH_MAX;
611 #else
612 const int buf_size = 1024;
613 #endif
614
615 char * const buf = mem_internal_allocate_n_zeroed_typed(buf_size, char);
616
617 const ssize_t length_result = readlink(c_path, buf, buf_size);
618
619 if (length_result <= 0)
620 THROW("readlink");
621
622 Parrot_str_free_cstring(c_path);
623
624 str = Parrot_str_new_init(interp, buf, length_result,
625 Parrot_platform_encoding_ptr, 0);
626
627 mem_sys_free(buf);
628 return str;
629 }
630
631 /*
632
633 =item C<void Parrot_file_link(PARROT_INTERP, STRING *from, STRING *to)>
634
635 Creates a hard link
636
637 =cut
638
639 */
640
641 void
Parrot_file_link(PARROT_INTERP,ARGIN (STRING * from),ARGIN (STRING * to))642 Parrot_file_link(PARROT_INTERP, ARGIN(STRING *from), ARGIN(STRING *to))
643 {
644 char * const c_from = Parrot_str_to_platform_cstring(interp, from);
645 char * const c_to = Parrot_str_to_platform_cstring(interp, to);
646 const int result = link(c_from, c_to);
647
648 Parrot_str_free_cstring(c_from);
649 Parrot_str_free_cstring(c_to);
650
651 if (result)
652 THROW("link");
653 }
654
655 /*
656
657 =item C<INTVAL Parrot_file_umask(PARROT_INTERP, INTVAL mask)>
658
659 Changes umask and return previous one
660
661 =cut
662
663 */
664
665 INTVAL
Parrot_file_umask(SHIM_INTERP,INTVAL mask)666 Parrot_file_umask(SHIM_INTERP, INTVAL mask)
667 {
668 return umask((mode_t)mask);
669 }
670
671 /*
672
673 =item C<void Parrot_file_chroot(PARROT_INTERP, STRING *path)>
674
675 Change root directory
676
677 =cut
678
679 */
680
681 void
Parrot_file_chroot(PARROT_INTERP,ARGIN (STRING * path))682 Parrot_file_chroot(PARROT_INTERP, ARGIN(STRING *path))
683 {
684 char *c_str = Parrot_str_to_platform_cstring(interp, path);
685 int result = chroot(c_str);
686 int resul2 = chdir("/");
687
688 Parrot_str_free_cstring(c_str);
689
690 if (result || resul2)
691 THROW("chroot");
692 }
693
694 /*
695
696 =item C<PMC * Parrot_file_readdir(PARROT_INTERP, STRING *path)>
697
698 Reads entries from a directory.
699
700 =cut
701
702 */
703
704 PARROT_CANNOT_RETURN_NULL
705 PMC *
Parrot_file_readdir(PARROT_INTERP,ARGIN (STRING * path))706 Parrot_file_readdir(PARROT_INTERP, ARGIN(STRING *path))
707 {
708 char *c_str = Parrot_str_to_platform_cstring(interp, path);
709 PMC *array = Parrot_pmc_new(interp, enum_class_ResizableStringArray);
710 DIR *dir = opendir(c_str);
711
712 struct dirent *dirent;
713
714 Parrot_str_free_cstring(c_str);
715
716 if (!dir)
717 THROW("readdir");
718
719 while ((dirent = readdir(dir)) != NULL) {
720 const char *const name = dirent->d_name;
721 VTABLE_push_string(interp, array,
722 Parrot_str_from_platform_cstring(interp, name));
723 }
724
725 closedir(dir);
726
727 return array;
728 }
729
730 /*
731
732 =item C<void Parrot_file_rename(PARROT_INTERP, STRING *from, STRING *to)>
733
734 Renames a file
735
736 =cut
737
738 */
739
740 void
Parrot_file_rename(PARROT_INTERP,ARGIN (STRING * from),ARGIN (STRING * to))741 Parrot_file_rename(PARROT_INTERP, ARGIN(STRING *from), ARGIN(STRING *to))
742 {
743 char * const c_from = Parrot_str_to_platform_cstring(interp, from);
744 char * const c_to = Parrot_str_to_platform_cstring(interp, to);
745 const int result = rename(c_from, c_to);
746
747 Parrot_str_free_cstring(c_from);
748 Parrot_str_free_cstring(c_to);
749
750 if (result)
751 THROW("rename");
752 }
753
754 /*
755
756 =item C<void Parrot_file_chmod(PARROT_INTERP, STRING *path, INTVAL mode)>
757
758 Changes permissions of file C<path>
759
760 =cut
761
762 */
763
764 void
Parrot_file_chmod(PARROT_INTERP,ARGIN (STRING * path),INTVAL mode)765 Parrot_file_chmod(PARROT_INTERP, ARGIN(STRING *path), INTVAL mode)
766 {
767 char *c_str = Parrot_str_to_platform_cstring(interp, path);
768 int result = chmod(c_str, mode);
769
770 Parrot_str_free_cstring(c_str);
771
772 if (result)
773 THROW("chmod");
774 }
775
776 /*
777
778 =item C<INTVAL Parrot_file_can_read(PARROT_INTERP, STRING *path)>
779
780 Tests whether a file can be read
781
782 =cut
783
784 */
785
786 INTVAL
Parrot_file_can_read(PARROT_INTERP,ARGIN (STRING * path))787 Parrot_file_can_read(PARROT_INTERP, ARGIN(STRING *path))
788 {
789 char *c_str = Parrot_str_to_platform_cstring(interp, path);
790 int result = access(c_str, R_OK);
791
792 Parrot_str_free_cstring(c_str);
793
794 return result == 0;
795 }
796
797 /*
798
799 =item C<INTVAL Parrot_file_can_write(PARROT_INTERP, STRING *path)>
800
801 Tests whether a file can be written
802
803 =cut
804
805 */
806
807 INTVAL
Parrot_file_can_write(PARROT_INTERP,ARGIN (STRING * path))808 Parrot_file_can_write(PARROT_INTERP, ARGIN(STRING *path))
809 {
810 char *c_str = Parrot_str_to_platform_cstring(interp, path);
811 int result = access(c_str, W_OK);
812
813 Parrot_str_free_cstring(c_str);
814
815 return result == 0;
816 }
817
818 /*
819
820 =item C<INTVAL Parrot_file_can_execute(PARROT_INTERP, STRING *path)>
821
822 Tests whether a file can be executed
823
824 =cut
825
826 */
827
828 INTVAL
Parrot_file_can_execute(PARROT_INTERP,ARGIN (STRING * path))829 Parrot_file_can_execute(PARROT_INTERP, ARGIN(STRING *path))
830 {
831 char *c_str = Parrot_str_to_platform_cstring(interp, path);
832 int result = access(c_str, X_OK);
833
834 Parrot_str_free_cstring(c_str);
835
836 return result == 0;
837 }
838
839 /*
840
841 =back
842
843 =cut
844
845 */
846
847
848 /*
849 * Local variables:
850 * c-file-style: "parrot"
851 * End:
852 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
853 */
854