tmi2_fluffos_v2/
tmi2_fluffos_v2/bin/
tmi2_fluffos_v2/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/ChangeLog.old/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/Win32/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/compat/simuls/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/clone/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/command/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/data/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/etc/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/include/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/inherit/master/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/log/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/compiler/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/efuns/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/single/tests/operators/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/testsuite/u/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/tmp/
tmi2_fluffos_v2/fluffos-2.7-ds2.018/windows/
tmi2_fluffos_v2/lib/
tmi2_fluffos_v2/lib/adm/
tmi2_fluffos_v2/lib/adm/daemons/languages/
tmi2_fluffos_v2/lib/adm/daemons/network/I3/
tmi2_fluffos_v2/lib/adm/daemons/virtual/
tmi2_fluffos_v2/lib/adm/daemons/virtual/template/
tmi2_fluffos_v2/lib/adm/news/
tmi2_fluffos_v2/lib/adm/obj/
tmi2_fluffos_v2/lib/adm/obj/master/
tmi2_fluffos_v2/lib/adm/priv/
tmi2_fluffos_v2/lib/adm/shell/
tmi2_fluffos_v2/lib/adm/tmp/
tmi2_fluffos_v2/lib/cmds/
tmi2_fluffos_v2/lib/d/
tmi2_fluffos_v2/lib/d/Conf/
tmi2_fluffos_v2/lib/d/Conf/adm/
tmi2_fluffos_v2/lib/d/Conf/boards/
tmi2_fluffos_v2/lib/d/Conf/cmds/
tmi2_fluffos_v2/lib/d/Conf/data/
tmi2_fluffos_v2/lib/d/Conf/logs/
tmi2_fluffos_v2/lib/d/Conf/obj/
tmi2_fluffos_v2/lib/d/Conf/text/help/
tmi2_fluffos_v2/lib/d/Fooland/adm/
tmi2_fluffos_v2/lib/d/Fooland/data/
tmi2_fluffos_v2/lib/d/Fooland/data/attic/
tmi2_fluffos_v2/lib/d/Fooland/items/
tmi2_fluffos_v2/lib/d/TMI/
tmi2_fluffos_v2/lib/d/TMI/adm/
tmi2_fluffos_v2/lib/d/TMI/boards/
tmi2_fluffos_v2/lib/d/TMI/data/
tmi2_fluffos_v2/lib/d/TMI/rooms/
tmi2_fluffos_v2/lib/d/grid/
tmi2_fluffos_v2/lib/d/grid/adm/
tmi2_fluffos_v2/lib/d/grid/data/
tmi2_fluffos_v2/lib/d/std/
tmi2_fluffos_v2/lib/d/std/adm/
tmi2_fluffos_v2/lib/data/adm/
tmi2_fluffos_v2/lib/data/adm/daemons/
tmi2_fluffos_v2/lib/data/adm/daemons/doc_d/
tmi2_fluffos_v2/lib/data/adm/daemons/emoted/
tmi2_fluffos_v2/lib/data/adm/daemons/network/http/
tmi2_fluffos_v2/lib/data/adm/daemons/network/services/mail_q/
tmi2_fluffos_v2/lib/data/adm/daemons/network/smtp/
tmi2_fluffos_v2/lib/data/adm/daemons/news/archives/
tmi2_fluffos_v2/lib/data/attic/connection/
tmi2_fluffos_v2/lib/data/attic/user/
tmi2_fluffos_v2/lib/data/std/connection/b/
tmi2_fluffos_v2/lib/data/std/connection/l/
tmi2_fluffos_v2/lib/data/std/user/a/
tmi2_fluffos_v2/lib/data/std/user/b/
tmi2_fluffos_v2/lib/data/std/user/d/
tmi2_fluffos_v2/lib/data/std/user/f/
tmi2_fluffos_v2/lib/data/std/user/l/
tmi2_fluffos_v2/lib/data/std/user/x/
tmi2_fluffos_v2/lib/data/u/d/dm/working/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/doc_d/
tmi2_fluffos_v2/lib/data/u/l/leto/smtp/
tmi2_fluffos_v2/lib/doc/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/
tmi2_fluffos_v2/lib/doc/driverdoc/applies/interactive/
tmi2_fluffos_v2/lib/doc/driverdoc/concepts/
tmi2_fluffos_v2/lib/doc/driverdoc/driver/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/arrays/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/buffers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/compile/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/ed/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/filesystem/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/floats/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/functions/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/general/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/mappings/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/numbers/
tmi2_fluffos_v2/lib/doc/driverdoc/efuns/parsing/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/constructs/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/preprocessor/
tmi2_fluffos_v2/lib/doc/driverdoc/lpc/types/
tmi2_fluffos_v2/lib/doc/driverdoc/platforms/
tmi2_fluffos_v2/lib/doc/mudlib/
tmi2_fluffos_v2/lib/ftp/
tmi2_fluffos_v2/lib/include/driver/
tmi2_fluffos_v2/lib/log/
tmi2_fluffos_v2/lib/log/driver/
tmi2_fluffos_v2/lib/obj/net/
tmi2_fluffos_v2/lib/obj/shells/
tmi2_fluffos_v2/lib/obj/tools/
tmi2_fluffos_v2/lib/std/adt/
tmi2_fluffos_v2/lib/std/board/
tmi2_fluffos_v2/lib/std/body/
tmi2_fluffos_v2/lib/std/fun/
tmi2_fluffos_v2/lib/std/living/
tmi2_fluffos_v2/lib/std/object/
tmi2_fluffos_v2/lib/std/shop/
tmi2_fluffos_v2/lib/std/socket/
tmi2_fluffos_v2/lib/std/user/
tmi2_fluffos_v2/lib/std/virtual/
tmi2_fluffos_v2/lib/student/
tmi2_fluffos_v2/lib/student/kalypso/
tmi2_fluffos_v2/lib/student/kalypso/armor/
tmi2_fluffos_v2/lib/student/kalypso/rooms/
tmi2_fluffos_v2/lib/student/kalypso/weapons/
tmi2_fluffos_v2/lib/u/l/leto/
tmi2_fluffos_v2/lib/u/l/leto/cmds/
tmi2_fluffos_v2/lib/www/errors/
tmi2_fluffos_v2/lib/www/gateways/
tmi2_fluffos_v2/lib/www/images/
tmi2_fluffos_v2/old/
tmi2_fluffos_v2/win32/
//
// File: flock.c
// Creator: Robocoder@TMI-2
//
// Revision history:
//   06-22-93 - robo - created
//   06-25-93 - robo - optimizations; remove_stale_locks() no longer needed
//   06-25-93 - robo - replaced array deletion code with exclude_array()
//   ??-??-93 - ???? - added DEBUG_FLOCK code to track down a suspected bug
//   08-25-93 - robo - kludge to reuse an unfreed editor lock
//                   - removed DEBUG_FLOCK code
//   04-09-94 - robo - kludge to identify ftp user
//
// File locking mechanism/server
// Based on code in /cmds/file/_ed.c by Buddha.

#include <config.h>
#include <mudlib.h>
#include <flock.h>
#include <logs.h>
#include <net/daemons.h>
#include <commands.h>
#include <uid.h>
#include <driver/origin.h>

inherit SERVER;

// Uses 2 arrays rather than a mapping for the ease in searching for
// either the file or the lockobj (player/object that locked the file).
// It's difficult to keep the lists accurate, but not impossible to handle:
//   o  multiple logins of the same character
//   o  one object may have many locks
//   o  stale locks from link-deaths

string *files, *lockobjs;

// A special mapping tracks a file's timestamps and previous object
// for logging and resource tracking (see below).

mapping filestats;

// To enable logging:
//   #define FILE_LOG in $(MUDLIB)/include/logs.h

// For more selective logging, #define NON_CRITICAL_PATHS
// in $(MUDLIB)/include/flock.h.
// This should be a list of paths that _should not_ be logged.
// For example,
//   #define NON_CRITICAL_PATHS "/tmp/","/open/","/ftp/"
// Note: the leading and trailing slashes, the quotes around each top level
//   path, and the commas for delimeters.

// prototypes for local functions
void log_change(string pathname, string flag);
string query_file_change(string pathname);
int get_timestamp(string pathname);

#define PUBLIC
#define PRIVATE static

PUBLIC void create() {
    seteuid(ROOT_UID);
    files = ({ });
    lockobjs = ({ });
    filestats = ([ ]);
}

/*
 * flock()
 *   If mode == F_LOCK, attempt to gain a file lock.
 *   If mode == F_UNLOCK, attempt to remove a file lock.
 *   Returns 1 if successful, 0 otherwise.
 */
PUBLIC int flock(string pathname, int mode) {
    int position;
    object tobj, locker;

    // sanity checks
    //   if the arrays are off, then reset them,
    //   and pray nothing [else] goes wrong...
    if (sizeof(lockobjs) != sizeof(files)) create();
    //   reject bad pathnames, i.e. null or a null string
    if (!pathname || pathname == "") return 0;

    locker = this_player();
    if (!this_player() || !geteuid(this_player()))
        locker = previous_object();

    if (mode == F_LOCK) {
        position = member_array(pathname, files);
        if (position != -1) {
            // sanity check
            //   file is already locked...let's see if the lock is stale

#ifdef FILE_LOG
            if (!lockobjs[position]) {
                log_change(pathname, "Uh-Oh");
                return 0;
            }
#endif

            // who own's the lock, and is he/she still online?
            tobj = find_object(lockobjs[position]);
            if (tobj && tobj->query_linkdead()) {
                // Ok, just re-assign lock
                lockobjs[position] = file_name(locker);
                return 1;
            } else {
#ifdef REUSE_ED_LOCK_KLUDGE
                // Allow a user to reuse an editor lock under special conditions
                if (locker == tobj && files[position] == pathname
                      && file_name(previous_object()) == CMD_ED
                      && filestats[pathname]["prevobj"] == CMD_ED
                      && !in_edit(locker)) {
                    return 1;
                }
#endif
                // File busy
                return 0;
            }
        }
        lockobjs += ({ file_name(locker) });
        files += ({ pathname });
        filestats[pathname] =
              ([ "timestamp" : get_timestamp(pathname),
                 "prevobj" : file_name(previous_object()) ]);

    } else if (mode == F_UNLOCK) {
        position = member_array(pathname, files);
        if (position == -1) {
            return 0;
        }

        // check owner of lock
        if (this_player()
              && file_name(locker) != lockobjs[position]
              && !adminp(geteuid(locker))) {
#ifdef FILE_LOG
            // Hmm...naughty, naughty...
            log_change(pathname, "***");
#endif /* FILE_LOG */
            return 0;
        }

        // remove lock
#ifdef FILE_LOG
        log_change(pathname, query_file_change(pathname));
#endif /* FILE_LOG */

        filestats[pathname] = ([ ]);
        map_delete(filestats, pathname);
        files -= ({ pathname });
        lockobjs = exclude_array(lockobjs, position);
    } else {
        // unrecognized mode
        return 0;
    }
    return 1;
}

/*
 * free_lockobj()
 *   Frees all locks associated with a player.
 *   Note: this function is called by /std/user.c
 */
PUBLIC void free_lockobj(object player) {
    int position;
    string tstr;
    string pathname;

  //if(base_name(previous_object()) != USER_OB ) return; // Leto
    tstr = file_name(player);
    while ((position = member_array(tstr, lockobjs)) != -1) {
        pathname = files[position];
        if (in_edit(player)
              && filestats[pathname]["prevobj"] == CMD_ED) {
            call_other(CMD_ED, "done_editing");
            continue;
        }
#ifdef FILE_LOG
        log_change(pathname, query_file_change(pathname));
#endif /* FILE_LOG */

        filestats[pathname] = ([ ]);
        map_delete(filestats, pathname);
        files -= ({ files[position] });
        lockobjs = exclude_array(lockobjs, position);
    }
}

/*
 * query_lockobj()
 *   Returns the object that owns that lock on "file"
 */
PUBLIC object query_lockobj(string file) {
    int i;

    if (!file || file == "") return 0;

    i = member_array(file, files);
    if (i != -1) {
        return find_object(lockobjs[i]);
    }
    return 0;
}

/*
 * query_lockfn()
 *   Returns the name of _a_ file associated with the locking object.
 */
PUBLIC string query_lockfn(object locker) {
    int i, j, k;
    string s, t;

    if (!locker) return 0;

    s = file_name(locker);
    j = sizeof(lockobjs);
    k = member_array(s, lockobjs);
    if (k != -1) {
        for (i = k; i < j; i++) {
            t = files[i];
            if (s == lockobjs[i]
                  && filestats[t]["prevobj"] == file_name(previous_object()))
                return t;
        }
    }
    return 0;
}

/*
 * get_timestamp()
 *   Returns the timestamp of a file, or 0 if the file doesn't exist.
 */
PRIVATE int get_timestamp(string pathname) {
    mixed *stats;
    int position;
    int stamp;

    if (file_size(pathname) >= 0) {
        stats = stat(pathname);
        stamp = stats[1];
    } else
        stamp = 0;
    return stamp;
}

/*
 * query_file_change()
 *   Returns a string that identifies the manner by which a file was changed.
 */
PRIVATE string query_file_change(string pathname) {
    mixed *stats;
    int position;
    int oldstamp, newstamp;

    if ((position = member_array(pathname, files)) == -1)
        return 0;
    newstamp = get_timestamp(pathname);
    oldstamp = filestats[pathname]["timestamp"];

    if (oldstamp != newstamp) {
        if (oldstamp) {
            if (newstamp)
                return "!"; // changed
            else
                return "-"; // purged
        } else
            return "+";     // added
    }
    // else file not changed or not created
    return 0;
}

#ifdef FILE_LOG
/*
 * log_change()
 *   Logs file changes to the log file $(FILE_LOG).
 */
PUBLIC void log_change(string pathname, string flag) {
    string s;

#ifdef NON_CRITICAL_PATHS
    string *paths;
    int i, k, x;

    if (!(previous_object() == MASTER_OB || origin() == ORIGIN_LOCAL))
        return;

    if (!flag || flag == "")
        return;

    paths = ({ NON_CRITICAL_PATHS });
    if (this_player()) {
        paths += ({ user_path(geteuid(this_player())) });
    } else if (previous_object() == find_object(FTP_D)) {
        paths += ({ user_path(geteuid(previous_object())) });
    }

    x = sizeof(paths);
    for (i = 0; i < x; i++) {
        s = paths[i];
        k = strlen(paths[i]);
        if (k <= strlen(pathname) && s == pathname[0..k-1]) {
            // don't log this one
            return;
        }
    }
#else
    if (!(previous_object() == MASTER_OB || origin() == ORIGIN_LOCAL))
        return;

    if (!flag || flag == "")
        return;
#endif /* !NON_CRITICAL_PATHS */

    if (this_player())
        s = capitalize(geteuid(this_player()));
    else {
        s = file_name(previous_object());

        // ftpd kludge...assuming ftpd does a seteuid()
        if (s == FTP_D) {
            s = "[ftp] " + capitalize(geteuid(previous_object()));
        }
    }

    log_file(FILE_LOG, wrap(s + " " + flag + " \"" + pathname +
          "\" [" + extract(ctime(time()), 4, 15) + "]"));
}
#endif /* FILE_LOG */

/*
 * dump_locks()
 *   A debugging function that prints out a list of outstanding locks--
 *   filename, lock owner, timestamp of file.
 */
PUBLIC void dump_locks() {
    int i, j, k;
    string tstr, tstr2;
    object tobj;

    i = sizeof(lockobjs);
    j = sizeof(files);
    k = sizeof(filestats);

    if (i != j) {
        if (i < j)
            j = i;
        write("Hmm...array inconsistency.\n");
    }
    if (i != k) {
        write("Hmm...mapping inconsistency.\n");
    }

    for (i = 0; i < j; i++) {
        if (lockobjs[i]) {
            tobj = find_object(lockobjs[i]);
            if (tobj) {
                tstr = geteuid(tobj);
                if (!tstr)
                    tstr = "(None)";
                tstr += " (" + lockobjs[i] + ")";
            } else
                tstr = lockobjs[i];
            tstr2 = files[i];
            if (k = filestats[tstr2]["timestamp"])
                printf("%20s\t%s\t%s\n", tstr, tstr2, ctime(k));
            else
                printf("%20s\t%s\t[New File]\n", tstr, tstr2);
        } else {
            write("Hmm...invalid entries.\n");
        }
    }
}