/***************************************************************************/
/***************************************************************************/
/* */
/* (c) 1995-1999. The Regents of the University of California. All */
/* rights reserved. */
/* */
/* This work was produced at the University of California, Lawrence */
/* Livermore National Laboratory (UC LLNL) under contract no. */
/* W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy */
/* (DOE) and The Regents of the University of California (University) */
/* for the operation of UC LLNL. Copyright is reserved to the */
/* University for purposes of controlled dissemination, */
/* commercialization through formal licensing, or other disposition */
/* under terms of Contract 48; DOE policies, regulations and orders; */
/* and U.S. statutes. The rights of the Federal Government are */
/* reserved under Contract 48 subject to the restrictions agreed upon */
/* by the DOE and University. */
/* */
/* */
/* DISCLAIMER */
/* */
/* This software was prepared as an account of work sponsored by an */
/* agency of the United States Government. Neither the United States */
/* Government nor the University of California nor any of their */
/* employees, makes any warranty, express or implied, or assumes any */
/* liability or responsibility for the accuracy, completeness, or */
/* usefulness of any information, apparatus, product, or process */
/* disclosed, or represents that its specific commercial products, */
/* process, or service by trade name, trademark, manufacturer, or */
/* otherwise, does not necessarily constitute or imply its */
/* endorsement, recommendation, or favoring by the United States */
/* Government or the University of California. The views and opinions */
/* of the authors expressed herein do not necessarily state or reflect */
/* those of the United States Government or the University of */
/* California, and shall not be used for advertising or product */
/* endorsement purposes. */
/* */
/* Permission to use, copy, modify and distribute this software and its */
/* documentation for any non-commercial purpose, without fee, is */
/* hereby granted, provided that the above copyright notice and this */
/* permission notice appear in all copies of the software and */
/* supporting documentation, and that all UC LLNL identification in */
/* the user interface remain unchanged. The title to copyright LLNL */
/* XDIR shall at all times remain with The Regents of the University */
/* of California and users agree to preserve same. Users seeking the */
/* right to make derivative works with LLNL XDIR for commercial */
/* purposes may obtain a license from the Lawrence Livermore National */
/* Laboratory's Technology Transfer Office, P.O. Box 808, L-795, */
/* Livermore, CA 94550. */
/* */
/***************************************************************************/
/***************************************************************************/
#include <Xm/Xm.h>
#include "xdir.h"
#include "list.h"
#define BYTES_PER_KB 1024
#define DIRLIST 0
#define TRUEPATH 1
struct hostuser_st {
struct hostuser_st *next;
char *hostname;
char *username;
};
struct dirlist_part {
int layout;
int dotfiles;
int count;
char *list;
};
struct mapping_part {
char *true_path;
};
struct cache_link {
struct cache_link *prev;
struct cache_link *next;
struct hostuser_st *hostuser;
char *path;
long len;
int type;
union {
struct dirlist_part d;
struct mapping_part m;
} part;
};
static struct hostuser_st *head_hostuser = NULL;
static struct cache_link *head = NULL;
static struct cache_link *tail = NULL;
static long cache_len = 0;
extern int max_dir_cache_len;
extern struct st_host_info hinfo[];
extern int diagnostics;
void free_cache_entry();
void report_cache_addition();
void report_cache_deletion();
void report_cache_truepath_hit();
void report_cache_dirlist_hit();
void check_max_cache_len();
/*
* insert_at_cache_head - Insert the cache entry pointed by "ptr" at the
* head of the cache.
*/
void
insert_at_cache_head(ptr)
struct cache_link *ptr;
{
ptr->next = head;
ptr->prev = NULL;
if (head)
head->prev = ptr;
head = ptr;
if (!tail)
tail = ptr;
}
/*
* make_room_in_cache - Free up the least recently used cache entries
* to create enough space for a directory list
* "len" bytes in length. Returns True if successful,
* else False.
*/
make_room_in_cache(len)
long len;
{
long bytes_available = max_dir_cache_len*BYTES_PER_KB-cache_len;
/* No hope if entry is bigger than entire cache */
if (len > max_dir_cache_len*BYTES_PER_KB)
return False;
/* Delete least recently used entries until there is enough room */
while (head && (bytes_available<len)) {
bytes_available += tail->len;
free_cache_entry(tail);
}
/* Sanity check */
if (len > bytes_available)
fatal_error("Bug in make_room_in_cache()");
/* Looks good */
return True;
}
/*
* free_cache_entry - Free the cache entry pointed to by "ptr". This
* function is a no-op if "ptr" is NULL.
*/
void
free_cache_entry(ptr)
struct cache_link *ptr;
{
/* No-op if pointer is NULL */
if (!ptr)
return;
/* Debug edit */
report_cache_deletion(ptr);
/* Adjust cache len */
cache_len -= ptr->len;
/* Free the entry's fields */
XtFree(ptr->path);
switch (ptr->type) {
case DIRLIST:
XtFree(ptr->part.d.list);
break;
case TRUEPATH:
XtFree(ptr->part.m.true_path);
}
/* Now remove the entry from the doubly-linked list */
if (ptr->prev)
ptr->prev->next = ptr->next;
else
head = ptr->next;
if (ptr->next)
ptr->next->prev = ptr->prev;
else
tail = ptr->prev;
XtFree((char *)ptr);
}
/*
* find_dirlist_in_cache - Return a pointer to the link in the cache
* that contains the directory list that is
* uniquely specified by the arguments. If
* there is no hit, return NULL.
*/
struct cache_link *
find_dirlist_in_cache(host, path, layout, dotfiles)
int host;
char *path;
int layout;
int dotfiles;
{
struct hostuser_st *hostuser = head_hostuser;
struct cache_link *ptr = head;
/* Find hostname/username pair */
while (hostuser) {
if (!strcmp(hinfo[host].hostname, hostuser->hostname) &&
(!strcmp(hinfo[host].username, hostuser->username)))
break;
hostuser = hostuser->next;
}
if (hostuser == NULL)
return NULL;
/* TREE layout is the same as ICONIC */
if (layout == TREE)
layout = ICONIC;
/* Search the cache for a match */
while (ptr) {
if ((ptr->type == DIRLIST) && (hostuser == ptr->hostuser) &&
!strcmp(path, ptr->path) && (layout == ptr->part.d.layout) &&
(dotfiles == ptr->part.d.dotfiles))
return ptr;
ptr = ptr->next;
}
return NULL;
}
/*
* find_path_in_cache - Return a pointer to the link in the cache
* that contains the directory mapping that is
* uniquely specified by the arguments. If
* there is no hit, return NULL.
*/
struct cache_link *
find_path_in_cache(host, path, type)
int host;
char *path;
int type;
{
struct hostuser_st *hostuser = head_hostuser;
struct cache_link *ptr = head;
/* Find hostname/username pair */
while (hostuser) {
if (!strcmp(hinfo[host].hostname, hostuser->hostname) &&
(!strcmp(hinfo[host].username, hostuser->username)))
break;
hostuser = hostuser->next;
}
if (hostuser == NULL)
return NULL;
/* Search the cache for an exact match */
while (ptr) {
if ((ptr->type == type) && (ptr->hostuser == hostuser) &&
!strcmp(ptr->path, path))
return ptr;
ptr = ptr->next;
}
return NULL;
}
/*
* find_truepath_in_cache - Return a pointer to the link in the cache
* that contains the specified path in the
* "true_path" field. If there is no hit,
* return NULL.
*/
struct cache_link *
find_truepath_in_cache(host, path)
int host;
char *path;
{
struct hostuser_st *hostuser = head_hostuser;
struct cache_link *ptr = head;
/* Find hostname/username pair */
while (hostuser) {
if (!strcmp(hinfo[host].hostname, hostuser->hostname) &&
(!strcmp(hinfo[host].username, hostuser->username)))
break;
hostuser = hostuser->next;
}
if (hostuser == NULL)
return NULL;
/* Search the cache for an exact match */
while (ptr) {
if ((ptr->type == TRUEPATH) && (ptr->hostuser == hostuser) &&
!strcmp(ptr->part.m.true_path, path))
return ptr;
ptr = ptr->next;
}
return NULL;
}
/*
* add_dirlist_to_cache - Add to the cache the directory list "dlist",
* which is uniquely specified by the other
* arguments.
*/
void
add_dirlist_to_cache(host, path, layout, dotfiles, dlist)
int host;
char *path;
int layout;
int dotfiles;
struct sl_struct *dlist;
{
struct hostuser_st *hostuser = head_hostuser;
long len;
long list_len;
int i;
int slen;
struct cache_link *ptr;
char *p;
/* Make sure that cache len is consistent with current max len */
check_max_cache_len();
/* Find hostname/username pair */
while (hostuser) {
if (!strcmp(hinfo[host].hostname, hostuser->hostname) &&
(!strcmp(hinfo[host].username, hostuser->username)))
break;
hostuser = hostuser->next;
}
if (hostuser == NULL) {
hostuser = XtNew(struct hostuser_st);
hostuser->hostname = XtNewString(hinfo[host].hostname);
hostuser->username = XtNewString(hinfo[host].username);
hostuser->next = head_hostuser;
head_hostuser = hostuser;
}
/* If directory is already in the cache, delete it */
free_cache_entry(find_dirlist_in_cache(host, path, layout, dotfiles));
/* Determine the length of the directory list (plus overhead) */
list_len = 0;
for (i=0; i<dlist->nentries; i++)
list_len += strlen(dlist->entries[i]);
list_len += dlist->nentries;
len = list_len+strlen(path)+sizeof(struct cache_link);
/* Make room for cache entry */
if (!make_room_in_cache(len))
return;
/* Create and initialize the cache entry */
ptr = XtNew(struct cache_link);
ptr->type = DIRLIST;
ptr->hostuser = hostuser;
ptr->path = XtNewString(path);
if (layout == TREE)
ptr->part.d.layout = ICONIC;
else
ptr->part.d.layout = layout;
ptr->part.d.dotfiles = dotfiles;
ptr->len = len;
ptr->part.d.count = dlist->nentries;
ptr->part.d.list = XtMalloc(len);
/* Now copy the actual directory entries */
p = ptr->part.d.list;
for (i=0; i<dlist->nentries; i++) {
slen = strlen(dlist->entries[i]);
bcopy(dlist->entries[i], p, slen+1);
p += slen+1;
}
/* Insert the entry at the head of the the cache */
insert_at_cache_head(ptr);
cache_len += ptr->len;
report_cache_addition();
}
/*
* add_truepath_to_cache - Add to the cache the directory mapping specified
* by the arguments.
*/
void
add_truepath_to_cache(host, path, true_path)
int host;
char *path;
char *true_path;
{
struct hostuser_st *hostuser = head_hostuser;
long len;
struct cache_link *ptr;
/* Make sure that cache len is consistent with current max len */
check_max_cache_len();
/* Find hostname/username pair */
while (hostuser) {
if (!strcmp(hinfo[host].hostname, hostuser->hostname) &&
(!strcmp(hinfo[host].username, hostuser->username)))
break;
hostuser = hostuser->next;
}
if (hostuser == NULL) {
hostuser = XtNew(struct hostuser_st);
hostuser->hostname = XtNewString(hinfo[host].hostname);
hostuser->username = XtNewString(hinfo[host].username);
hostuser->next = head_hostuser;
head_hostuser = hostuser;
}
/* If a mapping for "path" is already in the cache, delete it */
ptr = find_path_in_cache(host, path, TRUEPATH);
free_cache_entry(ptr);
/* Determine the length of the mapping (plus overhead) */
len = strlen(path)+strlen(true_path)+sizeof(struct cache_link);
/* Make room for cache entry */
if (!make_room_in_cache(len))
return;
/* Create and initialize the cache entry */
ptr = XtNew(struct cache_link);
ptr->type = TRUEPATH;
ptr->hostuser = hostuser;
ptr->path = XtNewString(path);
ptr->part.m.true_path = XtNewString(true_path);
ptr->len = len;
/* Insert the entry at the head of the the cache */
insert_at_cache_head(ptr);
cache_len += ptr->len;
report_cache_addition();
}
/*
* fetch_dirlist_from_cache - If the directory list uniquely specified
* by the input arguments exists in the cache,
* then this function sets "dlist" to a pointer
* to a structure that contains that directory
* list. Returns True if successful, else False.
*/
fetch_dirlist_from_cache(host, path, layout, dotfiles, dlist)
int host;
char *path;
int layout;
int dotfiles;
struct sl_struct **dlist;
{
struct cache_link *ptr;
int i;
int slen;
char *p;
/* Make sure that cache len is consistent with current max len */
check_max_cache_len();
/* Look for directory in cache */
if ((ptr = find_dirlist_in_cache(host, path, layout, dotfiles)) == NULL)
return False;
/* Move found directory to head of cache */
if (ptr->prev)
ptr->prev->next = ptr->next;
else
head = ptr->next;
if (ptr->next)
ptr->next->prev = ptr->prev;
else
tail = ptr->prev;
insert_at_cache_head(ptr);
/* Allocate list structure and fill it in */
*dlist = XtNew(struct sl_struct);
(*dlist)->nentries = ptr->part.d.count;
(*dlist)->entries = (char **)XtMalloc(sizeof(char *)*ptr->part.d.count);
p = ptr->part.d.list;
for (i=0; i<ptr->part.d.count; i++) {
slen = strlen(p)+1;
(*dlist)->entries[i] = XtMalloc(slen);
bcopy(p, (*dlist)->entries[i], slen);
p += slen;
}
report_cache_dirlist_hit();
return True;
}
/*
* fetch_truepath_from_cache - If the true path information specified by the
* input arguments exists in the cache, then
* this function sets "true_path" to a pointer
* to a string that contains the true directory
* path for "path". Returns True if successful,
* else False.
*/
fetch_truepath_from_cache(host, path, true_path)
int host;
char *path;
char **true_path;
{
struct cache_link *ptr;
/* Make sure that cache len is consistent with current max len */
check_max_cache_len();
/* First look for mapping in cache */
if ((ptr = find_path_in_cache(host, path, TRUEPATH)) == NULL)
if ((ptr = find_truepath_in_cache(host, path)) == NULL)
return False;
/* Move found mapping to head of cache */
if (ptr->prev)
ptr->prev->next = ptr->next;
else
head = ptr->next;
if (ptr->next)
ptr->next->prev = ptr->prev;
else
tail = ptr->prev;
insert_at_cache_head(ptr);
/* Return true path */
*true_path = XtNewString(ptr->part.m.true_path);
report_cache_truepath_hit();
return True;
}
/*
* report_cache_use - Let's user know if cache information was used to
* update "dirwin". Set "used_cache" to True for
* message to be displayed. Set "used_cache" to
* False for no message.
*/
void
report_cache_use(dirwin, used_cache)
struct dirwin_st *dirwin;
int used_cache;
{
if (used_cache)
XtManageChild(dirwin->w_cacheMsg);
else
XtUnmanageChild(dirwin->w_cacheMsg);
}
/*
* report_cache_addition - Debug edit
*/
void
report_cache_addition()
{
char msg[100];
if (diagnostics == DEBUG) {
sprintf(msg, "*** Entry added to cache. Cache len = %ld\n", cache_len);
write_log(msg);
}
}
/*
* report_cache_deletion - Debug edit
*/
void
report_cache_deletion(ptr)
struct cache_link *ptr;
{
char msg[200];
if (diagnostics == DEBUG) {
if (ptr->type == DIRLIST) {
sprintf(msg,
"*** Removed directory list from cache. Cache len = %ld\n",
cache_len);
write_log(msg);
sprintf(msg, " %s", ptr->path);
write_log(msg);
switch (ptr->part.d.layout) {
case TABULAR:
write_log(", Tabular");
break;
case ICONIC:
case TREE:
write_log(", Iconic/Tree");
break;
case FULL_INFO:
write_log(", Full Info");
}
if (ptr->part.d.dotfiles)
write_log(", Dotfiles");
write_log("\n");
} else {
sprintf(msg,
"*** Removed true path from cache. Cache len = %ld\n",
cache_len);
write_log(msg);
sprintf(msg, " %s\n", ptr->path);
write_log(msg);
}
}
}
/*
* report_cache_truepath_hit - Debug edit
*/
void
report_cache_truepath_hit()
{
if (diagnostics == DEBUG)
write_log("*** True path cache hit\n");
}
/*
* report_cache_dirlist_hit - Debug edit
*/
void
report_cache_dirlist_hit()
{
if (diagnostics == DEBUG)
write_log("*** Directory list cache hit\n");
}
/*
* check_max_cache_len - If cache length exceeds the maximum allowable (this
* could happen if the user changes this limit), then
* free up as many of the least recently used cache
* entries as necessary.
*/
void
check_max_cache_len()
{
long bytes_available = max_dir_cache_len*BYTES_PER_KB-cache_len;
/* Delete least recently used entries until cache len is small enough */
while (head && (bytes_available<0)) {
bytes_available += tail->len;
free_cache_entry(tail);
}
/* Sanity check */
if (bytes_available < 0)
fatal_error("Bug in check_max_cache_len()");
}
/*
* remove_dirlist_from_cache - Remove the cache entry that contains the
* directory list that is uniquely specified
* by the arguments.
*/
void
remove_dirlist_from_cache(host, path, layout, dotfiles)
int host;
char *path;
int layout;
int dotfiles;
{
free_cache_entry(find_dirlist_in_cache(host, path, layout, dotfiles));
}
/*
* flush_cache_all - Removes all entries from the cache.
*/
void
flush_cache_all()
{
while (head)
free_cache_entry(head);
}
/*
* flush_cache_directory - Remove all cache entries for the directory
* specified by "host" and "path".
*/
void
flush_cache_directory(host, path)
int host;
char *path;
{
struct hostuser_st *hostuser = head_hostuser;
struct cache_link *ptr = head;
struct cache_link *tptr;
/* Find hostname/username pair */
while (hostuser) {
if (!strcmp(hinfo[host].hostname, hostuser->hostname) &&
(!strcmp(hinfo[host].username, hostuser->username)))
break;
hostuser = hostuser->next;
}
if (hostuser == NULL)
return;
/* Now remove cache entries */
while (ptr) {
tptr = ptr;
ptr = ptr->next;
if ((hostuser == tptr->hostuser) && !strcmp(path, tptr->path))
free_cache_entry(tptr);
}
}
syntax highlighted by Code2HTML, v. 0.9.1