Annotation of fam/fam/DirectoryScanner.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 "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>