1 /*
2 * $Id: stat.xs,v 1.31 2012/10/23 03:36:24 dankogai Exp $
3 */
4
5 #include "EXTERN.h"
6 #include "perl.h"
7 #include "XSUB.h"
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <sys/time.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13
14 /*
15 * Perl prior to 5.6.0 lacks newSVuv()
16 * Though perl 5.00503 does have sv_setuv() statcache uses IV instead.
17 * so we simply define newSVuv newSViv (Ugh!)
18 * I thank Sergey Skvortsov <skv@protey.ru> for reporting this problem.
19 *
20 * Perl prior to 5.6.0 lacks PERL_API_VERSION macro so we use it
21 * to tell the difference
22 */
23
24 #ifndef PERL_API_VERSION
25 #define newSVuv newSViv
26 #endif
27
28 static int
not_here(char * s)29 not_here(char *s)
30 {
31 croak("%s not implemented on this architecture", s);
32 return -1;
33 }
34
35 static int
setbang(int err)36 setbang(int err)
37 {
38 SV* bang = perl_get_sv("!", 1);
39 if (err){
40 sv_setpv(bang, strerror(errno));
41 sv_setiv(bang, errno << 8);
42 }else{
43 sv_setpv(bang, "");
44 sv_setiv(bang, 0);
45 }
46 return err;
47 }
48
49 #define NUMSTATMEM 18
50
51 static SV *
st2aref(struct stat * st)52 st2aref(struct stat *st){
53 SV* retval;
54 SV* sva[NUMSTATMEM];
55 int i;
56
57 /* same as CORE::stat */
58
59 sva[0] = sv_2mortal(newSViv(PL_statcache.st_dev = st->st_dev));
60 sva[1] = sv_2mortal(newSViv(PL_statcache.st_ino = st->st_ino));
61 sva[2] = sv_2mortal(newSVuv(PL_statcache.st_mode = st->st_mode));
62 sva[3] = sv_2mortal(newSVuv(PL_statcache.st_nlink = st->st_nlink));
63 sva[4] = sv_2mortal(newSVuv(PL_statcache.st_uid = st->st_uid));
64 sva[5] = sv_2mortal(newSVuv(PL_statcache.st_gid = st->st_gid));
65 sva[6] = sv_2mortal(newSViv(PL_statcache.st_rdev = st->st_rdev));
66 sva[7] = sv_2mortal(newSVnv(PL_statcache.st_size = st->st_size));
67 sva[8] = sv_2mortal(newSViv(PL_statcache.st_atime = st->st_atime));
68 sva[9] = sv_2mortal(newSViv(PL_statcache.st_mtime = st->st_mtime));
69 sva[10] = sv_2mortal(newSViv(PL_statcache.st_ctime = st->st_ctime));
70 sva[11] = sv_2mortal(newSVuv(PL_statcache.st_blksize = st->st_blksize));
71 sva[12] = sv_2mortal(newSVuv(PL_statcache.st_blocks = st->st_blocks));
72
73
74 /* BSD-specific */
75
76 sva[13] = sv_2mortal(newSViv(st->st_atimespec.tv_nsec));
77 sva[14] = sv_2mortal(newSViv(st->st_mtimespec.tv_nsec));
78 sva[15] = sv_2mortal(newSViv(st->st_ctimespec.tv_nsec));
79 sva[16] = sv_2mortal(newSVuv(st->st_flags));
80 sva[17] = sv_2mortal(newSVuv(st->st_gen));
81
82 retval = newRV_noinc((SV *)av_make(NUMSTATMEM, sva));
83 return retval;
84 }
85
86 static SV *
xs_stat(char * path)87 xs_stat(char *path){
88 struct stat st;
89 int err = stat(path, &st);
90 if (setbang(err)){
91 return &PL_sv_undef;
92 }else{
93 PL_laststype = OP_STAT;
94 return st2aref(&st);
95 }
96 }
97
98 static SV *
xs_lstat(char * path)99 xs_lstat(char *path){
100 struct stat st;
101 int err = lstat(path, &st);
102 if (setbang(err)){
103 return &PL_sv_undef;
104 }else{
105 PL_laststype = OP_LSTAT;
106 return st2aref(&st);
107 }
108 }
109
110 static SV *
xs_fstat(int fd,int waslstat)111 xs_fstat(int fd, int waslstat){
112 struct stat st;
113 int err = fstat(fd, &st);
114 if (setbang(err)){
115 return &PL_sv_undef;
116 }else{
117 PL_laststype = waslstat ? OP_LSTAT : OP_STAT;
118 return st2aref(&st);
119 }
120 }
121
122 static int
xs_chflags(char * path,int flags)123 xs_chflags(char *path, int flags){
124 int err = chflags(path, flags);
125 return setbang(err);
126 }
127
128 static int
xs_utimes(double atime,double mtime,char * path)129 xs_utimes(double atime, double mtime, char *path){
130 struct timeval times[2];
131 times[0].tv_sec = (int)atime;
132 times[0].tv_usec = (int)((atime - times[0].tv_sec) * 1e6);
133 times[1].tv_sec = (int)mtime;
134 times[1].tv_usec = (int)((mtime - times[1].tv_sec) * 1e6);
135 int err = utimes(path, times);
136 return setbang(err);
137 }
138
139 static int
xs_lutimes(double atime,double mtime,char * path)140 xs_lutimes(double atime, double mtime, char *path){
141 #ifdef __OpenBSD__
142 struct timespec times[2];
143 times[0].tv_sec = (int)atime;
144 times[0].tv_nsec = (int)((atime - times[0].tv_sec) * 1e9);
145 times[1].tv_sec = (int)mtime;
146 times[1].tv_nsec = (int)((mtime - times[1].tv_sec) * 1e9);
147 int err = utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW);
148 #else
149 struct timeval times[2];
150 times[0].tv_sec = (int)atime;
151 times[0].tv_usec = (int)((atime - times[0].tv_sec) * 1e6);
152 times[1].tv_sec = (int)mtime;
153 times[1].tv_usec = (int)((mtime - times[1].tv_sec) * 1e6);
154 int err = lutimes(path, times);
155 #endif
156 return setbang(err);
157 }
158
159 static int
xs_futimes(double atime,double mtime,int fd)160 xs_futimes(double atime, double mtime, int fd){
161 struct timeval times[2];
162 times[0].tv_sec = (int)atime;
163 times[0].tv_usec = (int)((atime - times[0].tv_sec) * 1e6);
164 times[1].tv_sec = (int)mtime;
165 times[1].tv_usec = (int)((mtime - times[1].tv_sec) * 1e6);
166 int err = futimes(fd, times);
167 return setbang(err);
168 }
169
170 /* */
171
172 MODULE = BSD::stat PACKAGE = BSD::stat
173
174 PROTOTYPES: ENABLE
175
176 SV *
177 xs_stat(path)
178 char * path;
179 CODE:
180 RETVAL = xs_stat(path);
181 OUTPUT:
182 RETVAL
183
184 SV *
185 xs_lstat(path)
186 char * path;
187 CODE:
188 RETVAL = xs_lstat(path);
189 OUTPUT:
190 RETVAL
191
192 SV *
193 xs_fstat(fd, waslstat)
194 int fd;
195 int waslstat;
196 CODE:
197 RETVAL = xs_fstat(fd, waslstat);
198 OUTPUT:
199 RETVAL
200
201 int
202 xs_chflags(path, flags)
203 char * path;
204 int flags;
205 CODE:
206 RETVAL = xs_chflags(path, flags);
207 OUTPUT:
208 RETVAL
209
210 int
211 xs_utimes(atime, mtime, path)
212 double atime;
213 double mtime;
214 char * path;
215 CODE:
216 RETVAL = xs_utimes(atime, mtime, path);
217 OUTPUT:
218 RETVAL
219
220 int
221 xs_lutimes(atime, mtime, path)
222 double atime;
223 double mtime;
224 char * path;
225 CODE:
226 RETVAL = xs_lutimes(atime, mtime, path);
227 OUTPUT:
228 RETVAL
229
230 int
231 xs_futimes(atime, mtime, fd)
232 double atime;
233 double mtime;
234 int fd;
235 CODE:
236 RETVAL = xs_futimes(atime, mtime, fd);
237 OUTPUT:
238 RETVAL
239