#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <types.h>
#include <stat.h>
#include <assert.h>
#include <unistd.h>
#include "symdir.h"

/*
 * make a symbolic link named 'new' to the file named 'old'
 */

int
symlink(old, new)
	char *old, *new;
{
	char linkpath[FILENAME_MAX];
	char *name;
	SYMDIR *dir;
	SYMENTRY *d;
	char *s;
	int r, save_errno;

/* Problem: to TOS, "Makefile", "Makefile", and "makefilefoo" are all
 * identical. Fortunately, _unx2dos can distinguish them, and
 * returns _NM_CHANGE for names that are not "canonical" (_NM_OK
 * means a normal file, _NM_LINK means an existing symbolic link).
 * So if _unx2dos returns _NM_OK, and access finds the file, then
 * it already exists; if _unx2dos returns _NM_LINK, the file already
 * exists as a symbolic link (access would work in this case, but
 * is redundant).
 */

        save_errno = errno;
	r = _unx2dos(new, linkpath);
	if ((r == _NM_LINK) || (r == _NM_OK) && !access(new, 0)) {
		errno = EEXIST;
		return -1;
	}
	errno = save_errno;

/*
 * find the name (from the original path in "new"), and the canonical form
 * of the path to it (from what _unx2dos just gave us)
 */

	name = new;
	for (s = new; *s; s++) {
		if (*s == '\\' || (_tSLASH && *s == '/'))
			name = s+1;
	}
	if ((s = strrchr(linkpath, '\\'))) {
		*s = 0;
	}
/*
 * now get the directory information
 */
	dir = _read_symdir(linkpath);
	if (!dir) {
		/* errno was already set */
		return -1;
	}

	d = (SYMENTRY *)
		malloc(sizeof(SYMENTRY)+strlen(old)+strlen(name)+2);
	if (d == 0) {
		errno = ENOMEM;
		return -1;
		_free_symdir(dir);
	}
	strcpy(d->linkname, name);
	for (s = d->linkname; *s; s++)
		;
	d->flags = 0;
	d->cflags = s;	/* an empty string */
	++s;
	d->linkto = s;
	strcpy(s, old);
	d->next = dir->s_dir;
	dir->s_dir = d;
	r = _write_symdir(linkpath, dir);
	_free_symdir(dir);
	if (r) {
		errno = -r;
		return -1;
	}
	return 0;
}

/*
 * read a symbolic link
 */

int
readlink(filename, linkto, siz)
	char *filename, *linkto;
	int siz;
{
	char tmp[FILENAME_MAX], linkpath[FILENAME_MAX], *s, *lastslash = 0;
	SYMDIR *dir;
	SYMENTRY *ent;
        size_t len;

	strcpy(tmp, filename);
	for (s = tmp; *s; s++) {
		if (*s == '\\' || (_tSLASH && (*s == '/')))
			lastslash = s;
	}
        if (lastslash==tmp) {
            lastslash++;
            _unx2dos("/",linkpath);
        } else if (lastslash) {
		*lastslash++ = 0;
		_unx2dos(tmp, linkpath);
	}
	else {
		lastslash = tmp;
		_unx2dos(".", linkpath);
	}
	if (!(dir = _read_symdir(linkpath))) {
		errno = EPATH;
		return -1;
	}
	if (!(ent = _symdir_lookup(dir, lastslash))) {
		_free_symdir(dir);
		errno = ENOENT;
		return -1;
	}
	strncpy(linkto, ent->linkto, siz);

        /* must get length right */
        len=strlen(ent->linkto);
        if (len>siz) {
           len=siz;
        }
	_free_symdir(dir);
	return len;
}
