1 | /* |
2 | +----------------------------------------------------------------------+ |
3 | | PHP Version 5 | |
4 | +----------------------------------------------------------------------+ |
5 | | Copyright (c) 1997-2015 The PHP Group | |
6 | +----------------------------------------------------------------------+ |
7 | | This source file is subject to version 3.01 of the PHP license, | |
8 | | that is bundled with this package in the file LICENSE, and is | |
9 | | available through the world-wide-web at the following url: | |
10 | | http://www.php.net/license/3_01.txt | |
11 | | If you did not receive a copy of the PHP license and are unable to | |
12 | | obtain it through the world-wide-web, please send a note to | |
13 | | license@php.net so we can mail you a copy immediately. | |
14 | +----------------------------------------------------------------------+ |
15 | | Author: Jim Winstead <jimw@php.net> | |
16 | +----------------------------------------------------------------------+ |
17 | */ |
18 | |
19 | /* $Id$ */ |
20 | |
21 | #include "php.h" |
22 | #include "fopen_wrappers.h" |
23 | #include "php_globals.h" |
24 | |
25 | #include <stdlib.h> |
26 | #include <sys/stat.h> |
27 | #include <string.h> |
28 | #include <errno.h> |
29 | #include <ctype.h> |
30 | #include <time.h> |
31 | |
32 | #if HAVE_UNISTD_H |
33 | # include <unistd.h> |
34 | #endif |
35 | |
36 | #if HAVE_SYS_PARAM_H |
37 | # include <sys/param.h> |
38 | #endif |
39 | |
40 | #if HAVE_SYS_VFS_H |
41 | # include <sys/vfs.h> |
42 | #endif |
43 | |
44 | #ifdef OS2 |
45 | # define INCL_DOS |
46 | # include <os2.h> |
47 | #endif |
48 | |
49 | #if defined(HAVE_SYS_STATVFS_H) && defined(HAVE_STATVFS) |
50 | # include <sys/statvfs.h> |
51 | #elif defined(HAVE_SYS_STATFS_H) && defined(HAVE_STATFS) |
52 | # include <sys/statfs.h> |
53 | #elif defined(HAVE_SYS_MOUNT_H) && defined(HAVE_STATFS) |
54 | # include <sys/mount.h> |
55 | #endif |
56 | |
57 | #if HAVE_PWD_H |
58 | # ifdef PHP_WIN32 |
59 | # include "win32/pwd.h" |
60 | # else |
61 | # include <pwd.h> |
62 | # endif |
63 | #endif |
64 | |
65 | #if HAVE_GRP_H |
66 | # ifdef PHP_WIN32 |
67 | # include "win32/grp.h" |
68 | # else |
69 | # include <grp.h> |
70 | # endif |
71 | #endif |
72 | |
73 | #if HAVE_UTIME |
74 | # ifdef PHP_WIN32 |
75 | # include <sys/utime.h> |
76 | # else |
77 | # include <utime.h> |
78 | # endif |
79 | #endif |
80 | |
81 | #ifdef PHP_WIN32 |
82 | #include "win32/winutil.h" |
83 | #endif |
84 | |
85 | #include "basic_functions.h" |
86 | #include "php_filestat.h" |
87 | |
88 | #ifndef S_ISDIR |
89 | #define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) |
90 | #endif |
91 | #ifndef S_ISREG |
92 | #define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG) |
93 | #endif |
94 | #ifndef S_ISLNK |
95 | #define S_ISLNK(mode) (((mode)&S_IFMT) == S_IFLNK) |
96 | #endif |
97 | |
98 | #define S_IXROOT ( S_IXUSR | S_IXGRP | S_IXOTH ) |
99 | |
100 | PHP_RINIT_FUNCTION(filestat) /* {{{ */ |
101 | { |
102 | BG(CurrentStatFile)=NULL; |
103 | BG(CurrentLStatFile)=NULL; |
104 | return SUCCESS; |
105 | } |
106 | /* }}} */ |
107 | |
108 | PHP_RSHUTDOWN_FUNCTION(filestat) /* {{{ */ |
109 | { |
110 | if (BG(CurrentStatFile)) { |
111 | efree (BG(CurrentStatFile)); |
112 | BG(CurrentStatFile) = NULL; |
113 | } |
114 | if (BG(CurrentLStatFile)) { |
115 | efree (BG(CurrentLStatFile)); |
116 | BG(CurrentLStatFile) = NULL; |
117 | } |
118 | return SUCCESS; |
119 | } |
120 | /* }}} */ |
121 | |
122 | static int php_disk_total_space(char *path, double *space TSRMLS_DC) /* {{{ */ |
123 | #if defined(WINDOWS) /* {{{ */ |
124 | { |
125 | double bytestotal = 0; |
126 | HINSTANCE kernel32; |
127 | FARPROC gdfse; |
128 | typedef BOOL (WINAPI *gdfse_func)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER); |
129 | gdfse_func func; |
130 | |
131 | /* These are used by GetDiskFreeSpaceEx, if available. */ |
132 | ULARGE_INTEGER FreeBytesAvailableToCaller; |
133 | ULARGE_INTEGER TotalNumberOfBytes; |
134 | ULARGE_INTEGER TotalNumberOfFreeBytes; |
135 | |
136 | /* These are used by GetDiskFreeSpace otherwise. */ |
137 | DWORD SectorsPerCluster; |
138 | DWORD BytesPerSector; |
139 | DWORD NumberOfFreeClusters; |
140 | DWORD TotalNumberOfClusters; |
141 | |
142 | /* GetDiskFreeSpaceEx is only available in NT and Win95 post-OSR2, |
143 | so we have to jump through some hoops to see if the function |
144 | exists. */ |
145 | kernel32 = LoadLibrary("kernel32.dll" ); |
146 | if (kernel32) { |
147 | gdfse = GetProcAddress(kernel32, "GetDiskFreeSpaceExA" ); |
148 | /* It's available, so we can call it. */ |
149 | if (gdfse) { |
150 | func = (gdfse_func)gdfse; |
151 | if (func(path, |
152 | &FreeBytesAvailableToCaller, |
153 | &TotalNumberOfBytes, |
154 | &TotalNumberOfFreeBytes) == 0) { |
155 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s" , php_win_err()); |
156 | return FAILURE; |
157 | } |
158 | |
159 | /* i know - this is ugly, but i works <thies@thieso.net> */ |
160 | bytestotal = TotalNumberOfBytes.HighPart * |
161 | (double) (((unsigned long)1) << 31) * 2.0 + |
162 | TotalNumberOfBytes.LowPart; |
163 | } else { /* If it's not available, we just use GetDiskFreeSpace */ |
164 | if (GetDiskFreeSpace(path, |
165 | &SectorsPerCluster, &BytesPerSector, |
166 | &NumberOfFreeClusters, &TotalNumberOfClusters) == 0) { |
167 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s" , php_win_err()); |
168 | return FAILURE; |
169 | } |
170 | bytestotal = (double)TotalNumberOfClusters * (double)SectorsPerCluster * (double)BytesPerSector; |
171 | } |
172 | } else { |
173 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to load kernel32.dll" ); |
174 | return FAILURE; |
175 | } |
176 | |
177 | *space = bytestotal; |
178 | return SUCCESS; |
179 | } |
180 | /* }}} */ |
181 | #elif defined(OS2) /* {{{ */ |
182 | { |
183 | double bytestotal = 0; |
184 | FSALLOCATE fsinfo; |
185 | char drive = path[0] & 95; |
186 | |
187 | if (DosQueryFSInfo( drive ? drive - 64 : 0, FSIL_ALLOC, &fsinfo, sizeof( fsinfo ) ) == 0) { |
188 | bytestotal = (double)fsinfo.cbSector * fsinfo.cSectorUnit * fsinfo.cUnit; |
189 | *space = bytestotal; |
190 | return SUCCESS; |
191 | } |
192 | return FAILURE; |
193 | } |
194 | /* }}} */ |
195 | #else /* {{{ if !defined(OS2) && !defined(WINDOWS) */ |
196 | { |
197 | double bytestotal = 0; |
198 | #if defined(HAVE_SYS_STATVFS_H) && defined(HAVE_STATVFS) |
199 | struct statvfs buf; |
200 | #elif (defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_MOUNT_H)) && defined(HAVE_STATFS) |
201 | struct statfs buf; |
202 | #endif |
203 | |
204 | #if defined(HAVE_SYS_STATVFS_H) && defined(HAVE_STATVFS) |
205 | if (statvfs(path, &buf)) { |
206 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s" , strerror(errno)); |
207 | return FAILURE; |
208 | } |
209 | if (buf.f_frsize) { |
210 | bytestotal = (((double)buf.f_blocks) * ((double)buf.f_frsize)); |
211 | } else { |
212 | bytestotal = (((double)buf.f_blocks) * ((double)buf.f_bsize)); |
213 | } |
214 | |
215 | #elif (defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_MOUNT_H)) && defined(HAVE_STATFS) |
216 | if (statfs(path, &buf)) { |
217 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s" , strerror(errno)); |
218 | return FAILURE; |
219 | } |
220 | bytestotal = (((double)buf.f_bsize) * ((double)buf.f_blocks)); |
221 | #endif |
222 | |
223 | *space = bytestotal; |
224 | return SUCCESS; |
225 | } |
226 | #endif |
227 | /* }}} */ |
228 | /* }}} */ |
229 | |
230 | /* {{{ proto float disk_total_space(string path) |
231 | Get total disk space for filesystem that path is on */ |
232 | PHP_FUNCTION(disk_total_space) |
233 | { |
234 | double bytestotal; |
235 | char *path; |
236 | int path_len; |
237 | |
238 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p" , &path, &path_len) == FAILURE) { |
239 | return; |
240 | } |
241 | |
242 | if (php_check_open_basedir(path TSRMLS_CC)) { |
243 | RETURN_FALSE; |
244 | } |
245 | |
246 | if (php_disk_total_space(path, &bytestotal TSRMLS_CC) == SUCCESS) { |
247 | RETURN_DOUBLE(bytestotal); |
248 | } |
249 | RETURN_FALSE; |
250 | } |
251 | /* }}} */ |
252 | |
253 | static int php_disk_free_space(char *path, double *space TSRMLS_DC) /* {{{ */ |
254 | #if defined(WINDOWS) /* {{{ */ |
255 | { |
256 | double bytesfree = 0; |
257 | |
258 | HINSTANCE kernel32; |
259 | FARPROC gdfse; |
260 | typedef BOOL (WINAPI *gdfse_func)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER); |
261 | gdfse_func func; |
262 | |
263 | /* These are used by GetDiskFreeSpaceEx, if available. */ |
264 | ULARGE_INTEGER FreeBytesAvailableToCaller; |
265 | ULARGE_INTEGER TotalNumberOfBytes; |
266 | ULARGE_INTEGER TotalNumberOfFreeBytes; |
267 | |
268 | /* These are used by GetDiskFreeSpace otherwise. */ |
269 | DWORD SectorsPerCluster; |
270 | DWORD BytesPerSector; |
271 | DWORD NumberOfFreeClusters; |
272 | DWORD TotalNumberOfClusters; |
273 | |
274 | /* GetDiskFreeSpaceEx is only available in NT and Win95 post-OSR2, |
275 | so we have to jump through some hoops to see if the function |
276 | exists. */ |
277 | kernel32 = LoadLibrary("kernel32.dll" ); |
278 | if (kernel32) { |
279 | gdfse = GetProcAddress(kernel32, "GetDiskFreeSpaceExA" ); |
280 | /* It's available, so we can call it. */ |
281 | if (gdfse) { |
282 | func = (gdfse_func)gdfse; |
283 | if (func(path, |
284 | &FreeBytesAvailableToCaller, |
285 | &TotalNumberOfBytes, |
286 | &TotalNumberOfFreeBytes) == 0) { |
287 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s" , php_win_err()); |
288 | return FAILURE; |
289 | } |
290 | |
291 | /* i know - this is ugly, but i works <thies@thieso.net> */ |
292 | bytesfree = FreeBytesAvailableToCaller.HighPart * |
293 | (double) (((unsigned long)1) << 31) * 2.0 + |
294 | FreeBytesAvailableToCaller.LowPart; |
295 | } else { /* If it's not available, we just use GetDiskFreeSpace */ |
296 | if (GetDiskFreeSpace(path, |
297 | &SectorsPerCluster, &BytesPerSector, |
298 | &NumberOfFreeClusters, &TotalNumberOfClusters) == 0) { |
299 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s" , php_win_err()); |
300 | return FAILURE; |
301 | } |
302 | bytesfree = (double)NumberOfFreeClusters * (double)SectorsPerCluster * (double)BytesPerSector; |
303 | } |
304 | } else { |
305 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to load kernel32.dll" ); |
306 | return FAILURE; |
307 | } |
308 | |
309 | *space = bytesfree; |
310 | return SUCCESS; |
311 | } |
312 | /* }}} */ |
313 | #elif defined(OS2) /* {{{ */ |
314 | { |
315 | double bytesfree = 0; |
316 | FSALLOCATE fsinfo; |
317 | char drive = path[0] & 95; |
318 | |
319 | if (DosQueryFSInfo( drive ? drive - 64 : 0, FSIL_ALLOC, &fsinfo, sizeof( fsinfo ) ) == 0) { |
320 | bytesfree = (double)fsinfo.cbSector * fsinfo.cSectorUnit * fsinfo.cUnitAvail; |
321 | *space = bytesfree; |
322 | return SUCCESS; |
323 | } |
324 | return FAILURE; |
325 | } |
326 | /* }}} */ |
327 | #else /* {{{ if !defined(OS2) && !defined(WINDOWS) */ |
328 | { |
329 | double bytesfree = 0; |
330 | #if defined(HAVE_SYS_STATVFS_H) && defined(HAVE_STATVFS) |
331 | struct statvfs buf; |
332 | #elif (defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_MOUNT_H)) && defined(HAVE_STATFS) |
333 | struct statfs buf; |
334 | #endif |
335 | |
336 | #if defined(HAVE_SYS_STATVFS_H) && defined(HAVE_STATVFS) |
337 | if (statvfs(path, &buf)) { |
338 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s" , strerror(errno)); |
339 | return FAILURE; |
340 | } |
341 | if (buf.f_frsize) { |
342 | bytesfree = (((double)buf.f_bavail) * ((double)buf.f_frsize)); |
343 | } else { |
344 | bytesfree = (((double)buf.f_bavail) * ((double)buf.f_bsize)); |
345 | } |
346 | #elif (defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_MOUNT_H)) && defined(HAVE_STATFS) |
347 | if (statfs(path, &buf)) { |
348 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s" , strerror(errno)); |
349 | return FAILURE; |
350 | } |
351 | #ifdef NETWARE |
352 | bytesfree = (((double)buf.f_bsize) * ((double)buf.f_bfree)); |
353 | #else |
354 | bytesfree = (((double)buf.f_bsize) * ((double)buf.f_bavail)); |
355 | #endif |
356 | #endif |
357 | |
358 | *space = bytesfree; |
359 | return SUCCESS; |
360 | } |
361 | #endif |
362 | /* }}} */ |
363 | /* }}} */ |
364 | |
365 | /* {{{ proto float disk_free_space(string path) |
366 | Get free disk space for filesystem that path is on */ |
367 | PHP_FUNCTION(disk_free_space) |
368 | { |
369 | double bytesfree; |
370 | char *path; |
371 | int path_len; |
372 | |
373 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p" , &path, &path_len) == FAILURE) { |
374 | return; |
375 | } |
376 | |
377 | if (php_check_open_basedir(path TSRMLS_CC)) { |
378 | RETURN_FALSE; |
379 | } |
380 | |
381 | if (php_disk_free_space(path, &bytesfree TSRMLS_CC) == SUCCESS) { |
382 | RETURN_DOUBLE(bytesfree); |
383 | } |
384 | RETURN_FALSE; |
385 | } |
386 | /* }}} */ |
387 | |
388 | #if !defined(WINDOWS) && !defined(NETWARE) |
389 | PHPAPI int php_get_gid_by_name(const char *name, gid_t *gid TSRMLS_DC) |
390 | { |
391 | #if defined(ZTS) && defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX) |
392 | struct group gr; |
393 | struct group *retgrptr; |
394 | long grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX); |
395 | char *grbuf; |
396 | |
397 | if (grbuflen < 1) { |
398 | return FAILURE; |
399 | } |
400 | |
401 | grbuf = emalloc(grbuflen); |
402 | if (getgrnam_r(name, &gr, grbuf, grbuflen, &retgrptr) != 0 || retgrptr == NULL) { |
403 | efree(grbuf); |
404 | return FAILURE; |
405 | } |
406 | efree(grbuf); |
407 | *gid = gr.gr_gid; |
408 | #else |
409 | struct group *gr = getgrnam(name); |
410 | |
411 | if (!gr) { |
412 | return FAILURE; |
413 | } |
414 | *gid = gr->gr_gid; |
415 | #endif |
416 | return SUCCESS; |
417 | } |
418 | #endif |
419 | |
420 | static void php_do_chgrp(INTERNAL_FUNCTION_PARAMETERS, int do_lchgrp) /* {{{ */ |
421 | { |
422 | char *filename; |
423 | int filename_len; |
424 | zval *group; |
425 | #if !defined(WINDOWS) |
426 | gid_t gid; |
427 | int ret; |
428 | #endif |
429 | php_stream_wrapper *wrapper; |
430 | |
431 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "pz/" , &filename, &filename_len, &group) == FAILURE) { |
432 | RETURN_FALSE; |
433 | } |
434 | |
435 | wrapper = php_stream_locate_url_wrapper(filename, NULL, 0 TSRMLS_CC); |
436 | if(wrapper != &php_plain_files_wrapper || strncasecmp("file://" , filename, 7) == 0) { |
437 | if(wrapper && wrapper->wops->stream_metadata) { |
438 | int option; |
439 | void *value; |
440 | if (Z_TYPE_P(group) == IS_LONG) { |
441 | option = PHP_STREAM_META_GROUP; |
442 | value = &Z_LVAL_P(group); |
443 | } else if (Z_TYPE_P(group) == IS_STRING) { |
444 | option = PHP_STREAM_META_GROUP_NAME; |
445 | value = Z_STRVAL_P(group); |
446 | } else { |
447 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "parameter 2 should be string or integer, %s given" , zend_zval_type_name(group)); |
448 | RETURN_FALSE; |
449 | } |
450 | if(wrapper->wops->stream_metadata(wrapper, filename, option, value, NULL TSRMLS_CC)) { |
451 | RETURN_TRUE; |
452 | } else { |
453 | RETURN_FALSE; |
454 | } |
455 | } else { |
456 | #if !defined(WINDOWS) |
457 | /* On Windows, we expect regular chgrp to fail silently by default */ |
458 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can not call chgrp() for a non-standard stream" ); |
459 | #endif |
460 | RETURN_FALSE; |
461 | } |
462 | } |
463 | |
464 | #if defined(WINDOWS) |
465 | /* We have no native chgrp on Windows, nothing left to do if stream doesn't have own implementation */ |
466 | RETURN_FALSE; |
467 | #else |
468 | if (Z_TYPE_P(group) == IS_LONG) { |
469 | gid = (gid_t)Z_LVAL_P(group); |
470 | } else if (Z_TYPE_P(group) == IS_STRING) { |
471 | if(php_get_gid_by_name(Z_STRVAL_P(group), &gid TSRMLS_CC) != SUCCESS) { |
472 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find gid for %s" , Z_STRVAL_P(group)); |
473 | RETURN_FALSE; |
474 | } |
475 | } else { |
476 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "parameter 2 should be string or integer, %s given" , zend_zval_type_name(group)); |
477 | RETURN_FALSE; |
478 | } |
479 | |
480 | /* Check the basedir */ |
481 | if (php_check_open_basedir(filename TSRMLS_CC)) { |
482 | RETURN_FALSE; |
483 | } |
484 | |
485 | if (do_lchgrp) { |
486 | #if HAVE_LCHOWN |
487 | ret = VCWD_LCHOWN(filename, -1, gid); |
488 | #endif |
489 | } else { |
490 | ret = VCWD_CHOWN(filename, -1, gid); |
491 | } |
492 | if (ret == -1) { |
493 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s" , strerror(errno)); |
494 | RETURN_FALSE; |
495 | } |
496 | RETURN_TRUE; |
497 | #endif |
498 | } |
499 | /* }}} */ |
500 | |
501 | #ifndef NETWARE |
502 | /* {{{ proto bool chgrp(string filename, mixed group) |
503 | Change file group */ |
504 | PHP_FUNCTION(chgrp) |
505 | { |
506 | php_do_chgrp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); |
507 | } |
508 | /* }}} */ |
509 | |
510 | /* {{{ proto bool lchgrp(string filename, mixed group) |
511 | Change symlink group */ |
512 | #if HAVE_LCHOWN |
513 | PHP_FUNCTION(lchgrp) |
514 | { |
515 | # if !defined(WINDOWS) |
516 | php_do_chgrp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); |
517 | # else |
518 | RETURN_FALSE; |
519 | # endif |
520 | } |
521 | #endif |
522 | /* }}} */ |
523 | #endif /* !NETWARE */ |
524 | |
525 | #if !defined(WINDOWS) && !defined(NETWARE) |
526 | PHPAPI uid_t php_get_uid_by_name(const char *name, uid_t *uid TSRMLS_DC) |
527 | { |
528 | #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWNAM_R) |
529 | struct passwd pw; |
530 | struct passwd *retpwptr = NULL; |
531 | long pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); |
532 | char *pwbuf; |
533 | |
534 | if (pwbuflen < 1) { |
535 | return FAILURE; |
536 | } |
537 | |
538 | pwbuf = emalloc(pwbuflen); |
539 | if (getpwnam_r(name, &pw, pwbuf, pwbuflen, &retpwptr) != 0 || retpwptr == NULL) { |
540 | efree(pwbuf); |
541 | return FAILURE; |
542 | } |
543 | efree(pwbuf); |
544 | *uid = pw.pw_uid; |
545 | #else |
546 | struct passwd *pw = getpwnam(name); |
547 | |
548 | if (!pw) { |
549 | return FAILURE; |
550 | } |
551 | *uid = pw->pw_uid; |
552 | #endif |
553 | return SUCCESS; |
554 | } |
555 | #endif |
556 | |
557 | static void php_do_chown(INTERNAL_FUNCTION_PARAMETERS, int do_lchown) /* {{{ */ |
558 | { |
559 | char *filename; |
560 | int filename_len; |
561 | zval *user; |
562 | #if !defined(WINDOWS) |
563 | uid_t uid; |
564 | int ret; |
565 | #endif |
566 | php_stream_wrapper *wrapper; |
567 | |
568 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "pz/" , &filename, &filename_len, &user) == FAILURE) { |
569 | return; |
570 | } |
571 | |
572 | wrapper = php_stream_locate_url_wrapper(filename, NULL, 0 TSRMLS_CC); |
573 | if(wrapper != &php_plain_files_wrapper || strncasecmp("file://" , filename, 7) == 0) { |
574 | if(wrapper && wrapper->wops->stream_metadata) { |
575 | int option; |
576 | void *value; |
577 | if (Z_TYPE_P(user) == IS_LONG) { |
578 | option = PHP_STREAM_META_OWNER; |
579 | value = &Z_LVAL_P(user); |
580 | } else if (Z_TYPE_P(user) == IS_STRING) { |
581 | option = PHP_STREAM_META_OWNER_NAME; |
582 | value = Z_STRVAL_P(user); |
583 | } else { |
584 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "parameter 2 should be string or integer, %s given" , zend_zval_type_name(user)); |
585 | RETURN_FALSE; |
586 | } |
587 | if(wrapper->wops->stream_metadata(wrapper, filename, option, value, NULL TSRMLS_CC)) { |
588 | RETURN_TRUE; |
589 | } else { |
590 | RETURN_FALSE; |
591 | } |
592 | } else { |
593 | #if !defined(WINDOWS) |
594 | /* On Windows, we expect regular chown to fail silently by default */ |
595 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can not call chown() for a non-standard stream" ); |
596 | #endif |
597 | RETURN_FALSE; |
598 | } |
599 | } |
600 | |
601 | #if defined(WINDOWS) |
602 | /* We have no native chown on Windows, nothing left to do if stream doesn't have own implementation */ |
603 | RETURN_FALSE; |
604 | #else |
605 | |
606 | if (Z_TYPE_P(user) == IS_LONG) { |
607 | uid = (uid_t)Z_LVAL_P(user); |
608 | } else if (Z_TYPE_P(user) == IS_STRING) { |
609 | if(php_get_uid_by_name(Z_STRVAL_P(user), &uid TSRMLS_CC) != SUCCESS) { |
610 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find uid for %s" , Z_STRVAL_P(user)); |
611 | RETURN_FALSE; |
612 | } |
613 | } else { |
614 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "parameter 2 should be string or integer, %s given" , zend_zval_type_name(user)); |
615 | RETURN_FALSE; |
616 | } |
617 | |
618 | /* Check the basedir */ |
619 | if (php_check_open_basedir(filename TSRMLS_CC)) { |
620 | RETURN_FALSE; |
621 | } |
622 | |
623 | if (do_lchown) { |
624 | #if HAVE_LCHOWN |
625 | ret = VCWD_LCHOWN(filename, uid, -1); |
626 | #endif |
627 | } else { |
628 | ret = VCWD_CHOWN(filename, uid, -1); |
629 | } |
630 | if (ret == -1) { |
631 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s" , strerror(errno)); |
632 | RETURN_FALSE; |
633 | } |
634 | RETURN_TRUE; |
635 | #endif |
636 | } |
637 | /* }}} */ |
638 | |
639 | |
640 | #ifndef NETWARE |
641 | /* {{{ proto bool chown (string filename, mixed user) |
642 | Change file owner */ |
643 | PHP_FUNCTION(chown) |
644 | { |
645 | php_do_chown(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); |
646 | } |
647 | /* }}} */ |
648 | |
649 | /* {{{ proto bool chown (string filename, mixed user) |
650 | Change file owner */ |
651 | #if HAVE_LCHOWN |
652 | PHP_FUNCTION(lchown) |
653 | { |
654 | # if !defined(WINDOWS) |
655 | RETVAL_TRUE; |
656 | php_do_chown(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); |
657 | # else |
658 | RETURN_FALSE; |
659 | # endif |
660 | } |
661 | #endif |
662 | /* }}} */ |
663 | #endif /* !NETWARE */ |
664 | |
665 | /* {{{ proto bool chmod(string filename, int mode) |
666 | Change file mode */ |
667 | PHP_FUNCTION(chmod) |
668 | { |
669 | char *filename; |
670 | int filename_len; |
671 | long mode; |
672 | int ret; |
673 | mode_t imode; |
674 | php_stream_wrapper *wrapper; |
675 | |
676 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "pl" , &filename, &filename_len, &mode) == FAILURE) { |
677 | return; |
678 | } |
679 | |
680 | wrapper = php_stream_locate_url_wrapper(filename, NULL, 0 TSRMLS_CC); |
681 | if(wrapper != &php_plain_files_wrapper || strncasecmp("file://" , filename, 7) == 0) { |
682 | if(wrapper && wrapper->wops->stream_metadata) { |
683 | if(wrapper->wops->stream_metadata(wrapper, filename, PHP_STREAM_META_ACCESS, &mode, NULL TSRMLS_CC)) { |
684 | RETURN_TRUE; |
685 | } else { |
686 | RETURN_FALSE; |
687 | } |
688 | } else { |
689 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can not call chmod() for a non-standard stream" ); |
690 | RETURN_FALSE; |
691 | } |
692 | } |
693 | |
694 | /* Check the basedir */ |
695 | if (php_check_open_basedir(filename TSRMLS_CC)) { |
696 | RETURN_FALSE; |
697 | } |
698 | |
699 | imode = (mode_t) mode; |
700 | |
701 | ret = VCWD_CHMOD(filename, imode); |
702 | if (ret == -1) { |
703 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s" , strerror(errno)); |
704 | RETURN_FALSE; |
705 | } |
706 | RETURN_TRUE; |
707 | } |
708 | /* }}} */ |
709 | |
710 | #if HAVE_UTIME |
711 | /* {{{ proto bool touch(string filename [, int time [, int atime]]) |
712 | Set modification time of file */ |
713 | PHP_FUNCTION(touch) |
714 | { |
715 | char *filename; |
716 | int filename_len; |
717 | long filetime = 0, fileatime = 0; |
718 | int ret, argc = ZEND_NUM_ARGS(); |
719 | FILE *file; |
720 | struct utimbuf newtimebuf; |
721 | struct utimbuf *newtime = &newtimebuf; |
722 | php_stream_wrapper *wrapper; |
723 | |
724 | if (zend_parse_parameters(argc TSRMLS_CC, "p|ll" , &filename, &filename_len, &filetime, &fileatime) == FAILURE) { |
725 | return; |
726 | } |
727 | |
728 | if (!filename_len) { |
729 | RETURN_FALSE; |
730 | } |
731 | |
732 | switch (argc) { |
733 | case 1: |
734 | #ifdef HAVE_UTIME_NULL |
735 | newtime = NULL; |
736 | #else |
737 | newtime->modtime = newtime->actime = time(NULL); |
738 | #endif |
739 | break; |
740 | case 2: |
741 | newtime->modtime = newtime->actime = filetime; |
742 | break; |
743 | case 3: |
744 | newtime->modtime = filetime; |
745 | newtime->actime = fileatime; |
746 | break; |
747 | default: |
748 | /* Never reached */ |
749 | WRONG_PARAM_COUNT; |
750 | } |
751 | |
752 | wrapper = php_stream_locate_url_wrapper(filename, NULL, 0 TSRMLS_CC); |
753 | if(wrapper != &php_plain_files_wrapper || strncasecmp("file://" , filename, 7) == 0) { |
754 | if(wrapper && wrapper->wops->stream_metadata) { |
755 | if(wrapper->wops->stream_metadata(wrapper, filename, PHP_STREAM_META_TOUCH, newtime, NULL TSRMLS_CC)) { |
756 | RETURN_TRUE; |
757 | } else { |
758 | RETURN_FALSE; |
759 | } |
760 | } else { |
761 | php_stream *stream; |
762 | if(argc > 1) { |
763 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can not call touch() for a non-standard stream" ); |
764 | RETURN_FALSE; |
765 | } |
766 | stream = php_stream_open_wrapper_ex(filename, "c" , REPORT_ERRORS, NULL, NULL); |
767 | if(stream != NULL) { |
768 | php_stream_pclose(stream); |
769 | RETURN_TRUE; |
770 | } else { |
771 | RETURN_FALSE; |
772 | } |
773 | } |
774 | } |
775 | |
776 | /* Check the basedir */ |
777 | if (php_check_open_basedir(filename TSRMLS_CC)) { |
778 | RETURN_FALSE; |
779 | } |
780 | |
781 | /* create the file if it doesn't exist already */ |
782 | if (VCWD_ACCESS(filename, F_OK) != 0) { |
783 | file = VCWD_FOPEN(filename, "w" ); |
784 | if (file == NULL) { |
785 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create file %s because %s" , filename, strerror(errno)); |
786 | RETURN_FALSE; |
787 | } |
788 | fclose(file); |
789 | } |
790 | |
791 | ret = VCWD_UTIME(filename, newtime); |
792 | if (ret == -1) { |
793 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Utime failed: %s" , strerror(errno)); |
794 | RETURN_FALSE; |
795 | } |
796 | RETURN_TRUE; |
797 | } |
798 | /* }}} */ |
799 | #endif |
800 | |
801 | /* {{{ php_clear_stat_cache() |
802 | */ |
803 | PHPAPI void php_clear_stat_cache(zend_bool clear_realpath_cache, const char *filename, int filename_len TSRMLS_DC) |
804 | { |
805 | /* always clear CurrentStatFile and CurrentLStatFile even if filename is not NULL |
806 | * as it may contain outdated data (e.g. "nlink" for a directory when deleting a file |
807 | * in this directory, as shown by lstat_stat_variation9.phpt) */ |
808 | if (BG(CurrentStatFile)) { |
809 | efree(BG(CurrentStatFile)); |
810 | BG(CurrentStatFile) = NULL; |
811 | } |
812 | if (BG(CurrentLStatFile)) { |
813 | efree(BG(CurrentLStatFile)); |
814 | BG(CurrentLStatFile) = NULL; |
815 | } |
816 | if (clear_realpath_cache) { |
817 | if (filename != NULL) { |
818 | realpath_cache_del(filename, filename_len TSRMLS_CC); |
819 | } else { |
820 | realpath_cache_clean(TSRMLS_C); |
821 | } |
822 | } |
823 | } |
824 | /* }}} */ |
825 | |
826 | /* {{{ proto void clearstatcache([bool clear_realpath_cache[, string filename]]) |
827 | Clear file stat cache */ |
828 | PHP_FUNCTION(clearstatcache) |
829 | { |
830 | zend_bool clear_realpath_cache = 0; |
831 | char *filename = NULL; |
832 | int filename_len = 0; |
833 | |
834 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bp" , &clear_realpath_cache, &filename, &filename_len) == FAILURE) { |
835 | return; |
836 | } |
837 | |
838 | php_clear_stat_cache(clear_realpath_cache, filename, filename_len TSRMLS_CC); |
839 | } |
840 | /* }}} */ |
841 | |
842 | #define IS_LINK_OPERATION(__t) ((__t) == FS_TYPE || (__t) == FS_IS_LINK || (__t) == FS_LSTAT) |
843 | #define IS_EXISTS_CHECK(__t) ((__t) == FS_EXISTS || (__t) == FS_IS_W || (__t) == FS_IS_R || (__t) == FS_IS_X || (__t) == FS_IS_FILE || (__t) == FS_IS_DIR || (__t) == FS_IS_LINK) |
844 | #define IS_ABLE_CHECK(__t) ((__t) == FS_IS_R || (__t) == FS_IS_W || (__t) == FS_IS_X) |
845 | #define IS_ACCESS_CHECK(__t) (IS_ABLE_CHECK(type) || (__t) == FS_EXISTS) |
846 | |
847 | /* {{{ php_stat |
848 | */ |
849 | PHPAPI void php_stat(const char *filename, php_stat_len filename_length, int type, zval *return_value TSRMLS_DC) |
850 | { |
851 | zval *stat_dev, *stat_ino, *stat_mode, *stat_nlink, *stat_uid, *stat_gid, *stat_rdev, |
852 | *stat_size, *stat_atime, *stat_mtime, *stat_ctime, *stat_blksize, *stat_blocks; |
853 | struct stat *stat_sb; |
854 | php_stream_statbuf ssb; |
855 | int flags = 0, rmask=S_IROTH, wmask=S_IWOTH, xmask=S_IXOTH; /* access rights defaults to other */ |
856 | char *stat_sb_names[13] = { |
857 | "dev" , "ino" , "mode" , "nlink" , "uid" , "gid" , "rdev" , |
858 | "size" , "atime" , "mtime" , "ctime" , "blksize" , "blocks" |
859 | }; |
860 | const char *local; |
861 | php_stream_wrapper *wrapper; |
862 | |
863 | if (!filename_length) { |
864 | RETURN_FALSE; |
865 | } |
866 | |
867 | if ((wrapper = php_stream_locate_url_wrapper(filename, &local, 0 TSRMLS_CC)) == &php_plain_files_wrapper && php_check_open_basedir(local TSRMLS_CC)) { |
868 | RETURN_FALSE; |
869 | } |
870 | |
871 | if (IS_ACCESS_CHECK(type)) { |
872 | if (wrapper == &php_plain_files_wrapper) { |
873 | |
874 | switch (type) { |
875 | #ifdef F_OK |
876 | case FS_EXISTS: |
877 | RETURN_BOOL(VCWD_ACCESS(local, F_OK) == 0); |
878 | break; |
879 | #endif |
880 | #ifdef W_OK |
881 | case FS_IS_W: |
882 | RETURN_BOOL(VCWD_ACCESS(local, W_OK) == 0); |
883 | break; |
884 | #endif |
885 | #ifdef R_OK |
886 | case FS_IS_R: |
887 | RETURN_BOOL(VCWD_ACCESS(local, R_OK) == 0); |
888 | break; |
889 | #endif |
890 | #ifdef X_OK |
891 | case FS_IS_X: |
892 | RETURN_BOOL(VCWD_ACCESS(local, X_OK) == 0); |
893 | break; |
894 | #endif |
895 | } |
896 | } |
897 | } |
898 | |
899 | if (IS_LINK_OPERATION(type)) { |
900 | flags |= PHP_STREAM_URL_STAT_LINK; |
901 | } |
902 | if (IS_EXISTS_CHECK(type)) { |
903 | flags |= PHP_STREAM_URL_STAT_QUIET; |
904 | } |
905 | |
906 | if (php_stream_stat_path_ex((char *)filename, flags, &ssb, NULL)) { |
907 | /* Error Occurred */ |
908 | if (!IS_EXISTS_CHECK(type)) { |
909 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%sstat failed for %s" , IS_LINK_OPERATION(type) ? "L" : "" , filename); |
910 | } |
911 | RETURN_FALSE; |
912 | } |
913 | |
914 | stat_sb = &ssb.sb; |
915 | |
916 | |
917 | #ifndef NETWARE |
918 | if (type >= FS_IS_W && type <= FS_IS_X) { |
919 | if(ssb.sb.st_uid==getuid()) { |
920 | rmask=S_IRUSR; |
921 | wmask=S_IWUSR; |
922 | xmask=S_IXUSR; |
923 | } else if(ssb.sb.st_gid==getgid()) { |
924 | rmask=S_IRGRP; |
925 | wmask=S_IWGRP; |
926 | xmask=S_IXGRP; |
927 | } else { |
928 | int groups, n, i; |
929 | gid_t *gids; |
930 | |
931 | groups = getgroups(0, NULL); |
932 | if(groups > 0) { |
933 | gids=(gid_t *)safe_emalloc(groups, sizeof(gid_t), 0); |
934 | n=getgroups(groups, gids); |
935 | for(i=0;i<n;i++){ |
936 | if(ssb.sb.st_gid==gids[i]) { |
937 | rmask=S_IRGRP; |
938 | wmask=S_IWGRP; |
939 | xmask=S_IXGRP; |
940 | break; |
941 | } |
942 | } |
943 | efree(gids); |
944 | } |
945 | } |
946 | } |
947 | #endif |
948 | |
949 | #ifndef NETWARE |
950 | if (IS_ABLE_CHECK(type) && getuid() == 0) { |
951 | /* root has special perms on plain_wrapper |
952 | But we don't know about root under Netware */ |
953 | if (wrapper == &php_plain_files_wrapper) { |
954 | if (type == FS_IS_X) { |
955 | xmask = S_IXROOT; |
956 | } else { |
957 | RETURN_TRUE; |
958 | } |
959 | } |
960 | } |
961 | #endif |
962 | |
963 | switch (type) { |
964 | case FS_PERMS: |
965 | RETURN_LONG((long)ssb.sb.st_mode); |
966 | case FS_INODE: |
967 | RETURN_LONG((long)ssb.sb.st_ino); |
968 | case FS_SIZE: |
969 | RETURN_LONG((long)ssb.sb.st_size); |
970 | case FS_OWNER: |
971 | RETURN_LONG((long)ssb.sb.st_uid); |
972 | case FS_GROUP: |
973 | RETURN_LONG((long)ssb.sb.st_gid); |
974 | case FS_ATIME: |
975 | RETURN_LONG((long)ssb.sb.st_atime); |
976 | case FS_MTIME: |
977 | RETURN_LONG((long)ssb.sb.st_mtime); |
978 | case FS_CTIME: |
979 | RETURN_LONG((long)ssb.sb.st_ctime); |
980 | case FS_TYPE: |
981 | if (S_ISLNK(ssb.sb.st_mode)) { |
982 | RETURN_STRING("link" , 1); |
983 | } |
984 | switch(ssb.sb.st_mode & S_IFMT) { |
985 | case S_IFIFO: RETURN_STRING("fifo" , 1); |
986 | case S_IFCHR: RETURN_STRING("char" , 1); |
987 | case S_IFDIR: RETURN_STRING("dir" , 1); |
988 | case S_IFBLK: RETURN_STRING("block" , 1); |
989 | case S_IFREG: RETURN_STRING("file" , 1); |
990 | #if defined(S_IFSOCK) && !defined(ZEND_WIN32)&&!defined(__BEOS__) |
991 | case S_IFSOCK: RETURN_STRING("socket" , 1); |
992 | #endif |
993 | } |
994 | php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown file type (%d)" , ssb.sb.st_mode&S_IFMT); |
995 | RETURN_STRING("unknown" , 1); |
996 | case FS_IS_W: |
997 | RETURN_BOOL((ssb.sb.st_mode & wmask) != 0); |
998 | case FS_IS_R: |
999 | RETURN_BOOL((ssb.sb.st_mode&rmask)!=0); |
1000 | case FS_IS_X: |
1001 | RETURN_BOOL((ssb.sb.st_mode&xmask)!=0 && !S_ISDIR(ssb.sb.st_mode)); |
1002 | case FS_IS_FILE: |
1003 | RETURN_BOOL(S_ISREG(ssb.sb.st_mode)); |
1004 | case FS_IS_DIR: |
1005 | RETURN_BOOL(S_ISDIR(ssb.sb.st_mode)); |
1006 | case FS_IS_LINK: |
1007 | RETURN_BOOL(S_ISLNK(ssb.sb.st_mode)); |
1008 | case FS_EXISTS: |
1009 | RETURN_TRUE; /* the false case was done earlier */ |
1010 | case FS_LSTAT: |
1011 | /* FALLTHROUGH */ |
1012 | case FS_STAT: |
1013 | array_init(return_value); |
1014 | |
1015 | MAKE_LONG_ZVAL_INCREF(stat_dev, stat_sb->st_dev); |
1016 | MAKE_LONG_ZVAL_INCREF(stat_ino, stat_sb->st_ino); |
1017 | MAKE_LONG_ZVAL_INCREF(stat_mode, stat_sb->st_mode); |
1018 | MAKE_LONG_ZVAL_INCREF(stat_nlink, stat_sb->st_nlink); |
1019 | MAKE_LONG_ZVAL_INCREF(stat_uid, stat_sb->st_uid); |
1020 | MAKE_LONG_ZVAL_INCREF(stat_gid, stat_sb->st_gid); |
1021 | #ifdef HAVE_ST_RDEV |
1022 | MAKE_LONG_ZVAL_INCREF(stat_rdev, stat_sb->st_rdev); |
1023 | #else |
1024 | MAKE_LONG_ZVAL_INCREF(stat_rdev, -1); |
1025 | #endif |
1026 | MAKE_LONG_ZVAL_INCREF(stat_size, stat_sb->st_size); |
1027 | MAKE_LONG_ZVAL_INCREF(stat_atime, stat_sb->st_atime); |
1028 | MAKE_LONG_ZVAL_INCREF(stat_mtime, stat_sb->st_mtime); |
1029 | MAKE_LONG_ZVAL_INCREF(stat_ctime, stat_sb->st_ctime); |
1030 | #ifdef HAVE_ST_BLKSIZE |
1031 | MAKE_LONG_ZVAL_INCREF(stat_blksize, stat_sb->st_blksize); |
1032 | #else |
1033 | MAKE_LONG_ZVAL_INCREF(stat_blksize,-1); |
1034 | #endif |
1035 | #ifdef HAVE_ST_BLOCKS |
1036 | MAKE_LONG_ZVAL_INCREF(stat_blocks, stat_sb->st_blocks); |
1037 | #else |
1038 | MAKE_LONG_ZVAL_INCREF(stat_blocks,-1); |
1039 | #endif |
1040 | /* Store numeric indexes in propper order */ |
1041 | zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_dev, sizeof(zval *), NULL); |
1042 | zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_ino, sizeof(zval *), NULL); |
1043 | zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_mode, sizeof(zval *), NULL); |
1044 | zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_nlink, sizeof(zval *), NULL); |
1045 | zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_uid, sizeof(zval *), NULL); |
1046 | zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_gid, sizeof(zval *), NULL); |
1047 | |
1048 | zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_rdev, sizeof(zval *), NULL); |
1049 | zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_size, sizeof(zval *), NULL); |
1050 | zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_atime, sizeof(zval *), NULL); |
1051 | zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_mtime, sizeof(zval *), NULL); |
1052 | zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_ctime, sizeof(zval *), NULL); |
1053 | zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_blksize, sizeof(zval *), NULL); |
1054 | zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_blocks, sizeof(zval *), NULL); |
1055 | |
1056 | /* Store string indexes referencing the same zval*/ |
1057 | zend_hash_update(HASH_OF(return_value), stat_sb_names[0], strlen(stat_sb_names[0])+1, (void *) &stat_dev, sizeof(zval *), NULL); |
1058 | zend_hash_update(HASH_OF(return_value), stat_sb_names[1], strlen(stat_sb_names[1])+1, (void *) &stat_ino, sizeof(zval *), NULL); |
1059 | zend_hash_update(HASH_OF(return_value), stat_sb_names[2], strlen(stat_sb_names[2])+1, (void *) &stat_mode, sizeof(zval *), NULL); |
1060 | zend_hash_update(HASH_OF(return_value), stat_sb_names[3], strlen(stat_sb_names[3])+1, (void *) &stat_nlink, sizeof(zval *), NULL); |
1061 | zend_hash_update(HASH_OF(return_value), stat_sb_names[4], strlen(stat_sb_names[4])+1, (void *) &stat_uid, sizeof(zval *), NULL); |
1062 | zend_hash_update(HASH_OF(return_value), stat_sb_names[5], strlen(stat_sb_names[5])+1, (void *) &stat_gid, sizeof(zval *), NULL); |
1063 | zend_hash_update(HASH_OF(return_value), stat_sb_names[6], strlen(stat_sb_names[6])+1, (void *) &stat_rdev, sizeof(zval *), NULL); |
1064 | zend_hash_update(HASH_OF(return_value), stat_sb_names[7], strlen(stat_sb_names[7])+1, (void *) &stat_size, sizeof(zval *), NULL); |
1065 | zend_hash_update(HASH_OF(return_value), stat_sb_names[8], strlen(stat_sb_names[8])+1, (void *) &stat_atime, sizeof(zval *), NULL); |
1066 | zend_hash_update(HASH_OF(return_value), stat_sb_names[9], strlen(stat_sb_names[9])+1, (void *) &stat_mtime, sizeof(zval *), NULL); |
1067 | zend_hash_update(HASH_OF(return_value), stat_sb_names[10], strlen(stat_sb_names[10])+1, (void *) &stat_ctime, sizeof(zval *), NULL); |
1068 | zend_hash_update(HASH_OF(return_value), stat_sb_names[11], strlen(stat_sb_names[11])+1, (void *) &stat_blksize, sizeof(zval *), NULL); |
1069 | zend_hash_update(HASH_OF(return_value), stat_sb_names[12], strlen(stat_sb_names[12])+1, (void *) &stat_blocks, sizeof(zval *), NULL); |
1070 | |
1071 | return; |
1072 | } |
1073 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Didn't understand stat call" ); |
1074 | RETURN_FALSE; |
1075 | } |
1076 | /* }}} */ |
1077 | |
1078 | /* another quickie macro to make defining similar functions easier */ |
1079 | /* {{{ FileFunction(name, funcnum) */ |
1080 | #define FileFunction(name, funcnum) \ |
1081 | void name(INTERNAL_FUNCTION_PARAMETERS) { \ |
1082 | char *filename; \ |
1083 | int filename_len; \ |
1084 | \ |
1085 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p", &filename, &filename_len) == FAILURE) { \ |
1086 | return; \ |
1087 | } \ |
1088 | \ |
1089 | php_stat(filename, (php_stat_len) filename_len, funcnum, return_value TSRMLS_CC); \ |
1090 | } |
1091 | /* }}} */ |
1092 | |
1093 | /* {{{ proto int fileperms(string filename) |
1094 | Get file permissions */ |
1095 | FileFunction(PHP_FN(fileperms), FS_PERMS) |
1096 | /* }}} */ |
1097 | |
1098 | /* {{{ proto int fileinode(string filename) |
1099 | Get file inode */ |
1100 | FileFunction(PHP_FN(fileinode), FS_INODE) |
1101 | /* }}} */ |
1102 | |
1103 | /* {{{ proto int filesize(string filename) |
1104 | Get file size */ |
1105 | FileFunction(PHP_FN(filesize), FS_SIZE) |
1106 | /* }}} */ |
1107 | |
1108 | /* {{{ proto int fileowner(string filename) |
1109 | Get file owner */ |
1110 | FileFunction(PHP_FN(fileowner), FS_OWNER) |
1111 | /* }}} */ |
1112 | |
1113 | /* {{{ proto int filegroup(string filename) |
1114 | Get file group */ |
1115 | FileFunction(PHP_FN(filegroup), FS_GROUP) |
1116 | /* }}} */ |
1117 | |
1118 | /* {{{ proto int fileatime(string filename) |
1119 | Get last access time of file */ |
1120 | FileFunction(PHP_FN(fileatime), FS_ATIME) |
1121 | /* }}} */ |
1122 | |
1123 | /* {{{ proto int filemtime(string filename) |
1124 | Get last modification time of file */ |
1125 | FileFunction(PHP_FN(filemtime), FS_MTIME) |
1126 | /* }}} */ |
1127 | |
1128 | /* {{{ proto int filectime(string filename) |
1129 | Get inode modification time of file */ |
1130 | FileFunction(PHP_FN(filectime), FS_CTIME) |
1131 | /* }}} */ |
1132 | |
1133 | /* {{{ proto string filetype(string filename) |
1134 | Get file type */ |
1135 | FileFunction(PHP_FN(filetype), FS_TYPE) |
1136 | /* }}} */ |
1137 | |
1138 | /* {{{ proto bool is_writable(string filename) |
1139 | Returns true if file can be written */ |
1140 | FileFunction(PHP_FN(is_writable), FS_IS_W) |
1141 | /* }}} */ |
1142 | |
1143 | /* {{{ proto bool is_readable(string filename) |
1144 | Returns true if file can be read */ |
1145 | FileFunction(PHP_FN(is_readable), FS_IS_R) |
1146 | /* }}} */ |
1147 | |
1148 | /* {{{ proto bool is_executable(string filename) |
1149 | Returns true if file is executable */ |
1150 | FileFunction(PHP_FN(is_executable), FS_IS_X) |
1151 | /* }}} */ |
1152 | |
1153 | /* {{{ proto bool is_file(string filename) |
1154 | Returns true if file is a regular file */ |
1155 | FileFunction(PHP_FN(is_file), FS_IS_FILE) |
1156 | /* }}} */ |
1157 | |
1158 | /* {{{ proto bool is_dir(string filename) |
1159 | Returns true if file is directory */ |
1160 | FileFunction(PHP_FN(is_dir), FS_IS_DIR) |
1161 | /* }}} */ |
1162 | |
1163 | /* {{{ proto bool is_link(string filename) |
1164 | Returns true if file is symbolic link */ |
1165 | FileFunction(PHP_FN(is_link), FS_IS_LINK) |
1166 | /* }}} */ |
1167 | |
1168 | /* {{{ proto bool file_exists(string filename) |
1169 | Returns true if filename exists */ |
1170 | FileFunction(PHP_FN(file_exists), FS_EXISTS) |
1171 | /* }}} */ |
1172 | |
1173 | /* {{{ proto array lstat(string filename) |
1174 | Give information about a file or symbolic link */ |
1175 | FileFunction(php_if_lstat, FS_LSTAT) |
1176 | /* }}} */ |
1177 | |
1178 | /* {{{ proto array stat(string filename) |
1179 | Give information about a file */ |
1180 | FileFunction(php_if_stat, FS_STAT) |
1181 | /* }}} */ |
1182 | |
1183 | /* {{{ proto bool realpath_cache_size() |
1184 | Get current size of realpath cache */ |
1185 | PHP_FUNCTION(realpath_cache_size) |
1186 | { |
1187 | if (zend_parse_parameters_none() == FAILURE) { |
1188 | return; |
1189 | } |
1190 | RETURN_LONG(realpath_cache_size(TSRMLS_C)); |
1191 | } |
1192 | |
1193 | /* {{{ proto bool realpath_cache_get() |
1194 | Get current size of realpath cache */ |
1195 | PHP_FUNCTION(realpath_cache_get) |
1196 | { |
1197 | realpath_cache_bucket **buckets = realpath_cache_get_buckets(TSRMLS_C), **end = buckets + realpath_cache_max_buckets(TSRMLS_C); |
1198 | |
1199 | if (zend_parse_parameters_none() == FAILURE) { |
1200 | return; |
1201 | } |
1202 | |
1203 | array_init(return_value); |
1204 | while(buckets < end) { |
1205 | realpath_cache_bucket *bucket = *buckets; |
1206 | while(bucket) { |
1207 | zval *entry; |
1208 | MAKE_STD_ZVAL(entry); |
1209 | array_init(entry); |
1210 | |
1211 | /* bucket->key is unsigned long */ |
1212 | if (LONG_MAX >= bucket->key) { |
1213 | add_assoc_long(entry, "key" , bucket->key); |
1214 | } else { |
1215 | add_assoc_double(entry, "key" , (double)bucket->key); |
1216 | } |
1217 | add_assoc_bool(entry, "is_dir" , bucket->is_dir); |
1218 | add_assoc_stringl(entry, "realpath" , bucket->realpath, bucket->realpath_len, 1); |
1219 | add_assoc_long(entry, "expires" , bucket->expires); |
1220 | #ifdef PHP_WIN32 |
1221 | add_assoc_bool(entry, "is_rvalid" , bucket->is_rvalid); |
1222 | add_assoc_bool(entry, "is_wvalid" , bucket->is_wvalid); |
1223 | add_assoc_bool(entry, "is_readable" , bucket->is_readable); |
1224 | add_assoc_bool(entry, "is_writable" , bucket->is_writable); |
1225 | #endif |
1226 | zend_hash_update(Z_ARRVAL_P(return_value), bucket->path, bucket->path_len+1, &entry, sizeof(zval *), NULL); |
1227 | bucket = bucket->next; |
1228 | } |
1229 | buckets++; |
1230 | } |
1231 | } |
1232 | |
1233 | /* |
1234 | * Local variables: |
1235 | * tab-width: 4 |
1236 | * c-basic-offset: 4 |
1237 | * End: |
1238 | * vim600: sw=4 ts=4 fdm=marker |
1239 | * vim<600: sw=4 ts=4 |
1240 | */ |
1241 | |