[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

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>