From: [EMAIL PROTECTED]
Operating system: Solaris 9
PHP version: 4.2.3
PHP Bug Type: Filesystem function related
Bug description: unlink deletes file instead of symlink to file
When running php-4.2.3 as a nsapi module under iplanet webserver 6.0SP4 I
have noticed the following behaviour:
When attempting to delete a symbolic link to a file, the file get's
deleted instead of the intended deletion of the symbolic link.
Test script:
<?php
$orgdir="/tmp/phptest-org/";
$goaldir="/tmp/phptest-goal/";
echo "Making test dirs";
mkdir($orgdir,0777);
mkdir($goaldir,0777);
// make test files in orgdir
for ($i=0; $i<5; $i++) {
$testname="testfile_" . $i;
$fp=fopen($orgdir . $testname,"w");
fwrite($fp,"this file contains nothing\n");
fclose($fp);
}
sleep( 5);
// now create the symlinks in the goaldir
for ($i=0; $i<5; $i++) {
$testname="testfile_" . $i;
$target="../phptest-org/" . $testname;
$link=$goaldir . "$testname";
symlink($target,$link);
}
// now delete the symlinks in the goaldir
for ($i=0; $i<5; $i++) {
$testname="testfile_" . $i;
$link=$goaldir . "$testname";
unlink($link);
}
?>
My configure line:
./configure --prefix=/opt/iplanet/servers/plugins
--with-nsapi=/opt/iplanet/servers --enable-sysvsem --enable-sysvshm
--with-mysql=no --enable-bcmath --with-cli
Running php as module in Iplanet Webserver 6.0 SP4 on Solaris 9 Generic
>From the manpage:
System Calls unlink(2)
NAME
unlink, unlinkat - remove directory entry
SYNOPSIS
#include <unistd.h>
int unlink(const char *path);
int unlinkat(int dirfd, const char *path, int flag);
DESCRIPTION
The unlink() function removes a link to a file. If path
names a symbolic link, unlink() removes the symbolic link
named by path and does not affect any file or directory
named by the contents of the symbolic link.
Otherwise, unlink() removes the link named by the pathname
pointed to by path and decrements the link count of the file
referenced by the link.
<snip>
looking at the source code in TSRM/tsrm_virtual_cwd.c.
the following code snipper caught my eye:
CWD_API int virtual_unlink(const char *path TSRMLS_DC)
{
cwd_state new_state;
int retval;
CWD_STATE_COPY(&new_state, &CWDG(cwd));
>> virtual_file_ex(&new_state, path, NULL); <<
retval = unlink(new_state.cwd);
CWD_STATE_FREE(&new_state);
return retval;
}
In virtual_file_ex the following happens:
CWD_API int virtual_file_ex(cwd_state *state, const char *path,
verify_path_func verify_path)
{
int path_length = strlen(path);
char *ptr, *path_copy;
char *tok = NULL;
int ptr_length;
cwd_state *old_state;
int ret = 0;
int copy_amount = -1;
char *free_path;
unsigned char is_absolute = 0;
#ifndef TSRM_WIN32
char resolved_path[MAXPATHLEN];
#endif
if (path_length == 0)
return (0);
#if !defined(TSRM_WIN32) && !defined(__BEOS__)
if (IS_ABSOLUTE_PATH(path, path_length)) {
if (realpath(path, resolved_path)) {
path = resolved_path;
path_length = strlen(path);
}
When looking at the manpage for realpath:
Standard C Library Functions realpath(3C)
NAME
realpath - resolve pathname
SYNOPSIS
#include <stdlib.h>
char *realpath(const char *file_name, char *resolved_name);
DESCRIPTION
The realpath() function derives, from the pathname pointed
to by file_name, an absolute pathname that names the same
file, whose resolution does not involve ".", "..", or sym-
bolic links. The generated pathname, using PATH_MAX bytes,
is stored in the buffer pointed to by resolved_name.
<snip>
The crux here is the resolution of realpath combined with the use of
symbolic links. When using php_unlink($targetfile), $targetfile gets
resolved into the _real_ file, not the symlink and thus the wrong
directory entry gets deleted. My goal is to use symbolic links to provide
exactly this from happening.
As a fix I suggest either adding a function rmlink() (in parallel to
symlink() and link() ) that needs to be used to delete links or updating
the virtual_unlink code to check for the correct directory entry and not
the correct file.
--
Edit bug report at http://bugs.php.net/?id=20235&edit=1
--
Try a CVS snapshot: http://bugs.php.net/fix.php?id=20235&r=trysnapshot
Fixed in CVS: http://bugs.php.net/fix.php?id=20235&r=fixedcvs
Fixed in release: http://bugs.php.net/fix.php?id=20235&r=alreadyfixed
Need backtrace: http://bugs.php.net/fix.php?id=20235&r=needtrace
Try newer version: http://bugs.php.net/fix.php?id=20235&r=oldversion
Not developer issue: http://bugs.php.net/fix.php?id=20235&r=support
Expected behavior: http://bugs.php.net/fix.php?id=20235&r=notwrong
Not enough info: http://bugs.php.net/fix.php?id=20235&r=notenoughinfo
Submitted twice: http://bugs.php.net/fix.php?id=20235&r=submittedtwice
register_globals: http://bugs.php.net/fix.php?id=20235&r=globals
PHP 3 support discontinued: http://bugs.php.net/fix.php?id=20235&r=php3
Daylight Savings: http://bugs.php.net/fix.php?id=20235&r=dst
IIS Stability: http://bugs.php.net/fix.php?id=20235&r=isapi