php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #20235 unlink deletes file instead of symlink to file
Submitted: 2002-11-03 22:16 UTC Modified: 2002-11-03 23:19 UTC
From: bonebakker at attbi dot com Assigned:
Status: Closed Package: Filesystem function related
PHP Version: 4.2.3 OS: Solaris 9
Private report: No CVE-ID: None
 [2002-11-03 22:16 UTC] bonebakker at attbi dot com
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.


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2002-11-03 23:19 UTC] iliaa@php.net
This bug has been fixed in CVS.

In case this was a PHP problem, snapshots of the sources are packaged
every three hours; this change will be in the next snapshot. You can
grab the snapshot at http://snaps.php.net/.
 
In case this was a documentation problem, the fix will show up soon at
http://www.php.net/manual/.

In case this was a PHP.net website problem, the change will show
up on the PHP.net site and on the mirror sites in short time.
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 16:01:29 2024 UTC