Annotation of fam/fam/DirectoryScanner.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 "DirectoryScanner.h"
! 24:
! 25: #include <assert.h>
! 26: #include <string.h>
! 27: #include <errno.h>
! 28:
! 29: #include "Client.h"
! 30: #include "Directory.h"
! 31: #include "DirEntry.h"
! 32: #include "Log.h"
! 33:
! 34: //////////////////////////////////////////////////////////////////////////////
! 35:
! 36: DirectoryScanner::DirectoryScanner(Directory& d,
! 37: const Event& e, bool b,
! 38: DoneHandler dh, void *vp)
! 39: : directory(d), done_handler(dh), closure(vp), new_event(e),
! 40: scan_entries(b), dir(NULL), openErrno(0),
! 41: epp(&d.entries), discard(NULL)
! 42:
! 43: {
! 44: dir = opendir(d.name());
! 45: if (dir == NULL) {
! 46: openErrno = errno;
! 47: }
! 48: }
! 49:
! 50: DirectoryScanner::~DirectoryScanner()
! 51: {
! 52: if (dir)
! 53: closedir(dir);
! 54: }
! 55:
! 56: //////////////////////////////////////////////////////////////////////////////
! 57:
! 58: // return address of ptr to entry matching name
! 59:
! 60: DirEntry **
! 61: DirectoryScanner::match_name(DirEntry **epp, const char *name)
! 62: {
! 63: for (DirEntry *ep; ((ep = *epp) != NULL); epp = &ep->next)
! 64: if (!strcmp(ep->name(), name))
! 65: return epp;
! 66: return NULL;
! 67: }
! 68:
! 69: bool
! 70: DirectoryScanner::done()
! 71: {
! 72: #if HAVE_SGI_NOHANG
! 73: if (openErrno == ETIMEDOUT) {
! 74: // We got an nfs time out. We'll want to try again later.
! 75: directory.unhang();
! 76: Log::debug("openErrno == ETIMEDOUT");
! 77: (*done_handler)(closure);
! 78: return true;
! 79: }
! 80: #endif
! 81: bool ready = directory.client()->ready_for_events();
! 82:
! 83: directory.become_user();
! 84: if (!directory.chdir()) {
! 85: // Didn't have permission to read the directory. Send Delete events
! 86: // for its contents.
! 87: while (*epp && ready)
! 88: { DirEntry *ep = *epp;
! 89: *epp = ep->next;
! 90: ep->post_event(Event::Deleted);
! 91: ready = directory.client()->ready_for_events();
! 92: delete ep;
! 93: }
! 94: if (*epp || !ready)
! 95: return false;
! 96:
! 97: (*done_handler)(closure);
! 98: return true;
! 99: }
! 100:
! 101: while (dir && ready)
! 102: {
! 103: struct direct *dp = readdir(dir);
! 104: if (dp == NULL)
! 105: { closedir(dir);
! 106: dir = NULL;
! 107: break;
! 108: }
! 109:
! 110: // Ignore "." and "..".
! 111:
! 112: if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
! 113: continue;
! 114:
! 115: DirEntry *ep = *epp, **epp2;
! 116: if (ep && !strcmp(dp->d_name, ep->name()))
! 117: {
! 118: // Next entry in list matches. Do not change list.
! 119:
! 120: // Log::debug("checkdir match %s", dp->d_name);
! 121: }
! 122: else if ((epp2 = match_name(&discard, dp->d_name)) != NULL)
! 123: {
! 124: // Found in discard. Insert discarded entry before ep.
! 125:
! 126: // Log::debug("checkdir fdisc %s", dp->d_name);
! 127: ep = *epp2;
! 128: *epp2 = ep->next;
! 129: ep->next = *epp;
! 130: *epp = ep;
! 131: }
! 132: else if (ep && (epp2 = match_name(&ep->next, dp->d_name)))
! 133: {
! 134: // Found further in list. Prepend internode segment
! 135: // to discard.
! 136:
! 137: // Log::debug("checkdir furth %s", dp->d_name);
! 138: ep = *epp2;
! 139: *epp2 = discard;
! 140: discard = *epp;
! 141: *epp = ep;
! 142: }
! 143: else
! 144: {
! 145: // New entry. Insert.
! 146:
! 147: ep = new DirEntry(dp->d_name, &directory, *epp);
! 148: *epp = ep;
! 149: ep->post_event(new_event);
! 150: ready = directory.client()->ready_for_events();
! 151: epp = &ep->next;
! 152: continue; // Do not scan newly created entry.
! 153: }
! 154: if (scan_entries)
! 155: { ep->scan_no_chdir();
! 156: ready = directory.client()->ready_for_events();
! 157: }
! 158: epp = &ep->next;
! 159: }
! 160:
! 161: directory.chdir_root(); // chdir back to "/"
! 162:
! 163: while (*epp && ready)
! 164: { DirEntry *ep = *epp;
! 165: *epp = ep->next;
! 166: ep->post_event(Event::Deleted);
! 167: ready = directory.client()->ready_for_events();
! 168: delete ep;
! 169: }
! 170:
! 171: while (discard && ready)
! 172: { DirEntry *ep = discard;
! 173: discard = discard->next;
! 174: ep->post_event(Event::Deleted);
! 175: ready = directory.client()->ready_for_events();
! 176: delete ep;
! 177: }
! 178:
! 179: if (dir || *epp || discard || !ready)
! 180: return false;
! 181:
! 182: (*done_handler)(closure);
! 183: return true;
! 184: }
! 185:
! 186: //////////////////////////////////////////////////////////////////////////////
! 187: // Memory management. Maintain a cache of one DirectoryScanner to reduce
! 188: // heap stirring.
! 189:
! 190: DirectoryScanner *DirectoryScanner::cache;
! 191:
! 192: void *
! 193: DirectoryScanner::operator new (size_t size)
! 194: {
! 195: assert(size == sizeof (DirectoryScanner));
! 196: DirectoryScanner *p = cache ? cache : (DirectoryScanner *) new char[size];
! 197: if (cache)
! 198: cache = NULL;
! 199: return p;
! 200: }
! 201:
! 202: void
! 203: DirectoryScanner::operator delete (void *p)
! 204: {
! 205: assert(p != NULL);
! 206: if (cache)
! 207: delete [] cache;
! 208: cache = (DirectoryScanner *) p;
! 209: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>