mirror of
https://github.com/adtools/clib2.git
synced 2026-05-02 10:16:27 +00:00
251 lines
6.0 KiB
C
251 lines
6.0 KiB
C
/*
|
|
* $Id: unistd_readlink.c,v 1.9 2006-11-13 09:25:28 obarthel Exp $
|
|
*
|
|
* :ts=4
|
|
*
|
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* - Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
|
* may be used to endorse or promote products derived from this
|
|
* software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef _STDLIB_NULL_POINTER_CHECK_H
|
|
#include "stdlib_null_pointer_check.h"
|
|
#endif /* _STDLIB_NULL_POINTER_CHECK_H */
|
|
|
|
/****************************************************************************/
|
|
|
|
#ifndef _UNISTD_HEADERS_H
|
|
#include "unistd_headers.h"
|
|
#endif /* _UNISTD_HEADERS_H */
|
|
|
|
#ifndef _STAT_HEADERS_H
|
|
#include "stat_headers.h"
|
|
#endif /* _STAT_HEADERS_H */
|
|
|
|
/****************************************************************************/
|
|
|
|
/* The following is not part of the ISO 'C' (1994) standard. */
|
|
|
|
/****************************************************************************/
|
|
|
|
int
|
|
readlink(const char * path_name, char * buffer, int buffer_size)
|
|
{
|
|
#if defined(UNIX_PATH_SEMANTICS)
|
|
struct name_translation_info path_name_nti;
|
|
struct name_translation_info buffer_nti;
|
|
#endif /* UNIX_PATH_SEMANTICS */
|
|
|
|
D_S(struct bcpl_name, bname);
|
|
const size_t name_size = sizeof(bname->name);
|
|
|
|
BPTR lock = ZERO;
|
|
int result = ERROR;
|
|
struct DevProc *dvp = NULL;
|
|
char * new_name = NULL;
|
|
char * path_part;
|
|
size_t name_len;
|
|
size_t new_name_size;
|
|
LONG readlink_result;
|
|
LONG error;
|
|
|
|
ENTER();
|
|
|
|
SHOWSTRING(path_name);
|
|
SHOWPOINTER(buffer);
|
|
SHOWVALUE(buffer_size);
|
|
|
|
assert( path_name != NULL && buffer != NULL );
|
|
|
|
if (__check_abort_enabled)
|
|
__check_abort();
|
|
|
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
|
{
|
|
if (path_name == NULL || buffer == NULL)
|
|
{
|
|
SHOWSTRING("invalid parameters");
|
|
|
|
__set_errno(EFAULT);
|
|
goto out;
|
|
}
|
|
}
|
|
#endif /* CHECK_FOR_NULL_POINTERS */
|
|
|
|
#if defined(UNIX_PATH_SEMANTICS)
|
|
{
|
|
if (__unix_path_semantics)
|
|
{
|
|
if (path_name[0] == '\0')
|
|
{
|
|
SHOWMSG("no name given");
|
|
|
|
__set_errno(ENOENT);
|
|
goto out;
|
|
}
|
|
|
|
if (__translate_unix_to_amiga_path_name(&path_name, &path_name_nti) != 0)
|
|
goto out;
|
|
}
|
|
}
|
|
#endif /* UNIX_PATH_SEMANTICS */
|
|
|
|
name_len = strlen(path_name);
|
|
if (name_len >= name_size)
|
|
{
|
|
SHOWMSG("name too long");
|
|
|
|
SetIoErr(ERROR_LINE_TOO_LONG);
|
|
goto out;
|
|
}
|
|
|
|
/* Convert the name into a BCPL string. */
|
|
bname->name[0] = name_len;
|
|
memcpy(&bname->name[1], path_name, name_len);
|
|
|
|
/* Get a handle on the device, volume or assignment name in the path. */
|
|
dvp = GetDeviceProc((STRPTR)path_name, dvp);
|
|
if (dvp == NULL)
|
|
{
|
|
SHOWMSG("dvp == NULL");
|
|
goto out;
|
|
}
|
|
|
|
/* Try to obtain a lock on the object. It should be a link and not
|
|
* a file or directory.
|
|
*/
|
|
lock = DoPkt(dvp->dvp_Port, ACTION_LOCATE_OBJECT, dvp->dvp_Lock, MKBADDR(bname), SHARED_LOCK, 0, 0);
|
|
if (lock != ZERO)
|
|
{
|
|
SHOWMSG("lock != ZERO");
|
|
|
|
SetIoErr(ERROR_OBJECT_WRONG_TYPE);
|
|
goto out;
|
|
}
|
|
|
|
error = IoErr();
|
|
|
|
if (error != ERROR_IS_SOFT_LINK)
|
|
{
|
|
SHOWMSG("not a soft link");
|
|
goto out;
|
|
}
|
|
|
|
/* We only need the leading path name. */
|
|
name_len = ((BYTE *)PathPart(path_name)) - (BYTE *)path_name;
|
|
|
|
path_part = malloc(name_len+1);
|
|
if (path_part == NULL)
|
|
{
|
|
SHOWMSG("path_part too long");
|
|
|
|
SetIoErr(ERROR_NO_FREE_STORE);
|
|
goto out;
|
|
}
|
|
|
|
memcpy(path_part, path_name, name_len);
|
|
path_part[name_len] = '\0';
|
|
|
|
PROFILE_OFF();
|
|
lock = Lock((STRPTR)path_part, SHARED_LOCK);
|
|
PROFILE_ON();
|
|
|
|
new_name_size = name_size+1;
|
|
|
|
/* Provide as much buffer space as possible. */
|
|
if (buffer_size > 0 && (size_t)buffer_size > new_name_size)
|
|
new_name_size = buffer_size;
|
|
|
|
/* For soft link resolution we need a temporary buffer to
|
|
let the file system store the resolved path name in. */
|
|
new_name = malloc(new_name_size);
|
|
if (new_name == NULL)
|
|
{
|
|
SHOWMSG("new_name too long");
|
|
|
|
SetIoErr(ERROR_NO_FREE_STORE);
|
|
goto out;
|
|
}
|
|
|
|
/* Now ask the file system to resolve the entire path. */
|
|
readlink_result = ReadLink(dvp->dvp_Port, lock, (STRPTR)FilePart(path_name), (STRPTR)new_name, (LONG)new_name_size);
|
|
if (readlink_result < 0)
|
|
{
|
|
SHOWMSG("ReadLink");
|
|
|
|
/* This will return either -1 (resolution error) or -2
|
|
(buffer too small). We regard both as trouble. */
|
|
SetIoErr(ERROR_INVALID_COMPONENT_NAME);
|
|
goto out;
|
|
}
|
|
|
|
assert( result > 0 );
|
|
|
|
/* If the caller supplied a buffer, copy as much of the name
|
|
as possible into it. */
|
|
if (buffer != NULL && buffer_size > 0)
|
|
{
|
|
strlcpy(buffer, new_name, buffer_size);
|
|
|
|
#if defined(UNIX_PATH_SEMANTICS)
|
|
{
|
|
if (__unix_path_semantics)
|
|
{
|
|
if (__translate_amiga_to_unix_path_name((char const **)&buffer, &buffer_nti) != 0)
|
|
goto out;
|
|
|
|
__restore_path_name((char const **)&buffer,&buffer_nti);
|
|
|
|
strcpy(buffer, buffer_nti.substitute);
|
|
}
|
|
}
|
|
#endif /* UNIX_PATH_SEMANTICS */
|
|
|
|
result = strlen(buffer);
|
|
|
|
SHOWSTRING(buffer);
|
|
}
|
|
else
|
|
{
|
|
result = 0;
|
|
}
|
|
|
|
out:
|
|
|
|
PROFILE_OFF();
|
|
|
|
if (dvp != NULL)
|
|
FreeDeviceProc(dvp);
|
|
|
|
UnLock(lock);
|
|
|
|
PROFILE_ON();
|
|
|
|
RETURN(result);
|
|
|
|
return result;
|
|
}
|