[BACK]Return to Directory.c++ CVS log [TXT][DIR] Up to [Development] / fam / fam

Annotation of fam/fam/Directory.c++, Revision 1.1

1.1     ! trev        1: //  Copyright (C) 1999 Silicon Graphics, Inc.  All Rights Reserved.
        !             2: //
        !             3: //  This program is free software; you can redistribute it and/or modify it
        !             4: //  under the terms of version 2 of the GNU General Public License as
        !             5: //  published by the Free Software Foundation.
        !             6: //
        !             7: //  This program is distributed in the hope that it would be useful, but
        !             8: //  WITHOUT ANY WARRANTY; without even the implied warranty of
        !             9: //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Further, any
        !            10: //  license provided herein, whether implied or otherwise, is limited to
        !            11: //  this program in accordance with the express provisions of the GNU
        !            12: //  General Public License.  Patent licenses, if any, provided herein do not
        !            13: //  apply to combinations of this program with other product or programs, or
        !            14: //  any other product whatsoever.  This program is distributed without any
        !            15: //  warranty that the program is delivered free of the rightful claim of any
        !            16: //  third person by way of infringement or the like.  See the GNU General
        !            17: //  Public License for more details.
        !            18: //
        !            19: //  You should have received a copy of the GNU General Public License along
        !            20: //  with this program; if not, write the Free Software Foundation, Inc., 59
        !            21: //  Temple Place - Suite 330, Boston MA 02111-1307, USA.
        !            22:
        !            23: #include "Directory.h"
        !            24:
        !            25: #include <assert.h>
        !            26: #include <errno.h>
        !            27: #include <string.h>
        !            28: #include <stdio.h>
        !            29: #include <sys/dir.h>
        !            30: #include <sys/stat.h>
        !            31: #include <sys/wait.h>
        !            32: #include <unistd.h>
        !            33:
        !            34: #include "Client.h"
        !            35: #include "DirEntry.h"
        !            36: #include "DirectoryScanner.h"
        !            37: #include "Event.h"
        !            38: #include "FileSystem.h"
        !            39: #include "Log.h"
        !            40: #include "Scheduler.h"
        !            41:
        !            42: Directory *Directory::current_dir;
        !            43:
        !            44: Directory::Directory(const char *name, Client *c, Request r, const Cred& cr)
        !            45:     : ClientInterest(name, c, r, cr, DIRECTORY), entries(NULL), unhangPid(-1)
        !            46: {
        !            47:     dir_bits() = 0;
        !            48:     if (exported_to_host())
        !            49:     {
        !            50:         dir_bits() = SCANNING;
        !            51:         DirectoryScanner *scanner = new DirectoryScanner(*this,
        !            52: 						         Event::Exists, false,
        !            53: 						         new_done_handler, this);
        !            54:         if (scanner->done()) {
        !            55:             delete scanner;
        !            56:         } else {
        !            57: 	    client()->enqueue_scanner(scanner);
        !            58:         }
        !            59:     }
        !            60: }
        !            61:
        !            62: void
        !            63: Directory::new_done_handler(void *closure)
        !            64: {
        !            65:     Directory *dir = (Directory *) closure;
        !            66:     dir->dir_bits() &= ~SCANNING;
        !            67:     dir->post_event(Event::EndExist);
        !            68: }
        !            69:
        !            70: Directory::~Directory()
        !            71: {
        !            72:     assert(!(dir_bits() & SCANNING));
        !            73:     if (dir_bits() & RESCAN_SCHEDULED)
        !            74: 	Scheduler::remove_onetime_task(scan_task, this);
        !            75:     DirEntry *q, *p = entries;
        !            76:     if (p)
        !            77:     {   (void) chdir();
        !            78: 	while (p)
        !            79: 	{   q = p->next;
        !            80: 	    delete p;
        !            81: 	    p = q;
        !            82: 	}
        !            83:     }
        !            84:     if (current_dir == this)
        !            85: 	chdir_root();
        !            86: }
        !            87:
        !            88: ClientInterest::Type
        !            89: Directory::type() const
        !            90: {
        !            91:     assert(!(dir_bits() & SCANNING));
        !            92:     return DIRECTORY;
        !            93: }
        !            94:
        !            95: void
        !            96: Directory::resume()
        !            97: {
        !            98:     assert(!(dir_bits() & SCANNING));
        !            99:     ClientInterest::resume();
        !           100:     for (DirEntry *ep = entries; ep; ep = ep->next)
        !           101: 	if (ep->needs_scan())
        !           102: 	    ep->scan();
        !           103: }
        !           104:
        !           105: Interest *
        !           106: Directory::find_name(const char *name)
        !           107: {
        !           108:     assert(!(dir_bits() & SCANNING));
        !           109:     if (name[0] == '/')
        !           110:         // I don't know why this happens, but just in case ...
        !           111: 	return this;
        !           112:     else
        !           113: 	for (DirEntry *ep = entries; ep; ep = ep->next)
        !           114: 	    if (!strcmp(name, ep->name()))
        !           115: 		return ep;
        !           116:     return NULL;
        !           117: }
        !           118:
        !           119: //  Directory::do_scan() scans a Directory.  There are several cases.
        !           120: //
        !           121: //  If monitoring is suspended, do nothing.
        !           122: //
        !           123: //  If the Directory is actually not a directory (e.g., a file, a
        !           124: //  device or nonexistent), then it is lstat'd once, and a Changed,
        !           125: //  Deleted or Created event is written if appropriate.
        !           126: //
        !           127: //  If a Directory changes from a directory to something else, then
        !           128: //  all its entries are deleted and Deleted events are sent.
        !           129: //
        !           130: //  If it is a real directory, then it is lstat'd repeatedly and read
        !           131: //  repeatedly until it stops changing.  This prevents fam from
        !           132: //  missing files in race conditions (I hope).
        !           133:
        !           134: bool
        !           135: Directory::do_scan()
        !           136: {
        !           137:     if (!active() || !needs_scan() || (dir_bits() & SCANNING))
        !           138: 	return false;
        !           139:     become_user();
        !           140:     bool stat_changed = do_stat();
        !           141:     if (stat_changed && !isdir())   // Seems like a bug to send Changed after
        !           142: 	post_event(Event::Changed); // Deleted, but what would fixing it break?
        !           143:     bool scan_entries = filesystem()->dir_entries_scanned();
        !           144:     dir_bits() |= SCANNING;
        !           145:     DirectoryScanner *scanner = new DirectoryScanner(*this, Event::Created,
        !           146: 						     scan_entries,
        !           147: 						     scan_done_handler,
        !           148: 						     this);
        !           149:     if (scanner->done()) {
        !           150:         delete scanner;
        !           151:     } else {
        !           152: 	client()->enqueue_scanner(scanner);
        !           153:     }
        !           154:     return stat_changed;
        !           155: }
        !           156:
        !           157: void
        !           158: Directory::scan_task(void *closure)
        !           159: {
        !           160:     Directory *dir = (Directory *) closure;
        !           161:     dir->dir_bits() &= ~RESCAN_SCHEDULED;
        !           162:     dir->scan();
        !           163: }
        !           164:
        !           165: void
        !           166: Directory::scan_done_handler(void *closure)
        !           167: {
        !           168:     Directory *dir = (Directory *) closure;
        !           169:     dir->dir_bits() &= ~SCANNING;
        !           170: }
        !           171:
        !           172: bool
        !           173: Directory::chdir()
        !           174: {
        !           175:     if (current_dir == this)
        !           176: 	return true;
        !           177:
        !           178:     int rc = ::chdir(name());
        !           179:     Log::debug("+chdir to \"%s\"", name());
        !           180:     if (rc < 0)
        !           181:     {   Log::info("can't chdir(\"%s\"): %m", name());
        !           182: 	if ((errno == EACCES) && (client() != NULL))
        !           183:         {
        !           184:             client()->suggest_insecure_compat(name());
        !           185:         }
        !           186: 	return false;
        !           187:     }
        !           188:
        !           189:     current_dir = this;
        !           190:     return true;
        !           191: }
        !           192:
        !           193: bool
        !           194: Directory::chdir_root()
        !           195: {
        !           196:     int rc = 0;
        !           197:     if (current_dir)
        !           198:     {
        !           199:         rc = ::chdir("/");
        !           200:         Log::debug("-chdir to \"/\"");
        !           201: 	current_dir = NULL;
        !           202:     }
        !           203:     return rc == 0;
        !           204: }
        !           205:
        !           206: //
        !           207: //  void
        !           208: //  Directory::unhang()
        !           209: //
        !           210: //  Description:
        !           211: //      This gets called after a system call has failed with oserror()
        !           212: //      set to ETIMEDOUT.  This means that we can't contact the nfs
        !           213: //      server.  In order to reconnect when the server becomes visible
        !           214: //      again, a process has to acually hang on the mount.  We fork and
        !           215: //      exec nfsunhang to do this for us.  We don't care about
        !           216: //      nfsunhang's exit status because we poll nfs mounts anyway.
        !           217: //
        !           218: #if HAVE_SGI_NOHANG
        !           219: void
        !           220: Directory::unhang()
        !           221: {
        !           222:     int status;
        !           223:     if (unhangPid == -1
        !           224: 	|| waitpid(unhangPid, &status, WNOHANG) != 0) {
        !           225:
        !           226: 	if (access("/usr/lib/nfsunhang", X_OK) == -1) {
        !           227: 	    return;
        !           228: 	}
        !           229:
        !           230: 	unhangPid = fork();
        !           231: 	if (unhangPid == 0) {
        !           232: 	    for (int fd = getdtablesize() - 1; fd > 2; fd--) {
        !           233: 		close(fd);
        !           234: 	    }
        !           235: 	    execl("/usr/lib/nfsunhang", "nfsunhang", name(), NULL);
        !           236: 	    exit(1);
        !           237: 	}
        !           238: 	Log::debug("unhangPid: %d", unhangPid);
        !           239:     }
        !           240: }
        !           241: #endif // HAVE_SGI_NOHANG

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>