/* * Symisc PH7: An embeddable bytecode compiler and a virtual machine for the PHP(5) programming language. * Copyright (C) 2011-2012, Symisc Systems http://ph7.symisc.net/ * Version 2.1.4 * For information on licensing,redistribution of this file,and for a DISCLAIMER OF ALL WARRANTIES * please contact Symisc Systems via: * legal@symisc.net * licensing@symisc.net * contact@symisc.net * or visit: * http://ph7.symisc.net/ */ /* $SymiscID: vfs.c v2.1 Win7 2012-05-24 01:18 devel $ */ #ifndef PH7_AMALGAMATION #include "ph7int.h" #endif /* * This file implement a virtual file systems (VFS) for the PH7 engine. */ /* * Given a string containing the path of a file or directory, this function * return the parent directory's path. */ PH7_PRIVATE const char * PH7_ExtractDirName(const char *zPath,int nByte,int *pLen) { const char *zEnd = &zPath[nByte - 1]; int c,d; c = d = '/'; #ifdef __WINNT__ d = '\\'; #endif while( zEnd > zPath && ( (int)zEnd[0] != c && (int)zEnd[0] != d ) ){ zEnd--; } *pLen = (int)(zEnd-zPath); #ifdef __WINNT__ if( (*pLen) == (int)sizeof(char) && zPath[0] == '/' ){ /* Normalize path on windows */ return "\\"; } #endif if( zEnd == zPath && ( (int)zEnd[0] != c && (int)zEnd[0] != d) ){ /* No separator,return "." as the current directory */ *pLen = sizeof(char); return "."; } if( (*pLen) == 0 ){ *pLen = sizeof(char); #ifdef __WINNT__ return "\\"; #else return "/"; #endif } return zPath; } /* * Omit the vfs layer implementation from the built if the PH7_DISABLE_BUILTIN_FUNC directive is defined. */ #ifndef PH7_DISABLE_BUILTIN_FUNC /* * bool chdir(string $directory) * Change the current directory. * Parameters * $directory * The new current directory * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_chdir(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_vfs *pVfs; int rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xChdir == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ rc = pVfs->xChdir(zPath); /* IO return value */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * bool chroot(string $directory) * Change the root directory. * Parameters * $directory * The path to change the root directory to * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_chroot(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_vfs *pVfs; int rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xChroot == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ rc = pVfs->xChroot(zPath); /* IO return value */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * string getcwd(void) * Gets the current working directory. * Parameters * None * Return * Returns the current working directory on success, or FALSE on failure. */ static int PH7_vfs_getcwd(ph7_context *pCtx,int nArg,ph7_value **apArg) { ph7_vfs *pVfs; int rc; /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xGetcwd == 0 ){ SXUNUSED(nArg); /* cc warning */ SXUNUSED(apArg); /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } ph7_result_string(pCtx,"",0); /* Perform the requested operation */ rc = pVfs->xGetcwd(pCtx); if( rc != PH7_OK ){ /* Error,return FALSE */ ph7_result_bool(pCtx,0); } return PH7_OK; } /* * bool rmdir(string $directory) * Removes directory. * Parameters * $directory * The path to the directory * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_rmdir(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_vfs *pVfs; int rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xRmdir == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ rc = pVfs->xRmdir(zPath); /* IO return value */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * bool is_dir(string $filename) * Tells whether the given filename is a directory. * Parameters * $filename * Path to the file. * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_is_dir(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_vfs *pVfs; int rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xIsdir == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ rc = pVfs->xIsdir(zPath); /* IO return value */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * bool mkdir(string $pathname[,int $mode = 0777 [,bool $recursive = false]) * Make a directory. * Parameters * $pathname * The directory path. * $mode * The mode is 0777 by default, which means the widest possible access. * Note: * mode is ignored on Windows. * Note that you probably want to specify the mode as an octal number, which means * it should have a leading zero. The mode is also modified by the current umask * which you can change using umask(). * $recursive * Allows the creation of nested directories specified in the pathname. * Defaults to FALSE. (Not used) * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_mkdir(ph7_context *pCtx,int nArg,ph7_value **apArg) { int iRecursive = 0; const char *zPath; ph7_vfs *pVfs; int iMode,rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xMkdir == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); #ifdef __WINNT__ iMode = 0; #else /* Assume UNIX */ iMode = 0777; #endif if( nArg > 1 ){ iMode = ph7_value_to_int(apArg[1]); if( nArg > 2 ){ iRecursive = ph7_value_to_bool(apArg[2]); } } /* Perform the requested operation */ rc = pVfs->xMkdir(zPath,iMode,iRecursive); /* IO return value */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * bool rename(string $oldname,string $newname) * Attempts to rename oldname to newname. * Parameters * $oldname * Old name. * $newname * New name. * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_rename(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zOld,*zNew; ph7_vfs *pVfs; int rc; if( nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xRename == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Perform the requested operation */ zOld = ph7_value_to_string(apArg[0],0); zNew = ph7_value_to_string(apArg[1],0); rc = pVfs->xRename(zOld,zNew); /* IO result */ ph7_result_bool(pCtx,rc == PH7_OK ); return PH7_OK; } /* * string realpath(string $path) * Returns canonicalized absolute pathname. * Parameters * $path * Target path. * Return * Canonicalized absolute pathname on success. or FALSE on failure. */ static int PH7_vfs_realpath(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_vfs *pVfs; int rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xRealpath == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Set an empty string untnil the underlying OS interface change that */ ph7_result_string(pCtx,"",0); /* Perform the requested operation */ zPath = ph7_value_to_string(apArg[0],0); rc = pVfs->xRealpath(zPath,pCtx); if( rc != PH7_OK ){ ph7_result_bool(pCtx,0); } return PH7_OK; } /* * int sleep(int $seconds) * Delays the program execution for the given number of seconds. * Parameters * $seconds * Halt time in seconds. * Return * Zero on success or FALSE on failure. */ static int PH7_vfs_sleep(ph7_context *pCtx,int nArg,ph7_value **apArg) { ph7_vfs *pVfs; int rc,nSleep; if( nArg < 1 || !ph7_value_is_int(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xSleep == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Amount to sleep */ nSleep = ph7_value_to_int(apArg[0]); if( nSleep < 0 ){ /* Invalid value,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Perform the requested operation (Microseconds) */ rc = pVfs->xSleep((unsigned int)(nSleep * SX_USEC_PER_SEC)); if( rc != PH7_OK ){ /* Return FALSE */ ph7_result_bool(pCtx,0); }else{ /* Return zero */ ph7_result_int(pCtx,0); } return PH7_OK; } /* * void usleep(int $micro_seconds) * Delays program execution for the given number of micro seconds. * Parameters * $micro_seconds * Halt time in micro seconds. A micro second is one millionth of a second. * Return * None. */ static int PH7_vfs_usleep(ph7_context *pCtx,int nArg,ph7_value **apArg) { ph7_vfs *pVfs; int nSleep; if( nArg < 1 || !ph7_value_is_int(apArg[0]) ){ /* Missing/Invalid argument,return immediately */ return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xSleep == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS", ph7_function_name(pCtx) ); return PH7_OK; } /* Amount to sleep */ nSleep = ph7_value_to_int(apArg[0]); if( nSleep < 0 ){ /* Invalid value,return immediately */ return PH7_OK; } /* Perform the requested operation (Microseconds) */ pVfs->xSleep((unsigned int)nSleep); return PH7_OK; } /* * bool unlink (string $filename) * Delete a file. * Parameters * $filename * Path to the file. * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_unlink(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_vfs *pVfs; int rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xUnlink == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ rc = pVfs->xUnlink(zPath); /* IO return value */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * bool chmod(string $filename,int $mode) * Attempts to change the mode of the specified file to that given in mode. * Parameters * $filename * Path to the file. * $mode * Mode (Must be an integer) * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_chmod(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_vfs *pVfs; int iMode; int rc; if( nArg < 2 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xChmod == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Extract the mode */ iMode = ph7_value_to_int(apArg[1]); /* Perform the requested operation */ rc = pVfs->xChmod(zPath,iMode); /* IO return value */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * bool chown(string $filename,string $user) * Attempts to change the owner of the file filename to user user. * Parameters * $filename * Path to the file. * $user * Username. * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_chown(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath,*zUser; ph7_vfs *pVfs; int rc; if( nArg < 2 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xChown == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Extract the user */ zUser = ph7_value_to_string(apArg[1],0); /* Perform the requested operation */ rc = pVfs->xChown(zPath,zUser); /* IO return value */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * bool chgrp(string $filename,string $group) * Attempts to change the group of the file filename to group. * Parameters * $filename * Path to the file. * $group * groupname. * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_chgrp(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath,*zGroup; ph7_vfs *pVfs; int rc; if( nArg < 2 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xChgrp == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Extract the user */ zGroup = ph7_value_to_string(apArg[1],0); /* Perform the requested operation */ rc = pVfs->xChgrp(zPath,zGroup); /* IO return value */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * int64 disk_free_space(string $directory) * Returns available space on filesystem or disk partition. * Parameters * $directory * A directory of the filesystem or disk partition. * Return * Returns the number of available bytes as a 64-bit integer or FALSE on failure. */ static int PH7_vfs_disk_free_space(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_int64 iSize; ph7_vfs *pVfs; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xFreeSpace == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ iSize = pVfs->xFreeSpace(zPath); /* IO return value */ ph7_result_int64(pCtx,iSize); return PH7_OK; } /* * int64 disk_total_space(string $directory) * Returns the total size of a filesystem or disk partition. * Parameters * $directory * A directory of the filesystem or disk partition. * Return * Returns the number of available bytes as a 64-bit integer or FALSE on failure. */ static int PH7_vfs_disk_total_space(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_int64 iSize; ph7_vfs *pVfs; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xTotalSpace == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ iSize = pVfs->xTotalSpace(zPath); /* IO return value */ ph7_result_int64(pCtx,iSize); return PH7_OK; } /* * bool file_exists(string $filename) * Checks whether a file or directory exists. * Parameters * $filename * Path to the file. * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_file_exists(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_vfs *pVfs; int rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xFileExists == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ rc = pVfs->xFileExists(zPath); /* IO return value */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * int64 file_size(string $filename) * Gets the size for the given file. * Parameters * $filename * Path to the file. * Return * File size on success or FALSE on failure. */ static int PH7_vfs_file_size(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_int64 iSize; ph7_vfs *pVfs; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xFileSize == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ iSize = pVfs->xFileSize(zPath); /* IO return value */ ph7_result_int64(pCtx,iSize); return PH7_OK; } /* * int64 fileatime(string $filename) * Gets the last access time of the given file. * Parameters * $filename * Path to the file. * Return * File atime on success or FALSE on failure. */ static int PH7_vfs_file_atime(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_int64 iTime; ph7_vfs *pVfs; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xFileAtime == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ iTime = pVfs->xFileAtime(zPath); /* IO return value */ ph7_result_int64(pCtx,iTime); return PH7_OK; } /* * int64 filemtime(string $filename) * Gets file modification time. * Parameters * $filename * Path to the file. * Return * File mtime on success or FALSE on failure. */ static int PH7_vfs_file_mtime(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_int64 iTime; ph7_vfs *pVfs; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xFileMtime == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ iTime = pVfs->xFileMtime(zPath); /* IO return value */ ph7_result_int64(pCtx,iTime); return PH7_OK; } /* * int64 filectime(string $filename) * Gets inode change time of file. * Parameters * $filename * Path to the file. * Return * File ctime on success or FALSE on failure. */ static int PH7_vfs_file_ctime(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_int64 iTime; ph7_vfs *pVfs; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xFileCtime == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ iTime = pVfs->xFileCtime(zPath); /* IO return value */ ph7_result_int64(pCtx,iTime); return PH7_OK; } /* * bool is_file(string $filename) * Tells whether the filename is a regular file. * Parameters * $filename * Path to the file. * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_is_file(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_vfs *pVfs; int rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xIsfile == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ rc = pVfs->xIsfile(zPath); /* IO return value */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * bool is_link(string $filename) * Tells whether the filename is a symbolic link. * Parameters * $filename * Path to the file. * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_is_link(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_vfs *pVfs; int rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xIslink == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ rc = pVfs->xIslink(zPath); /* IO return value */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * bool is_readable(string $filename) * Tells whether a file exists and is readable. * Parameters * $filename * Path to the file. * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_is_readable(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_vfs *pVfs; int rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xReadable == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ rc = pVfs->xReadable(zPath); /* IO return value */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * bool is_writable(string $filename) * Tells whether the filename is writable. * Parameters * $filename * Path to the file. * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_is_writable(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_vfs *pVfs; int rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xWritable == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ rc = pVfs->xWritable(zPath); /* IO return value */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * bool is_executable(string $filename) * Tells whether the filename is executable. * Parameters * $filename * Path to the file. * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_is_executable(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_vfs *pVfs; int rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xExecutable == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ rc = pVfs->xExecutable(zPath); /* IO return value */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * string filetype(string $filename) * Gets file type. * Parameters * $filename * Path to the file. * Return * The type of the file. Possible values are fifo, char, dir, block, link * file, socket and unknown. */ static int PH7_vfs_filetype(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; ph7_vfs *pVfs; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return 'unknown' */ ph7_result_string(pCtx,"unknown",sizeof("unknown")-1); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xFiletype == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the desired directory */ zPath = ph7_value_to_string(apArg[0],0); /* Set the empty string as the default return value */ ph7_result_string(pCtx,"",0); /* Perform the requested operation */ pVfs->xFiletype(zPath,pCtx); return PH7_OK; } /* * array stat(string $filename) * Gives information about a file. * Parameters * $filename * Path to the file. * Return * An associative array on success holding the following entries on success * 0 dev device number * 1 ino inode number (zero on windows) * 2 mode inode protection mode * 3 nlink number of links * 4 uid userid of owner (zero on windows) * 5 gid groupid of owner (zero on windows) * 6 rdev device type, if inode device * 7 size size in bytes * 8 atime time of last access (Unix timestamp) * 9 mtime time of last modification (Unix timestamp) * 10 ctime time of last inode change (Unix timestamp) * 11 blksize blocksize of filesystem IO (zero on windows) * 12 blocks number of 512-byte blocks allocated. * Note: * FALSE is returned on failure. */ static int PH7_vfs_stat(ph7_context *pCtx,int nArg,ph7_value **apArg) { ph7_value *pArray,*pValue; const char *zPath; ph7_vfs *pVfs; int rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xStat == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Create the array and the working value */ pArray = ph7_context_new_array(pCtx); pValue = ph7_context_new_scalar(pCtx); if( pArray == 0 || pValue == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the file path */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ rc = pVfs->xStat(zPath,pArray,pValue); if( rc != PH7_OK ){ /* IO error,return FALSE */ ph7_result_bool(pCtx,0); }else{ /* Return the associative array */ ph7_result_value(pCtx,pArray); } /* Don't worry about freeing memory here,everything will be released * automatically as soon we return from this function. */ return PH7_OK; } /* * array lstat(string $filename) * Gives information about a file or symbolic link. * Parameters * $filename * Path to the file. * Return * An associative array on success holding the following entries on success * 0 dev device number * 1 ino inode number (zero on windows) * 2 mode inode protection mode * 3 nlink number of links * 4 uid userid of owner (zero on windows) * 5 gid groupid of owner (zero on windows) * 6 rdev device type, if inode device * 7 size size in bytes * 8 atime time of last access (Unix timestamp) * 9 mtime time of last modification (Unix timestamp) * 10 ctime time of last inode change (Unix timestamp) * 11 blksize blocksize of filesystem IO (zero on windows) * 12 blocks number of 512-byte blocks allocated. * Note: * FALSE is returned on failure. */ static int PH7_vfs_lstat(ph7_context *pCtx,int nArg,ph7_value **apArg) { ph7_value *pArray,*pValue; const char *zPath; ph7_vfs *pVfs; int rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xlStat == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Create the array and the working value */ pArray = ph7_context_new_array(pCtx); pValue = ph7_context_new_scalar(pCtx); if( pArray == 0 || pValue == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the file path */ zPath = ph7_value_to_string(apArg[0],0); /* Perform the requested operation */ rc = pVfs->xlStat(zPath,pArray,pValue); if( rc != PH7_OK ){ /* IO error,return FALSE */ ph7_result_bool(pCtx,0); }else{ /* Return the associative array */ ph7_result_value(pCtx,pArray); } /* Don't worry about freeing memory here,everything will be released * automatically as soon we return from this function. */ return PH7_OK; } /* * string getenv(string $varname) * Gets the value of an environment variable. * Parameters * $varname * The variable name. * Return * Returns the value of the environment variable varname, or FALSE if the environment * variable varname does not exist. */ static int PH7_vfs_getenv(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zEnv; ph7_vfs *pVfs; int iLen; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xGetenv == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the environment variable */ zEnv = ph7_value_to_string(apArg[0],&iLen); /* Set a boolean FALSE as the default return value */ ph7_result_bool(pCtx,0); if( iLen < 1 ){ /* Empty string */ return PH7_OK; } /* Perform the requested operation */ pVfs->xGetenv(zEnv,pCtx); return PH7_OK; } /* * bool putenv(string $settings) * Set the value of an environment variable. * Parameters * $setting * The setting, like "FOO=BAR" * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_putenv(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zName,*zValue; char *zSettings,*zEnd; ph7_vfs *pVfs; int iLen,rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the setting variable */ zSettings = (char *)ph7_value_to_string(apArg[0],&iLen); if( iLen < 1 ){ /* Empty string,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Parse the setting */ zEnd = &zSettings[iLen]; zValue = 0; zName = zSettings; while( zSettings < zEnd ){ if( zSettings[0] == '=' ){ /* Null terminate the name */ zSettings[0] = 0; zValue = &zSettings[1]; break; } zSettings++; } /* Install the environment variable in the $_Env array */ if( zValue == 0 || zName[0] == 0 || zValue >= zEnd || zName >= zValue ){ /* Invalid settings,retun FALSE */ ph7_result_bool(pCtx,0); if( zSettings < zEnd ){ zSettings[0] = '='; } return PH7_OK; } ph7_vm_config(pCtx->pVm,PH7_VM_CONFIG_ENV_ATTR,zName,zValue,(int)(zEnd-zValue)); /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xSetenv == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); zSettings[0] = '='; return PH7_OK; } /* Perform the requested operation */ rc = pVfs->xSetenv(zName,zValue); ph7_result_bool(pCtx,rc == PH7_OK ); zSettings[0] = '='; return PH7_OK; } /* * bool touch(string $filename[,int64 $time = time()[,int64 $atime]]) * Sets access and modification time of file. * Note: On windows * If the file does not exists,it will not be created. * Parameters * $filename * The name of the file being touched. * $time * The touch time. If time is not supplied, the current system time is used. * $atime * If present, the access time of the given filename is set to the value of atime. * Otherwise, it is set to the value passed to the time parameter. If neither are * present, the current system time is used. * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_touch(ph7_context *pCtx,int nArg,ph7_value **apArg) { ph7_int64 nTime,nAccess; const char *zFile; ph7_vfs *pVfs; int rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xTouch == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Perform the requested operation */ nTime = nAccess = -1; zFile = ph7_value_to_string(apArg[0],0); if( nArg > 1 ){ nTime = ph7_value_to_int64(apArg[1]); if( nArg > 2 ){ nAccess = ph7_value_to_int64(apArg[1]); }else{ nAccess = nTime; } } rc = pVfs->xTouch(zFile,nTime,nAccess); /* IO result */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * Path processing functions that do not need access to the VFS layer * Authors: * Symisc Systems,devel@symisc.net. * Copyright (C) Symisc Systems,http://ph7.symisc.net * Status: * Stable. */ /* * string dirname(string $path) * Returns parent directory's path. * Parameters * $path * Target path. * On Windows, both slash (/) and backslash (\) are used as directory separator character. * In other environments, it is the forward slash (/). * Return * The path of the parent directory. If there are no slashes in path, a dot ('.') * is returned, indicating the current directory. */ static int PH7_builtin_dirname(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath,*zDir; int iLen,iDirlen; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid arguments,return the empty string */ ph7_result_string(pCtx,"",0); return PH7_OK; } /* Point to the target path */ zPath = ph7_value_to_string(apArg[0],&iLen); if( iLen < 1 ){ /* Reuturn "." */ ph7_result_string(pCtx,".",sizeof(char)); return PH7_OK; } /* Perform the requested operation */ zDir = PH7_ExtractDirName(zPath,iLen,&iDirlen); /* Return directory name */ ph7_result_string(pCtx,zDir,iDirlen); return PH7_OK; } /* * string basename(string $path[, string $suffix ]) * Returns trailing name component of path. * Parameters * $path * Target path. * On Windows, both slash (/) and backslash (\) are used as directory separator character. * In other environments, it is the forward slash (/). * $suffix * If the name component ends in suffix this will also be cut off. * Return * The base name of the given path. */ static int PH7_builtin_basename(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath,*zBase,*zEnd; int c,d,iLen; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return the empty string */ ph7_result_string(pCtx,"",0); return PH7_OK; } c = d = '/'; #ifdef __WINNT__ d = '\\'; #endif /* Point to the target path */ zPath = ph7_value_to_string(apArg[0],&iLen); if( iLen < 1 ){ /* Empty string */ ph7_result_string(pCtx,"",0); return PH7_OK; } /* Perform the requested operation */ zEnd = &zPath[iLen - 1]; /* Ignore trailing '/' */ while( zEnd > zPath && ( (int)zEnd[0] == c || (int)zEnd[0] == d ) ){ zEnd--; } iLen = (int)(&zEnd[1]-zPath); while( zEnd > zPath && ( (int)zEnd[0] != c && (int)zEnd[0] != d ) ){ zEnd--; } zBase = (zEnd > zPath) ? &zEnd[1] : zPath; zEnd = &zPath[iLen]; if( nArg > 1 && ph7_value_is_string(apArg[1]) ){ const char *zSuffix; int nSuffix; /* Strip suffix */ zSuffix = ph7_value_to_string(apArg[1],&nSuffix); if( nSuffix > 0 && nSuffix < iLen && SyMemcmp(&zEnd[-nSuffix],zSuffix,nSuffix) == 0 ){ zEnd -= nSuffix; } } /* Store the basename */ ph7_result_string(pCtx,zBase,(int)(zEnd-zBase)); return PH7_OK; } /* * value pathinfo(string $path [,int $options = PATHINFO_DIRNAME | PATHINFO_BASENAME | PATHINFO_EXTENSION | PATHINFO_FILENAME ]) * Returns information about a file path. * Parameter * $path * The path to be parsed. * $options * If present, specifies a specific element to be returned; one of * PATHINFO_DIRNAME, PATHINFO_BASENAME, PATHINFO_EXTENSION or PATHINFO_FILENAME. * Return * If the options parameter is not passed, an associative array containing the following * elements is returned: dirname, basename, extension (if any), and filename. * If options is present, returns a string containing the requested element. */ typedef struct path_info path_info; struct path_info { SyString sDir; /* Directory [i.e: /var/www] */ SyString sBasename; /* Basename [i.e httpd.conf] */ SyString sExtension; /* File extension [i.e xml,pdf..] */ SyString sFilename; /* Filename */ }; /* * Extract path fields. */ static sxi32 ExtractPathInfo(const char *zPath,int nByte,path_info *pOut) { const char *zPtr,*zEnd = &zPath[nByte - 1]; SyString *pCur; int c,d; c = d = '/'; #ifdef __WINNT__ d = '\\'; #endif /* Zero the structure */ SyZero(pOut,sizeof(path_info)); /* Handle special case */ if( nByte == sizeof(char) && ( (int)zPath[0] == c || (int)zPath[0] == d ) ){ #ifdef __WINNT__ SyStringInitFromBuf(&pOut->sDir,"\\",sizeof(char)); #else SyStringInitFromBuf(&pOut->sDir,"/",sizeof(char)); #endif return SXRET_OK; } /* Extract the basename */ while( zEnd > zPath && ( (int)zEnd[0] != c && (int)zEnd[0] != d ) ){ zEnd--; } zPtr = (zEnd > zPath) ? &zEnd[1] : zPath; zEnd = &zPath[nByte]; /* dirname */ pCur = &pOut->sDir; SyStringInitFromBuf(pCur,zPath,zPtr-zPath); if( pCur->nByte > 1 ){ SyStringTrimTrailingChar(pCur,'/'); #ifdef __WINNT__ SyStringTrimTrailingChar(pCur,'\\'); #endif }else if( (int)zPath[0] == c || (int)zPath[0] == d ){ #ifdef __WINNT__ SyStringInitFromBuf(&pOut->sDir,"\\",sizeof(char)); #else SyStringInitFromBuf(&pOut->sDir,"/",sizeof(char)); #endif } /* basename/filename */ pCur = &pOut->sBasename; SyStringInitFromBuf(pCur,zPtr,zEnd-zPtr); SyStringTrimLeadingChar(pCur,'/'); #ifdef __WINNT__ SyStringTrimLeadingChar(pCur,'\\'); #endif SyStringDupPtr(&pOut->sFilename,pCur); if( pCur->nByte > 0 ){ /* extension */ zEnd--; while( zEnd > pCur->zString /*basename*/ && zEnd[0] != '.' ){ zEnd--; } if( zEnd > pCur->zString ){ zEnd++; /* Jump leading dot */ SyStringInitFromBuf(&pOut->sExtension,zEnd,&zPath[nByte]-zEnd); /* Fix filename */ pCur = &pOut->sFilename; if( pCur->nByte > SyStringLength(&pOut->sExtension) ){ pCur->nByte -= 1 + SyStringLength(&pOut->sExtension); } } } return SXRET_OK; } /* * value pathinfo(string $path [,int $options = PATHINFO_DIRNAME | PATHINFO_BASENAME | PATHINFO_EXTENSION | PATHINFO_FILENAME ]) * See block comment above. */ static int PH7_builtin_pathinfo(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zPath; path_info sInfo; SyString *pComp; int iLen; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid argument,return the empty string */ ph7_result_string(pCtx,"",0); return PH7_OK; } /* Point to the target path */ zPath = ph7_value_to_string(apArg[0],&iLen); if( iLen < 1 ){ /* Empty string */ ph7_result_string(pCtx,"",0); return PH7_OK; } /* Extract path info */ ExtractPathInfo(zPath,iLen,&sInfo); if( nArg > 1 && ph7_value_is_int(apArg[1]) ){ /* Return path component */ int nComp = ph7_value_to_int(apArg[1]); switch(nComp){ case 1: /* PATHINFO_DIRNAME */ pComp = &sInfo.sDir; if( pComp->nByte > 0 ){ ph7_result_string(pCtx,pComp->zString,(int)pComp->nByte); }else{ /* Expand the empty string */ ph7_result_string(pCtx,"",0); } break; case 2: /*PATHINFO_BASENAME*/ pComp = &sInfo.sBasename; if( pComp->nByte > 0 ){ ph7_result_string(pCtx,pComp->zString,(int)pComp->nByte); }else{ /* Expand the empty string */ ph7_result_string(pCtx,"",0); } break; case 3: /*PATHINFO_EXTENSION*/ pComp = &sInfo.sExtension; if( pComp->nByte > 0 ){ ph7_result_string(pCtx,pComp->zString,(int)pComp->nByte); }else{ /* Expand the empty string */ ph7_result_string(pCtx,"",0); } break; case 4: /*PATHINFO_FILENAME*/ pComp = &sInfo.sFilename; if( pComp->nByte > 0 ){ ph7_result_string(pCtx,pComp->zString,(int)pComp->nByte); }else{ /* Expand the empty string */ ph7_result_string(pCtx,"",0); } break; default: /* Expand the empty string */ ph7_result_string(pCtx,"",0); break; } }else{ /* Return an associative array */ ph7_value *pArray,*pValue; pArray = ph7_context_new_array(pCtx); pValue = ph7_context_new_scalar(pCtx); if( pArray == 0 || pValue == 0 ){ /* Out of mem,return NULL */ ph7_result_bool(pCtx,0); return PH7_OK; } /* dirname */ pComp = &sInfo.sDir; if( pComp->nByte > 0 ){ ph7_value_string(pValue,pComp->zString,(int)pComp->nByte); /* Perform the insertion */ ph7_array_add_strkey_elem(pArray,"dirname",pValue); /* Will make it's own copy */ } /* Reset the string cursor */ ph7_value_reset_string_cursor(pValue); /* basername */ pComp = &sInfo.sBasename; if( pComp->nByte > 0 ){ ph7_value_string(pValue,pComp->zString,(int)pComp->nByte); /* Perform the insertion */ ph7_array_add_strkey_elem(pArray,"basename",pValue); /* Will make it's own copy */ } /* Reset the string cursor */ ph7_value_reset_string_cursor(pValue); /* extension */ pComp = &sInfo.sExtension; if( pComp->nByte > 0 ){ ph7_value_string(pValue,pComp->zString,(int)pComp->nByte); /* Perform the insertion */ ph7_array_add_strkey_elem(pArray,"extension",pValue); /* Will make it's own copy */ } /* Reset the string cursor */ ph7_value_reset_string_cursor(pValue); /* filename */ pComp = &sInfo.sFilename; if( pComp->nByte > 0 ){ ph7_value_string(pValue,pComp->zString,(int)pComp->nByte); /* Perform the insertion */ ph7_array_add_strkey_elem(pArray,"filename",pValue); /* Will make it's own copy */ } /* Return the created array */ ph7_result_value(pCtx,pArray); /* Don't worry about freeing memory, everything will be released * automatically as soon we return from this foreign function. */ } return PH7_OK; } /* * Globbing implementation extracted from the sqlite3 source tree. * Original author: D. Richard Hipp (http://www.sqlite.org) * Status: Public Domain */ typedef unsigned char u8; /* An array to map all upper-case characters into their corresponding ** lower-case character. ** ** SQLite only considers US-ASCII (or EBCDIC) characters. We do not ** handle case conversions for the UTF character set since the tables ** involved are nearly as big or bigger than SQLite itself. */ static const unsigned char sqlite3UpperToLower[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103, 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121, 122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107, 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125, 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161, 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179, 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197, 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215, 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233, 234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251, 252,253,254,255 }; #define GlogUpperToLower(A) if( A<0x80 ){ A = sqlite3UpperToLower[A]; } /* ** Assuming zIn points to the first byte of a UTF-8 character, ** advance zIn to point to the first byte of the next UTF-8 character. */ #define SQLITE_SKIP_UTF8(zIn) { \ if( (*(zIn++))>=0xc0 ){ \ while( (*zIn & 0xc0)==0x80 ){ zIn++; } \ } \ } /* ** Compare two UTF-8 strings for equality where the first string can ** potentially be a "glob" expression. Return true (1) if they ** are the same and false (0) if they are different. ** ** Globbing rules: ** ** '*' Matches any sequence of zero or more characters. ** ** '?' Matches exactly one character. ** ** [...] Matches one character from the enclosed list of ** characters. ** ** [^...] Matches one character not in the enclosed list. ** ** With the [...] and [^...] matching, a ']' character can be included ** in the list by making it the first character after '[' or '^'. A ** range of characters can be specified using '-'. Example: ** "[a-z]" matches any single lower-case letter. To match a '-', make ** it the last character in the list. ** ** This routine is usually quick, but can be N**2 in the worst case. ** ** Hints: to match '*' or '?', put them in "[]". Like this: ** ** abc[*]xyz Matches "abc*xyz" only */ static int patternCompare( const u8 *zPattern, /* The glob pattern */ const u8 *zString, /* The string to compare against the glob */ const int esc, /* The escape character */ int noCase ){ int c, c2; int invert; int seen; u8 matchOne = '?'; u8 matchAll = '*'; u8 matchSet = '['; int prevEscape = 0; /* True if the previous character was 'escape' */ if( !zPattern || !zString ) return 0; while( (c = PH7_Utf8Read(zPattern,0,&zPattern))!=0 ){ if( !prevEscape && c==matchAll ){ while( (c=PH7_Utf8Read(zPattern,0,&zPattern)) == matchAll || c == matchOne ){ if( c==matchOne && PH7_Utf8Read(zString, 0, &zString)==0 ){ return 0; } } if( c==0 ){ return 1; }else if( c==esc ){ c = PH7_Utf8Read(zPattern, 0, &zPattern); if( c==0 ){ return 0; } }else if( c==matchSet ){ if( (esc==0) || (matchSet<0x80) ) return 0; while( *zString && patternCompare(&zPattern[-1],zString,esc,noCase)==0 ){ SQLITE_SKIP_UTF8(zString); } return *zString!=0; } while( (c2 = PH7_Utf8Read(zString,0,&zString))!=0 ){ if( noCase ){ GlogUpperToLower(c2); GlogUpperToLower(c); while( c2 != 0 && c2 != c ){ c2 = PH7_Utf8Read(zString, 0, &zString); GlogUpperToLower(c2); } }else{ while( c2 != 0 && c2 != c ){ c2 = PH7_Utf8Read(zString, 0, &zString); } } if( c2==0 ) return 0; if( patternCompare(zPattern,zString,esc,noCase) ) return 1; } return 0; }else if( !prevEscape && c==matchOne ){ if( PH7_Utf8Read(zString, 0, &zString)==0 ){ return 0; } }else if( c==matchSet ){ int prior_c = 0; if( esc == 0 ) return 0; seen = 0; invert = 0; c = PH7_Utf8Read(zString, 0, &zString); if( c==0 ) return 0; c2 = PH7_Utf8Read(zPattern, 0, &zPattern); if( c2=='^' ){ invert = 1; c2 = PH7_Utf8Read(zPattern, 0, &zPattern); } if( c2==']' ){ if( c==']' ) seen = 1; c2 = PH7_Utf8Read(zPattern, 0, &zPattern); } while( c2 && c2!=']' ){ if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){ c2 = PH7_Utf8Read(zPattern, 0, &zPattern); if( c>=prior_c && c<=c2 ) seen = 1; prior_c = 0; }else{ if( c==c2 ){ seen = 1; } prior_c = c2; } c2 = PH7_Utf8Read(zPattern, 0, &zPattern); } if( c2==0 || (seen ^ invert)==0 ){ return 0; } }else if( esc==c && !prevEscape ){ prevEscape = 1; }else{ c2 = PH7_Utf8Read(zString, 0, &zString); if( noCase ){ GlogUpperToLower(c); GlogUpperToLower(c2); } if( c!=c2 ){ return 0; } prevEscape = 0; } } return *zString==0; } /* * Wrapper around patternCompare() defined above. * See block comment above for more information. */ static int Glob(const unsigned char *zPattern,const unsigned char *zString,int iEsc,int CaseCompare) { int rc; if( iEsc < 0 ){ iEsc = '\\'; } rc = patternCompare(zPattern,zString,iEsc,CaseCompare); return rc; } /* * bool fnmatch(string $pattern,string $string[,int $flags = 0 ]) * Match filename against a pattern. * Parameters * $pattern * The shell wildcard pattern. * $string * The tested string. * $flags * A list of possible flags: * FNM_NOESCAPE Disable backslash escaping. * FNM_PATHNAME Slash in string only matches slash in the given pattern. * FNM_PERIOD Leading period in string must be exactly matched by period in the given pattern. * FNM_CASEFOLD Caseless match. * Return * TRUE if there is a match, FALSE otherwise. */ static int PH7_builtin_fnmatch(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zString,*zPattern; int iEsc = '\\'; int noCase = 0; int rc; if( nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the pattern and the string */ zPattern = ph7_value_to_string(apArg[0],0); zString = ph7_value_to_string(apArg[1],0); /* Extract the flags if avaialble */ if( nArg > 2 && ph7_value_is_int(apArg[2]) ){ rc = ph7_value_to_int(apArg[2]); if( rc & 0x01 /*FNM_NOESCAPE*/){ iEsc = 0; } if( rc & 0x08 /*FNM_CASEFOLD*/){ noCase = 1; } } /* Go globbing */ rc = Glob((const unsigned char *)zPattern,(const unsigned char *)zString,iEsc,noCase); /* Globbing result */ ph7_result_bool(pCtx,rc); return PH7_OK; } /* * bool strglob(string $pattern,string $string) * Match string against a pattern. * Parameters * $pattern * The shell wildcard pattern. * $string * The tested string. * Return * TRUE if there is a match, FALSE otherwise. * Note that this a symisc eXtension. */ static int PH7_builtin_strglob(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zString,*zPattern; int iEsc = '\\'; int rc; if( nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the pattern and the string */ zPattern = ph7_value_to_string(apArg[0],0); zString = ph7_value_to_string(apArg[1],0); /* Go globbing */ rc = Glob((const unsigned char *)zPattern,(const unsigned char *)zString,iEsc,0); /* Globbing result */ ph7_result_bool(pCtx,rc); return PH7_OK; } /* * bool link(string $target,string $link) * Create a hard link. * Parameters * $target * Target of the link. * $link * The link name. * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_link(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zTarget,*zLink; ph7_vfs *pVfs; int rc; if( nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xLink == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the given arguments */ zTarget = ph7_value_to_string(apArg[0],0); zLink = ph7_value_to_string(apArg[1],0); /* Perform the requested operation */ rc = pVfs->xLink(zTarget,zLink,0/*Not a symbolic link */); /* IO result */ ph7_result_bool(pCtx,rc == PH7_OK ); return PH7_OK; } /* * bool symlink(string $target,string $link) * Creates a symbolic link. * Parameters * $target * Target of the link. * $link * The link name. * Return * TRUE on success or FALSE on failure. */ static int PH7_vfs_symlink(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zTarget,*zLink; ph7_vfs *pVfs; int rc; if( nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xLink == 0 ){ /* IO routine not implemented,return NULL */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS,PH7 is returning FALSE", ph7_function_name(pCtx) ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the given arguments */ zTarget = ph7_value_to_string(apArg[0],0); zLink = ph7_value_to_string(apArg[1],0); /* Perform the requested operation */ rc = pVfs->xLink(zTarget,zLink,1/*A symbolic link */); /* IO result */ ph7_result_bool(pCtx,rc == PH7_OK ); return PH7_OK; } /* * int umask([ int $mask ]) * Changes the current umask. * Parameters * $mask * The new umask. * Return * umask() without arguments simply returns the current umask. * Otherwise the old umask is returned. */ static int PH7_vfs_umask(ph7_context *pCtx,int nArg,ph7_value **apArg) { int iOld,iNew; ph7_vfs *pVfs; /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xUmask == 0 ){ /* IO routine not implemented,return -1 */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS", ph7_function_name(pCtx) ); ph7_result_int(pCtx,0); return PH7_OK; } iNew = 0; if( nArg > 0 ){ iNew = ph7_value_to_int(apArg[0]); } /* Perform the requested operation */ iOld = pVfs->xUmask(iNew); /* Old mask */ ph7_result_int(pCtx,iOld); return PH7_OK; } /* * string sys_get_temp_dir() * Returns directory path used for temporary files. * Parameters * None * Return * Returns the path of the temporary directory. */ static int PH7_vfs_sys_get_temp_dir(ph7_context *pCtx,int nArg,ph7_value **apArg) { ph7_vfs *pVfs; /* Set the empty string as the default return value */ ph7_result_string(pCtx,"",0); /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xTempDir == 0 ){ SXUNUSED(nArg); /* cc warning */ SXUNUSED(apArg); /* IO routine not implemented,return "" */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS", ph7_function_name(pCtx) ); return PH7_OK; } /* Perform the requested operation */ pVfs->xTempDir(pCtx); return PH7_OK; } /* * string get_current_user() * Returns the name of the current working user. * Parameters * None * Return * Returns the name of the current working user. */ static int PH7_vfs_get_current_user(ph7_context *pCtx,int nArg,ph7_value **apArg) { ph7_vfs *pVfs; /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xUsername == 0 ){ SXUNUSED(nArg); /* cc warning */ SXUNUSED(apArg); /* IO routine not implemented */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS", ph7_function_name(pCtx) ); /* Set a dummy username */ ph7_result_string(pCtx,"unknown",sizeof("unknown")-1); return PH7_OK; } /* Perform the requested operation */ pVfs->xUsername(pCtx); return PH7_OK; } /* * int64 getmypid() * Gets process ID. * Parameters * None * Return * Returns the process ID. */ static int PH7_vfs_getmypid(ph7_context *pCtx,int nArg,ph7_value **apArg) { ph7_int64 nProcessId; ph7_vfs *pVfs; /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xProcessId == 0 ){ SXUNUSED(nArg); /* cc warning */ SXUNUSED(apArg); /* IO routine not implemented,return -1 */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS", ph7_function_name(pCtx) ); ph7_result_int(pCtx,-1); return PH7_OK; } /* Perform the requested operation */ nProcessId = (ph7_int64)pVfs->xProcessId(); /* Set the result */ ph7_result_int64(pCtx,nProcessId); return PH7_OK; } /* * int getmyuid() * Get user ID. * Parameters * None * Return * Returns the user ID. */ static int PH7_vfs_getmyuid(ph7_context *pCtx,int nArg,ph7_value **apArg) { ph7_vfs *pVfs; int nUid; /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xUid == 0 ){ SXUNUSED(nArg); /* cc warning */ SXUNUSED(apArg); /* IO routine not implemented,return -1 */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS", ph7_function_name(pCtx) ); ph7_result_int(pCtx,-1); return PH7_OK; } /* Perform the requested operation */ nUid = pVfs->xUid(); /* Set the result */ ph7_result_int(pCtx,nUid); return PH7_OK; } /* * int getmygid() * Get group ID. * Parameters * None * Return * Returns the group ID. */ static int PH7_vfs_getmygid(ph7_context *pCtx,int nArg,ph7_value **apArg) { ph7_vfs *pVfs; int nGid; /* Point to the underlying vfs */ pVfs = (ph7_vfs *)ph7_context_user_data(pCtx); if( pVfs == 0 || pVfs->xGid == 0 ){ SXUNUSED(nArg); /* cc warning */ SXUNUSED(apArg); /* IO routine not implemented,return -1 */ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying VFS", ph7_function_name(pCtx) ); ph7_result_int(pCtx,-1); return PH7_OK; } /* Perform the requested operation */ nGid = pVfs->xGid(); /* Set the result */ ph7_result_int(pCtx,nGid); return PH7_OK; } #ifdef __WINNT__ #include #elif defined(__UNIXES__) #include #endif /* * string php_uname([ string $mode = "a" ]) * Returns information about the host operating system. * Parameters * $mode * mode is a single character that defines what information is returned: * 'a': This is the default. Contains all modes in the sequence "s n r v m". * 's': Operating system name. eg. FreeBSD. * 'n': Host name. eg. localhost.example.com. * 'r': Release name. eg. 5.1.2-RELEASE. * 'v': Version information. Varies a lot between operating systems. * 'm': Machine type. eg. i386. * Return * OS description as a string. */ static int PH7_vfs_ph7_uname(ph7_context *pCtx,int nArg,ph7_value **apArg) { #if defined(__WINNT__) const char *zName = "Microsoft Windows"; OSVERSIONINFOW sVer; #elif defined(__UNIXES__) struct utsname sName; #endif const char *zMode = "a"; if( nArg > 0 && ph7_value_is_string(apArg[0]) ){ /* Extract the desired mode */ zMode = ph7_value_to_string(apArg[0],0); } #if defined(__WINNT__) sVer.dwOSVersionInfoSize = sizeof(sVer); if( TRUE != GetVersionExW(&sVer)){ ph7_result_string(pCtx,zName,-1); return PH7_OK; } if( sVer.dwPlatformId == VER_PLATFORM_WIN32_NT ){ if( sVer.dwMajorVersion <= 4 ){ zName = "Microsoft Windows NT"; }else if( sVer.dwMajorVersion == 5 ){ switch(sVer.dwMinorVersion){ case 0: zName = "Microsoft Windows 2000"; break; case 1: zName = "Microsoft Windows XP"; break; case 2: zName = "Microsoft Windows Server 2003"; break; } }else if( sVer.dwMajorVersion == 6){ switch(sVer.dwMinorVersion){ case 0: zName = "Microsoft Windows Vista"; break; case 1: zName = "Microsoft Windows 7"; break; case 2: zName = "Microsoft Windows Server 2008"; break; case 3: zName = "Microsoft Windows 8"; break; default: break; } } } switch(zMode[0]){ case 's': /* Operating system name */ ph7_result_string(pCtx,zName,-1/* Compute length automatically*/); break; case 'n': /* Host name */ ph7_result_string(pCtx,"localhost",(int)sizeof("localhost")-1); break; case 'r': case 'v': /* Version information. */ ph7_result_string_format(pCtx,"%u.%u build %u", sVer.dwMajorVersion,sVer.dwMinorVersion,sVer.dwBuildNumber ); break; case 'm': /* Machine name */ ph7_result_string(pCtx,"x86",(int)sizeof("x86")-1); break; default: ph7_result_string_format(pCtx,"%s localhost %u.%u build %u x86", zName, sVer.dwMajorVersion,sVer.dwMinorVersion,sVer.dwBuildNumber ); break; } #elif defined(__UNIXES__) if( uname(&sName) != 0 ){ ph7_result_string(pCtx,"Unix",(int)sizeof("Unix")-1); return PH7_OK; } switch(zMode[0]){ case 's': /* Operating system name */ ph7_result_string(pCtx,sName.sysname,-1/* Compute length automatically*/); break; case 'n': /* Host name */ ph7_result_string(pCtx,sName.nodename,-1/* Compute length automatically*/); break; case 'r': /* Release information */ ph7_result_string(pCtx,sName.release,-1/* Compute length automatically*/); break; case 'v': /* Version information. */ ph7_result_string(pCtx,sName.version,-1/* Compute length automatically*/); break; case 'm': /* Machine name */ ph7_result_string(pCtx,sName.machine,-1/* Compute length automatically*/); break; default: ph7_result_string_format(pCtx, "%s %s %s %s %s", sName.sysname, sName.release, sName.version, sName.nodename, sName.machine ); break; } #else ph7_result_string(pCtx,"Unknown Operating System",(int)sizeof("Unknown Operating System")-1); #endif return PH7_OK; } /* * Section: * IO stream implementation. * Authors: * Symisc Systems,devel@symisc.net. * Copyright (C) Symisc Systems,http://ph7.symisc.net * Status: * Stable. */ typedef struct io_private io_private; struct io_private { const ph7_io_stream *pStream; /* Underlying IO device */ void *pHandle; /* IO handle */ /* Unbuffered IO */ SyBlob sBuffer; /* Working buffer */ sxu32 nOfft; /* Current read offset */ sxu32 iMagic; /* Sanity check to avoid misuse */ }; #define IO_PRIVATE_MAGIC 0xFEAC14 /* Make sure we are dealing with a valid io_private instance */ #define IO_PRIVATE_INVALID(IO) ( IO == 0 || IO->iMagic != IO_PRIVATE_MAGIC ) /* Forward declaration */ static void ResetIOPrivate(io_private *pDev); /* * bool ftruncate(resource $handle,int64 $size) * Truncates a file to a given length. * Parameters * $handle * The file pointer. * Note: * The handle must be open for writing. * $size * The size to truncate to. * Return * TRUE on success or FALSE on failure. */ static int PH7_builtin_ftruncate(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; io_private *pDev; int rc; if( nArg < 2 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 || pStream->xTrunc == 0){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Perform the requested operation */ rc = pStream->xTrunc(pDev->pHandle,ph7_value_to_int64(apArg[1])); if( rc == PH7_OK ){ /* Discard buffered data */ ResetIOPrivate(pDev); } /* IO result */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * int fseek(resource $handle,int $offset[,int $whence = SEEK_SET ]) * Seeks on a file pointer. * Parameters * $handle * A file system pointer resource that is typically created using fopen(). * $offset * The offset. * To move to a position before the end-of-file, you need to pass a negative * value in offset and set whence to SEEK_END. * whence * whence values are: * SEEK_SET - Set position equal to offset bytes. * SEEK_CUR - Set position to current location plus offset. * SEEK_END - Set position to end-of-file plus offset. * Return * 0 on success,-1 on failure */ static int PH7_builtin_fseek(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; io_private *pDev; ph7_int64 iOfft; int whence; int rc; if( nArg < 2 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_int(pCtx,-1); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_int(pCtx,-1); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 || pStream->xSeek == 0){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_int(pCtx,-1); return PH7_OK; } /* Extract the offset */ iOfft = ph7_value_to_int64(apArg[1]); whence = 0;/* SEEK_SET */ if( nArg > 2 && ph7_value_is_int(apArg[2]) ){ whence = ph7_value_to_int(apArg[2]); } /* Perform the requested operation */ rc = pStream->xSeek(pDev->pHandle,iOfft,whence); if( rc == PH7_OK ){ /* Ignore buffered data */ ResetIOPrivate(pDev); } /* IO result */ ph7_result_int(pCtx,rc == PH7_OK ? 0 : - 1); return PH7_OK; } /* * int64 ftell(resource $handle) * Returns the current position of the file read/write pointer. * Parameters * $handle * The file pointer. * Return * Returns the position of the file pointer referenced by handle * as an integer; i.e., its offset into the file stream. * FALSE is returned on failure. */ static int PH7_builtin_ftell(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; io_private *pDev; ph7_int64 iOfft; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 || pStream->xTell == 0){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Perform the requested operation */ iOfft = pStream->xTell(pDev->pHandle); /* IO result */ ph7_result_int64(pCtx,iOfft); return PH7_OK; } /* * bool rewind(resource $handle) * Rewind the position of a file pointer. * Parameters * $handle * The file pointer. * Return * TRUE on success or FALSE on failure. */ static int PH7_builtin_rewind(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; io_private *pDev; int rc; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 || pStream->xSeek == 0){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Perform the requested operation */ rc = pStream->xSeek(pDev->pHandle,0,0/*SEEK_SET*/); if( rc == PH7_OK ){ /* Ignore buffered data */ ResetIOPrivate(pDev); } /* IO result */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * bool fflush(resource $handle) * Flushes the output to a file. * Parameters * $handle * The file pointer. * Return * TRUE on success or FALSE on failure. */ static int PH7_builtin_fflush(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; io_private *pDev; int rc; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 || pStream->xSync == 0){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Perform the requested operation */ rc = pStream->xSync(pDev->pHandle); /* IO result */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * bool feof(resource $handle) * Tests for end-of-file on a file pointer. * Parameters * $handle * The file pointer. * Return * Returns TRUE if the file pointer is at EOF.FALSE otherwise */ static int PH7_builtin_feof(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; io_private *pDev; int rc; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,1); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,1); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,1); return PH7_OK; } rc = SXERR_EOF; /* Perform the requested operation */ if( SyBlobLength(&pDev->sBuffer) - pDev->nOfft > 0 ){ /* Data is available */ rc = PH7_OK; }else{ char zBuf[4096]; ph7_int64 n; /* Perform a buffered read */ n = pStream->xRead(pDev->pHandle,zBuf,sizeof(zBuf)); if( n > 0 ){ /* Copy buffered data */ SyBlobAppend(&pDev->sBuffer,zBuf,(sxu32)n); rc = PH7_OK; } } /* EOF or not */ ph7_result_bool(pCtx,rc == SXERR_EOF); return PH7_OK; } /* * Read n bytes from the underlying IO stream device. * Return total numbers of bytes readen on success. A number < 1 on failure * [i.e: IO error ] or EOF. */ static ph7_int64 StreamRead(io_private *pDev,void *pBuf,ph7_int64 nLen) { const ph7_io_stream *pStream = pDev->pStream; char *zBuf = (char *)pBuf; ph7_int64 n,nRead; n = SyBlobLength(&pDev->sBuffer) - pDev->nOfft; if( n > 0 ){ if( n > nLen ){ n = nLen; } /* Copy the buffered data */ SyMemcpy(SyBlobDataAt(&pDev->sBuffer,pDev->nOfft),pBuf,(sxu32)n); /* Update the read offset */ pDev->nOfft += (sxu32)n; if( pDev->nOfft >= SyBlobLength(&pDev->sBuffer) ){ /* Reset the working buffer so that we avoid excessive memory allocation */ SyBlobReset(&pDev->sBuffer); pDev->nOfft = 0; } nLen -= n; if( nLen < 1 ){ /* All done */ return n; } /* Advance the cursor */ zBuf += n; } /* Read without buffering */ nRead = pStream->xRead(pDev->pHandle,zBuf,nLen); if( nRead > 0 ){ n += nRead; }else if( n < 1 ){ /* EOF or IO error */ return nRead; } return n; } /* * Extract a single line from the buffered input. */ static sxi32 GetLine(io_private *pDev,ph7_int64 *pLen,const char **pzLine) { const char *zIn,*zEnd,*zPtr; zIn = (const char *)SyBlobDataAt(&pDev->sBuffer,pDev->nOfft); zEnd = &zIn[SyBlobLength(&pDev->sBuffer)-pDev->nOfft]; zPtr = zIn; while( zIn < zEnd ){ if( zIn[0] == '\n' ){ /* Line found */ zIn++; /* Include the line ending as requested by the PHP specification */ *pLen = (ph7_int64)(zIn-zPtr); *pzLine = zPtr; return SXRET_OK; } zIn++; } /* No line were found */ return SXERR_NOTFOUND; } /* * Read a single line from the underlying IO stream device. */ static ph7_int64 StreamReadLine(io_private *pDev,const char **pzData,ph7_int64 nMaxLen) { const ph7_io_stream *pStream = pDev->pStream; char zBuf[8192]; ph7_int64 n; sxi32 rc; n = 0; if( pDev->nOfft >= SyBlobLength(&pDev->sBuffer) ){ /* Reset the working buffer so that we avoid excessive memory allocation */ SyBlobReset(&pDev->sBuffer); pDev->nOfft = 0; } if( SyBlobLength(&pDev->sBuffer) - pDev->nOfft > 0 ){ /* Check if there is a line */ rc = GetLine(pDev,&n,pzData); if( rc == SXRET_OK ){ /* Got line,update the cursor */ pDev->nOfft += (sxu32)n; return n; } } /* Perform the read operation until a new line is extracted or length * limit is reached. */ for(;;){ n = pStream->xRead(pDev->pHandle,zBuf,(nMaxLen > 0 && nMaxLen < sizeof(zBuf)) ? nMaxLen : sizeof(zBuf)); if( n < 1 ){ /* EOF or IO error */ break; } /* Append the data just read */ SyBlobAppend(&pDev->sBuffer,zBuf,(sxu32)n); /* Try to extract a line */ rc = GetLine(pDev,&n,pzData); if( rc == SXRET_OK ){ /* Got one,return immediately */ pDev->nOfft += (sxu32)n; return n; } if( nMaxLen > 0 && (SyBlobLength(&pDev->sBuffer) - pDev->nOfft >= nMaxLen) ){ /* Read limit reached,return the available data */ *pzData = (const char *)SyBlobDataAt(&pDev->sBuffer,pDev->nOfft); n = SyBlobLength(&pDev->sBuffer) - pDev->nOfft; /* Reset the working buffer */ SyBlobReset(&pDev->sBuffer); pDev->nOfft = 0; return n; } } if( SyBlobLength(&pDev->sBuffer) - pDev->nOfft > 0 ){ /* Read limit reached,return the available data */ *pzData = (const char *)SyBlobDataAt(&pDev->sBuffer,pDev->nOfft); n = SyBlobLength(&pDev->sBuffer) - pDev->nOfft; /* Reset the working buffer */ SyBlobReset(&pDev->sBuffer); pDev->nOfft = 0; } return n; } /* * Open an IO stream handle. * Notes on stream: * According to the PHP reference manual. * In its simplest definition, a stream is a resource object which exhibits streamable behavior. * That is, it can be read from or written to in a linear fashion, and may be able to fseek() * to an arbitrary locations within the stream. * A wrapper is additional code which tells the stream how to handle specific protocols/encodings. * For example, the http wrapper knows how to translate a URL into an HTTP/1.0 request for a file * on a remote server. * A stream is referenced as: scheme://target * scheme(string) - The name of the wrapper to be used. Examples include: file, http... * If no wrapper is specified, the function default is used (typically file://). * target - Depends on the wrapper used. For filesystem related streams this is typically a path * and filename of the desired file. For network related streams this is typically a hostname, often * with a path appended. * * Note that PH7 IO streams looks like PHP streams but their implementation differ greately. * Please refer to the official documentation for a full discussion. * This function return a handle on success. Otherwise null. */ PH7_PRIVATE void * PH7_StreamOpenHandle(ph7_vm *pVm,const ph7_io_stream *pStream,const char *zFile, int iFlags,int use_include,ph7_value *pResource,int bPushInclude,int *pNew) { void *pHandle = 0; /* cc warning */ SyString sFile; int rc; if( pStream == 0 ){ /* No such stream device */ return 0; } SyStringInitFromBuf(&sFile,zFile,SyStrlen(zFile)); if( use_include ){ if( sFile.zString[0] == '/' || #ifdef __WINNT__ (sFile.nByte > 2 && sFile.zString[1] == ':' && (sFile.zString[2] == '\\' || sFile.zString[2] == '/') ) || #endif (sFile.nByte > 1 && sFile.zString[0] == '.' && sFile.zString[1] == '/') || (sFile.nByte > 2 && sFile.zString[0] == '.' && sFile.zString[1] == '.' && sFile.zString[2] == '/') ){ /* Open the file directly */ rc = pStream->xOpen(zFile,iFlags,pResource,&pHandle); }else{ SyString *pPath; SyBlob sWorker; #ifdef __WINNT__ static const int c = '\\'; #else static const int c = '/'; #endif /* Init the path builder working buffer */ SyBlobInit(&sWorker,&pVm->sAllocator); /* Build a path from the set of include path */ SySetResetCursor(&pVm->aPaths); rc = SXERR_IO; while( SXRET_OK == SySetGetNextEntry(&pVm->aPaths,(void **)&pPath) ){ /* Build full path */ SyBlobFormat(&sWorker,"%z%c%z",pPath,c,&sFile); /* Append null terminator */ if( SXRET_OK != SyBlobNullAppend(&sWorker) ){ continue; } /* Try to open the file */ rc = pStream->xOpen((const char *)SyBlobData(&sWorker),iFlags,pResource,&pHandle); if( rc == PH7_OK ){ if( bPushInclude ){ /* Mark as included */ PH7_VmPushFilePath(pVm,(const char *)SyBlobData(&sWorker),SyBlobLength(&sWorker),FALSE,pNew); } break; } /* Reset the working buffer */ SyBlobReset(&sWorker); /* Check the next path */ } SyBlobRelease(&sWorker); } if( rc == PH7_OK ){ if( bPushInclude ){ /* Mark as included */ PH7_VmPushFilePath(pVm,sFile.zString,sFile.nByte,FALSE,pNew); } } }else{ /* Open the URI direcly */ rc = pStream->xOpen(zFile,iFlags,pResource,&pHandle); } if( rc != PH7_OK ){ /* IO error */ return 0; } /* Return the file handle */ return pHandle; } /* * Read the whole contents of an open IO stream handle [i.e local file/URL..] * Store the read data in the given BLOB (last argument). * The read operation is stopped when he hit the EOF or an IO error occurs. */ PH7_PRIVATE sxi32 PH7_StreamReadWholeFile(void *pHandle,const ph7_io_stream *pStream,SyBlob *pOut) { ph7_int64 nRead; char zBuf[8192]; /* 8K */ int rc; /* Perform the requested operation */ for(;;){ nRead = pStream->xRead(pHandle,zBuf,sizeof(zBuf)); if( nRead < 1 ){ /* EOF or IO error */ break; } /* Append contents */ rc = SyBlobAppend(pOut,zBuf,(sxu32)nRead); if( rc != SXRET_OK ){ break; } } return SyBlobLength(pOut) > 0 ? SXRET_OK : -1; } /* * Close an open IO stream handle [i.e local file/URI..]. */ PH7_PRIVATE void PH7_StreamCloseHandle(const ph7_io_stream *pStream,void *pHandle) { if( pStream->xClose ){ pStream->xClose(pHandle); } } /* * string fgetc(resource $handle) * Gets a character from the given file pointer. * Parameters * $handle * The file pointer. * Return * Returns a string containing a single character read from the file * pointed to by handle. Returns FALSE on EOF. * WARNING * This operation is extremely slow.Avoid using it. */ static int PH7_builtin_fgetc(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; io_private *pDev; int c,n; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Perform the requested operation */ n = (int)StreamRead(pDev,(void *)&c,sizeof(char)); /* IO result */ if( n < 1 ){ /* EOF or error,return FALSE */ ph7_result_bool(pCtx,0); }else{ /* Return the string holding the character */ ph7_result_string(pCtx,(const char *)&c,sizeof(char)); } return PH7_OK; } /* * string fgets(resource $handle[,int64 $length ]) * Gets line from file pointer. * Parameters * $handle * The file pointer. * $length * Reading ends when length - 1 bytes have been read, on a newline * (which is included in the return value), or on EOF (whichever comes first). * If no length is specified, it will keep reading from the stream until it reaches * the end of the line. * Return * Returns a string of up to length - 1 bytes read from the file pointed to by handle. * If there is no more data to read in the file pointer, then FALSE is returned. * If an error occurs, FALSE is returned. */ static int PH7_builtin_fgets(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; const char *zLine; io_private *pDev; ph7_int64 n,nLen; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } nLen = -1; if( nArg > 1 ){ /* Maximum data to read */ nLen = ph7_value_to_int64(apArg[1]); } /* Perform the requested operation */ n = StreamReadLine(pDev,&zLine,nLen); if( n < 1 ){ /* EOF or IO error,return FALSE */ ph7_result_bool(pCtx,0); }else{ /* Return the freshly extracted line */ ph7_result_string(pCtx,zLine,(int)n); } return PH7_OK; } /* * string fread(resource $handle,int64 $length) * Binary-safe file read. * Parameters * $handle * The file pointer. * $length * Up to length number of bytes read. * Return * The data readen on success or FALSE on failure. */ static int PH7_builtin_fread(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; io_private *pDev; ph7_int64 nRead; void *pBuf; int nLen; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } nLen = 4096; if( nArg > 1 ){ nLen = ph7_value_to_int(apArg[1]); if( nLen < 1 ){ /* Invalid length,set a default length */ nLen = 4096; } } /* Allocate enough buffer */ pBuf = ph7_context_alloc_chunk(pCtx,(unsigned int)nLen,FALSE,FALSE); if( pBuf == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Perform the requested operation */ nRead = StreamRead(pDev,pBuf,(ph7_int64)nLen); if( nRead < 1 ){ /* Nothing read,return FALSE */ ph7_result_bool(pCtx,0); }else{ /* Make a copy of the data just read */ ph7_result_string(pCtx,(const char *)pBuf,(int)nRead); } /* Release the buffer */ ph7_context_free_chunk(pCtx,pBuf); return PH7_OK; } /* * array fgetcsv(resource $handle [, int $length = 0 * [,string $delimiter = ','[,string $enclosure = '"'[,string $escape='\\']]]]) * Gets line from file pointer and parse for CSV fields. * Parameters * $handle * The file pointer. * $length * Reading ends when length - 1 bytes have been read, on a newline * (which is included in the return value), or on EOF (whichever comes first). * If no length is specified, it will keep reading from the stream until it reaches * the end of the line. * $delimiter * Set the field delimiter (one character only). * $enclosure * Set the field enclosure character (one character only). * $escape * Set the escape character (one character only). Defaults as a backslash (\) * Return * Returns a string of up to length - 1 bytes read from the file pointed to by handle. * If there is no more data to read in the file pointer, then FALSE is returned. * If an error occurs, FALSE is returned. */ static int PH7_builtin_fgetcsv(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; const char *zLine; io_private *pDev; ph7_int64 n,nLen; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } nLen = -1; if( nArg > 1 ){ /* Maximum data to read */ nLen = ph7_value_to_int64(apArg[1]); } /* Perform the requested operation */ n = StreamReadLine(pDev,&zLine,nLen); if( n < 1 ){ /* EOF or IO error,return FALSE */ ph7_result_bool(pCtx,0); }else{ ph7_value *pArray; int delim = ','; /* Delimiter */ int encl = '"' ; /* Enclosure */ int escape = '\\'; /* Escape character */ if( nArg > 2 ){ const char *zPtr; int i; if( ph7_value_is_string(apArg[2]) ){ /* Extract the delimiter */ zPtr = ph7_value_to_string(apArg[2],&i); if( i > 0 ){ delim = zPtr[0]; } } if( nArg > 3 ){ if( ph7_value_is_string(apArg[3]) ){ /* Extract the enclosure */ zPtr = ph7_value_to_string(apArg[3],&i); if( i > 0 ){ encl = zPtr[0]; } } if( nArg > 4 ){ if( ph7_value_is_string(apArg[4]) ){ /* Extract the escape character */ zPtr = ph7_value_to_string(apArg[4],&i); if( i > 0 ){ escape = zPtr[0]; } } } } } /* Create our array */ pArray = ph7_context_new_array(pCtx); if( pArray == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory"); ph7_result_null(pCtx); return PH7_OK; } /* Parse the raw input */ PH7_ProcessCsv(zLine,(int)n,delim,encl,escape,PH7_CsvConsumer,pArray); /* Return the freshly created array */ ph7_result_value(pCtx,pArray); } return PH7_OK; } /* * string fgetss(resource $handle [,int $length [,string $allowable_tags ]]) * Gets line from file pointer and strip HTML tags. * Parameters * $handle * The file pointer. * $length * Reading ends when length - 1 bytes have been read, on a newline * (which is included in the return value), or on EOF (whichever comes first). * If no length is specified, it will keep reading from the stream until it reaches * the end of the line. * $allowable_tags * You can use the optional second parameter to specify tags which should not be stripped. * Return * Returns a string of up to length - 1 bytes read from the file pointed to by * handle, with all HTML and PHP code stripped. If an error occurs, returns FALSE. */ static int PH7_builtin_fgetss(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; const char *zLine; io_private *pDev; ph7_int64 n,nLen; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } nLen = -1; if( nArg > 1 ){ /* Maximum data to read */ nLen = ph7_value_to_int64(apArg[1]); } /* Perform the requested operation */ n = StreamReadLine(pDev,&zLine,nLen); if( n < 1 ){ /* EOF or IO error,return FALSE */ ph7_result_bool(pCtx,0); }else{ const char *zTaglist = 0; int nTaglen = 0; if( nArg > 2 && ph7_value_is_string(apArg[2]) ){ /* Allowed tag */ zTaglist = ph7_value_to_string(apArg[2],&nTaglen); } /* Process data just read */ PH7_StripTagsFromString(pCtx,zLine,(int)n,zTaglist,nTaglen); } return PH7_OK; } /* * string readdir(resource $dir_handle) * Read entry from directory handle. * Parameter * $dir_handle * The directory handle resource previously opened with opendir(). * Return * Returns the filename on success or FALSE on failure. */ static int PH7_builtin_readdir(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; io_private *pDev; int rc; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 || pStream->xReadDir == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } ph7_result_bool(pCtx,0); /* Perform the requested operation */ rc = pStream->xReadDir(pDev->pHandle,pCtx); if( rc != PH7_OK ){ /* Return FALSE */ ph7_result_bool(pCtx,0); } return PH7_OK; } /* * void rewinddir(resource $dir_handle) * Rewind directory handle. * Parameter * $dir_handle * The directory handle resource previously opened with opendir(). * Return * FALSE on failure. */ static int PH7_builtin_rewinddir(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; io_private *pDev; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 || pStream->xRewindDir == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Perform the requested operation */ pStream->xRewindDir(pDev->pHandle); return PH7_OK; } /* Forward declaration */ static void InitIOPrivate(ph7_vm *pVm,const ph7_io_stream *pStream,io_private *pOut); static void ReleaseIOPrivate(ph7_context *pCtx,io_private *pDev); /* * void closedir(resource $dir_handle) * Close directory handle. * Parameter * $dir_handle * The directory handle resource previously opened with opendir(). * Return * FALSE on failure. */ static int PH7_builtin_closedir(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; io_private *pDev; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 || pStream->xCloseDir == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Perform the requested operation */ pStream->xCloseDir(pDev->pHandle); /* Release the private stucture */ ReleaseIOPrivate(pCtx,pDev); PH7_MemObjRelease(apArg[0]); return PH7_OK; } /* * resource opendir(string $path[,resource $context]) * Open directory handle. * Parameters * $path * The directory path that is to be opened. * $context * A context stream resource. * Return * A directory handle resource on success,or FALSE on failure. */ static int PH7_builtin_opendir(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; const char *zPath; io_private *pDev; int iLen,rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a directory path"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the target path */ zPath = ph7_value_to_string(apArg[0],&iLen); /* Try to extract a stream */ pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zPath,iLen); if( pStream == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "No stream device is associated with the given path(%s)",zPath); ph7_result_bool(pCtx,0); return PH7_OK; } if( pStream->xOpenDir == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device", ph7_function_name(pCtx),pStream->zName ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Allocate a new IO private instance */ pDev = (io_private *)ph7_context_alloc_chunk(pCtx,sizeof(io_private),TRUE,FALSE); if( pDev == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Initialize the structure */ InitIOPrivate(pCtx->pVm,pStream,pDev); /* Open the target directory */ rc = pStream->xOpenDir(zPath,nArg > 1 ? apArg[1] : 0,&pDev->pHandle); if( rc != PH7_OK ){ /* IO error,return FALSE */ ReleaseIOPrivate(pCtx,pDev); ph7_result_bool(pCtx,0); }else{ /* Return the handle as a resource */ ph7_result_resource(pCtx,pDev); } return PH7_OK; } /* * int readfile(string $filename[,bool $use_include_path = false [,resource $context ]]) * Reads a file and writes it to the output buffer. * Parameters * $filename * The filename being read. * $use_include_path * You can use the optional second parameter and set it to * TRUE, if you want to search for the file in the include_path, too. * $context * A context stream resource. * Return * The number of bytes read from the file on success or FALSE on failure. */ static int PH7_builtin_readfile(ph7_context *pCtx,int nArg,ph7_value **apArg) { int use_include = FALSE; const ph7_io_stream *pStream; ph7_int64 n,nRead; const char *zFile; char zBuf[8192]; void *pHandle; int rc,nLen; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the file path */ zFile = ph7_value_to_string(apArg[0],&nLen); /* Point to the target IO stream device */ pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen); if( pStream == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE"); ph7_result_bool(pCtx,0); return PH7_OK; } if( nArg > 1 ){ use_include = ph7_value_to_bool(apArg[1]); } /* Try to open the file in read-only mode */ pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,PH7_IO_OPEN_RDONLY, use_include,nArg > 2 ? apArg[2] : 0,FALSE,0); if( pHandle == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile); ph7_result_bool(pCtx,0); return PH7_OK; } /* Perform the requested operation */ nRead = 0; for(;;){ n = pStream->xRead(pHandle,zBuf,sizeof(zBuf)); if( n < 1 ){ /* EOF or IO error,break immediately */ break; } /* Output data */ rc = ph7_context_output(pCtx,zBuf,(int)n); if( rc == PH7_ABORT ){ break; } /* Increment counter */ nRead += n; } /* Close the stream */ PH7_StreamCloseHandle(pStream,pHandle); /* Total number of bytes readen */ ph7_result_int64(pCtx,nRead); return PH7_OK; } /* * string file_get_contents(string $filename[,bool $use_include_path = false * [, resource $context [, int $offset = -1 [, int $maxlen ]]]]) * Reads entire file into a string. * Parameters * $filename * The filename being read. * $use_include_path * You can use the optional second parameter and set it to * TRUE, if you want to search for the file in the include_path, too. * $context * A context stream resource. * $offset * The offset where the reading starts on the original stream. * $maxlen * Maximum length of data read. The default is to read until end of file * is reached. Note that this parameter is applied to the stream processed by the filters. * Return * The function returns the read data or FALSE on failure. */ static int PH7_builtin_file_get_contents(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; ph7_int64 n,nRead,nMaxlen; int use_include = FALSE; const char *zFile; char zBuf[8192]; void *pHandle; int nLen; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the file path */ zFile = ph7_value_to_string(apArg[0],&nLen); /* Point to the target IO stream device */ pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen); if( pStream == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE"); ph7_result_bool(pCtx,0); return PH7_OK; } nMaxlen = -1; if( nArg > 1 ){ use_include = ph7_value_to_bool(apArg[1]); } /* Try to open the file in read-only mode */ pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,PH7_IO_OPEN_RDONLY,use_include,nArg > 2 ? apArg[2] : 0,FALSE,0); if( pHandle == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile); ph7_result_bool(pCtx,0); return PH7_OK; } if( nArg > 3 ){ /* Extract the offset */ n = ph7_value_to_int64(apArg[3]); if( n > 0 ){ if( pStream->xSeek ){ /* Seek to the desired offset */ pStream->xSeek(pHandle,n,0/*SEEK_SET*/); } } if( nArg > 4 ){ /* Maximum data to read */ nMaxlen = ph7_value_to_int64(apArg[4]); } } /* Perform the requested operation */ nRead = 0; for(;;){ n = pStream->xRead(pHandle,zBuf, (nMaxlen > 0 && (nMaxlen < sizeof(zBuf))) ? nMaxlen : sizeof(zBuf)); if( n < 1 ){ /* EOF or IO error,break immediately */ break; } /* Append data */ ph7_result_string(pCtx,zBuf,(int)n); /* Increment read counter */ nRead += n; if( nMaxlen > 0 && nRead >= nMaxlen ){ /* Read limit reached */ break; } } /* Close the stream */ PH7_StreamCloseHandle(pStream,pHandle); /* Check if we have read something */ if( ph7_context_result_buf_length(pCtx) < 1 ){ /* Nothing read,return FALSE */ ph7_result_bool(pCtx,0); } return PH7_OK; } /* * int file_put_contents(string $filename,mixed $data[,int $flags = 0[,resource $context]]) * Write a string to a file. * Parameters * $filename * Path to the file where to write the data. * $data * The data to write(Must be a string). * $flags * The value of flags can be any combination of the following * flags, joined with the binary OR (|) operator. * FILE_USE_INCLUDE_PATH Search for filename in the include directory. See include_path for more information. * FILE_APPEND If file filename already exists, append the data to the file instead of overwriting it. * LOCK_EX Acquire an exclusive lock on the file while proceeding to the writing. * context * A context stream resource. * Return * The function returns the number of bytes that were written to the file, or FALSE on failure. */ static int PH7_builtin_file_put_contents(ph7_context *pCtx,int nArg,ph7_value **apArg) { int use_include = FALSE; const ph7_io_stream *pStream; const char *zFile; const char *zData; int iOpenFlags; void *pHandle; int iFlags; int nLen; if( nArg < 2 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the file path */ zFile = ph7_value_to_string(apArg[0],&nLen); /* Point to the target IO stream device */ pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen); if( pStream == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Data to write */ zData = ph7_value_to_string(apArg[1],&nLen); if( nLen < 1 ){ /* Nothing to write,return immediately */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Try to open the file in read-write mode */ iOpenFlags = PH7_IO_OPEN_CREATE|PH7_IO_OPEN_RDWR|PH7_IO_OPEN_TRUNC; /* Extract the flags */ iFlags = 0; if( nArg > 2 ){ iFlags = ph7_value_to_int(apArg[2]); if( iFlags & 0x01 /*FILE_USE_INCLUDE_PATH*/){ use_include = TRUE; } if( iFlags & 0x08 /* FILE_APPEND */){ /* If the file already exists, append the data to the file * instead of overwriting it. */ iOpenFlags &= ~PH7_IO_OPEN_TRUNC; /* Append mode */ iOpenFlags |= PH7_IO_OPEN_APPEND; } } pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,iOpenFlags,use_include, nArg > 3 ? apArg[3] : 0,FALSE,FALSE); if( pHandle == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile); ph7_result_bool(pCtx,0); return PH7_OK; } if( pStream->xWrite ){ ph7_int64 n; if( (iFlags & 0x01/* LOCK_EX */) && pStream->xLock ){ /* Try to acquire an exclusive lock */ pStream->xLock(pHandle,1/* LOCK_EX */); } /* Perform the write operation */ n = pStream->xWrite(pHandle,(const void *)zData,nLen); if( n < 1 ){ /* IO error,return FALSE */ ph7_result_bool(pCtx,0); }else{ /* Total number of bytes written */ ph7_result_int64(pCtx,n); } }else{ /* Read-only stream */ ph7_context_throw_error_format(pCtx,PH7_CTX_ERR, "Read-only stream(%s): Cannot perform write operation", pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); } /* Close the handle */ PH7_StreamCloseHandle(pStream,pHandle); return PH7_OK; } /* * array file(string $filename[,int $flags = 0[,resource $context]]) * Reads entire file into an array. * Parameters * $filename * The filename being read. * $flags * The optional parameter flags can be one, or more, of the following constants: * FILE_USE_INCLUDE_PATH * Search for the file in the include_path. * FILE_IGNORE_NEW_LINES * Do not add newline at the end of each array element * FILE_SKIP_EMPTY_LINES * Skip empty lines * $context * A context stream resource. * Return * The function returns the read data or FALSE on failure. */ static int PH7_builtin_file(ph7_context *pCtx,int nArg,ph7_value **apArg) { const char *zFile,*zPtr,*zEnd,*zBuf; ph7_value *pArray,*pLine; const ph7_io_stream *pStream; int use_include = 0; io_private *pDev; ph7_int64 n; int iFlags; int nLen; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the file path */ zFile = ph7_value_to_string(apArg[0],&nLen); /* Point to the target IO stream device */ pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen); if( pStream == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Allocate a new IO private instance */ pDev = (io_private *)ph7_context_alloc_chunk(pCtx,sizeof(io_private),TRUE,FALSE); if( pDev == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Initialize the structure */ InitIOPrivate(pCtx->pVm,pStream,pDev); iFlags = 0; if( nArg > 1 ){ iFlags = ph7_value_to_int(apArg[1]); } if( iFlags & 0x01 /*FILE_USE_INCLUDE_PATH*/ ){ use_include = TRUE; } /* Create the array and the working value */ pArray = ph7_context_new_array(pCtx); pLine = ph7_context_new_scalar(pCtx); if( pArray == 0 || pLine == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Try to open the file in read-only mode */ pDev->pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,PH7_IO_OPEN_RDONLY,use_include,nArg > 2 ? apArg[2] : 0,FALSE,0); if( pDev->pHandle == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile); ph7_result_bool(pCtx,0); /* Don't worry about freeing memory, everything will be released automatically * as soon we return from this function. */ return PH7_OK; } /* Perform the requested operation */ for(;;){ /* Try to extract a line */ n = StreamReadLine(pDev,&zBuf,-1); if( n < 1 ){ /* EOF or IO error */ break; } /* Reset the cursor */ ph7_value_reset_string_cursor(pLine); /* Remove line ending if requested by the caller */ zPtr = zBuf; zEnd = &zBuf[n]; if( iFlags & 0x02 /* FILE_IGNORE_NEW_LINES */ ){ /* Ignore trailig lines */ while( zPtr < zEnd && (zEnd[-1] == '\n' #ifdef __WINNT__ || zEnd[-1] == '\r' #endif )){ n--; zEnd--; } } if( iFlags & 0x04 /* FILE_SKIP_EMPTY_LINES */ ){ /* Ignore empty lines */ while( zPtr < zEnd && (unsigned char)zPtr[0] < 0xc0 && SyisSpace(zPtr[0]) ){ zPtr++; } if( zPtr >= zEnd ){ /* Empty line */ continue; } } ph7_value_string(pLine,zBuf,(int)(zEnd-zBuf)); /* Insert line */ ph7_array_add_elem(pArray,0/* Automatic index assign*/,pLine); } /* Close the stream */ PH7_StreamCloseHandle(pStream,pDev->pHandle); /* Release the io_private instance */ ReleaseIOPrivate(pCtx,pDev); /* Return the created array */ ph7_result_value(pCtx,pArray); return PH7_OK; } /* * bool copy(string $source,string $dest[,resource $context ] ) * Makes a copy of the file source to dest. * Parameters * $source * Path to the source file. * $dest * The destination path. If dest is a URL, the copy operation * may fail if the wrapper does not support overwriting of existing files. * $context * A context stream resource. * Return * TRUE on success or FALSE on failure. */ static int PH7_builtin_copy(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pSin,*pSout; const char *zFile; char zBuf[8192]; void *pIn,*pOut; ph7_int64 n; int nLen; if( nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_string(apArg[1])){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a source and a destination path"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the source name */ zFile = ph7_value_to_string(apArg[0],&nLen); /* Point to the target IO stream device */ pSin = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen); if( pSin == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Try to open the source file in a read-only mode */ pIn = PH7_StreamOpenHandle(pCtx->pVm,pSin,zFile,PH7_IO_OPEN_RDONLY,FALSE,nArg > 2 ? apArg[2] : 0,FALSE,0); if( pIn == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening source: '%s'",zFile); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the destination name */ zFile = ph7_value_to_string(apArg[1],&nLen); /* Point to the target IO stream device */ pSout = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen); if( pSout == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE"); ph7_result_bool(pCtx,0); PH7_StreamCloseHandle(pSin,pIn); return PH7_OK; } if( pSout->xWrite == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pSin->zName ); ph7_result_bool(pCtx,0); PH7_StreamCloseHandle(pSin,pIn); return PH7_OK; } /* Try to open the destination file in a read-write mode */ pOut = PH7_StreamOpenHandle(pCtx->pVm,pSout,zFile, PH7_IO_OPEN_CREATE|PH7_IO_OPEN_TRUNC|PH7_IO_OPEN_RDWR,FALSE,nArg > 2 ? apArg[2] : 0,FALSE,0); if( pOut == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening destination: '%s'",zFile); ph7_result_bool(pCtx,0); PH7_StreamCloseHandle(pSin,pIn); return PH7_OK; } /* Perform the requested operation */ for(;;){ /* Read from source */ n = pSin->xRead(pIn,zBuf,sizeof(zBuf)); if( n < 1 ){ /* EOF or IO error,break immediately */ break; } /* Write to dest */ n = pSout->xWrite(pOut,zBuf,n); if( n < 1 ){ /* IO error,break immediately */ break; } } /* Close the streams */ PH7_StreamCloseHandle(pSin,pIn); PH7_StreamCloseHandle(pSout,pOut); /* Return TRUE */ ph7_result_bool(pCtx,1); return PH7_OK; } /* * array fstat(resource $handle) * Gets information about a file using an open file pointer. * Parameters * $handle * The file pointer. * Return * Returns an array with the statistics of the file or FALSE on failure. */ static int PH7_builtin_fstat(ph7_context *pCtx,int nArg,ph7_value **apArg) { ph7_value *pArray,*pValue; const ph7_io_stream *pStream; io_private *pDev; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /* Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 || pStream->xStat == 0){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Create the array and the working value */ pArray = ph7_context_new_array(pCtx); pValue = ph7_context_new_scalar(pCtx); if( pArray == 0 || pValue == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Perform the requested operation */ pStream->xStat(pDev->pHandle,pArray,pValue); /* Return the freshly created array */ ph7_result_value(pCtx,pArray); /* Don't worry about freeing memory here,everything will be * released automatically as soon we return from this function. */ return PH7_OK; } /* * int fwrite(resource $handle,string $string[,int $length]) * Writes the contents of string to the file stream pointed to by handle. * Parameters * $handle * The file pointer. * $string * The string that is to be written. * $length * If the length argument is given, writing will stop after length bytes have been written * or the end of string is reached, whichever comes first. * Return * Returns the number of bytes written, or FALSE on error. */ static int PH7_builtin_fwrite(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; const char *zString; io_private *pDev; int nLen,n; if( nArg < 2 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /* Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 || pStream->xWrite == 0){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the data to write */ zString = ph7_value_to_string(apArg[1],&nLen); if( nArg > 2 ){ /* Maximum data length to write */ n = ph7_value_to_int(apArg[2]); if( n >= 0 && n < nLen ){ nLen = n; } } if( nLen < 1 ){ /* Nothing to write */ ph7_result_int(pCtx,0); return PH7_OK; } /* Perform the requested operation */ n = (int)pStream->xWrite(pDev->pHandle,(const void *)zString,nLen); if( n < 0 ){ /* IO error,return FALSE */ ph7_result_bool(pCtx,0); }else{ /* #Bytes written */ ph7_result_int(pCtx,n); } return PH7_OK; } /* * bool flock(resource $handle,int $operation) * Portable advisory file locking. * Parameters * $handle * The file pointer. * $operation * operation is one of the following: * LOCK_SH to acquire a shared lock (reader). * LOCK_EX to acquire an exclusive lock (writer). * LOCK_UN to release a lock (shared or exclusive). * Return * Returns TRUE on success or FALSE on failure. */ static int PH7_builtin_flock(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; io_private *pDev; int nLock; int rc; if( nArg < 2 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 || pStream->xLock == 0){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Requested lock operation */ nLock = ph7_value_to_int(apArg[1]); /* Lock operation */ rc = pStream->xLock(pDev->pHandle,nLock); /* IO result */ ph7_result_bool(pCtx,rc == PH7_OK); return PH7_OK; } /* * int fpassthru(resource $handle) * Output all remaining data on a file pointer. * Parameters * $handle * The file pointer. * Return * Total number of characters read from handle and passed through * to the output on success or FALSE on failure. */ static int PH7_builtin_fpassthru(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; io_private *pDev; ph7_int64 n,nRead; char zBuf[8192]; int rc; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Perform the requested operation */ nRead = 0; for(;;){ n = StreamRead(pDev,zBuf,sizeof(zBuf)); if( n < 1 ){ /* Error or EOF */ break; } /* Increment the read counter */ nRead += n; /* Output data */ rc = ph7_context_output(pCtx,zBuf,(int)nRead /* FIXME: 64-bit issues */); if( rc == PH7_ABORT ){ /* Consumer callback request an operation abort */ break; } } /* Total number of bytes readen */ ph7_result_int64(pCtx,nRead); return PH7_OK; } /* CSV reader/writer private data */ struct csv_data { int delimiter; /* Delimiter. Default ',' */ int enclosure; /* Enclosure. Default '"'*/ io_private *pDev; /* Open stream handle */ int iCount; /* Counter */ }; /* * The following callback is used by the fputcsv() function inorder to iterate * throw array entries and output CSV data based on the current key and it's * associated data. */ static int csv_write_callback(ph7_value *pKey,ph7_value *pValue,void *pUserData) { struct csv_data *pData = (struct csv_data *)pUserData; const char *zData; int nLen,c2; sxu32 n; /* Point to the raw data */ zData = ph7_value_to_string(pValue,&nLen); if( nLen < 1 ){ /* Nothing to write */ return PH7_OK; } if( pData->iCount > 0 ){ /* Write the delimiter */ pData->pDev->pStream->xWrite(pData->pDev->pHandle,(const void *)&pData->delimiter,sizeof(char)); } n = 1; c2 = 0; if( SyByteFind(zData,(sxu32)nLen,pData->delimiter,0) == SXRET_OK || SyByteFind(zData,(sxu32)nLen,pData->enclosure,&n) == SXRET_OK ){ c2 = 1; if( n == 0 ){ c2 = 2; } /* Write the enclosure */ pData->pDev->pStream->xWrite(pData->pDev->pHandle,(const void *)&pData->enclosure,sizeof(char)); if( c2 > 1 ){ pData->pDev->pStream->xWrite(pData->pDev->pHandle,(const void *)&pData->enclosure,sizeof(char)); } } /* Write the data */ if( pData->pDev->pStream->xWrite(pData->pDev->pHandle,(const void *)zData,(ph7_int64)nLen) < 1 ){ SXUNUSED(pKey); /* cc warning */ return PH7_ABORT; } if( c2 > 0 ){ /* Write the enclosure */ pData->pDev->pStream->xWrite(pData->pDev->pHandle,(const void *)&pData->enclosure,sizeof(char)); if( c2 > 1 ){ pData->pDev->pStream->xWrite(pData->pDev->pHandle,(const void *)&pData->enclosure,sizeof(char)); } } pData->iCount++; return PH7_OK; } /* * int fputcsv(resource $handle,array $fields[,string $delimiter = ','[,string $enclosure = '"' ]]) * Format line as CSV and write to file pointer. * Parameters * $handle * Open file handle. * $fields * An array of values. * $delimiter * The optional delimiter parameter sets the field delimiter (one character only). * $enclosure * The optional enclosure parameter sets the field enclosure (one character only). */ static int PH7_builtin_fputcsv(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; struct csv_data sCsv; io_private *pDev; char *zEol; int eolen; if( nArg < 2 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_array(apArg[1]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Missing/Invalid arguments"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 || pStream->xWrite == 0){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Set default csv separator */ sCsv.delimiter = ','; sCsv.enclosure = '"'; sCsv.pDev = pDev; sCsv.iCount = 0; if( nArg > 2 ){ /* User delimiter */ const char *z; int n; z = ph7_value_to_string(apArg[2],&n); if( n > 0 ){ sCsv.delimiter = z[0]; } if( nArg > 3 ){ z = ph7_value_to_string(apArg[3],&n); if( n > 0 ){ sCsv.enclosure = z[0]; } } } /* Iterate throw array entries and write csv data */ ph7_array_walk(apArg[1],csv_write_callback,&sCsv); /* Write a line ending */ #ifdef __WINNT__ zEol = "\r\n"; eolen = (int)sizeof("\r\n")-1; #else /* Assume UNIX LF */ zEol = "\n"; eolen = (int)sizeof(char); #endif pDev->pStream->xWrite(pDev->pHandle,(const void *)zEol,eolen); return PH7_OK; } /* * fprintf,vfprintf private data. * An instance of the following structure is passed to the formatted * input consumer callback defined below. */ typedef struct fprintf_data fprintf_data; struct fprintf_data { io_private *pIO; /* IO stream */ ph7_int64 nCount; /* Total number of bytes written */ }; /* * Callback [i.e: Formatted input consumer] for the fprintf function. */ static int fprintfConsumer(ph7_context *pCtx,const char *zInput,int nLen,void *pUserData) { fprintf_data *pFdata = (fprintf_data *)pUserData; ph7_int64 n; /* Write the formatted data */ n = pFdata->pIO->pStream->xWrite(pFdata->pIO->pHandle,(const void *)zInput,nLen); if( n < 1 ){ SXUNUSED(pCtx); /* cc warning */ /* IO error,abort immediately */ return SXERR_ABORT; } /* Increment counter */ pFdata->nCount += n; return PH7_OK; } /* * int fprintf(resource $handle,string $format[,mixed $args [, mixed $... ]]) * Write a formatted string to a stream. * Parameters * $handle * The file pointer. * $format * String format (see sprintf()). * Return * The length of the written string. */ static int PH7_builtin_fprintf(ph7_context *pCtx,int nArg,ph7_value **apArg) { fprintf_data sFdata; const char *zFormat; io_private *pDev; int nLen; if( nArg < 2 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_string(apArg[1]) ){ /* Missing/Invalid arguments,return zero */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Invalid arguments"); ph7_result_int(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_int(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ if( pDev->pStream == 0 || pDev->pStream->xWrite == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device", ph7_function_name(pCtx),pDev->pStream ? pDev->pStream->zName : "null_stream" ); ph7_result_int(pCtx,0); return PH7_OK; } /* Extract the string format */ zFormat = ph7_value_to_string(apArg[1],&nLen); if( nLen < 1 ){ /* Empty string,return zero */ ph7_result_int(pCtx,0); return PH7_OK; } /* Prepare our private data */ sFdata.nCount = 0; sFdata.pIO = pDev; /* Format the string */ PH7_InputFormat(fprintfConsumer,pCtx,zFormat,nLen,nArg - 1,&apArg[1],(void *)&sFdata,FALSE); /* Return total number of bytes written */ ph7_result_int64(pCtx,sFdata.nCount); return PH7_OK; } /* * int vfprintf(resource $handle,string $format,array $args) * Write a formatted string to a stream. * Parameters * $handle * The file pointer. * $format * String format (see sprintf()). * $args * User arguments. * Return * The length of the written string. */ static int PH7_builtin_vfprintf(ph7_context *pCtx,int nArg,ph7_value **apArg) { fprintf_data sFdata; const char *zFormat; ph7_hashmap *pMap; io_private *pDev; SySet sArg; int n,nLen; if( nArg < 3 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_string(apArg[1]) || !ph7_value_is_array(apArg[2]) ){ /* Missing/Invalid arguments,return zero */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Invalid arguments"); ph7_result_int(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_int(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ if( pDev->pStream == 0 || pDev->pStream->xWrite == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device", ph7_function_name(pCtx),pDev->pStream ? pDev->pStream->zName : "null_stream" ); ph7_result_int(pCtx,0); return PH7_OK; } /* Extract the string format */ zFormat = ph7_value_to_string(apArg[1],&nLen); if( nLen < 1 ){ /* Empty string,return zero */ ph7_result_int(pCtx,0); return PH7_OK; } /* Point to hashmap */ pMap = (ph7_hashmap *)apArg[2]->x.pOther; /* Extract arguments from the hashmap */ n = PH7_HashmapValuesToSet(pMap,&sArg); /* Prepare our private data */ sFdata.nCount = 0; sFdata.pIO = pDev; /* Format the string */ PH7_InputFormat(fprintfConsumer,pCtx,zFormat,nLen,n,(ph7_value **)SySetBasePtr(&sArg),(void *)&sFdata,TRUE); /* Return total number of bytes written*/ ph7_result_int64(pCtx,sFdata.nCount); SySetRelease(&sArg); return PH7_OK; } /* * Convert open modes (string passed to the fopen() function) [i.e: 'r','w+','a',...] into PH7 flags. * According to the PHP reference manual: * The mode parameter specifies the type of access you require to the stream. It may be any of the following * 'r' Open for reading only; place the file pointer at the beginning of the file. * 'r+' Open for reading and writing; place the file pointer at the beginning of the file. * 'w' Open for writing only; place the file pointer at the beginning of the file and truncate the file * to zero length. If the file does not exist, attempt to create it. * 'w+' Open for reading and writing; place the file pointer at the beginning of the file and truncate * the file to zero length. If the file does not exist, attempt to create it. * 'a' Open for writing only; place the file pointer at the end of the file. If the file does not * exist, attempt to create it. * 'a+' Open for reading and writing; place the file pointer at the end of the file. If the file does * not exist, attempt to create it. * 'x' Create and open for writing only; place the file pointer at the beginning of the file. If the file * already exists, * the fopen() call will fail by returning FALSE and generating an error of level E_WARNING. If the file * does not exist attempt to create it. This is equivalent to specifying O_EXCL|O_CREAT flags for * the underlying open(2) system call. * 'x+' Create and open for reading and writing; otherwise it has the same behavior as 'x'. * 'c' Open the file for writing only. If the file does not exist, it is created. If it exists, it is neither truncated * (as opposed to 'w'), nor the call to this function fails (as is the case with 'x'). The file pointer * is positioned on the beginning of the file. * This may be useful if it's desired to get an advisory lock (see flock()) before attempting to modify the file * as using 'w' could truncate the file before the lock was obtained (if truncation is desired, ftruncate() can * be used after the lock is requested). * 'c+' Open the file for reading and writing; otherwise it has the same behavior as 'c'. */ static int StrModeToFlags(ph7_context *pCtx,const char *zMode,int nLen) { const char *zEnd = &zMode[nLen]; int iFlag = 0; int c; if( nLen < 1 ){ /* Open in a read-only mode */ return PH7_IO_OPEN_RDONLY; } c = zMode[0]; if( c == 'r' || c == 'R' ){ /* Read-only access */ iFlag = PH7_IO_OPEN_RDONLY; zMode++; /* Advance */ if( zMode < zEnd ){ c = zMode[0]; if( c == '+' || c == 'w' || c == 'W' ){ /* Read+Write access */ iFlag = PH7_IO_OPEN_RDWR; } } }else if( c == 'w' || c == 'W' ){ /* Overwrite mode. * If the file does not exists,try to create it */ iFlag = PH7_IO_OPEN_WRONLY|PH7_IO_OPEN_TRUNC|PH7_IO_OPEN_CREATE; zMode++; /* Advance */ if( zMode < zEnd ){ c = zMode[0]; if( c == '+' || c == 'r' || c == 'R' ){ /* Read+Write access */ iFlag &= ~PH7_IO_OPEN_WRONLY; iFlag |= PH7_IO_OPEN_RDWR; } } }else if( c == 'a' || c == 'A' ){ /* Append mode (place the file pointer at the end of the file). * Create the file if it does not exists. */ iFlag = PH7_IO_OPEN_WRONLY|PH7_IO_OPEN_APPEND|PH7_IO_OPEN_CREATE; zMode++; /* Advance */ if( zMode < zEnd ){ c = zMode[0]; if( c == '+' ){ /* Read-Write access */ iFlag &= ~PH7_IO_OPEN_WRONLY; iFlag |= PH7_IO_OPEN_RDWR; } } }else if( c == 'x' || c == 'X' ){ /* Exclusive access. * If the file already exists,return immediately with a failure code. * Otherwise create a new file. */ iFlag = PH7_IO_OPEN_WRONLY|PH7_IO_OPEN_EXCL; zMode++; /* Advance */ if( zMode < zEnd ){ c = zMode[0]; if( c == '+' || c == 'r' || c == 'R' ){ /* Read-Write access */ iFlag &= ~PH7_IO_OPEN_WRONLY; iFlag |= PH7_IO_OPEN_RDWR; } } }else if( c == 'c' || c == 'C' ){ /* Overwrite mode.Create the file if it does not exists.*/ iFlag = PH7_IO_OPEN_WRONLY|PH7_IO_OPEN_CREATE; zMode++; /* Advance */ if( zMode < zEnd ){ c = zMode[0]; if( c == '+' ){ /* Read-Write access */ iFlag &= ~PH7_IO_OPEN_WRONLY; iFlag |= PH7_IO_OPEN_RDWR; } } }else{ /* Invalid mode. Assume a read only open */ ph7_context_throw_error(pCtx,PH7_CTX_NOTICE,"Invalid open mode,PH7 is assuming a Read-Only open"); iFlag = PH7_IO_OPEN_RDONLY; } while( zMode < zEnd ){ c = zMode[0]; if( c == 'b' || c == 'B' ){ iFlag &= ~PH7_IO_OPEN_TEXT; iFlag |= PH7_IO_OPEN_BINARY; }else if( c == 't' || c == 'T' ){ iFlag &= ~PH7_IO_OPEN_BINARY; iFlag |= PH7_IO_OPEN_TEXT; } zMode++; } return iFlag; } /* * Initialize the IO private structure. */ static void InitIOPrivate(ph7_vm *pVm,const ph7_io_stream *pStream,io_private *pOut) { pOut->pStream = pStream; SyBlobInit(&pOut->sBuffer,&pVm->sAllocator); pOut->nOfft = 0; /* Set the magic number */ pOut->iMagic = IO_PRIVATE_MAGIC; } /* * Release the IO private structure. */ static void ReleaseIOPrivate(ph7_context *pCtx,io_private *pDev) { SyBlobRelease(&pDev->sBuffer); pDev->iMagic = 0x2126; /* Invalid magic number so we can detetct misuse */ /* Release the whole structure */ ph7_context_free_chunk(pCtx,pDev); } /* * Reset the IO private structure. */ static void ResetIOPrivate(io_private *pDev) { SyBlobReset(&pDev->sBuffer); pDev->nOfft = 0; } /* Forward declaration */ static int is_php_stream(const ph7_io_stream *pStream); /* * resource fopen(string $filename,string $mode [,bool $use_include_path = false[,resource $context ]]) * Open a file,a URL or any other IO stream. * Parameters * $filename * If filename is of the form "scheme://...", it is assumed to be a URL and PHP will search * for a protocol handler (also known as a wrapper) for that scheme. If no scheme is given * then a regular file is assumed. * $mode * The mode parameter specifies the type of access you require to the stream * See the block comment associated with the StrModeToFlags() for the supported * modes. * $use_include_path * You can use the optional second parameter and set it to * TRUE, if you want to search for the file in the include_path, too. * $context * A context stream resource. * Return * File handle on success or FALSE on failure. */ static int PH7_builtin_fopen(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; const char *zUri,*zMode; ph7_value *pResource; io_private *pDev; int iLen,imLen; int iOpenFlags; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path or URL"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the URI and the desired access mode */ zUri = ph7_value_to_string(apArg[0],&iLen); if( nArg > 1 ){ zMode = ph7_value_to_string(apArg[1],&imLen); }else{ /* Set a default read-only mode */ zMode = "r"; imLen = (int)sizeof(char); } /* Try to extract a stream */ pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zUri,iLen); if( pStream == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "No stream device is associated with the given URI(%s)",zUri); ph7_result_bool(pCtx,0); return PH7_OK; } /* Allocate a new IO private instance */ pDev = (io_private *)ph7_context_alloc_chunk(pCtx,sizeof(io_private),TRUE,FALSE); if( pDev == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory"); ph7_result_bool(pCtx,0); return PH7_OK; } pResource = 0; if( nArg > 3 ){ pResource = apArg[3]; }else if( is_php_stream(pStream) ){ /* TICKET 1433-80: The php:// stream need a ph7_value to access the underlying * virtual machine. */ pResource = apArg[0]; } /* Initialize the structure */ InitIOPrivate(pCtx->pVm,pStream,pDev); /* Convert open mode to PH7 flags */ iOpenFlags = StrModeToFlags(pCtx,zMode,imLen); /* Try to get a handle */ pDev->pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zUri,iOpenFlags, nArg > 2 ? ph7_value_to_bool(apArg[2]) : FALSE,pResource,FALSE,0); if( pDev->pHandle == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zUri); ph7_result_bool(pCtx,0); ph7_context_free_chunk(pCtx,pDev); return PH7_OK; } /* All done,return the io_private instance as a resource */ ph7_result_resource(pCtx,pDev); return PH7_OK; } /* * bool fclose(resource $handle) * Closes an open file pointer * Parameters * $handle * The file pointer. * Return * TRUE on success or FALSE on failure. */ static int PH7_builtin_fclose(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; io_private *pDev; ph7_vm *pVm; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract our private data */ pDev = (io_private *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid io_private instance */ if( IO_PRIVATE_INVALID(pDev) ){ /*Expecting an IO handle */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting an IO handle"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the target IO stream device */ pStream = pDev->pStream; if( pStream == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_WARNING, "IO routine(%s) not implemented in the underlying stream(%s) device,PH7 is returning FALSE", ph7_function_name(pCtx),pStream ? pStream->zName : "null_stream" ); ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the VM that own this context */ pVm = pCtx->pVm; /* TICKET 1433-62: Keep the STDIN/STDOUT/STDERR handles open */ if( pDev != pVm->pStdin && pDev != pVm->pStdout && pDev != pVm->pStderr ){ /* Perform the requested operation */ PH7_StreamCloseHandle(pStream,pDev->pHandle); /* Release the IO private structure */ ReleaseIOPrivate(pCtx,pDev); /* Invalidate the resource handle */ ph7_value_release(apArg[0]); } /* Return TRUE */ ph7_result_bool(pCtx,1); return PH7_OK; } #if !defined(PH7_DISABLE_HASH_FUNC) /* * MD5/SHA1 digest consumer. */ static int vfsHashConsumer(const void *pData,unsigned int nLen,void *pUserData) { /* Append hex chunk verbatim */ ph7_result_string((ph7_context *)pUserData,(const char *)pData,(int)nLen); return SXRET_OK; } /* * string md5_file(string $uri[,bool $raw_output = false ]) * Calculates the md5 hash of a given file. * Parameters * $uri * Target URI (file(/path/to/something) or URL(http://www.symisc.net/)) * $raw_output * When TRUE, returns the digest in raw binary format with a length of 16. * Return * Return the MD5 digest on success or FALSE on failure. */ static int PH7_builtin_md5_file(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; unsigned char zDigest[16]; int raw_output = FALSE; const char *zFile; MD5Context sCtx; char zBuf[8192]; void *pHandle; ph7_int64 n; int nLen; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the file path */ zFile = ph7_value_to_string(apArg[0],&nLen); /* Point to the target IO stream device */ pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen); if( pStream == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE"); ph7_result_bool(pCtx,0); return PH7_OK; } if( nArg > 1 ){ raw_output = ph7_value_to_bool(apArg[1]); } /* Try to open the file in read-only mode */ pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,PH7_IO_OPEN_RDONLY,FALSE,0,FALSE,0); if( pHandle == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile); ph7_result_bool(pCtx,0); return PH7_OK; } /* Init the MD5 context */ MD5Init(&sCtx); /* Perform the requested operation */ for(;;){ n = pStream->xRead(pHandle,zBuf,sizeof(zBuf)); if( n < 1 ){ /* EOF or IO error,break immediately */ break; } MD5Update(&sCtx,(const unsigned char *)zBuf,(unsigned int)n); } /* Close the stream */ PH7_StreamCloseHandle(pStream,pHandle); /* Extract the digest */ MD5Final(zDigest,&sCtx); if( raw_output ){ /* Output raw digest */ ph7_result_string(pCtx,(const char *)zDigest,sizeof(zDigest)); }else{ /* Perform a binary to hex conversion */ SyBinToHexConsumer((const void *)zDigest,sizeof(zDigest),vfsHashConsumer,pCtx); } return PH7_OK; } /* * string sha1_file(string $uri[,bool $raw_output = false ]) * Calculates the SHA1 hash of a given file. * Parameters * $uri * Target URI (file(/path/to/something) or URL(http://www.symisc.net/)) * $raw_output * When TRUE, returns the digest in raw binary format with a length of 20. * Return * Return the SHA1 digest on success or FALSE on failure. */ static int PH7_builtin_sha1_file(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; unsigned char zDigest[20]; int raw_output = FALSE; const char *zFile; SHA1Context sCtx; char zBuf[8192]; void *pHandle; ph7_int64 n; int nLen; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the file path */ zFile = ph7_value_to_string(apArg[0],&nLen); /* Point to the target IO stream device */ pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen); if( pStream == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE"); ph7_result_bool(pCtx,0); return PH7_OK; } if( nArg > 1 ){ raw_output = ph7_value_to_bool(apArg[1]); } /* Try to open the file in read-only mode */ pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,PH7_IO_OPEN_RDONLY,FALSE,0,FALSE,0); if( pHandle == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile); ph7_result_bool(pCtx,0); return PH7_OK; } /* Init the SHA1 context */ SHA1Init(&sCtx); /* Perform the requested operation */ for(;;){ n = pStream->xRead(pHandle,zBuf,sizeof(zBuf)); if( n < 1 ){ /* EOF or IO error,break immediately */ break; } SHA1Update(&sCtx,(const unsigned char *)zBuf,(unsigned int)n); } /* Close the stream */ PH7_StreamCloseHandle(pStream,pHandle); /* Extract the digest */ SHA1Final(&sCtx,zDigest); if( raw_output ){ /* Output raw digest */ ph7_result_string(pCtx,(const char *)zDigest,sizeof(zDigest)); }else{ /* Perform a binary to hex conversion */ SyBinToHexConsumer((const void *)zDigest,sizeof(zDigest),vfsHashConsumer,pCtx); } return PH7_OK; } #endif /* PH7_DISABLE_HASH_FUNC */ /* * array parse_ini_file(string $filename[, bool $process_sections = false [, int $scanner_mode = INI_SCANNER_NORMAL ]] ) * Parse a configuration file. * Parameters * $filename * The filename of the ini file being parsed. * $process_sections * By setting the process_sections parameter to TRUE, you get a multidimensional array * with the section names and settings included. * The default for process_sections is FALSE. * $scanner_mode * Can either be INI_SCANNER_NORMAL (default) or INI_SCANNER_RAW. * If INI_SCANNER_RAW is supplied, then option values will not be parsed. * Return * The settings are returned as an associative array on success. * Otherwise is returned. */ static int PH7_builtin_parse_ini_file(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; const char *zFile; SyBlob sContents; void *pHandle; int nLen; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the file path */ zFile = ph7_value_to_string(apArg[0],&nLen); /* Point to the target IO stream device */ pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen); if( pStream == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Try to open the file in read-only mode */ pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,PH7_IO_OPEN_RDONLY,FALSE,0,FALSE,0); if( pHandle == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile); ph7_result_bool(pCtx,0); return PH7_OK; } SyBlobInit(&sContents,&pCtx->pVm->sAllocator); /* Read the whole file */ PH7_StreamReadWholeFile(pHandle,pStream,&sContents); if( SyBlobLength(&sContents) < 1 ){ /* Empty buffer,return FALSE */ ph7_result_bool(pCtx,0); }else{ /* Process the raw INI buffer */ PH7_ParseIniString(pCtx,(const char *)SyBlobData(&sContents),SyBlobLength(&sContents), nArg > 1 ? ph7_value_to_bool(apArg[1]) : 0); } /* Close the stream */ PH7_StreamCloseHandle(pStream,pHandle); /* Release the working buffer */ SyBlobRelease(&sContents); return PH7_OK; } /* * Section: * ZIP archive processing. * Authors: * Symisc Systems,devel@symisc.net. * Copyright (C) Symisc Systems,http://ph7.symisc.net * Status: * Stable. */ typedef struct zip_raw_data zip_raw_data; struct zip_raw_data { int iType; /* Where the raw data is stored */ union raw_data{ struct mmap_data{ void *pMap; /* Memory mapped data */ ph7_int64 nSize; /* Map size */ const ph7_vfs *pVfs; /* Underlying vfs */ }mmap; SyBlob sBlob; /* Memory buffer */ }raw; }; #define ZIP_RAW_DATA_MMAPED 1 /* Memory mapped ZIP raw data */ #define ZIP_RAW_DATA_MEMBUF 2 /* ZIP raw data stored in a dynamically * allocated memory chunk. */ /* * mixed zip_open(string $filename) * Opens a new zip archive for reading. * Parameters * $filename * The file name of the ZIP archive to open. * Return * A resource handle for later use with zip_read() and zip_close() or FALSE on failure. */ static int PH7_builtin_zip_open(ph7_context *pCtx,int nArg,ph7_value **apArg) { const ph7_io_stream *pStream; SyArchive *pArchive; zip_raw_data *pRaw; const char *zFile; SyBlob *pContents; void *pHandle; int nLen; sxi32 rc; if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){ /* Missing/Invalid arguments,return FALSE */ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Expecting a file path"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the file path */ zFile = ph7_value_to_string(apArg[0],&nLen); /* Point to the target IO stream device */ pStream = PH7_VmGetStreamDevice(pCtx->pVm,&zFile,nLen); if( pStream == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"No such stream device,PH7 is returning FALSE"); ph7_result_bool(pCtx,0); return PH7_OK; } /* Create an in-memory archive */ pArchive = (SyArchive *)ph7_context_alloc_chunk(pCtx,sizeof(SyArchive)+sizeof(zip_raw_data),TRUE,FALSE); if( pArchive == 0 ){ ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"PH7 is running out of memory"); ph7_result_bool(pCtx,0); return PH7_OK; } pRaw = (zip_raw_data *)&pArchive[1]; /* Initialize the archive */ SyArchiveInit(pArchive,&pCtx->pVm->sAllocator,0,0); /* Extract the default stream */ if( pStream == pCtx->pVm->pDefStream /* file:// stream*/){ const ph7_vfs *pVfs; /* Try to get a memory view of the whole file since ZIP files * tends to be very big this days,this is a huge performance win. */ pVfs = PH7_ExportBuiltinVfs(); if( pVfs && pVfs->xMmap ){ rc = pVfs->xMmap(zFile,&pRaw->raw.mmap.pMap,&pRaw->raw.mmap.nSize); if( rc == PH7_OK ){ /* Nice,Extract the whole archive */ rc = SyZipExtractFromBuf(pArchive,(const char *)pRaw->raw.mmap.pMap,(sxu32)pRaw->raw.mmap.nSize); if( rc != SXRET_OK ){ if( pVfs->xUnmap ){ pVfs->xUnmap(pRaw->raw.mmap.pMap,pRaw->raw.mmap.nSize); } /* Release the allocated chunk */ ph7_context_free_chunk(pCtx,pArchive); /* Something goes wrong with this ZIP archive,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Archive successfully opened */ pRaw->iType = ZIP_RAW_DATA_MMAPED; pRaw->raw.mmap.pVfs = pVfs; goto success; } } /* FALL THROUGH */ } /* Try to open the file in read-only mode */ pHandle = PH7_StreamOpenHandle(pCtx->pVm,pStream,zFile,PH7_IO_OPEN_RDONLY,FALSE,0,FALSE,0); if( pHandle == 0 ){ ph7_context_throw_error_format(pCtx,PH7_CTX_ERR,"IO error while opening '%s'",zFile); ph7_result_bool(pCtx,0); return PH7_OK; } pContents = &pRaw->raw.sBlob; SyBlobInit(pContents,&pCtx->pVm->sAllocator); /* Read the whole file */ PH7_StreamReadWholeFile(pHandle,pStream,pContents); /* Assume an invalid ZIP file */ rc = SXERR_INVALID; if( SyBlobLength(pContents) > 0 ){ /* Extract archive entries */ rc = SyZipExtractFromBuf(pArchive,(const char *)SyBlobData(pContents),SyBlobLength(pContents)); } pRaw->iType = ZIP_RAW_DATA_MEMBUF; /* Close the stream */ PH7_StreamCloseHandle(pStream,pHandle); if( rc != SXRET_OK ){ /* Release the working buffer */ SyBlobRelease(pContents); /* Release the allocated chunk */ ph7_context_free_chunk(pCtx,pArchive); /* Something goes wrong with this ZIP archive,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } success: /* Reset the loop cursor */ SyArchiveResetLoopCursor(pArchive); /* Return the in-memory archive as a resource handle */ ph7_result_resource(pCtx,pArchive); return PH7_OK; } /* * void zip_close(resource $zip) * Close an in-memory ZIP archive. * Parameters * $zip * A ZIP file previously opened with zip_open(). * Return * null. */ static int PH7_builtin_zip_close(ph7_context *pCtx,int nArg,ph7_value **apArg) { SyArchive *pArchive; zip_raw_data *pRaw; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments */ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive"); return PH7_OK; } /* Point to the in-memory archive */ pArchive = (SyArchive *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid ZIP archive */ if( SXARCH_INVALID(pArchive) ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive"); return PH7_OK; } /* Release the archive */ SyArchiveRelease(pArchive); pRaw = (zip_raw_data *)&pArchive[1]; if( pRaw->iType == ZIP_RAW_DATA_MEMBUF ){ SyBlobRelease(&pRaw->raw.sBlob); }else{ const ph7_vfs *pVfs = pRaw->raw.mmap.pVfs; if( pVfs->xUnmap ){ /* Unmap the memory view */ pVfs->xUnmap(pRaw->raw.mmap.pMap,pRaw->raw.mmap.nSize); } } /* Release the memory chunk */ ph7_context_free_chunk(pCtx,pArchive); return PH7_OK; } /* * mixed zip_read(resource $zip) * Reads the next entry from an in-memory ZIP archive. * Parameters * $zip * A ZIP file previously opened with zip_open(). * Return * A directory entry resource for later use with the zip_entry_... functions * or FALSE if there are no more entries to read, or an error code if an error occurred. */ static int PH7_builtin_zip_read(ph7_context *pCtx,int nArg,ph7_value **apArg) { SyArchiveEntry *pNext = 0; /* cc warning */ SyArchive *pArchive; sxi32 rc; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments */ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the in-memory archive */ pArchive = (SyArchive *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid ZIP archive */ if( SXARCH_INVALID(pArchive) ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Extract the next entry */ rc = SyArchiveGetNextEntry(pArchive,&pNext); if( rc != SXRET_OK ){ /* No more entries in the central directory,return FALSE */ ph7_result_bool(pCtx,0); }else{ /* Return as a resource handle */ ph7_result_resource(pCtx,pNext); /* Point to the ZIP raw data */ pNext->pUserData = (void *)&pArchive[1]; } return PH7_OK; } /* * bool zip_entry_open(resource $zip,resource $zip_entry[,string $mode ]) * Open a directory entry for reading * Parameters * $zip * A ZIP file previously opened with zip_open(). * $zip_entry * A directory entry returned by zip_read(). * $mode * Not used * Return * A directory entry resource for later use with the zip_entry_... functions * or FALSE if there are no more entries to read, or an error code if an error occurred. */ static int PH7_builtin_zip_entry_open(ph7_context *pCtx,int nArg,ph7_value **apArg) { SyArchiveEntry *pEntry; SyArchive *pArchive; if( nArg < 2 || !ph7_value_is_resource(apArg[0]) || !ph7_value_is_resource(apArg[1]) ){ /* Missing/Invalid arguments */ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Point to the in-memory archive */ pArchive = (SyArchive *)ph7_value_to_resource(apArg[0]); /* Make sure we are dealing with a valid ZIP archive */ if( SXARCH_INVALID(pArchive) ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Make sure we are dealing with a valid ZIP archive entry */ pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[1]); if( SXARCH_ENTRY_INVALID(pEntry) ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* All done. Actually this function is a no-op,return TRUE */ ph7_result_bool(pCtx,1); return PH7_OK; } /* * bool zip_entry_close(resource $zip_entry) * Close a directory entry. * Parameters * $zip_entry * A directory entry returned by zip_read(). * Return * Returns TRUE on success or FALSE on failure. */ static int PH7_builtin_zip_entry_close(ph7_context *pCtx,int nArg,ph7_value **apArg) { SyArchiveEntry *pEntry; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments */ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Make sure we are dealing with a valid ZIP archive entry */ pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]); if( SXARCH_ENTRY_INVALID(pEntry) ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Reset the read cursor */ pEntry->nReadCount = 0; /*All done. Actually this function is a no-op,return TRUE */ ph7_result_bool(pCtx,1); return PH7_OK; } /* * string zip_entry_name(resource $zip_entry) * Retrieve the name of a directory entry. * Parameters * $zip_entry * A directory entry returned by zip_read(). * Return * The name of the directory entry. */ static int PH7_builtin_zip_entry_name(ph7_context *pCtx,int nArg,ph7_value **apArg) { SyArchiveEntry *pEntry; SyString *pName; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments */ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Make sure we are dealing with a valid ZIP archive entry */ pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]); if( SXARCH_ENTRY_INVALID(pEntry) ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Return entry name */ pName = &pEntry->sFileName; ph7_result_string(pCtx,pName->zString,(int)pName->nByte); return PH7_OK; } /* * int64 zip_entry_filesize(resource $zip_entry) * Retrieve the actual file size of a directory entry. * Parameters * $zip_entry * A directory entry returned by zip_read(). * Return * The size of the directory entry. */ static int PH7_builtin_zip_entry_filesize(ph7_context *pCtx,int nArg,ph7_value **apArg) { SyArchiveEntry *pEntry; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments */ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Make sure we are dealing with a valid ZIP archive entry */ pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]); if( SXARCH_ENTRY_INVALID(pEntry) ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Return entry size */ ph7_result_int64(pCtx,(ph7_int64)pEntry->nByte); return PH7_OK; } /* * int64 zip_entry_compressedsize(resource $zip_entry) * Retrieve the compressed size of a directory entry. * Parameters * $zip_entry * A directory entry returned by zip_read(). * Return * The compressed size. */ static int PH7_builtin_zip_entry_compressedsize(ph7_context *pCtx,int nArg,ph7_value **apArg) { SyArchiveEntry *pEntry; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments */ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Make sure we are dealing with a valid ZIP archive entry */ pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]); if( SXARCH_ENTRY_INVALID(pEntry) ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Return entry compressed size */ ph7_result_int64(pCtx,(ph7_int64)pEntry->nByteCompr); return PH7_OK; } /* * string zip_entry_read(resource $zip_entry[,int $length]) * Reads from an open directory entry. * Parameters * $zip_entry * A directory entry returned by zip_read(). * $length * The number of bytes to return. If not specified, this function * will attempt to read 1024 bytes. * Return * Returns the data read, or FALSE if the end of the file is reached. */ static int PH7_builtin_zip_entry_read(ph7_context *pCtx,int nArg,ph7_value **apArg) { SyArchiveEntry *pEntry; zip_raw_data *pRaw; const char *zData; int iLength; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments */ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Make sure we are dealing with a valid ZIP archive entry */ pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]); if( SXARCH_ENTRY_INVALID(pEntry) ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } zData = 0; if( pEntry->nReadCount >= pEntry->nByteCompr ){ /* No more data to read,return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Set a default read length */ iLength = 1024; if( nArg > 1 ){ iLength = ph7_value_to_int(apArg[1]); if( iLength < 1 ){ iLength = 1024; } } if( (sxu32)iLength > pEntry->nByteCompr - pEntry->nReadCount ){ iLength = (int)(pEntry->nByteCompr - pEntry->nReadCount); } /* Return the entry contents */ pRaw = (zip_raw_data *)pEntry->pUserData; if( pRaw->iType == ZIP_RAW_DATA_MEMBUF ){ zData = (const char *)SyBlobDataAt(&pRaw->raw.sBlob,(pEntry->nOfft+pEntry->nReadCount)); }else{ const char *zMap = (const char *)pRaw->raw.mmap.pMap; /* Memory mmaped chunk */ zData = &zMap[pEntry->nOfft+pEntry->nReadCount]; } /* Increment the read counter */ pEntry->nReadCount += iLength; /* Return the raw data */ ph7_result_string(pCtx,zData,iLength); return PH7_OK; } /* * bool zip_entry_reset_read_cursor(resource $zip_entry) * Reset the read cursor of an open directory entry. * Parameters * $zip_entry * A directory entry returned by zip_read(). * Return * TRUE on success,FALSE on failure. * Note that this is a symisc eXtension. */ static int PH7_builtin_zip_entry_reset_read_cursor(ph7_context *pCtx,int nArg,ph7_value **apArg) { SyArchiveEntry *pEntry; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments */ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Make sure we are dealing with a valid ZIP archive entry */ pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]); if( SXARCH_ENTRY_INVALID(pEntry) ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Reset the cursor */ pEntry->nReadCount = 0; /* Return TRUE */ ph7_result_bool(pCtx,1); return PH7_OK; } /* * string zip_entry_compressionmethod(resource $zip_entry) * Retrieve the compression method of a directory entry. * Parameters * $zip_entry * A directory entry returned by zip_read(). * Return * The compression method on success or FALSE on failure. */ static int PH7_builtin_zip_entry_compressionmethod(ph7_context *pCtx,int nArg,ph7_value **apArg) { SyArchiveEntry *pEntry; if( nArg < 1 || !ph7_value_is_resource(apArg[0]) ){ /* Missing/Invalid arguments */ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } /* Make sure we are dealing with a valid ZIP archive entry */ pEntry = (SyArchiveEntry *)ph7_value_to_resource(apArg[0]); if( SXARCH_ENTRY_INVALID(pEntry) ){ ph7_context_throw_error(pCtx,PH7_CTX_ERR,"Expecting a ZIP archive entry"); /* return FALSE */ ph7_result_bool(pCtx,0); return PH7_OK; } switch(pEntry->nComprMeth){ case 0: /* No compression;entry is stored */ ph7_result_string(pCtx,"stored",(int)sizeof("stored")-1); break; case 8: /* Entry is deflated (Default compression algorithm) */ ph7_result_string(pCtx,"deflate",(int)sizeof("deflate")-1); break; /* Exotic compression algorithms */ case 1: ph7_result_string(pCtx,"shrunk",(int)sizeof("shrunk")-1); break; case 2: case 3: case 4: case 5: /* Entry is reduced */ ph7_result_string(pCtx,"reduced",(int)sizeof("reduced")-1); break; case 6: /* Entry is imploded */ ph7_result_string(pCtx,"implode",(int)sizeof("implode")-1); break; default: ph7_result_string(pCtx,"unknown",(int)sizeof("unknown")-1); break; } return PH7_OK; } #endif /* #ifndef PH7_DISABLE_BUILTIN_FUNC*/ /* NULL VFS [i.e: a no-op VFS]*/ static const ph7_vfs null_vfs = { "null_vfs", PH7_VFS_VERSION, 0, /* int (*xChdir)(const char *) */ 0, /* int (*xChroot)(const char *); */ 0, /* int (*xGetcwd)(ph7_context *) */ 0, /* int (*xMkdir)(const char *,int,int) */ 0, /* int (*xRmdir)(const char *) */ 0, /* int (*xIsdir)(const char *) */ 0, /* int (*xRename)(const char *,const char *) */ 0, /*int (*xRealpath)(const char *,ph7_context *)*/ 0, /* int (*xSleep)(unsigned int) */ 0, /* int (*xUnlink)(const char *) */ 0, /* int (*xFileExists)(const char *) */ 0, /*int (*xChmod)(const char *,int)*/ 0, /*int (*xChown)(const char *,const char *)*/ 0, /*int (*xChgrp)(const char *,const char *)*/ 0, /* ph7_int64 (*xFreeSpace)(const char *) */ 0, /* ph7_int64 (*xTotalSpace)(const char *) */ 0, /* ph7_int64 (*xFileSize)(const char *) */ 0, /* ph7_int64 (*xFileAtime)(const char *) */ 0, /* ph7_int64 (*xFileMtime)(const char *) */ 0, /* ph7_int64 (*xFileCtime)(const char *) */ 0, /* int (*xStat)(const char *,ph7_value *,ph7_value *) */ 0, /* int (*xlStat)(const char *,ph7_value *,ph7_value *) */ 0, /* int (*xIsfile)(const char *) */ 0, /* int (*xIslink)(const char *) */ 0, /* int (*xReadable)(const char *) */ 0, /* int (*xWritable)(const char *) */ 0, /* int (*xExecutable)(const char *) */ 0, /* int (*xFiletype)(const char *,ph7_context *) */ 0, /* int (*xGetenv)(const char *,ph7_context *) */ 0, /* int (*xSetenv)(const char *,const char *) */ 0, /* int (*xTouch)(const char *,ph7_int64,ph7_int64) */ 0, /* int (*xMmap)(const char *,void **,ph7_int64 *) */ 0, /* void (*xUnmap)(void *,ph7_int64); */ 0, /* int (*xLink)(const char *,const char *,int) */ 0, /* int (*xUmask)(int) */ 0, /* void (*xTempDir)(ph7_context *) */ 0, /* unsigned int (*xProcessId)(void) */ 0, /* int (*xUid)(void) */ 0, /* int (*xGid)(void) */ 0, /* void (*xUsername)(ph7_context *) */ 0 /* int (*xExec)(const char *,ph7_context *) */ }; #ifndef PH7_DISABLE_BUILTIN_FUNC #ifndef PH7_DISABLE_DISK_IO #ifdef __WINNT__ /* * Windows VFS implementation for the PH7 engine. * Authors: * Symisc Systems,devel@symisc.net. * Copyright (C) Symisc Systems,http://ph7.symisc.net * Status: * Stable. */ /* What follows here is code that is specific to windows systems. */ #include /* ** Convert a UTF-8 string to microsoft unicode (UTF-16?). ** ** Space to hold the returned string is obtained from HeapAlloc(). ** Taken from the sqlite3 source tree ** status: Public Domain */ static WCHAR *utf8ToUnicode(const char *zFilename){ int nChar; WCHAR *zWideFilename; nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, 0, 0); zWideFilename = (WCHAR *)HeapAlloc(GetProcessHeap(),0,nChar*sizeof(zWideFilename[0])); if( zWideFilename == 0 ){ return 0; } nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar); if( nChar==0 ){ HeapFree(GetProcessHeap(),0,zWideFilename); return 0; } return zWideFilename; } /* ** Convert a UTF-8 filename into whatever form the underlying ** operating system wants filenames in.Space to hold the result ** is obtained from HeapAlloc() and must be freed by the calling ** function. ** Taken from the sqlite3 source tree ** status: Public Domain */ static void *convertUtf8Filename(const char *zFilename){ void *zConverted; zConverted = utf8ToUnicode(zFilename); return zConverted; } /* ** Convert microsoft unicode to UTF-8. Space to hold the returned string is ** obtained from HeapAlloc(). ** Taken from the sqlite3 source tree ** status: Public Domain */ static char *unicodeToUtf8(const WCHAR *zWideFilename){ char *zFilename; int nByte; nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0); zFilename = (char *)HeapAlloc(GetProcessHeap(),0,nByte); if( zFilename == 0 ){ return 0; } nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,0, 0); if( nByte == 0 ){ HeapFree(GetProcessHeap(),0,zFilename); return 0; } return zFilename; } /* int (*xchdir)(const char *) */ static int WinVfs_chdir(const char *zPath) { void * pConverted; BOOL rc; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } rc = SetCurrentDirectoryW((LPCWSTR)pConverted); HeapFree(GetProcessHeap(),0,pConverted); return rc ? PH7_OK : -1; } /* int (*xGetcwd)(ph7_context *) */ static int WinVfs_getcwd(ph7_context *pCtx) { WCHAR zDir[2048]; char *zConverted; DWORD rc; /* Get the current directory */ rc = GetCurrentDirectoryW(sizeof(zDir),zDir); if( rc < 1 ){ return -1; } zConverted = unicodeToUtf8(zDir); if( zConverted == 0 ){ return -1; } ph7_result_string(pCtx,zConverted,-1/*Compute length automatically*/); /* Will make it's own copy */ HeapFree(GetProcessHeap(),0,zConverted); return PH7_OK; } /* int (*xMkdir)(const char *,int,int) */ static int WinVfs_mkdir(const char *zPath,int mode,int recursive) { void * pConverted; BOOL rc; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } mode= 0; /* MSVC warning */ recursive = 0; rc = CreateDirectoryW((LPCWSTR)pConverted,0); HeapFree(GetProcessHeap(),0,pConverted); return rc ? PH7_OK : -1; } /* int (*xRmdir)(const char *) */ static int WinVfs_rmdir(const char *zPath) { void * pConverted; BOOL rc; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } rc = RemoveDirectoryW((LPCWSTR)pConverted); HeapFree(GetProcessHeap(),0,pConverted); return rc ? PH7_OK : -1; } /* int (*xIsdir)(const char *) */ static int WinVfs_isdir(const char *zPath) { void * pConverted; DWORD dwAttr; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } dwAttr = GetFileAttributesW((LPCWSTR)pConverted); HeapFree(GetProcessHeap(),0,pConverted); if( dwAttr == INVALID_FILE_ATTRIBUTES ){ return -1; } return (dwAttr & FILE_ATTRIBUTE_DIRECTORY) ? PH7_OK : -1; } /* int (*xRename)(const char *,const char *) */ static int WinVfs_Rename(const char *zOld,const char *zNew) { void *pOld,*pNew; BOOL rc = 0; pOld = convertUtf8Filename(zOld); if( pOld == 0 ){ return -1; } pNew = convertUtf8Filename(zNew); if( pNew ){ rc = MoveFileW((LPCWSTR)pOld,(LPCWSTR)pNew); } HeapFree(GetProcessHeap(),0,pOld); if( pNew ){ HeapFree(GetProcessHeap(),0,pNew); } return rc ? PH7_OK : - 1; } /* int (*xRealpath)(const char *,ph7_context *) */ static int WinVfs_Realpath(const char *zPath,ph7_context *pCtx) { WCHAR zTemp[2048]; void *pPath; char *zReal; DWORD n; pPath = convertUtf8Filename(zPath); if( pPath == 0 ){ return -1; } n = GetFullPathNameW((LPCWSTR)pPath,0,0,0); if( n > 0 ){ if( n >= sizeof(zTemp) ){ n = sizeof(zTemp) - 1; } GetFullPathNameW((LPCWSTR)pPath,n,zTemp,0); } HeapFree(GetProcessHeap(),0,pPath); if( !n ){ return -1; } zReal = unicodeToUtf8(zTemp); if( zReal == 0 ){ return -1; } ph7_result_string(pCtx,zReal,-1); /* Will make it's own copy */ HeapFree(GetProcessHeap(),0,zReal); return PH7_OK; } /* int (*xSleep)(unsigned int) */ static int WinVfs_Sleep(unsigned int uSec) { Sleep(uSec/1000/*uSec per Millisec */); return PH7_OK; } /* int (*xUnlink)(const char *) */ static int WinVfs_unlink(const char *zPath) { void * pConverted; BOOL rc; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } rc = DeleteFileW((LPCWSTR)pConverted); HeapFree(GetProcessHeap(),0,pConverted); return rc ? PH7_OK : - 1; } /* ph7_int64 (*xFreeSpace)(const char *) */ static ph7_int64 WinVfs_DiskFreeSpace(const char *zPath) { #ifdef _WIN32_WCE /* GetDiskFreeSpace is not supported under WINCE */ SXUNUSED(zPath); return 0; #else DWORD dwSectPerClust,dwBytesPerSect,dwFreeClusters,dwTotalClusters; void * pConverted; WCHAR *p; BOOL rc; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return 0; } p = (WCHAR *)pConverted; for(;*p;p++){ if( *p == '\\' || *p == '/'){ *p = '\0'; break; } } rc = GetDiskFreeSpaceW((LPCWSTR)pConverted,&dwSectPerClust,&dwBytesPerSect,&dwFreeClusters,&dwTotalClusters); if( !rc ){ return 0; } return (ph7_int64)dwFreeClusters * dwSectPerClust * dwBytesPerSect; #endif } /* ph7_int64 (*xTotalSpace)(const char *) */ static ph7_int64 WinVfs_DiskTotalSpace(const char *zPath) { #ifdef _WIN32_WCE /* GetDiskFreeSpace is not supported under WINCE */ SXUNUSED(zPath); return 0; #else DWORD dwSectPerClust,dwBytesPerSect,dwFreeClusters,dwTotalClusters; void * pConverted; WCHAR *p; BOOL rc; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return 0; } p = (WCHAR *)pConverted; for(;*p;p++){ if( *p == '\\' || *p == '/'){ *p = '\0'; break; } } rc = GetDiskFreeSpaceW((LPCWSTR)pConverted,&dwSectPerClust,&dwBytesPerSect,&dwFreeClusters,&dwTotalClusters); if( !rc ){ return 0; } return (ph7_int64)dwTotalClusters * dwSectPerClust * dwBytesPerSect; #endif } /* int (*xFileExists)(const char *) */ static int WinVfs_FileExists(const char *zPath) { void * pConverted; DWORD dwAttr; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } dwAttr = GetFileAttributesW((LPCWSTR)pConverted); HeapFree(GetProcessHeap(),0,pConverted); if( dwAttr == INVALID_FILE_ATTRIBUTES ){ return -1; } return PH7_OK; } /* Open a file in a read-only mode */ static HANDLE OpenReadOnly(LPCWSTR pPath) { DWORD dwType = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS; DWORD dwShare = FILE_SHARE_READ | FILE_SHARE_WRITE; DWORD dwAccess = GENERIC_READ; DWORD dwCreate = OPEN_EXISTING; HANDLE pHandle; pHandle = CreateFileW(pPath,dwAccess,dwShare,0,dwCreate,dwType,0); if( pHandle == INVALID_HANDLE_VALUE){ return 0; } return pHandle; } /* ph7_int64 (*xFileSize)(const char *) */ static ph7_int64 WinVfs_FileSize(const char *zPath) { DWORD dwLow,dwHigh; void * pConverted; ph7_int64 nSize; HANDLE pHandle; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } /* Open the file in read-only mode */ pHandle = OpenReadOnly((LPCWSTR)pConverted); HeapFree(GetProcessHeap(),0,pConverted); if( pHandle ){ dwLow = GetFileSize(pHandle,&dwHigh); nSize = dwHigh; nSize <<= 32; nSize += dwLow; CloseHandle(pHandle); }else{ nSize = -1; } return nSize; } #define TICKS_PER_SECOND 10000000 #define EPOCH_DIFFERENCE 11644473600LL /* Convert Windows timestamp to UNIX timestamp */ static ph7_int64 convertWindowsTimeToUnixTime(LPFILETIME pTime) { ph7_int64 input,temp; input = pTime->dwHighDateTime; input <<= 32; input += pTime->dwLowDateTime; temp = input / TICKS_PER_SECOND; /*convert from 100ns intervals to seconds*/ temp = temp - EPOCH_DIFFERENCE; /*subtract number of seconds between epochs*/ return temp; } /* Convert UNIX timestamp to Windows timestamp */ static void convertUnixTimeToWindowsTime(ph7_int64 nUnixtime,LPFILETIME pOut) { ph7_int64 result = EPOCH_DIFFERENCE; result += nUnixtime; result *= 10000000LL; pOut->dwHighDateTime = (DWORD)(nUnixtime>>32); pOut->dwLowDateTime = (DWORD)nUnixtime; } /* int (*xTouch)(const char *,ph7_int64,ph7_int64) */ static int WinVfs_Touch(const char *zPath,ph7_int64 touch_time,ph7_int64 access_time) { FILETIME sTouch,sAccess; void *pConverted; void *pHandle; BOOL rc = 0; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } pHandle = OpenReadOnly((LPCWSTR)pConverted); if( pHandle ){ if( touch_time < 0 ){ GetSystemTimeAsFileTime(&sTouch); }else{ convertUnixTimeToWindowsTime(touch_time,&sTouch); } if( access_time < 0 ){ /* Use the touch time */ sAccess = sTouch; /* Structure assignment */ }else{ convertUnixTimeToWindowsTime(access_time,&sAccess); } rc = SetFileTime(pHandle,&sTouch,&sAccess,0); /* Close the handle */ CloseHandle(pHandle); } HeapFree(GetProcessHeap(),0,pConverted); return rc ? PH7_OK : -1; } /* ph7_int64 (*xFileAtime)(const char *) */ static ph7_int64 WinVfs_FileAtime(const char *zPath) { BY_HANDLE_FILE_INFORMATION sInfo; void * pConverted; ph7_int64 atime; HANDLE pHandle; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } /* Open the file in read-only mode */ pHandle = OpenReadOnly((LPCWSTR)pConverted); if( pHandle ){ BOOL rc; rc = GetFileInformationByHandle(pHandle,&sInfo); if( rc ){ atime = convertWindowsTimeToUnixTime(&sInfo.ftLastAccessTime); }else{ atime = -1; } CloseHandle(pHandle); }else{ atime = -1; } HeapFree(GetProcessHeap(),0,pConverted); return atime; } /* ph7_int64 (*xFileMtime)(const char *) */ static ph7_int64 WinVfs_FileMtime(const char *zPath) { BY_HANDLE_FILE_INFORMATION sInfo; void * pConverted; ph7_int64 mtime; HANDLE pHandle; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } /* Open the file in read-only mode */ pHandle = OpenReadOnly((LPCWSTR)pConverted); if( pHandle ){ BOOL rc; rc = GetFileInformationByHandle(pHandle,&sInfo); if( rc ){ mtime = convertWindowsTimeToUnixTime(&sInfo.ftLastWriteTime); }else{ mtime = -1; } CloseHandle(pHandle); }else{ mtime = -1; } HeapFree(GetProcessHeap(),0,pConverted); return mtime; } /* ph7_int64 (*xFileCtime)(const char *) */ static ph7_int64 WinVfs_FileCtime(const char *zPath) { BY_HANDLE_FILE_INFORMATION sInfo; void * pConverted; ph7_int64 ctime; HANDLE pHandle; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } /* Open the file in read-only mode */ pHandle = OpenReadOnly((LPCWSTR)pConverted); if( pHandle ){ BOOL rc; rc = GetFileInformationByHandle(pHandle,&sInfo); if( rc ){ ctime = convertWindowsTimeToUnixTime(&sInfo.ftCreationTime); }else{ ctime = -1; } CloseHandle(pHandle); }else{ ctime = -1; } HeapFree(GetProcessHeap(),0,pConverted); return ctime; } /* int (*xStat)(const char *,ph7_value *,ph7_value *) */ /* int (*xlStat)(const char *,ph7_value *,ph7_value *) */ static int WinVfs_Stat(const char *zPath,ph7_value *pArray,ph7_value *pWorker) { BY_HANDLE_FILE_INFORMATION sInfo; void *pConverted; HANDLE pHandle; BOOL rc; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } /* Open the file in read-only mode */ pHandle = OpenReadOnly((LPCWSTR)pConverted); HeapFree(GetProcessHeap(),0,pConverted); if( pHandle == 0 ){ return -1; } rc = GetFileInformationByHandle(pHandle,&sInfo); CloseHandle(pHandle); if( !rc ){ return -1; } /* dev */ ph7_value_int64(pWorker,(ph7_int64)sInfo.dwVolumeSerialNumber); ph7_array_add_strkey_elem(pArray,"dev",pWorker); /* Will make it's own copy */ /* ino */ ph7_value_int64(pWorker,(ph7_int64)(((ph7_int64)sInfo.nFileIndexHigh << 32) | sInfo.nFileIndexLow)); ph7_array_add_strkey_elem(pArray,"ino",pWorker); /* Will make it's own copy */ /* mode */ ph7_value_int(pWorker,0); ph7_array_add_strkey_elem(pArray,"mode",pWorker); /* nlink */ ph7_value_int(pWorker,(int)sInfo.nNumberOfLinks); ph7_array_add_strkey_elem(pArray,"nlink",pWorker); /* Will make it's own copy */ /* uid,gid,rdev */ ph7_value_int(pWorker,0); ph7_array_add_strkey_elem(pArray,"uid",pWorker); ph7_array_add_strkey_elem(pArray,"gid",pWorker); ph7_array_add_strkey_elem(pArray,"rdev",pWorker); /* size */ ph7_value_int64(pWorker,(ph7_int64)(((ph7_int64)sInfo.nFileSizeHigh << 32) | sInfo.nFileSizeLow)); ph7_array_add_strkey_elem(pArray,"size",pWorker); /* Will make it's own copy */ /* atime */ ph7_value_int64(pWorker,convertWindowsTimeToUnixTime(&sInfo.ftLastAccessTime)); ph7_array_add_strkey_elem(pArray,"atime",pWorker); /* Will make it's own copy */ /* mtime */ ph7_value_int64(pWorker,convertWindowsTimeToUnixTime(&sInfo.ftLastWriteTime)); ph7_array_add_strkey_elem(pArray,"mtime",pWorker); /* Will make it's own copy */ /* ctime */ ph7_value_int64(pWorker,convertWindowsTimeToUnixTime(&sInfo.ftCreationTime)); ph7_array_add_strkey_elem(pArray,"ctime",pWorker); /* Will make it's own copy */ /* blksize,blocks */ ph7_value_int(pWorker,0); ph7_array_add_strkey_elem(pArray,"blksize",pWorker); ph7_array_add_strkey_elem(pArray,"blocks",pWorker); return PH7_OK; } /* int (*xIsfile)(const char *) */ static int WinVfs_isfile(const char *zPath) { void * pConverted; DWORD dwAttr; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } dwAttr = GetFileAttributesW((LPCWSTR)pConverted); HeapFree(GetProcessHeap(),0,pConverted); if( dwAttr == INVALID_FILE_ATTRIBUTES ){ return -1; } return (dwAttr & (FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE)) ? PH7_OK : -1; } /* int (*xIslink)(const char *) */ static int WinVfs_islink(const char *zPath) { void * pConverted; DWORD dwAttr; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } dwAttr = GetFileAttributesW((LPCWSTR)pConverted); HeapFree(GetProcessHeap(),0,pConverted); if( dwAttr == INVALID_FILE_ATTRIBUTES ){ return -1; } return (dwAttr & FILE_ATTRIBUTE_REPARSE_POINT) ? PH7_OK : -1; } /* int (*xWritable)(const char *) */ static int WinVfs_iswritable(const char *zPath) { void * pConverted; DWORD dwAttr; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } dwAttr = GetFileAttributesW((LPCWSTR)pConverted); HeapFree(GetProcessHeap(),0,pConverted); if( dwAttr == INVALID_FILE_ATTRIBUTES ){ return -1; } if( (dwAttr & (FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_NORMAL)) == 0 ){ /* Not a regular file */ return -1; } if( dwAttr & FILE_ATTRIBUTE_READONLY ){ /* Read-only file */ return -1; } /* File is writable */ return PH7_OK; } /* int (*xExecutable)(const char *) */ static int WinVfs_isexecutable(const char *zPath) { void * pConverted; DWORD dwAttr; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } dwAttr = GetFileAttributesW((LPCWSTR)pConverted); HeapFree(GetProcessHeap(),0,pConverted); if( dwAttr == INVALID_FILE_ATTRIBUTES ){ return -1; } if( (dwAttr & FILE_ATTRIBUTE_NORMAL) == 0 ){ /* Not a regular file */ return -1; } /* File is executable */ return PH7_OK; } /* int (*xFiletype)(const char *,ph7_context *) */ static int WinVfs_Filetype(const char *zPath,ph7_context *pCtx) { void * pConverted; DWORD dwAttr; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ /* Expand 'unknown' */ ph7_result_string(pCtx,"unknown",sizeof("unknown")-1); return -1; } dwAttr = GetFileAttributesW((LPCWSTR)pConverted); HeapFree(GetProcessHeap(),0,pConverted); if( dwAttr == INVALID_FILE_ATTRIBUTES ){ /* Expand 'unknown' */ ph7_result_string(pCtx,"unknown",sizeof("unknown")-1); return -1; } if(dwAttr & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE) ){ ph7_result_string(pCtx,"file",sizeof("file")-1); }else if(dwAttr & FILE_ATTRIBUTE_DIRECTORY){ ph7_result_string(pCtx,"dir",sizeof("dir")-1); }else if(dwAttr & FILE_ATTRIBUTE_REPARSE_POINT){ ph7_result_string(pCtx,"link",sizeof("link")-1); }else if(dwAttr & (FILE_ATTRIBUTE_DEVICE)){ ph7_result_string(pCtx,"block",sizeof("block")-1); }else{ ph7_result_string(pCtx,"unknown",sizeof("unknown")-1); } return PH7_OK; } /* int (*xGetenv)(const char *,ph7_context *) */ static int WinVfs_Getenv(const char *zVar,ph7_context *pCtx) { char zValue[1024]; DWORD n; /* * According to MSDN * If lpBuffer is not large enough to hold the data, the return * value is the buffer size, in characters, required to hold the * string and its terminating null character and the contents * of lpBuffer are undefined. */ n = sizeof(zValue); SyMemcpy("Undefined",zValue,sizeof("Undefined")-1); /* Extract the environment value */ n = GetEnvironmentVariableA(zVar,zValue,sizeof(zValue)); if( !n ){ /* No such variable*/ return -1; } ph7_result_string(pCtx,zValue,(int)n); return PH7_OK; } /* int (*xSetenv)(const char *,const char *) */ static int WinVfs_Setenv(const char *zName,const char *zValue) { BOOL rc; rc = SetEnvironmentVariableA(zName,zValue); return rc ? PH7_OK : -1; } /* int (*xMmap)(const char *,void **,ph7_int64 *) */ static int WinVfs_Mmap(const char *zPath,void **ppMap,ph7_int64 *pSize) { DWORD dwSizeLow,dwSizeHigh; HANDLE pHandle,pMapHandle; void *pConverted,*pView; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } pHandle = OpenReadOnly((LPCWSTR)pConverted); HeapFree(GetProcessHeap(),0,pConverted); if( pHandle == 0 ){ return -1; } /* Get the file size */ dwSizeLow = GetFileSize(pHandle,&dwSizeHigh); /* Create the mapping */ pMapHandle = CreateFileMappingW(pHandle,0,PAGE_READONLY,dwSizeHigh,dwSizeLow,0); if( pMapHandle == 0 ){ CloseHandle(pHandle); return -1; } *pSize = ((ph7_int64)dwSizeHigh << 32) | dwSizeLow; /* Obtain the view */ pView = MapViewOfFile(pMapHandle,FILE_MAP_READ,0,0,(SIZE_T)(*pSize)); if( pView ){ /* Let the upper layer point to the view */ *ppMap = pView; } /* Close the handle * According to MSDN it's OK the close the HANDLES. */ CloseHandle(pMapHandle); CloseHandle(pHandle); return pView ? PH7_OK : -1; } /* void (*xUnmap)(void *,ph7_int64) */ static void WinVfs_Unmap(void *pView,ph7_int64 nSize) { nSize = 0; /* Compiler warning */ UnmapViewOfFile(pView); } /* void (*xTempDir)(ph7_context *) */ static void WinVfs_TempDir(ph7_context *pCtx) { CHAR zTemp[1024]; DWORD n; n = GetTempPathA(sizeof(zTemp),zTemp); if( n < 1 ){ /* Assume the default windows temp directory */ ph7_result_string(pCtx,"C:\\Windows\\Temp",-1/*Compute length automatically*/); }else{ ph7_result_string(pCtx,zTemp,(int)n); } } /* unsigned int (*xProcessId)(void) */ static unsigned int WinVfs_ProcessId(void) { DWORD nID = 0; #ifndef __MINGW32__ nID = GetProcessId(GetCurrentProcess()); #endif /* __MINGW32__ */ return (unsigned int)nID; } /* void (*xUsername)(ph7_context *) */ static void WinVfs_Username(ph7_context *pCtx) { WCHAR zUser[1024]; DWORD nByte; BOOL rc; nByte = sizeof(zUser); rc = GetUserNameW(zUser,&nByte); if( !rc ){ /* Set a dummy name */ ph7_result_string(pCtx,"Unknown",sizeof("Unknown")-1); }else{ char *zName; zName = unicodeToUtf8(zUser); if( zName == 0 ){ ph7_result_string(pCtx,"Unknown",sizeof("Unknown")-1); }else{ ph7_result_string(pCtx,zName,-1/*Compute length automatically*/); /* Will make it's own copy */ HeapFree(GetProcessHeap(),0,zName); } } } /* Export the windows vfs */ static const ph7_vfs sWinVfs = { "Windows_vfs", PH7_VFS_VERSION, WinVfs_chdir, /* int (*xChdir)(const char *) */ 0, /* int (*xChroot)(const char *); */ WinVfs_getcwd, /* int (*xGetcwd)(ph7_context *) */ WinVfs_mkdir, /* int (*xMkdir)(const char *,int,int) */ WinVfs_rmdir, /* int (*xRmdir)(const char *) */ WinVfs_isdir, /* int (*xIsdir)(const char *) */ WinVfs_Rename, /* int (*xRename)(const char *,const char *) */ WinVfs_Realpath, /*int (*xRealpath)(const char *,ph7_context *)*/ WinVfs_Sleep, /* int (*xSleep)(unsigned int) */ WinVfs_unlink, /* int (*xUnlink)(const char *) */ WinVfs_FileExists, /* int (*xFileExists)(const char *) */ 0, /*int (*xChmod)(const char *,int)*/ 0, /*int (*xChown)(const char *,const char *)*/ 0, /*int (*xChgrp)(const char *,const char *)*/ WinVfs_DiskFreeSpace,/* ph7_int64 (*xFreeSpace)(const char *) */ WinVfs_DiskTotalSpace,/* ph7_int64 (*xTotalSpace)(const char *) */ WinVfs_FileSize, /* ph7_int64 (*xFileSize)(const char *) */ WinVfs_FileAtime,/* ph7_int64 (*xFileAtime)(const char *) */ WinVfs_FileMtime,/* ph7_int64 (*xFileMtime)(const char *) */ WinVfs_FileCtime,/* ph7_int64 (*xFileCtime)(const char *) */ WinVfs_Stat, /* int (*xStat)(const char *,ph7_value *,ph7_value *) */ WinVfs_Stat, /* int (*xlStat)(const char *,ph7_value *,ph7_value *) */ WinVfs_isfile, /* int (*xIsfile)(const char *) */ WinVfs_islink, /* int (*xIslink)(const char *) */ WinVfs_isfile, /* int (*xReadable)(const char *) */ WinVfs_iswritable, /* int (*xWritable)(const char *) */ WinVfs_isexecutable, /* int (*xExecutable)(const char *) */ WinVfs_Filetype, /* int (*xFiletype)(const char *,ph7_context *) */ WinVfs_Getenv, /* int (*xGetenv)(const char *,ph7_context *) */ WinVfs_Setenv, /* int (*xSetenv)(const char *,const char *) */ WinVfs_Touch, /* int (*xTouch)(const char *,ph7_int64,ph7_int64) */ WinVfs_Mmap, /* int (*xMmap)(const char *,void **,ph7_int64 *) */ WinVfs_Unmap, /* void (*xUnmap)(void *,ph7_int64); */ 0, /* int (*xLink)(const char *,const char *,int) */ 0, /* int (*xUmask)(int) */ WinVfs_TempDir, /* void (*xTempDir)(ph7_context *) */ WinVfs_ProcessId, /* unsigned int (*xProcessId)(void) */ 0, /* int (*xUid)(void) */ 0, /* int (*xGid)(void) */ WinVfs_Username, /* void (*xUsername)(ph7_context *) */ 0 /* int (*xExec)(const char *,ph7_context *) */ }; /* Windows file IO */ #ifndef INVALID_SET_FILE_POINTER # define INVALID_SET_FILE_POINTER ((DWORD)-1) #endif /* int (*xOpen)(const char *,int,ph7_value *,void **) */ static int WinFile_Open(const char *zPath,int iOpenMode,ph7_value *pResource,void **ppHandle) { DWORD dwType = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS; DWORD dwAccess = GENERIC_READ; DWORD dwShare,dwCreate; void *pConverted; HANDLE pHandle; pConverted = convertUtf8Filename(zPath); if( pConverted == 0 ){ return -1; } /* Set the desired flags according to the open mode */ if( iOpenMode & PH7_IO_OPEN_CREATE ){ /* Open existing file, or create if it doesn't exist */ dwCreate = OPEN_ALWAYS; if( iOpenMode & PH7_IO_OPEN_TRUNC ){ /* If the specified file exists and is writable, the function overwrites the file */ dwCreate = CREATE_ALWAYS; } }else if( iOpenMode & PH7_IO_OPEN_EXCL ){ /* Creates a new file, only if it does not already exist. * If the file exists, it fails. */ dwCreate = CREATE_NEW; }else if( iOpenMode & PH7_IO_OPEN_TRUNC ){ /* Opens a file and truncates it so that its size is zero bytes * The file must exist. */ dwCreate = TRUNCATE_EXISTING; }else{ /* Opens a file, only if it exists. */ dwCreate = OPEN_EXISTING; } if( iOpenMode & PH7_IO_OPEN_RDWR ){ /* Read+Write access */ dwAccess |= GENERIC_WRITE; }else if( iOpenMode & PH7_IO_OPEN_WRONLY ){ /* Write only access */ dwAccess = GENERIC_WRITE; } if( iOpenMode & PH7_IO_OPEN_APPEND ){ /* Append mode */ dwAccess = FILE_APPEND_DATA; } if( iOpenMode & PH7_IO_OPEN_TEMP ){ /* File is temporary */ dwType = FILE_ATTRIBUTE_TEMPORARY; } dwShare = FILE_SHARE_READ | FILE_SHARE_WRITE; pHandle = CreateFileW((LPCWSTR)pConverted,dwAccess,dwShare,0,dwCreate,dwType,0); HeapFree(GetProcessHeap(),0,pConverted); if( pHandle == INVALID_HANDLE_VALUE){ SXUNUSED(pResource); /* MSVC warning */ return -1; } /* Make the handle accessible to the upper layer */ *ppHandle = (void *)pHandle; return PH7_OK; } /* An instance of the following structure is used to record state information * while iterating throw directory entries. */ typedef struct WinDir_Info WinDir_Info; struct WinDir_Info { HANDLE pDirHandle; void *pPath; WIN32_FIND_DATAW sInfo; int rc; }; /* int (*xOpenDir)(const char *,ph7_value *,void **) */ static int WinDir_Open(const char *zPath,ph7_value *pResource,void **ppHandle) { WinDir_Info *pDirInfo; void *pConverted; char *zPrep; sxu32 n; /* Prepare the path */ n = SyStrlen(zPath); zPrep = (char *)HeapAlloc(GetProcessHeap(),0,n+sizeof("\\*")+4); if( zPrep == 0 ){ return -1; } SyMemcpy((const void *)zPath,zPrep,n); zPrep[n] = '\\'; zPrep[n+1] = '*'; zPrep[n+2] = 0; pConverted = convertUtf8Filename(zPrep); HeapFree(GetProcessHeap(),0,zPrep); if( pConverted == 0 ){ return -1; } /* Allocate a new instance */ pDirInfo = (WinDir_Info *)HeapAlloc(GetProcessHeap(),0,sizeof(WinDir_Info)); if( pDirInfo == 0 ){ pResource = 0; /* Compiler warning */ return -1; } pDirInfo->rc = SXRET_OK; pDirInfo->pDirHandle = FindFirstFileW((LPCWSTR)pConverted,&pDirInfo->sInfo); if( pDirInfo->pDirHandle == INVALID_HANDLE_VALUE ){ /* Cannot open directory */ HeapFree(GetProcessHeap(),0,pConverted); HeapFree(GetProcessHeap(),0,pDirInfo); return -1; } /* Save the path */ pDirInfo->pPath = pConverted; /* Save our structure */ *ppHandle = pDirInfo; return PH7_OK; } /* void (*xCloseDir)(void *) */ static void WinDir_Close(void *pUserData) { WinDir_Info *pDirInfo = (WinDir_Info *)pUserData; if( pDirInfo->pDirHandle != INVALID_HANDLE_VALUE ){ FindClose(pDirInfo->pDirHandle); } HeapFree(GetProcessHeap(),0,pDirInfo->pPath); HeapFree(GetProcessHeap(),0,pDirInfo); } /* void (*xClose)(void *); */ static void WinFile_Close(void *pUserData) { HANDLE pHandle = (HANDLE)pUserData; CloseHandle(pHandle); } /* int (*xReadDir)(void *,ph7_context *) */ static int WinDir_Read(void *pUserData,ph7_context *pCtx) { WinDir_Info *pDirInfo = (WinDir_Info *)pUserData; LPWIN32_FIND_DATAW pData; char *zName; BOOL rc; sxu32 n; if( pDirInfo->rc != SXRET_OK ){ /* No more entry to process */ return -1; } pData = &pDirInfo->sInfo; for(;;){ zName = unicodeToUtf8(pData->cFileName); if( zName == 0 ){ /* Out of memory */ return -1; } n = SyStrlen(zName); /* Ignore '.' && '..' */ if( n > sizeof("..")-1 || zName[0] != '.' || ( n == sizeof("..")-1 && zName[1] != '.') ){ break; } HeapFree(GetProcessHeap(),0,zName); rc = FindNextFileW(pDirInfo->pDirHandle,&pDirInfo->sInfo); if( !rc ){ return -1; } } /* Return the current file name */ ph7_result_string(pCtx,zName,-1); HeapFree(GetProcessHeap(),0,zName); /* Point to the next entry */ rc = FindNextFileW(pDirInfo->pDirHandle,&pDirInfo->sInfo); if( !rc ){ pDirInfo->rc = SXERR_EOF; } return PH7_OK; } /* void (*xRewindDir)(void *) */ static void WinDir_RewindDir(void *pUserData) { WinDir_Info *pDirInfo = (WinDir_Info *)pUserData; FindClose(pDirInfo->pDirHandle); pDirInfo->pDirHandle = FindFirstFileW((LPCWSTR)pDirInfo->pPath,&pDirInfo->sInfo); if( pDirInfo->pDirHandle == INVALID_HANDLE_VALUE ){ pDirInfo->rc = SXERR_EOF; }else{ pDirInfo->rc = SXRET_OK; } } /* ph7_int64 (*xRead)(void *,void *,ph7_int64); */ static ph7_int64 WinFile_Read(void *pOS,void *pBuffer,ph7_int64 nDatatoRead) { HANDLE pHandle = (HANDLE)pOS; DWORD nRd; BOOL rc; rc = ReadFile(pHandle,pBuffer,(DWORD)nDatatoRead,&nRd,0); if( !rc ){ /* EOF or IO error */ return -1; } return (ph7_int64)nRd; } /* ph7_int64 (*xWrite)(void *,const void *,ph7_int64); */ static ph7_int64 WinFile_Write(void *pOS,const void *pBuffer,ph7_int64 nWrite) { const char *zData = (const char *)pBuffer; HANDLE pHandle = (HANDLE)pOS; ph7_int64 nCount; DWORD nWr; BOOL rc; nWr = 0; nCount = 0; for(;;){ if( nWrite < 1 ){ break; } rc = WriteFile(pHandle,zData,(DWORD)nWrite,&nWr,0); if( !rc ){ /* IO error */ break; } nWrite -= nWr; nCount += nWr; zData += nWr; } if( nWrite > 0 ){ return -1; } return nCount; } /* int (*xSeek)(void *,ph7_int64,int) */ static int WinFile_Seek(void *pUserData,ph7_int64 iOfft,int whence) { HANDLE pHandle = (HANDLE)pUserData; DWORD dwMove,dwNew; LONG nHighOfft; switch(whence){ case 1:/*SEEK_CUR*/ dwMove = FILE_CURRENT; break; case 2: /* SEEK_END */ dwMove = FILE_END; break; case 0: /* SEEK_SET */ default: dwMove = FILE_BEGIN; break; } nHighOfft = (LONG)(iOfft >> 32); dwNew = SetFilePointer(pHandle,(LONG)iOfft,&nHighOfft,dwMove); if( dwNew == INVALID_SET_FILE_POINTER ){ return -1; } return PH7_OK; } /* int (*xLock)(void *,int) */ static int WinFile_Lock(void *pUserData,int lock_type) { HANDLE pHandle = (HANDLE)pUserData; static DWORD dwLo = 0,dwHi = 0; /* xx: MT-SAFE */ OVERLAPPED sDummy; BOOL rc; SyZero(&sDummy,sizeof(sDummy)); /* Get the file size */ if( lock_type < 1 ){ /* Unlock the file */ rc = UnlockFileEx(pHandle,0,dwLo,dwHi,&sDummy); }else{ DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; /* Shared non-blocking lock by default*/ /* Lock the file */ if( lock_type == 1 /* LOCK_EXCL */ ){ dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; } dwLo = GetFileSize(pHandle,&dwHi); rc = LockFileEx(pHandle,dwFlags,0,dwLo,dwHi,&sDummy); } return rc ? PH7_OK : -1 /* Lock error */; } /* ph7_int64 (*xTell)(void *) */ static ph7_int64 WinFile_Tell(void *pUserData) { HANDLE pHandle = (HANDLE)pUserData; DWORD dwNew; dwNew = SetFilePointer(pHandle,0,0,FILE_CURRENT/* SEEK_CUR */); if( dwNew == INVALID_SET_FILE_POINTER ){ return -1; } return (ph7_int64)dwNew; } /* int (*xTrunc)(void *,ph7_int64) */ static int WinFile_Trunc(void *pUserData,ph7_int64 nOfft) { HANDLE pHandle = (HANDLE)pUserData; LONG HighOfft; DWORD dwNew; BOOL rc; HighOfft = (LONG)(nOfft >> 32); dwNew = SetFilePointer(pHandle,(LONG)nOfft,&HighOfft,FILE_BEGIN); if( dwNew == INVALID_SET_FILE_POINTER ){ return -1; } rc = SetEndOfFile(pHandle); return rc ? PH7_OK : -1; } /* int (*xSync)(void *); */ static int WinFile_Sync(void *pUserData) { HANDLE pHandle = (HANDLE)pUserData; BOOL rc; rc = FlushFileBuffers(pHandle); return rc ? PH7_OK : - 1; } /* int (*xStat)(void *,ph7_value *,ph7_value *) */ static int WinFile_Stat(void *pUserData,ph7_value *pArray,ph7_value *pWorker) { BY_HANDLE_FILE_INFORMATION sInfo; HANDLE pHandle = (HANDLE)pUserData; BOOL rc; rc = GetFileInformationByHandle(pHandle,&sInfo); if( !rc ){ return -1; } /* dev */ ph7_value_int64(pWorker,(ph7_int64)sInfo.dwVolumeSerialNumber); ph7_array_add_strkey_elem(pArray,"dev",pWorker); /* Will make it's own copy */ /* ino */ ph7_value_int64(pWorker,(ph7_int64)(((ph7_int64)sInfo.nFileIndexHigh << 32) | sInfo.nFileIndexLow)); ph7_array_add_strkey_elem(pArray,"ino",pWorker); /* Will make it's own copy */ /* mode */ ph7_value_int(pWorker,0); ph7_array_add_strkey_elem(pArray,"mode",pWorker); /* nlink */ ph7_value_int(pWorker,(int)sInfo.nNumberOfLinks); ph7_array_add_strkey_elem(pArray,"nlink",pWorker); /* Will make it's own copy */ /* uid,gid,rdev */ ph7_value_int(pWorker,0); ph7_array_add_strkey_elem(pArray,"uid",pWorker); ph7_array_add_strkey_elem(pArray,"gid",pWorker); ph7_array_add_strkey_elem(pArray,"rdev",pWorker); /* size */ ph7_value_int64(pWorker,(ph7_int64)(((ph7_int64)sInfo.nFileSizeHigh << 32) | sInfo.nFileSizeLow)); ph7_array_add_strkey_elem(pArray,"size",pWorker); /* Will make it's own copy */ /* atime */ ph7_value_int64(pWorker,convertWindowsTimeToUnixTime(&sInfo.ftLastAccessTime)); ph7_array_add_strkey_elem(pArray,"atime",pWorker); /* Will make it's own copy */ /* mtime */ ph7_value_int64(pWorker,convertWindowsTimeToUnixTime(&sInfo.ftLastWriteTime)); ph7_array_add_strkey_elem(pArray,"mtime",pWorker); /* Will make it's own copy */ /* ctime */ ph7_value_int64(pWorker,convertWindowsTimeToUnixTime(&sInfo.ftCreationTime)); ph7_array_add_strkey_elem(pArray,"ctime",pWorker); /* Will make it's own copy */ /* blksize,blocks */ ph7_value_int(pWorker,0); ph7_array_add_strkey_elem(pArray,"blksize",pWorker); ph7_array_add_strkey_elem(pArray,"blocks",pWorker); return PH7_OK; } /* Export the file:// stream */ static const ph7_io_stream sWinFileStream = { "file", /* Stream name */ PH7_IO_STREAM_VERSION, WinFile_Open, /* xOpen */ WinDir_Open, /* xOpenDir */ WinFile_Close, /* xClose */ WinDir_Close, /* xCloseDir */ WinFile_Read, /* xRead */ WinDir_Read, /* xReadDir */ WinFile_Write, /* xWrite */ WinFile_Seek, /* xSeek */ WinFile_Lock, /* xLock */ WinDir_RewindDir, /* xRewindDir */ WinFile_Tell, /* xTell */ WinFile_Trunc, /* xTrunc */ WinFile_Sync, /* xSeek */ WinFile_Stat /* xStat */ }; #elif defined(__UNIXES__) /* * UNIX VFS implementation for the PH7 engine. * Authors: * Symisc Systems,devel@symisc.net. * Copyright (C) Symisc Systems,http://ph7.symisc.net * Status: * Stable. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* int (*xchdir)(const char *) */ static int UnixVfs_chdir(const char *zPath) { int rc; rc = chdir(zPath); return rc == 0 ? PH7_OK : -1; } /* int (*xGetcwd)(ph7_context *) */ static int UnixVfs_getcwd(ph7_context *pCtx) { char zBuf[4096]; char *zDir; /* Get the current directory */ zDir = getcwd(zBuf,sizeof(zBuf)); if( zDir == 0 ){ return -1; } ph7_result_string(pCtx,zDir,-1/*Compute length automatically*/); return PH7_OK; } /* int (*xMkdir)(const char *,int,int) */ static int UnixVfs_mkdir(const char *zPath,int mode,int recursive) { int rc; rc = mkdir(zPath,mode); recursive = 0; /* cc warning */ return rc == 0 ? PH7_OK : -1; } /* int (*xRmdir)(const char *) */ static int UnixVfs_rmdir(const char *zPath) { int rc; rc = rmdir(zPath); return rc == 0 ? PH7_OK : -1; } /* int (*xIsdir)(const char *) */ static int UnixVfs_isdir(const char *zPath) { struct stat st; int rc; rc = stat(zPath,&st); if( rc != 0 ){ return -1; } rc = S_ISDIR(st.st_mode); return rc ? PH7_OK : -1 ; } /* int (*xRename)(const char *,const char *) */ static int UnixVfs_Rename(const char *zOld,const char *zNew) { int rc; rc = rename(zOld,zNew); return rc == 0 ? PH7_OK : -1; } /* int (*xRealpath)(const char *,ph7_context *) */ static int UnixVfs_Realpath(const char *zPath,ph7_context *pCtx) { #ifndef PH7_UNIX_OLD_LIBC char *zReal; zReal = realpath(zPath,0); if( zReal == 0 ){ return -1; } ph7_result_string(pCtx,zReal,-1/*Compute length automatically*/); /* Release the allocated buffer */ free(zReal); return PH7_OK; #else zPath = 0; /* cc warning */ pCtx = 0; return -1; #endif } /* int (*xSleep)(unsigned int) */ static int UnixVfs_Sleep(unsigned int uSec) { usleep(uSec); return PH7_OK; } /* int (*xUnlink)(const char *) */ static int UnixVfs_unlink(const char *zPath) { int rc; rc = unlink(zPath); return rc == 0 ? PH7_OK : -1 ; } /* int (*xFileExists)(const char *) */ static int UnixVfs_FileExists(const char *zPath) { int rc; rc = access(zPath,F_OK); return rc == 0 ? PH7_OK : -1; } /* ph7_int64 (*xFileSize)(const char *) */ static ph7_int64 UnixVfs_FileSize(const char *zPath) { struct stat st; int rc; rc = stat(zPath,&st); if( rc != 0 ){ return -1; } return (ph7_int64)st.st_size; } /* int (*xTouch)(const char *,ph7_int64,ph7_int64) */ static int UnixVfs_Touch(const char *zPath,ph7_int64 touch_time,ph7_int64 access_time) { struct utimbuf ut; int rc; ut.actime = (time_t)access_time; ut.modtime = (time_t)touch_time; rc = utime(zPath,&ut); if( rc != 0 ){ return -1; } return PH7_OK; } /* ph7_int64 (*xFileAtime)(const char *) */ static ph7_int64 UnixVfs_FileAtime(const char *zPath) { struct stat st; int rc; rc = stat(zPath,&st); if( rc != 0 ){ return -1; } return (ph7_int64)st.st_atime; } /* ph7_int64 (*xFileMtime)(const char *) */ static ph7_int64 UnixVfs_FileMtime(const char *zPath) { struct stat st; int rc; rc = stat(zPath,&st); if( rc != 0 ){ return -1; } return (ph7_int64)st.st_mtime; } /* ph7_int64 (*xFileCtime)(const char *) */ static ph7_int64 UnixVfs_FileCtime(const char *zPath) { struct stat st; int rc; rc = stat(zPath,&st); if( rc != 0 ){ return -1; } return (ph7_int64)st.st_ctime; } /* int (*xStat)(const char *,ph7_value *,ph7_value *) */ static int UnixVfs_Stat(const char *zPath,ph7_value *pArray,ph7_value *pWorker) { struct stat st; int rc; rc = stat(zPath,&st); if( rc != 0 ){ return -1; } /* dev */ ph7_value_int64(pWorker,(ph7_int64)st.st_dev); ph7_array_add_strkey_elem(pArray,"dev",pWorker); /* Will make it's own copy */ /* ino */ ph7_value_int64(pWorker,(ph7_int64)st.st_ino); ph7_array_add_strkey_elem(pArray,"ino",pWorker); /* Will make it's own copy */ /* mode */ ph7_value_int(pWorker,(int)st.st_mode); ph7_array_add_strkey_elem(pArray,"mode",pWorker); /* nlink */ ph7_value_int(pWorker,(int)st.st_nlink); ph7_array_add_strkey_elem(pArray,"nlink",pWorker); /* Will make it's own copy */ /* uid,gid,rdev */ ph7_value_int(pWorker,(int)st.st_uid); ph7_array_add_strkey_elem(pArray,"uid",pWorker); ph7_value_int(pWorker,(int)st.st_gid); ph7_array_add_strkey_elem(pArray,"gid",pWorker); ph7_value_int(pWorker,(int)st.st_rdev); ph7_array_add_strkey_elem(pArray,"rdev",pWorker); /* size */ ph7_value_int64(pWorker,(ph7_int64)st.st_size); ph7_array_add_strkey_elem(pArray,"size",pWorker); /* Will make it's own copy */ /* atime */ ph7_value_int64(pWorker,(ph7_int64)st.st_atime); ph7_array_add_strkey_elem(pArray,"atime",pWorker); /* Will make it's own copy */ /* mtime */ ph7_value_int64(pWorker,(ph7_int64)st.st_mtime); ph7_array_add_strkey_elem(pArray,"mtime",pWorker); /* Will make it's own copy */ /* ctime */ ph7_value_int64(pWorker,(ph7_int64)st.st_ctime); ph7_array_add_strkey_elem(pArray,"ctime",pWorker); /* Will make it's own copy */ /* blksize,blocks */ ph7_value_int(pWorker,(int)st.st_blksize); ph7_array_add_strkey_elem(pArray,"blksize",pWorker); ph7_value_int(pWorker,(int)st.st_blocks); ph7_array_add_strkey_elem(pArray,"blocks",pWorker); return PH7_OK; } /* int (*xlStat)(const char *,ph7_value *,ph7_value *) */ static int UnixVfs_lStat(const char *zPath,ph7_value *pArray,ph7_value *pWorker) { struct stat st; int rc; rc = lstat(zPath,&st); if( rc != 0 ){ return -1; } /* dev */ ph7_value_int64(pWorker,(ph7_int64)st.st_dev); ph7_array_add_strkey_elem(pArray,"dev",pWorker); /* Will make it's own copy */ /* ino */ ph7_value_int64(pWorker,(ph7_int64)st.st_ino); ph7_array_add_strkey_elem(pArray,"ino",pWorker); /* Will make it's own copy */ /* mode */ ph7_value_int(pWorker,(int)st.st_mode); ph7_array_add_strkey_elem(pArray,"mode",pWorker); /* nlink */ ph7_value_int(pWorker,(int)st.st_nlink); ph7_array_add_strkey_elem(pArray,"nlink",pWorker); /* Will make it's own copy */ /* uid,gid,rdev */ ph7_value_int(pWorker,(int)st.st_uid); ph7_array_add_strkey_elem(pArray,"uid",pWorker); ph7_value_int(pWorker,(int)st.st_gid); ph7_array_add_strkey_elem(pArray,"gid",pWorker); ph7_value_int(pWorker,(int)st.st_rdev); ph7_array_add_strkey_elem(pArray,"rdev",pWorker); /* size */ ph7_value_int64(pWorker,(ph7_int64)st.st_size); ph7_array_add_strkey_elem(pArray,"size",pWorker); /* Will make it's own copy */ /* atime */ ph7_value_int64(pWorker,(ph7_int64)st.st_atime); ph7_array_add_strkey_elem(pArray,"atime",pWorker); /* Will make it's own copy */ /* mtime */ ph7_value_int64(pWorker,(ph7_int64)st.st_mtime); ph7_array_add_strkey_elem(pArray,"mtime",pWorker); /* Will make it's own copy */ /* ctime */ ph7_value_int64(pWorker,(ph7_int64)st.st_ctime); ph7_array_add_strkey_elem(pArray,"ctime",pWorker); /* Will make it's own copy */ /* blksize,blocks */ ph7_value_int(pWorker,(int)st.st_blksize); ph7_array_add_strkey_elem(pArray,"blksize",pWorker); ph7_value_int(pWorker,(int)st.st_blocks); ph7_array_add_strkey_elem(pArray,"blocks",pWorker); return PH7_OK; } /* int (*xChmod)(const char *,int) */ static int UnixVfs_Chmod(const char *zPath,int mode) { int rc; rc = chmod(zPath,(mode_t)mode); return rc == 0 ? PH7_OK : - 1; } /* int (*xChown)(const char *,const char *) */ static int UnixVfs_Chown(const char *zPath,const char *zUser) { #ifndef PH7_UNIX_STATIC_BUILD struct passwd *pwd; uid_t uid; int rc; pwd = getpwnam(zUser); /* Try getting UID for username */ if (pwd == 0) { return -1; } uid = pwd->pw_uid; rc = chown(zPath,uid,-1); return rc == 0 ? PH7_OK : -1; #else SXUNUSED(zPath); SXUNUSED(zUser); return -1; #endif /* PH7_UNIX_STATIC_BUILD */ } /* int (*xChgrp)(const char *,const char *) */ static int UnixVfs_Chgrp(const char *zPath,const char *zGroup) { #ifndef PH7_UNIX_STATIC_BUILD struct group *group; gid_t gid; int rc; group = getgrnam(zGroup); if (group == 0) { return -1; } gid = group->gr_gid; rc = chown(zPath,-1,gid); return rc == 0 ? PH7_OK : -1; #else SXUNUSED(zPath); SXUNUSED(zGroup); return -1; #endif /* PH7_UNIX_STATIC_BUILD */ } /* int (*xIsfile)(const char *) */ static int UnixVfs_isfile(const char *zPath) { struct stat st; int rc; rc = stat(zPath,&st); if( rc != 0 ){ return -1; } rc = S_ISREG(st.st_mode); return rc ? PH7_OK : -1 ; } /* int (*xIslink)(const char *) */ static int UnixVfs_islink(const char *zPath) { struct stat st; int rc; rc = stat(zPath,&st); if( rc != 0 ){ return -1; } rc = S_ISLNK(st.st_mode); return rc ? PH7_OK : -1 ; } /* int (*xReadable)(const char *) */ static int UnixVfs_isreadable(const char *zPath) { int rc; rc = access(zPath,R_OK); return rc == 0 ? PH7_OK : -1; } /* int (*xWritable)(const char *) */ static int UnixVfs_iswritable(const char *zPath) { int rc; rc = access(zPath,W_OK); return rc == 0 ? PH7_OK : -1; } /* int (*xExecutable)(const char *) */ static int UnixVfs_isexecutable(const char *zPath) { int rc; rc = access(zPath,X_OK); return rc == 0 ? PH7_OK : -1; } /* int (*xFiletype)(const char *,ph7_context *) */ static int UnixVfs_Filetype(const char *zPath,ph7_context *pCtx) { struct stat st; int rc; rc = stat(zPath,&st); if( rc != 0 ){ /* Expand 'unknown' */ ph7_result_string(pCtx,"unknown",sizeof("unknown")-1); return -1; } if(S_ISREG(st.st_mode) ){ ph7_result_string(pCtx,"file",sizeof("file")-1); }else if(S_ISDIR(st.st_mode)){ ph7_result_string(pCtx,"dir",sizeof("dir")-1); }else if(S_ISLNK(st.st_mode)){ ph7_result_string(pCtx,"link",sizeof("link")-1); }else if(S_ISBLK(st.st_mode)){ ph7_result_string(pCtx,"block",sizeof("block")-1); }else if(S_ISSOCK(st.st_mode)){ ph7_result_string(pCtx,"socket",sizeof("socket")-1); }else if(S_ISFIFO(st.st_mode)){ ph7_result_string(pCtx,"fifo",sizeof("fifo")-1); }else{ ph7_result_string(pCtx,"unknown",sizeof("unknown")-1); } return PH7_OK; } /* int (*xGetenv)(const char *,ph7_context *) */ static int UnixVfs_Getenv(const char *zVar,ph7_context *pCtx) { char *zEnv; zEnv = getenv(zVar); if( zEnv == 0 ){ return -1; } ph7_result_string(pCtx,zEnv,-1/*Compute length automatically*/); return PH7_OK; } /* int (*xSetenv)(const char *,const char *) */ static int UnixVfs_Setenv(const char *zName,const char *zValue) { int rc; rc = setenv(zName,zValue,1); return rc == 0 ? PH7_OK : -1; } /* int (*xMmap)(const char *,void **,ph7_int64 *) */ static int UnixVfs_Mmap(const char *zPath,void **ppMap,ph7_int64 *pSize) { struct stat st; void *pMap; int fd; int rc; /* Open the file in a read-only mode */ fd = open(zPath,O_RDONLY); if( fd < 0 ){ return -1; } /* stat the handle */ fstat(fd,&st); /* Obtain a memory view of the whole file */ pMap = mmap(0,st.st_size,PROT_READ,MAP_PRIVATE|MAP_FILE,fd,0); rc = PH7_OK; if( pMap == MAP_FAILED ){ rc = -1; }else{ /* Point to the memory view */ *ppMap = pMap; *pSize = (ph7_int64)st.st_size; } close(fd); return rc; } /* void (*xUnmap)(void *,ph7_int64) */ static void UnixVfs_Unmap(void *pView,ph7_int64 nSize) { munmap(pView,(size_t)nSize); } /* void (*xTempDir)(ph7_context *) */ static void UnixVfs_TempDir(ph7_context *pCtx) { static const char *azDirs[] = { "/var/tmp", "/usr/tmp", "/usr/local/tmp" }; unsigned int i; struct stat buf; const char *zDir; zDir = getenv("TMPDIR"); if( zDir && zDir[0] != 0 && !access(zDir,07) ){ ph7_result_string(pCtx,zDir,-1); return; } for(i=0; ipw_name,-1); #else ph7_result_string(pCtx,"Unknown",-1); #endif /* PH7_UNIX_STATIC_BUILD */ return; } /* int (*xLink)(const char *,const char *,int) */ static int UnixVfs_link(const char *zSrc,const char *zTarget,int is_sym) { int rc; if( is_sym ){ /* Symbolic link */ rc = symlink(zSrc,zTarget); }else{ /* Hard link */ rc = link(zSrc,zTarget); } return rc == 0 ? PH7_OK : -1; } /* int (*xChroot)(const char *) */ static int UnixVfs_chroot(const char *zRootDir) { int rc; rc = chroot(zRootDir); return rc == 0 ? PH7_OK : -1; } /* Export the UNIX vfs */ static const ph7_vfs sUnixVfs = { "Unix_vfs", PH7_VFS_VERSION, UnixVfs_chdir, /* int (*xChdir)(const char *) */ UnixVfs_chroot, /* int (*xChroot)(const char *); */ UnixVfs_getcwd, /* int (*xGetcwd)(ph7_context *) */ UnixVfs_mkdir, /* int (*xMkdir)(const char *,int,int) */ UnixVfs_rmdir, /* int (*xRmdir)(const char *) */ UnixVfs_isdir, /* int (*xIsdir)(const char *) */ UnixVfs_Rename, /* int (*xRename)(const char *,const char *) */ UnixVfs_Realpath, /*int (*xRealpath)(const char *,ph7_context *)*/ UnixVfs_Sleep, /* int (*xSleep)(unsigned int) */ UnixVfs_unlink, /* int (*xUnlink)(const char *) */ UnixVfs_FileExists, /* int (*xFileExists)(const char *) */ UnixVfs_Chmod, /*int (*xChmod)(const char *,int)*/ UnixVfs_Chown, /*int (*xChown)(const char *,const char *)*/ UnixVfs_Chgrp, /*int (*xChgrp)(const char *,const char *)*/ 0, /* ph7_int64 (*xFreeSpace)(const char *) */ 0, /* ph7_int64 (*xTotalSpace)(const char *) */ UnixVfs_FileSize, /* ph7_int64 (*xFileSize)(const char *) */ UnixVfs_FileAtime,/* ph7_int64 (*xFileAtime)(const char *) */ UnixVfs_FileMtime,/* ph7_int64 (*xFileMtime)(const char *) */ UnixVfs_FileCtime,/* ph7_int64 (*xFileCtime)(const char *) */ UnixVfs_Stat, /* int (*xStat)(const char *,ph7_value *,ph7_value *) */ UnixVfs_lStat, /* int (*xlStat)(const char *,ph7_value *,ph7_value *) */ UnixVfs_isfile, /* int (*xIsfile)(const char *) */ UnixVfs_islink, /* int (*xIslink)(const char *) */ UnixVfs_isreadable, /* int (*xReadable)(const char *) */ UnixVfs_iswritable, /* int (*xWritable)(const char *) */ UnixVfs_isexecutable,/* int (*xExecutable)(const char *) */ UnixVfs_Filetype, /* int (*xFiletype)(const char *,ph7_context *) */ UnixVfs_Getenv, /* int (*xGetenv)(const char *,ph7_context *) */ UnixVfs_Setenv, /* int (*xSetenv)(const char *,const char *) */ UnixVfs_Touch, /* int (*xTouch)(const char *,ph7_int64,ph7_int64) */ UnixVfs_Mmap, /* int (*xMmap)(const char *,void **,ph7_int64 *) */ UnixVfs_Unmap, /* void (*xUnmap)(void *,ph7_int64); */ UnixVfs_link, /* int (*xLink)(const char *,const char *,int) */ UnixVfs_Umask, /* int (*xUmask)(int) */ UnixVfs_TempDir, /* void (*xTempDir)(ph7_context *) */ UnixVfs_ProcessId, /* unsigned int (*xProcessId)(void) */ UnixVfs_uid, /* int (*xUid)(void) */ UnixVfs_gid, /* int (*xGid)(void) */ UnixVfs_Username, /* void (*xUsername)(ph7_context *) */ 0 /* int (*xExec)(const char *,ph7_context *) */ }; /* UNIX File IO */ #define PH7_UNIX_OPEN_MODE 0640 /* Default open mode */ /* int (*xOpen)(const char *,int,ph7_value *,void **) */ static int UnixFile_Open(const char *zPath,int iOpenMode,ph7_value *pResource,void **ppHandle) { int iOpen = O_RDONLY; int fd; /* Set the desired flags according to the open mode */ if( iOpenMode & PH7_IO_OPEN_CREATE ){ /* Open existing file, or create if it doesn't exist */ iOpen = O_CREAT; if( iOpenMode & PH7_IO_OPEN_TRUNC ){ /* If the specified file exists and is writable, the function overwrites the file */ iOpen |= O_TRUNC; SXUNUSED(pResource); /* cc warning */ } }else if( iOpenMode & PH7_IO_OPEN_EXCL ){ /* Creates a new file, only if it does not already exist. * If the file exists, it fails. */ iOpen = O_CREAT|O_EXCL; }else if( iOpenMode & PH7_IO_OPEN_TRUNC ){ /* Opens a file and truncates it so that its size is zero bytes * The file must exist. */ iOpen = O_RDWR|O_TRUNC; } if( iOpenMode & PH7_IO_OPEN_RDWR ){ /* Read+Write access */ iOpen &= ~O_RDONLY; iOpen |= O_RDWR; }else if( iOpenMode & PH7_IO_OPEN_WRONLY ){ /* Write only access */ iOpen &= ~O_RDONLY; iOpen |= O_WRONLY; } if( iOpenMode & PH7_IO_OPEN_APPEND ){ /* Append mode */ iOpen |= O_APPEND; } #ifdef O_TEMP if( iOpenMode & PH7_IO_OPEN_TEMP ){ /* File is temporary */ iOpen |= O_TEMP; } #endif /* Open the file now */ fd = open(zPath,iOpen,PH7_UNIX_OPEN_MODE); if( fd < 0 ){ /* IO error */ return -1; } /* Save the handle */ *ppHandle = SX_INT_TO_PTR(fd); return PH7_OK; } /* int (*xOpenDir)(const char *,ph7_value *,void **) */ static int UnixDir_Open(const char *zPath,ph7_value *pResource,void **ppHandle) { DIR *pDir; /* Open the target directory */ pDir = opendir(zPath); if( pDir == 0 ){ pResource = 0; /* Compiler warning */ return -1; } /* Save our structure */ *ppHandle = pDir; return PH7_OK; } /* void (*xCloseDir)(void *) */ static void UnixDir_Close(void *pUserData) { closedir((DIR *)pUserData); } /* void (*xClose)(void *); */ static void UnixFile_Close(void *pUserData) { close(SX_PTR_TO_INT(pUserData)); } /* int (*xReadDir)(void *,ph7_context *) */ static int UnixDir_Read(void *pUserData,ph7_context *pCtx) { DIR *pDir = (DIR *)pUserData; struct dirent *pEntry; char *zName = 0; /* cc warning */ sxu32 n = 0; for(;;){ pEntry = readdir(pDir); if( pEntry == 0 ){ /* No more entries to process */ return -1; } zName = pEntry->d_name; n = SyStrlen(zName); /* Ignore '.' && '..' */ if( n > sizeof("..")-1 || zName[0] != '.' || ( n == sizeof("..")-1 && zName[1] != '.') ){ break; } /* Next entry */ } /* Return the current file name */ ph7_result_string(pCtx,zName,(int)n); return PH7_OK; } /* void (*xRewindDir)(void *) */ static void UnixDir_Rewind(void *pUserData) { rewinddir((DIR *)pUserData); } /* ph7_int64 (*xRead)(void *,void *,ph7_int64); */ static ph7_int64 UnixFile_Read(void *pUserData,void *pBuffer,ph7_int64 nDatatoRead) { ssize_t nRd; nRd = read(SX_PTR_TO_INT(pUserData),pBuffer,(size_t)nDatatoRead); if( nRd < 1 ){ /* EOF or IO error */ return -1; } return (ph7_int64)nRd; } /* ph7_int64 (*xWrite)(void *,const void *,ph7_int64); */ static ph7_int64 UnixFile_Write(void *pUserData,const void *pBuffer,ph7_int64 nWrite) { const char *zData = (const char *)pBuffer; int fd = SX_PTR_TO_INT(pUserData); ph7_int64 nCount; ssize_t nWr; nCount = 0; for(;;){ if( nWrite < 1 ){ break; } nWr = write(fd,zData,(size_t)nWrite); if( nWr < 1 ){ /* IO error */ break; } nWrite -= nWr; nCount += nWr; zData += nWr; } if( nWrite > 0 ){ return -1; } return nCount; } /* int (*xSeek)(void *,ph7_int64,int) */ static int UnixFile_Seek(void *pUserData,ph7_int64 iOfft,int whence) { off_t iNew; switch(whence){ case 1:/*SEEK_CUR*/ whence = SEEK_CUR; break; case 2: /* SEEK_END */ whence = SEEK_END; break; case 0: /* SEEK_SET */ default: whence = SEEK_SET; break; } iNew = lseek(SX_PTR_TO_INT(pUserData),(off_t)iOfft,whence); if( iNew < 0 ){ return -1; } return PH7_OK; } /* int (*xLock)(void *,int) */ static int UnixFile_Lock(void *pUserData,int lock_type) { int fd = SX_PTR_TO_INT(pUserData); int rc = PH7_OK; /* cc warning */ if( lock_type < 0 ){ /* Unlock the file */ rc = flock(fd,LOCK_UN); }else{ if( lock_type == 1 ){ /* Exculsive lock */ rc = flock(fd,LOCK_EX); }else{ /* Shared lock */ rc = flock(fd,LOCK_SH); } } return !rc ? PH7_OK : -1; } /* ph7_int64 (*xTell)(void *) */ static ph7_int64 UnixFile_Tell(void *pUserData) { off_t iNew; iNew = lseek(SX_PTR_TO_INT(pUserData),0,SEEK_CUR); return (ph7_int64)iNew; } /* int (*xTrunc)(void *,ph7_int64) */ static int UnixFile_Trunc(void *pUserData,ph7_int64 nOfft) { int rc; rc = ftruncate(SX_PTR_TO_INT(pUserData),(off_t)nOfft); if( rc != 0 ){ return -1; } return PH7_OK; } /* int (*xSync)(void *); */ static int UnixFile_Sync(void *pUserData) { int rc; rc = fsync(SX_PTR_TO_INT(pUserData)); return rc == 0 ? PH7_OK : - 1; } /* int (*xStat)(void *,ph7_value *,ph7_value *) */ static int UnixFile_Stat(void *pUserData,ph7_value *pArray,ph7_value *pWorker) { struct stat st; int rc; rc = fstat(SX_PTR_TO_INT(pUserData),&st); if( rc != 0 ){ return -1; } /* dev */ ph7_value_int64(pWorker,(ph7_int64)st.st_dev); ph7_array_add_strkey_elem(pArray,"dev",pWorker); /* Will make it's own copy */ /* ino */ ph7_value_int64(pWorker,(ph7_int64)st.st_ino); ph7_array_add_strkey_elem(pArray,"ino",pWorker); /* Will make it's own copy */ /* mode */ ph7_value_int(pWorker,(int)st.st_mode); ph7_array_add_strkey_elem(pArray,"mode",pWorker); /* nlink */ ph7_value_int(pWorker,(int)st.st_nlink); ph7_array_add_strkey_elem(pArray,"nlink",pWorker); /* Will make it's own copy */ /* uid,gid,rdev */ ph7_value_int(pWorker,(int)st.st_uid); ph7_array_add_strkey_elem(pArray,"uid",pWorker); ph7_value_int(pWorker,(int)st.st_gid); ph7_array_add_strkey_elem(pArray,"gid",pWorker); ph7_value_int(pWorker,(int)st.st_rdev); ph7_array_add_strkey_elem(pArray,"rdev",pWorker); /* size */ ph7_value_int64(pWorker,(ph7_int64)st.st_size); ph7_array_add_strkey_elem(pArray,"size",pWorker); /* Will make it's own copy */ /* atime */ ph7_value_int64(pWorker,(ph7_int64)st.st_atime); ph7_array_add_strkey_elem(pArray,"atime",pWorker); /* Will make it's own copy */ /* mtime */ ph7_value_int64(pWorker,(ph7_int64)st.st_mtime); ph7_array_add_strkey_elem(pArray,"mtime",pWorker); /* Will make it's own copy */ /* ctime */ ph7_value_int64(pWorker,(ph7_int64)st.st_ctime); ph7_array_add_strkey_elem(pArray,"ctime",pWorker); /* Will make it's own copy */ /* blksize,blocks */ ph7_value_int(pWorker,(int)st.st_blksize); ph7_array_add_strkey_elem(pArray,"blksize",pWorker); ph7_value_int(pWorker,(int)st.st_blocks); ph7_array_add_strkey_elem(pArray,"blocks",pWorker); return PH7_OK; } /* Export the file:// stream */ static const ph7_io_stream sUnixFileStream = { "file", /* Stream name */ PH7_IO_STREAM_VERSION, UnixFile_Open, /* xOpen */ UnixDir_Open, /* xOpenDir */ UnixFile_Close, /* xClose */ UnixDir_Close, /* xCloseDir */ UnixFile_Read, /* xRead */ UnixDir_Read, /* xReadDir */ UnixFile_Write, /* xWrite */ UnixFile_Seek, /* xSeek */ UnixFile_Lock, /* xLock */ UnixDir_Rewind, /* xRewindDir */ UnixFile_Tell, /* xTell */ UnixFile_Trunc, /* xTrunc */ UnixFile_Sync, /* xSeek */ UnixFile_Stat /* xStat */ }; #endif /* __WINNT__/__UNIXES__ */ #endif /* PH7_DISABLE_DISK_IO */ #endif /* PH7_DISABLE_BUILTIN_FUNC */ /* * Export the builtin vfs. * Return a pointer to the builtin vfs if available. * Otherwise return the null_vfs [i.e: a no-op vfs] instead. * Note: * The built-in vfs is always available for Windows/UNIX systems. * Note: * If the engine is compiled with the PH7_DISABLE_DISK_IO/PH7_DISABLE_BUILTIN_FUNC * directives defined then this function return the null_vfs instead. */ PH7_PRIVATE const ph7_vfs * PH7_ExportBuiltinVfs(void) { #ifndef PH7_DISABLE_BUILTIN_FUNC #ifdef PH7_DISABLE_DISK_IO return &null_vfs; #else #ifdef __WINNT__ return &sWinVfs; #elif defined(__UNIXES__) return &sUnixVfs; #else return &null_vfs; #endif /* __WINNT__/__UNIXES__ */ #endif /*PH7_DISABLE_DISK_IO*/ #else return &null_vfs; #endif /* PH7_DISABLE_BUILTIN_FUNC */ } #ifndef PH7_DISABLE_BUILTIN_FUNC #ifndef PH7_DISABLE_DISK_IO /* * The following defines are mostly used by the UNIX built and have * no particular meaning on windows. */ #ifndef STDIN_FILENO #define STDIN_FILENO 0 #endif #ifndef STDOUT_FILENO #define STDOUT_FILENO 1 #endif #ifndef STDERR_FILENO #define STDERR_FILENO 2 #endif /* * php:// Accessing various I/O streams * According to the PHP langage reference manual * PHP provides a number of miscellaneous I/O streams that allow access to PHP's own input * and output streams, the standard input, output and error file descriptors. * php://stdin, php://stdout and php://stderr: * Allow direct access to the corresponding input or output stream of the PHP process. * The stream references a duplicate file descriptor, so if you open php://stdin and later * close it, you close only your copy of the descriptor-the actual stream referenced by STDIN is unaffected. * php://stdin is read-only, whereas php://stdout and php://stderr are write-only. * php://output * php://output is a write-only stream that allows you to write to the output buffer * mechanism in the same way as print and echo. */ typedef struct ph7_stream_data ph7_stream_data; /* Supported IO streams */ #define PH7_IO_STREAM_STDIN 1 /* php://stdin */ #define PH7_IO_STREAM_STDOUT 2 /* php://stdout */ #define PH7_IO_STREAM_STDERR 3 /* php://stderr */ #define PH7_IO_STREAM_OUTPUT 4 /* php://output */ /* The following structure is the private data associated with the php:// stream */ struct ph7_stream_data { ph7_vm *pVm; /* VM that own this instance */ int iType; /* Stream type */ union{ void *pHandle; /* Stream handle */ ph7_output_consumer sConsumer; /* VM output consumer */ }x; }; /* * Allocate a new instance of the ph7_stream_data structure. */ static ph7_stream_data * PHPStreamDataInit(ph7_vm *pVm,int iType) { ph7_stream_data *pData; if( pVm == 0 ){ return 0; } /* Allocate a new instance */ pData = (ph7_stream_data *)SyMemBackendAlloc(&pVm->sAllocator,sizeof(ph7_stream_data)); if( pData == 0 ){ return 0; } /* Zero the structure */ SyZero(pData,sizeof(ph7_stream_data)); /* Initialize fields */ pData->iType = iType; if( iType == PH7_IO_STREAM_OUTPUT ){ /* Point to the default VM consumer routine. */ pData->x.sConsumer = pVm->sVmConsumer; }else{ #ifdef __WINNT__ DWORD nChannel; switch(iType){ case PH7_IO_STREAM_STDOUT: nChannel = STD_OUTPUT_HANDLE; break; case PH7_IO_STREAM_STDERR: nChannel = STD_ERROR_HANDLE; break; default: nChannel = STD_INPUT_HANDLE; break; } pData->x.pHandle = GetStdHandle(nChannel); #else /* Assume an UNIX system */ int ifd = STDIN_FILENO; switch(iType){ case PH7_IO_STREAM_STDOUT: ifd = STDOUT_FILENO; break; case PH7_IO_STREAM_STDERR: ifd = STDERR_FILENO; break; default: break; } pData->x.pHandle = SX_INT_TO_PTR(ifd); #endif } pData->pVm = pVm; return pData; } /* * Implementation of the php:// IO streams routines * Authors: * Symisc Systems,devel@symisc.net. * Copyright (C) Symisc Systems,http://ph7.symisc.net * Status: * Stable. */ /* int (*xOpen)(const char *,int,ph7_value *,void **) */ static int PHPStreamData_Open(const char *zName,int iMode,ph7_value *pResource,void ** ppHandle) { ph7_stream_data *pData; SyString sStream; SyStringInitFromBuf(&sStream,zName,SyStrlen(zName)); /* Trim leading and trailing white spaces */ SyStringFullTrim(&sStream); /* Stream to open */ if( SyStrnicmp(sStream.zString,"stdin",sizeof("stdin")-1) == 0 ){ iMode = PH7_IO_STREAM_STDIN; }else if( SyStrnicmp(sStream.zString,"output",sizeof("output")-1) == 0 ){ iMode = PH7_IO_STREAM_OUTPUT; }else if( SyStrnicmp(sStream.zString,"stdout",sizeof("stdout")-1) == 0 ){ iMode = PH7_IO_STREAM_STDOUT; }else if( SyStrnicmp(sStream.zString,"stderr",sizeof("stderr")-1) == 0 ){ iMode = PH7_IO_STREAM_STDERR; }else{ /* unknown stream name */ return -1; } /* Create our handle */ pData = PHPStreamDataInit(pResource?pResource->pVm:0,iMode); if( pData == 0 ){ return -1; } /* Make the handle public */ *ppHandle = (void *)pData; return PH7_OK; } /* ph7_int64 (*xRead)(void *,void *,ph7_int64) */ static ph7_int64 PHPStreamData_Read(void *pHandle,void *pBuffer,ph7_int64 nDatatoRead) { ph7_stream_data *pData = (ph7_stream_data *)pHandle; if( pData == 0 ){ return -1; } if( pData->iType != PH7_IO_STREAM_STDIN ){ /* Forbidden */ return -1; } #ifdef __WINNT__ { DWORD nRd; BOOL rc; rc = ReadFile(pData->x.pHandle,pBuffer,(DWORD)nDatatoRead,&nRd,0); if( !rc ){ /* IO error */ return -1; } return (ph7_int64)nRd; } #elif defined(__UNIXES__) { ssize_t nRd; int fd; fd = SX_PTR_TO_INT(pData->x.pHandle); nRd = read(fd,pBuffer,(size_t)nDatatoRead); if( nRd < 1 ){ return -1; } return (ph7_int64)nRd; } #else return -1; #endif } /* ph7_int64 (*xWrite)(void *,const void *,ph7_int64) */ static ph7_int64 PHPStreamData_Write(void *pHandle,const void *pBuf,ph7_int64 nWrite) { ph7_stream_data *pData = (ph7_stream_data *)pHandle; if( pData == 0 ){ return -1; } if( pData->iType == PH7_IO_STREAM_STDIN ){ /* Forbidden */ return -1; }else if( pData->iType == PH7_IO_STREAM_OUTPUT ){ ph7_output_consumer *pCons = &pData->x.sConsumer; int rc; /* Call the vm output consumer */ rc = pCons->xConsumer(pBuf,(unsigned int)nWrite,pCons->pUserData); if( rc == PH7_ABORT ){ return -1; } return nWrite; } #ifdef __WINNT__ { DWORD nWr; BOOL rc; rc = WriteFile(pData->x.pHandle,pBuf,(DWORD)nWrite,&nWr,0); if( !rc ){ /* IO error */ return -1; } return (ph7_int64)nWr; } #elif defined(__UNIXES__) { ssize_t nWr; int fd; fd = SX_PTR_TO_INT(pData->x.pHandle); nWr = write(fd,pBuf,(size_t)nWrite); if( nWr < 1 ){ return -1; } return (ph7_int64)nWr; } #else return -1; #endif } /* void (*xClose)(void *) */ static void PHPStreamData_Close(void *pHandle) { ph7_stream_data *pData = (ph7_stream_data *)pHandle; ph7_vm *pVm; if( pData == 0 ){ return; } pVm = pData->pVm; /* Free the instance */ SyMemBackendFree(&pVm->sAllocator,pData); } /* Export the php:// stream */ static const ph7_io_stream sPHP_Stream = { "php", PH7_IO_STREAM_VERSION, PHPStreamData_Open, /* xOpen */ 0, /* xOpenDir */ PHPStreamData_Close, /* xClose */ 0, /* xCloseDir */ PHPStreamData_Read, /* xRead */ 0, /* xReadDir */ PHPStreamData_Write, /* xWrite */ 0, /* xSeek */ 0, /* xLock */ 0, /* xRewindDir */ 0, /* xTell */ 0, /* xTrunc */ 0, /* xSeek */ 0 /* xStat */ }; #endif /* PH7_DISABLE_DISK_IO */ /* * Return TRUE if we are dealing with the php:// stream. * FALSE otherwise. */ static int is_php_stream(const ph7_io_stream *pStream) { #ifndef PH7_DISABLE_DISK_IO return pStream == &sPHP_Stream; #else SXUNUSED(pStream); /* cc warning */ return 0; #endif /* PH7_DISABLE_DISK_IO */ } #endif /* PH7_DISABLE_BUILTIN_FUNC */ /* * Export the IO routines defined above and the built-in IO streams * [i.e: file://,php://]. * Note: * If the engine is compiled with the PH7_DISABLE_BUILTIN_FUNC directive * defined then this function is a no-op. */ PH7_PRIVATE sxi32 PH7_RegisterIORoutine(ph7_vm *pVm) { #ifndef PH7_DISABLE_BUILTIN_FUNC /* VFS functions */ static const ph7_builtin_func aVfsFunc[] = { {"chdir", PH7_vfs_chdir }, {"chroot", PH7_vfs_chroot }, {"getcwd", PH7_vfs_getcwd }, {"rmdir", PH7_vfs_rmdir }, {"is_dir", PH7_vfs_is_dir }, {"mkdir", PH7_vfs_mkdir }, {"rename", PH7_vfs_rename }, {"realpath",PH7_vfs_realpath}, {"sleep", PH7_vfs_sleep }, {"usleep", PH7_vfs_usleep }, {"unlink", PH7_vfs_unlink }, {"delete", PH7_vfs_unlink }, {"chmod", PH7_vfs_chmod }, {"chown", PH7_vfs_chown }, {"chgrp", PH7_vfs_chgrp }, {"disk_free_space",PH7_vfs_disk_free_space }, {"diskfreespace", PH7_vfs_disk_free_space }, {"disk_total_space",PH7_vfs_disk_total_space}, {"file_exists", PH7_vfs_file_exists }, {"filesize", PH7_vfs_file_size }, {"fileatime", PH7_vfs_file_atime }, {"filemtime", PH7_vfs_file_mtime }, {"filectime", PH7_vfs_file_ctime }, {"is_file", PH7_vfs_is_file }, {"is_link", PH7_vfs_is_link }, {"is_readable", PH7_vfs_is_readable }, {"is_writable", PH7_vfs_is_writable }, {"is_executable",PH7_vfs_is_executable}, {"filetype", PH7_vfs_filetype }, {"stat", PH7_vfs_stat }, {"lstat", PH7_vfs_lstat }, {"getenv", PH7_vfs_getenv }, {"setenv", PH7_vfs_putenv }, {"putenv", PH7_vfs_putenv }, {"touch", PH7_vfs_touch }, {"link", PH7_vfs_link }, {"symlink", PH7_vfs_symlink }, {"umask", PH7_vfs_umask }, {"sys_get_temp_dir", PH7_vfs_sys_get_temp_dir }, {"get_current_user", PH7_vfs_get_current_user }, {"getmypid", PH7_vfs_getmypid }, {"getpid", PH7_vfs_getmypid }, {"getmyuid", PH7_vfs_getmyuid }, {"getuid", PH7_vfs_getmyuid }, {"getmygid", PH7_vfs_getmygid }, {"getgid", PH7_vfs_getmygid }, {"ph7_uname", PH7_vfs_ph7_uname}, {"php_uname", PH7_vfs_ph7_uname}, /* Path processing */ {"dirname", PH7_builtin_dirname }, {"basename", PH7_builtin_basename }, {"pathinfo", PH7_builtin_pathinfo }, {"strglob", PH7_builtin_strglob }, {"fnmatch", PH7_builtin_fnmatch }, /* ZIP processing */ {"zip_open", PH7_builtin_zip_open }, {"zip_close", PH7_builtin_zip_close}, {"zip_read", PH7_builtin_zip_read }, {"zip_entry_open", PH7_builtin_zip_entry_open }, {"zip_entry_close",PH7_builtin_zip_entry_close}, {"zip_entry_name", PH7_builtin_zip_entry_name }, {"zip_entry_filesize", PH7_builtin_zip_entry_filesize }, {"zip_entry_compressedsize",PH7_builtin_zip_entry_compressedsize }, {"zip_entry_read", PH7_builtin_zip_entry_read }, {"zip_entry_reset_read_cursor",PH7_builtin_zip_entry_reset_read_cursor}, {"zip_entry_compressionmethod",PH7_builtin_zip_entry_compressionmethod} }; /* IO stream functions */ static const ph7_builtin_func aIOFunc[] = { {"ftruncate", PH7_builtin_ftruncate }, {"fseek", PH7_builtin_fseek }, {"ftell", PH7_builtin_ftell }, {"rewind", PH7_builtin_rewind }, {"fflush", PH7_builtin_fflush }, {"feof", PH7_builtin_feof }, {"fgetc", PH7_builtin_fgetc }, {"fgets", PH7_builtin_fgets }, {"fread", PH7_builtin_fread }, {"fgetcsv", PH7_builtin_fgetcsv}, {"fgetss", PH7_builtin_fgetss }, {"readdir", PH7_builtin_readdir}, {"rewinddir", PH7_builtin_rewinddir }, {"closedir", PH7_builtin_closedir}, {"opendir", PH7_builtin_opendir }, {"readfile", PH7_builtin_readfile}, {"file_get_contents", PH7_builtin_file_get_contents}, {"file_put_contents", PH7_builtin_file_put_contents}, {"file", PH7_builtin_file }, {"copy", PH7_builtin_copy }, {"fstat", PH7_builtin_fstat }, {"fwrite", PH7_builtin_fwrite }, {"fputs", PH7_builtin_fwrite }, {"flock", PH7_builtin_flock }, {"fclose", PH7_builtin_fclose }, {"fopen", PH7_builtin_fopen }, {"fpassthru", PH7_builtin_fpassthru }, {"fputcsv", PH7_builtin_fputcsv }, {"fprintf", PH7_builtin_fprintf }, #if !defined(PH7_DISABLE_HASH_FUNC) {"md5_file", PH7_builtin_md5_file}, {"sha1_file", PH7_builtin_sha1_file}, #endif /* PH7_DISABLE_HASH_FUNC */ {"parse_ini_file", PH7_builtin_parse_ini_file}, {"vfprintf", PH7_builtin_vfprintf} }; const ph7_io_stream *pFileStream = 0; sxu32 n = 0; /* Register the functions defined above */ for( n = 0 ; n < SX_ARRAYSIZE(aVfsFunc) ; ++n ){ ph7_create_function(&(*pVm),aVfsFunc[n].zName,aVfsFunc[n].xFunc,(void *)pVm->pEngine->pVfs); } for( n = 0 ; n < SX_ARRAYSIZE(aIOFunc) ; ++n ){ ph7_create_function(&(*pVm),aIOFunc[n].zName,aIOFunc[n].xFunc,pVm); } #ifndef PH7_DISABLE_DISK_IO /* Register the file stream if available */ #ifdef __WINNT__ pFileStream = &sWinFileStream; #elif defined(__UNIXES__) pFileStream = &sUnixFileStream; #endif /* Install the php:// stream */ ph7_vm_config(pVm,PH7_VM_CONFIG_IO_STREAM,&sPHP_Stream); #endif /* PH7_DISABLE_DISK_IO */ if( pFileStream ){ /* Install the file:// stream */ ph7_vm_config(pVm,PH7_VM_CONFIG_IO_STREAM,pFileStream); } #else SXUNUSED(pVm); /* cc warning */ #endif /* PH7_DISABLE_BUILTIN_FUNC */ return SXRET_OK; } /* * Export the STDIN handle. */ PH7_PRIVATE void * PH7_ExportStdin(ph7_vm *pVm) { #ifndef PH7_DISABLE_BUILTIN_FUNC #ifndef PH7_DISABLE_DISK_IO if( pVm->pStdin == 0 ){ io_private *pIn; /* Allocate an IO private instance */ pIn = (io_private *)SyMemBackendAlloc(&pVm->sAllocator,sizeof(io_private)); if( pIn == 0 ){ return 0; } InitIOPrivate(pVm,&sPHP_Stream,pIn); /* Initialize the handle */ pIn->pHandle = PHPStreamDataInit(pVm,PH7_IO_STREAM_STDIN); /* Install the STDIN stream */ pVm->pStdin = pIn; return pIn; }else{ /* NULL or STDIN */ return pVm->pStdin; } #else return 0; #endif #else SXUNUSED(pVm); /* cc warning */ return 0; #endif } /* * Export the STDOUT handle. */ PH7_PRIVATE void * PH7_ExportStdout(ph7_vm *pVm) { #ifndef PH7_DISABLE_BUILTIN_FUNC #ifndef PH7_DISABLE_DISK_IO if( pVm->pStdout == 0 ){ io_private *pOut; /* Allocate an IO private instance */ pOut = (io_private *)SyMemBackendAlloc(&pVm->sAllocator,sizeof(io_private)); if( pOut == 0 ){ return 0; } InitIOPrivate(pVm,&sPHP_Stream,pOut); /* Initialize the handle */ pOut->pHandle = PHPStreamDataInit(pVm,PH7_IO_STREAM_STDOUT); /* Install the STDOUT stream */ pVm->pStdout = pOut; return pOut; }else{ /* NULL or STDOUT */ return pVm->pStdout; } #else return 0; #endif #else SXUNUSED(pVm); /* cc warning */ return 0; #endif } /* * Export the STDERR handle. */ PH7_PRIVATE void * PH7_ExportStderr(ph7_vm *pVm) { #ifndef PH7_DISABLE_BUILTIN_FUNC #ifndef PH7_DISABLE_DISK_IO if( pVm->pStderr == 0 ){ io_private *pErr; /* Allocate an IO private instance */ pErr = (io_private *)SyMemBackendAlloc(&pVm->sAllocator,sizeof(io_private)); if( pErr == 0 ){ return 0; } InitIOPrivate(pVm,&sPHP_Stream,pErr); /* Initialize the handle */ pErr->pHandle = PHPStreamDataInit(pVm,PH7_IO_STREAM_STDERR); /* Install the STDERR stream */ pVm->pStderr = pErr; return pErr; }else{ /* NULL or STDERR */ return pVm->pStderr; } #else return 0; #endif #else SXUNUSED(pVm); /* cc warning */ return 0; #endif }