📄 directory.c++
字号:
// Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved.// // This program is free software; you can redistribute it and/or modify it// under the terms of version 2 of the GNU General Public License as// published by the Free Software Foundation.//// This program is distributed in the hope that it would be useful, but// WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Further, any// license provided herein, whether implied or otherwise, is limited to// this program in accordance with the express provisions of the GNU// General Public License. Patent licenses, if any, provided herein do not// apply to combinations of this program with other product or programs, or// any other product whatsoever. This program is distributed without any// warranty that the program is delivered free of the rightful claim of any// third person by way of infringement or the like. See the GNU General// Public License for more details.//// You should have received a copy of the GNU General Public License along// with this program; if not, write the Free Software Foundation, Inc., 59// Temple Place - Suite 330, Boston MA 02111-1307, USA.#include "Directory.h"#include <assert.h>#include <errno.h>#include <string.h>#include <stdio.h>#include <sys/dir.h>#include <sys/stat.h>#include <sys/wait.h>#include <unistd.h>#include "Client.h"#include "DirEntry.h"#include "DirectoryScanner.h"#include "Event.h"#include "FileSystem.h"#include "Log.h"#include "Scheduler.h"Directory *Directory::current_dir;Directory::Directory(const char *name, Client *c, Request r, const Cred& cr) : ClientInterest(name, c, r, cr, DIRECTORY), entries(NULL), unhangPid(-1){ dir_bits() = 0; if (exported_to_host()) { dir_bits() = SCANNING; DirectoryScanner *scanner = new DirectoryScanner(*this, Event::Exists, false, new_done_handler, this); if (scanner->done()) { delete scanner; } else { client()->enqueue_scanner(scanner); } }}voidDirectory::new_done_handler(void *closure){ Directory *dir = (Directory *) closure; dir->dir_bits() &= ~SCANNING; dir->post_event(Event::EndExist);}Directory::~Directory(){ assert(!(dir_bits() & SCANNING)); if (dir_bits() & RESCAN_SCHEDULED) Scheduler::remove_onetime_task(scan_task, this); DirEntry *q, *p = entries; if (p) { (void) chdir(); while (p) { q = p->next; delete p; p = q; } } if (current_dir == this) chdir_root();}ClientInterest::TypeDirectory::type() const{ assert(!(dir_bits() & SCANNING)); return DIRECTORY;}voidDirectory::resume(){ assert(!(dir_bits() & SCANNING)); ClientInterest::resume(); for (DirEntry *ep = entries; ep; ep = ep->next) if (ep->needs_scan()) ep->scan();}Interest *Directory::find_name(const char *name){ assert(!(dir_bits() & SCANNING)); if (name[0] == '/') // I don't know why this happens, but just in case ... return this; else for (DirEntry *ep = entries; ep; ep = ep->next) if (!strcmp(name, ep->name())) return ep; return NULL;}// Directory::do_scan() scans a Directory. There are several cases.//// If monitoring is suspended, do nothing.//// If the Directory is actually not a directory (e.g., a file, a// device or nonexistent), then it is lstat'd once, and a Changed,// Deleted or Created event is written if appropriate.//// If a Directory changes from a directory to something else, then// all its entries are deleted and Deleted events are sent.//// If it is a real directory, then it is lstat'd repeatedly and read// repeatedly until it stops changing. This prevents fam from// missing files in race conditions (I hope).boolDirectory::do_scan(){ if (!active() || !needs_scan() || (dir_bits() & SCANNING)) return false; become_user(); bool stat_changed = do_stat(); if (stat_changed && !isdir()) // Seems like a bug to send Changed after post_event(Event::Changed); // Deleted, but what would fixing it break? bool scan_entries = filesystem()->dir_entries_scanned(); dir_bits() |= SCANNING; DirectoryScanner *scanner = new DirectoryScanner(*this, Event::Created, scan_entries, scan_done_handler, this); if (scanner->done()) { delete scanner; } else { client()->enqueue_scanner(scanner); } return stat_changed;}voidDirectory::scan_task(void *closure){ Directory *dir = (Directory *) closure; dir->dir_bits() &= ~RESCAN_SCHEDULED; dir->scan();}voidDirectory::scan_done_handler(void *closure){ Directory *dir = (Directory *) closure; dir->dir_bits() &= ~SCANNING;}boolDirectory::chdir(){ if (current_dir == this) return true; int rc = ::chdir(name()); Log::debug("+chdir to \"%s\"", name()); if (rc < 0) { Log::info("can't chdir(\"%s\"): %m", name()); if ((errno == EACCES) && (client() != NULL)) { client()->suggest_insecure_compat(name()); } return false; } current_dir = this; return true;}boolDirectory::chdir_root(){ int rc = 0; if (current_dir) { rc = ::chdir("/"); Log::debug("-chdir to \"/\""); current_dir = NULL; } return rc == 0;}//// void// Directory::unhang()//// Description:// This gets called after a system call has failed with oserror()// set to ETIMEDOUT. This means that we can't contact the nfs// server. In order to reconnect when the server becomes visible// again, a process has to acually hang on the mount. We fork and// exec nfsunhang to do this for us. We don't care about// nfsunhang's exit status because we poll nfs mounts anyway.//#if HAVE_SGI_NOHANGvoidDirectory::unhang(){ int status; if (unhangPid == -1 || waitpid(unhangPid, &status, WNOHANG) != 0) { if (access("/usr/lib/nfsunhang", X_OK) == -1) { return; } unhangPid = fork(); if (unhangPid == 0) { for (int fd = getdtablesize() - 1; fd > 2; fd--) { close(fd); } execl("/usr/lib/nfsunhang", "nfsunhang", name(), NULL); exit(1); } Log::debug("unhangPid: %d", unhangPid); }}#endif // HAVE_SGI_NOHANG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -