amiga-ixemul/general/getwd.c

276 lines
5.8 KiB
C

/*
* This file is part of ixemul.library for the Amiga.
* Copyright (C) 1991, 1992 Ray Burr
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Written and Copyright by Ray Burr.
* Put under the GNU Library General Public License.
* Thanks Ray !
*/
#define _KERNEL
#include "ixemul.h"
#include "kprintf.h"
#include <string.h>
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
/* _GetPathFromLock - Given a pointer to an AmigaOS Lock structure, build
a rooted path string in a buffer of a given size. The buffer should be
at least 'buffer_length' bytes. Returns a pointer to the result
or NULL on an error. 'errno' will be set in the case of an error. This
function returns the path string based at 'buffer[0]' but it can alter
any part of the buffer. */
static char *
_GetPathFromLock (BPTR lock, char *buffer, int buffer_length)
{
usetup;
char *p;
BPTR fl, next_fl;
int length;
struct FileInfoBlock *fib;
int omask;
char *result = 0;
/* Allocate space on stack for fib. */
BYTE fib_Block[sizeof (struct FileInfoBlock) + 2];
/* Make sure fib is longword aligned. */
fib = (struct FileInfoBlock *) fib_Block;
if (((ULONG) fib & 0x02) != 0)
fib = (struct FileInfoBlock *) ((ULONG) fib + 2);
p = 0L;
/* Duplicate the lock so that the directory structure can't change
while we're doing this. */
omask = syscall (SYS_sigsetmask, ~0);
fl = DupLock (lock);
/* Follow the chain of directories and build the name in 'buffer' */
while (fl != 0L)
{
if (Examine (fl, fib) == DOSFALSE)
{
errno = __ioerr_to_errno(IoErr());
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
UnLock (fl);
goto ret;
}
next_fl = ParentDir (fl);
UnLock (fl);
if (p != 0L)
{
if (next_fl != 0L)
*--p = '/';
else
*--p = ':';
}
else
{
p = buffer + buffer_length - 1; /* fix 20-jan-92 ## mw */
*p = '\0';
if (next_fl == 0L)
*--p = ':';
}
length = strlen (fib->fib_FileName);
p -= length;
if (p <= buffer)
{
if (next_fl != 0L)
UnLock (next_fl);
/* Remember to set errno! - Piru */
errno = ERANGE;
goto ret;
}
bcopy (fib->fib_FileName, p, length);
fl = next_fl;
}
/* Move the pathname so that it starts at buffer[0]. */
bcopy (p, buffer, strlen (p) + 1);
result = buffer;
ret:
syscall (SYS_sigsetmask, omask);
return result;
}
static char *
_get_pwd (char *buffer, int buffer_length)
{
usetup;
struct Process *proc;
char *result, *colon;
extern char *index (const char *, int);
if (u.u_is_root)
{
if (buffer_length < 2)
{
errno = ERANGE;
return 0L;
}
strcpy(buffer, "/");
return buffer;
}
proc = (struct Process *) SysBase->ThisTask;
/* Just return an empty string if this is not a process. */
if (proc == 0L || proc->pr_Task.tc_Node.ln_Type != NT_PROCESS)
{
if (buffer_length < 2)
{
errno = ERANGE;
return 0L;
}
buffer[0] = '\0';
return buffer;
}
/* make room for slash */
if (ix.ix_flags & ix_translate_slash)
{
if (buffer_length < 1)
{
errno = ERANGE;
return 0L;
}
buffer++;
/* 6-Aug-2003 bugfix: MUST sub the size by one, too, or else we
* could trash innocent memory. - Piru
*/
buffer_length--;
}
/* try NameFromLock first as GetCurrentDirName is limited by
CommandLineInterface size. - Piru */
if (NameFromLock(proc->pr_CurrentDir, buffer, buffer_length) ||
GetCurrentDirName (buffer, buffer_length))
{
result = buffer;
}
else
{
/* and as the last chance resort to the 1.3 algorithm */
result = _GetPathFromLock(proc->pr_CurrentDir, buffer, buffer_length);
}
#if 1
/* hack, convert "Ram Disk:" -> "RAM:" */
if (result && !strncasecmp(result, "Ram Disk:", 9))
{
memcpy(result, "RAM:", 4);
bcopy(result + 9, result + 4, strlen(result + 9) + 1);
}
#endif
if ((ix.ix_flags & ix_translate_slash) && result)
{
colon = index (result, ':');
if (colon)
{
*colon = '/';
result--;
result[0] = '/';
return result;
}
bcopy (result, result - 1, strlen (result) + 1);
return result - 1;
}
if (!result && IoErr() == ERROR_LINE_TOO_LONG)
{
errno = ERANGE;
}
return result;
}
char *
getwd (char *buffer)
{
usetup;
char *path;
path = _get_pwd (buffer, MAXPATHLEN);
if (path == 0L)
{
strcpy (buffer, "getwd - ");
strcat (buffer, strerror (errno));
return 0L;
}
return path;
}
char *
getcwd (char *buffer, size_t buffer_length)
{
usetup;
if (buffer == 0L)
{
if (buffer_length == 0)
{
/* Lame implementation of this extension, feel free to improve. */
buffer_length = 254;
}
/* Could be buffer_length as is IMO - Piru */
buffer = (char *) syscall (SYS_malloc, buffer_length + 2);
if (buffer == 0L)
{
errno = ENOMEM;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return 0L;
}
}
else
{
if (buffer_length == 0)
{
errno = EINVAL;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return 0L;
}
}
return _get_pwd (buffer, buffer_length);
}