NPAPI-chrome-file-api / X11 / FileWatcherTaskX11.cpp

ryanackley ede1a92 
ryanackley cf0cb11 

















ryanackley ede1a92 



ryanackley b69351f 
ryanackley ede1a92 









ryanackley b69351f 










ryanackley ede1a92 







ryanackley b69351f 



















ryanackley ede1a92 
























ryanackley b69351f 
ryanackley ede1a92 







































ryanackley b69351f 
ryanackley ede1a92 































ryanackley b69351f 



ryanackley ede1a92 






ryanackley b69351f 
ryanackley ede1a92 

/*
* Copyright 2012 Ryan Ackley (ryanackley@gmail.com)
*
* This file is part of NPAPI Chrome File API
*
* NPAPI Chrome File API is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  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 to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/


#include "FileWatcherTaskX11.h"
#include <sys/inotify.h>
#include <sys/signal.h>
#include <iostream>
#include "variant_list.h"

#define EVENT_SIZE  ( sizeof (struct inotify_event) )
#define EVENT_BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )

using namespace boost::filesystem;

void FileWatcherTaskX11::Watch(boost::filesystem::path p, FB::JSObjectPtr callback)
{
	thread = boost::thread(boost::bind(&FileWatcherTaskX11::ListenForFileEvents, this, p, callback));
	//thread.detach();
}

/* Signal handler that does nothing. This is necessary because
 * I send a signal to interrupt pselect. Without a signal handler for my signal,
 * the process will crash. I only care about interrupting the pselect.
 * */
static void hdl (int sig)
{
	//do nothing
}

void FileWatcherTaskX11::ListenForFileEvents(boost::filesystem::path path, FB::JSObjectPtr callback)
{
	int length;//, i = 0;
	int fd;
	int wd;
	char buffer[EVENT_BUF_LEN];
	sigset_t mask;
	sigset_t orig_mask;
	struct sigaction act;

	memset (&act, 0, sizeof(act));
	act.sa_handler = hdl;

	/* This server should shut down on SIGTERM. */
	if (sigaction(SIGUSR1, &act, 0)) {
		std::cerr << ("sigaction");
		return;
	}

	sigemptyset (&mask);
    sigaddset (&mask, SIGUSR1);

    if (sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0) {
		std::cerr << "sigprocmask";
		return;
	}

	/*creating the INOTIFY instance*/
	fd = inotify_init();

	/*checking for error*/
	if ( fd < 0 ) {
		std::cerr << "inotify_init" ;
	}

	std::map<int, boost::filesystem::path*> wdMap;

	this->AddWatchToDir(fd, path, wdMap );

	while (!this->_ShouldStop())
	{
		int i = 0;
		struct timeval time;
		fd_set set;

		time.tv_sec = 10;
		time.tv_usec = 0;

		FD_ZERO(&set);
		FD_SET(fd, &set);

		int sr = pselect (FD_SETSIZE, &set, NULL, NULL, NULL, &orig_mask);
		if (!sr) //timeout
		{
			continue;
		}
		else if (sr > 0)
		{
			length = read( fd, buffer, EVENT_BUF_LEN );

			/*checking for error*/
			if ( length < 0 )
			{
				std::cerr << "read";
			}

			/*actually read return the list of change events happens. Here, read the change event one by one and process it accordingly.*/
			while ( i < length )
			{
				struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];
				if ( event->len )
				{
					if ( ((event->mask & IN_MODIFY) || (event->mask & IN_MOVED_TO)) &&  !(event->mask & IN_ISDIR) )
					{
						std::string filename = event->name;
						if (filename[0] != '.')
						{
							boost::filesystem::path* root = wdMap[event->wd];
							boost::filesystem::path fsPath = *root / filename;
							callback->Invoke("", FB::variant_list_of(fsPath.generic_string()));
						}
					}
				}
				i += EVENT_SIZE + event->len;
			}
		}
		else
		{
			std::cerr << "select";
			break;
		}
	}
	//cleanup
	std::map<int, boost::filesystem::path*>::iterator it;
	for (it = wdMap.begin(); it != wdMap.end(); it++)
	{
		inotify_rm_watch( fd, (*it).first );
		delete (*it).second;
	}

	/*closing the INOTIFY instance*/
	close( fd );
}

void FileWatcherTaskX11::AddWatchToDir(int fd, boost::filesystem::path p, std::map<int, boost::filesystem::path*> &watchDescriptors)
{
	int wd = inotify_add_watch( fd, p.generic_string().c_str(), IN_MODIFY | IN_MOVED_TO);
	watchDescriptors[wd] = new path(p);

	directory_iterator di(p);
	directory_iterator eos;

	while(di != eos)
	{
		directory_entry de = *di;
		if (is_directory(de.status())){
			this->AddWatchToDir(fd, de.path(), watchDescriptors);
		}
		di++;
	}
}

void FileWatcherTaskX11::StopWatching()
{
	this->stop = 1;
	pthread_kill(thread.native_handle(), SIGUSR1);

	boost::posix_time::time_duration timeout = boost::posix_time::seconds(5);
	thread.timed_join(timeout);
}

bool FileWatcherTaskX11::_ShouldStop()
{
	return this->stop != 0;
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.