archie/prospero/lib/pfs/ul_insert.c
2024-05-27 16:13:40 +02:00

166 lines
5.8 KiB
C

/*
* Copyright (c) 1989, 1990 by the University of Washington
* Copyright (c) 1993 by the University of Southern California
*
* For copying and distribution information, please see the files
* <uw-copyright.h> and <usc-copyr.h>
*/
#include <uw-copyright.h>
#include <usc-copyr.h>
#include <stdio.h>
#include <pfs.h>
#include <perrno.h>
/*
* ul_insert - Insert a union link at the right location
*
* UL_INSERT takes a directory and a union link to be added
* to a the list of union links in the directory. It then
* inserts the union link in the right spot in the linked
* list of union links associated with that directory.
*
* If an identical link already exists, then the link which
* would be evaluated earlier (closer to the front of the list)
* wins and the other one is freed. If this happens, an error
* will also be returned.
*
* If a union link agrees with another link in all respects except for NAME
* and p is set to a vlink, then the link is tagged with ULINK_DONT_EXPAND.
* This is only used on the server.
*
* ARGS: ul - link to be inserted
* vd - directory to get link
* p - vl that this link will apper after
* NULL - This vl will go at end of list
* vd - This vl will go at head of list
*
* RETURNS: Success, or UL_INSERT_ALREADY_THERE or UL_INSERT_SUPERSEDING
*/
int
ul_insert(ul,vd,p)
VLINK ul; /* Link to be inserted or freed */
VDIR vd; /* Directory to receive link */
VLINK p; /* Union link to appear prior to new one */
{
VLINK current;
static ul_comp(VLINK vl1,VLINK vl2);
static ul_other_fields_equal(VLINK ul1, VLINK ul2);
/* Either (a) This is the first ul in the directory,
or (b) we are supposed to insert at the end anyway. */
if(vd->ulinks == NULL || p == NULL) {
APPEND_ITEM(ul, vd->ulinks);
return(PSUCCESS);
}
/* This ul will go at the head of the list */
if(p == (VLINK) vd) {
ul->next = vd->ulinks;
ul->previous = ( (ul->next) ? ul->next->previous : ul);
ul->next->previous = ul;
vd->ulinks = ul;
}
/* Otherwise, decide if it must be inserted at all */
/* If an identical link appears before the position */
/* at which the new one is to be inserted, we can */
/* return without inserting it */
else {
for(current = vd->ulinks; current; current = current->next) {
if(ul_comp(current,ul) == 0) {
if (current->expanded == ULINK_PLACEHOLDER) {
/* Remove the matching link. This isn't really necessary,
but it's a harmless efficiency hack. */
EXTRACT_ITEM(current, vd->ulinks);
vlfree(current);
/* Stick on the new link, but don't expand it. */
ul->expanded = ULINK_DONT_EXPAND;
APPEND_ITEM(ul, vd->ulinks);
return PSUCCESS;
}
if (ul_other_fields_equal(ul, current)) {
/* If the two links have the same link name */
vlfree(ul);
return(UL_INSERT_ALREADY_THERE);
} else {
/* different link names; might need to return both in a
directory listing. */
ul->expanded = ULINK_DONT_EXPAND;
APPEND_ITEM(ul, vd->ulinks);
return PSUCCESS;
}
}
if(current == p) break;
}
/* If current is null, p was not found */
if(current == NULL) {
vlfree(ul);
return(UL_INSERT_POS_NOTFOUND);
}
/* Insert ul */
ul->next = p->next;
p->next = ul;
ul->previous = p;
if(ul->next)
ul->next->previous = ul;
else /* appending at end of list */
vd->ulinks->previous = ul;
}
/* Check for matching links after ul. */
for(current = ul->next; current; current = current->next) {
if (ul_comp(current, ul) == 0) {
/* Don't expand both ulinks. If neither expanded yet, give first
one priority. */
if (current->expanded) ul->expanded = ULINK_DONT_EXPAND;
else current->expanded = ULINK_DONT_EXPAND;
/* Placeholder union links are always superseded. */
if (current->expanded == ULINK_PLACEHOLDER ) {
EXTRACT_ITEM(current, vd->ulinks);
vlfree(current);
return PSUCCESS;
}
if (ul_other_fields_equal(ul, current)) {
/* If the two links have the same link name, remove the
matching link */
EXTRACT_ITEM(current, vd->ulinks);
vlfree(current);
return(UL_INSERT_SUPERSEDING);
}
}
}
return PSUCCESS;
}
/* Like VL_COMP, but only compares the fields that matter when you're expanding
the union link (i.e., doesn't care about 'name') . */
static int
ul_comp(VLINK ul1,VLINK ul2)
{
int retval;
retval = strcmp(ul1->hosttype,ul2->hosttype);
if(!retval) retval = strcmp(ul1->host,ul2->host);
if(!retval) retval = strcmp(ul1->hsonametype,ul2->hsonametype);
if(!retval) retval = strcmp(ul1->hsoname,ul2->hsoname);
return(retval);
}
/* This assumes a ul_comp returned 0. Tests other particulars to see whether
two links should be included in a listing (currently just name)
*/
static int
ul_other_fields_equal(VLINK ul1, VLINK ul2)
{
if ((!ul1->name && !ul2->name)
|| strequal(ul1->name, ul2->name))
return TRUE; /* should we test other fields? */
return FALSE;
}