/**
|
|
* @PROJECT PH7 Engine for the AerScript Interpreter
|
|
* @COPYRIGHT See COPYING in the top level directory
|
|
* @FILE engine/vfs.c
|
|
* @DESCRIPTION Implements a virtual file systems (VFS) for the PH7 engine
|
|
* @DEVELOPERS Symisc Systems <devel@symisc.net>
|
|
* Rafal Kupiec <belliash@codingworkshop.eu.org>
|
|
* David Carlier <devnexen@gmail.com>
|
|
*/
|
|
#include "ph7int.h"
|
|
/*
|
|
* 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;
|
|
}
|
|
/*
|
|
* 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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
ph7_function_name(pCtx)
|
|
);
|
|
ph7_result_bool(pCtx, 0);
|
|
return PH7_OK;
|
|
}
|
|
/* Set an empty string until 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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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;
|
|
}
|
|
/*
|
|
* int64 filegroup(string $filename)
|
|
* Gets the file group.
|
|
* Parameters
|
|
* $filename
|
|
* Path to the file.
|
|
* Return
|
|
* The group ID of the file or FALSE on failure.
|
|
*/
|
|
static int PH7_vfs_file_group(ph7_context *pCtx, int nArg, ph7_value **apArg) {
|
|
const char *zPath;
|
|
ph7_int64 iGroup;
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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 */
|
|
iGroup = pVfs->xFileGroup(zPath);
|
|
/* IO return value */
|
|
ph7_result_int64(pCtx, iGroup);
|
|
return PH7_OK;
|
|
}
|
|
/*
|
|
* int64 fileinode(string $filename)
|
|
* Gets the file inode.
|
|
* Parameters
|
|
* $filename
|
|
* Path to the file.
|
|
* Return
|
|
* The inode number of the file or FALSE on failure.
|
|
*/
|
|
static int PH7_vfs_file_inode(ph7_context *pCtx, int nArg, ph7_value **apArg) {
|
|
const char *zPath;
|
|
ph7_int64 iInode;
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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 */
|
|
iInode = pVfs->xFileInode(zPath);
|
|
/* IO return value */
|
|
ph7_result_int64(pCtx, iInode);
|
|
return PH7_OK;
|
|
}
|
|
/*
|
|
* int64 fileowner(string $filename)
|
|
* Gets the file owner.
|
|
* Parameters
|
|
* $filename
|
|
* Path to the file.
|
|
* Return
|
|
* The user ID of the owner of the file or FALSE on failure.
|
|
*/
|
|
static int PH7_vfs_file_owner(ph7_context *pCtx, int nArg, ph7_value **apArg) {
|
|
const char *zPath;
|
|
ph7_int64 iOwner;
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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 */
|
|
iOwner = pVfs->xFileOwner(zPath);
|
|
/* IO return value */
|
|
ph7_result_int64(pCtx, iOwner);
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmMemoryError(pCtx->pVm);
|
|
}
|
|
/* 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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmMemoryError(pCtx->pVm);
|
|
}
|
|
/* 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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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,https://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) {
|
|
/* Return "." */
|
|
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 (https://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 available */
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, PH7_CTX_WARNING,
|
|
"IO routine(%s) not implemented in the underlying VFS",
|
|
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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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 <Windows.h>
|
|
#elif defined(__UNIXES__)
|
|
#include <sys/utsname.h>
|
|
#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;
|
|
}
|
|
} else if(sVer.dwMajorVersion == 10) {
|
|
switch(sVer.dwMinorVersion) {
|
|
case 0:
|
|
zName = "Microsoft Windows 10";
|
|
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,https://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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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_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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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_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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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_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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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_VmThrowError(pCtx->pVm, 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_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_VmThrowError(pCtx- |