#include #include #include #include #include #include #include #include #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; }