示例#1
0
文件: main.c 项目: OPSF/uClinux
static char *get_local_name(struct file_list *flist,char *name)
{
	STRUCT_STAT st;
	int e;

	if (verbose > 2)
		rprintf(FINFO,"get_local_name count=%d %s\n",
			flist->count, NS(name));

	if (!name)
		return NULL;

	if (do_stat(name,&st) == 0) {
		if (S_ISDIR(st.st_mode)) {
			if (!push_dir(name)) {
				rsyserr(FERROR, errno, "push_dir#1 %s failed",
					full_fname(name));
				exit_cleanup(RERR_FILESELECT);
			}
			return NULL;
		}
		if (flist->count > 1) {
			rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
			exit_cleanup(RERR_FILESELECT);
		}
		return name;
	}

	if (flist->count <= 1 && ((e = strlen(name)) <= 1 || name[e-1] != '/'))
		return name;

	if (do_mkdir(name,0777 & ~orig_umask) != 0) {
		rsyserr(FERROR, errno, "mkdir %s failed", full_fname(name));
		exit_cleanup(RERR_FILEIO);
	}
	if (verbose > 0)
		rprintf(FINFO, "created directory %s\n", safe_fname(name));

	if (dry_run) {
		dry_run++;
		return NULL;
	}

	if (!push_dir(name)) {
		rsyserr(FERROR, errno, "push_dir#2 %s failed",
			full_fname(name));
		exit_cleanup(RERR_FILESELECT);
	}

	return NULL;
}
示例#2
0
文件: get_dir.c 项目: vanner-a/my_ls
t_dir		*get_dir(char *path, t_option *option) {
  DIR		*rep;
  FDIR          *file;
  FSTAT		sfile;
  t_dir		*dir;
  char		*tfile;
  
  rep = opendir(path);
  dir = 0;
  if (rep == 0) {
    display_error(path);
    return (0);
  }
  while ((file = readdir(rep)) != 0) {
    tfile = cat_path(path, file->d_name);
    if (option->opt[7] == 1)
      stat(tfile, &sfile);
    else
      lstat(tfile, &sfile);
    dir = push_dir(dir, file->d_name, sfile, tfile);
    free(tfile);
  }
  closedir(rep);
  return (dir);
}
示例#3
0
void AllTextures::Parse_textureDir(std::istream &is){
	std::string line;
	std::string scriptPath;
	Tim::String::get_line(is, line, true, true);
	if (line == "ScriptPath:") {
		Tim::String::get_line(is, line, true, true);
		scriptPath = std::string(line);
		AllTextures* dir=new AllTextures(folder_path+scriptPath);
		push_dir(dir);
	}
}
static svn_error_t *
start_element(int *elem, void *baton, int parent_state, const char *nspace,
              const char *elt_name, const char **atts)
{
  replay_baton_t *rb = baton;

  const svn_ra_neon__xml_elm_t *elm
    = svn_ra_neon__lookup_xml_elem(editor_report_elements, nspace, elt_name);

  if (! elm)
    {
      *elem = NE_XML_DECLINE;
      return SVN_NO_ERROR;
    }

  if (parent_state == ELEM_root)
    {
      /* If we're at the root of the tree, the element has to be the editor
       * report itself. */
      if (elm->id != ELEM_editor_report)
        return UNEXPECTED_ELEMENT(nspace, elt_name);
    }
  else if (parent_state != ELEM_editor_report)
    {
      /* If we're not at the root, our parent has to be the editor report,
       * since we don't actually nest any elements. */
      return UNEXPECTED_ELEMENT(nspace, elt_name);
    }

  switch (elm->id)
    {
    case ELEM_target_revision:
      {
        const char *crev = svn_xml_get_attr_value("rev", atts);
        if (! crev)
          return MISSING_ATTR(nspace, elt_name, "rev");
        else
          return rb->editor->set_target_revision(rb->edit_baton,
                                                 SVN_STR_TO_REV(crev),
                                                 rb->pool);
      }
      break;

    case ELEM_open_root:
      {
        const char *crev = svn_xml_get_attr_value("rev", atts);

        if (! crev)
          return MISSING_ATTR(nspace, elt_name, "rev");
        else
          {
            apr_pool_t *subpool = svn_pool_create(rb->pool);
            void *dir_baton;
            SVN_ERR(rb->editor->open_root(rb->edit_baton,
                                          SVN_STR_TO_REV(crev), subpool,
                                          &dir_baton));
            push_dir(rb, dir_baton, "", subpool);
          }
      }
      break;

    case ELEM_delete_entry:
      {
        const char *path = svn_xml_get_attr_value("name", atts);
        const char *crev = svn_xml_get_attr_value("rev", atts);

        if (! path)
          return MISSING_ATTR(nspace, elt_name, "name");
        else if (! crev)
          return MISSING_ATTR(nspace, elt_name, "rev");
        else
          {
            dir_item_t *di = &TOP_DIR(rb);

            SVN_ERR(rb->editor->delete_entry(path, SVN_STR_TO_REV(crev),
                                             di->baton, di->pool));
          }
      }
      break;

    case ELEM_open_directory:
    case ELEM_add_directory:
      {
        const char *crev = svn_xml_get_attr_value("rev", atts);
        const char *name = svn_xml_get_attr_value("name", atts);

        if (! name)
          return MISSING_ATTR(nspace, elt_name, "name");
        else
          {
            dir_item_t *parent = &TOP_DIR(rb);
            apr_pool_t *subpool = svn_pool_create(parent->pool);
            svn_revnum_t rev;
            void *dir_baton;

            if (crev)
              rev = SVN_STR_TO_REV(crev);
            else
              rev = SVN_INVALID_REVNUM;

            if (elm->id == ELEM_open_directory)
              SVN_ERR(rb->editor->open_directory(name, parent->baton,
                                                 rev, subpool, &dir_baton));
            else if (elm->id == ELEM_add_directory)
              {
                const char *cpath = svn_xml_get_attr_value("copyfrom-path",
                                                           atts);

                crev = svn_xml_get_attr_value("copyfrom-rev", atts);

                if (crev)
                  rev = SVN_STR_TO_REV(crev);
                else
                  rev = SVN_INVALID_REVNUM;

                SVN_ERR(rb->editor->add_directory(name, parent->baton,
                                                  cpath, rev, subpool,
                                                  &dir_baton));
              }
            else
              SVN_ERR_MALFUNCTION();

            push_dir(rb, dir_baton, name, subpool);
          }
      }
      break;

    case ELEM_open_file:
    case ELEM_add_file:
      {
        const char *path = svn_xml_get_attr_value("name", atts);
        svn_revnum_t rev;

        dir_item_t *parent = &TOP_DIR(rb);

        if (! path)
          return MISSING_ATTR(nspace, elt_name, "name");

        svn_pool_clear(parent->file_pool);

        if (elm->id == ELEM_add_file)
          {
            const char *cpath = svn_xml_get_attr_value("copyfrom-path", atts);
            const char *crev = svn_xml_get_attr_value("copyfrom-rev", atts);

            if (crev)
              rev = SVN_STR_TO_REV(crev);
            else
              rev = SVN_INVALID_REVNUM;

            SVN_ERR(rb->editor->add_file(path, parent->baton, cpath, rev,
                                         parent->file_pool, &rb->file_baton));
          }
        else
          {
            const char *crev = svn_xml_get_attr_value("rev", atts);

            if (crev)
              rev = SVN_STR_TO_REV(crev);
            else
              rev = SVN_INVALID_REVNUM;

            SVN_ERR(rb->editor->open_file(path, parent->baton, rev,
                                          parent->file_pool,
                                          &rb->file_baton));
          }
      }
      break;

    case ELEM_apply_textdelta:
      if (! rb->file_baton)
        return svn_error_create
                 (SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
                  _("Got apply-textdelta element without preceding "
                    "add-file or open-file"));
      else
        {
          const char *checksum = svn_xml_get_attr_value("checksum", atts);

          SVN_ERR(rb->editor->apply_textdelta(rb->file_baton,
                                              checksum,
                                              TOP_DIR(rb).file_pool,
                                              &rb->whandler,
                                              &rb->whandler_baton));

          rb->svndiff_decoder = svn_txdelta_parse_svndiff
                                  (rb->whandler, rb->whandler_baton,
                                   TRUE, TOP_DIR(rb).file_pool);
          rb->base64_decoder = svn_base64_decode(rb->svndiff_decoder,
                                                 TOP_DIR(rb).file_pool);
        }
      break;

    case ELEM_close_file:
      if (! rb->file_baton)
        return svn_error_create
                  (SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
                   _("Got close-file element without preceding "
                     "add-file or open-file"));
      else
        {
          const char *checksum = svn_xml_get_attr_value("checksum", atts);

          SVN_ERR(rb->editor->close_file(rb->file_baton,
                                         checksum,
                                         TOP_DIR(rb).file_pool));
          rb->file_baton = NULL;
        }
      break;

    case ELEM_close_directory:
      if (rb->dirs->nelts == 0)
        return svn_error_create
                 (SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
                  _("Got close-directory element without ever opening "
                    "a directory"));
      else
        {
          dir_item_t *di = &TOP_DIR(rb);

          SVN_ERR(rb->editor->close_directory(di->baton, di->pool));

          svn_pool_destroy(di->pool);

          apr_array_pop(rb->dirs);
        }
      break;

    case ELEM_change_file_prop:
    case ELEM_change_dir_prop:
      {
        const char *name = svn_xml_get_attr_value("name", atts);

        if (! name)
          return MISSING_ATTR(nspace, elt_name, "name");
        else
          {
            svn_pool_clear(rb->prop_pool);

            if (svn_xml_get_attr_value("del", atts))
              rb->prop_accum = NULL;
            else
              rb->prop_accum = svn_stringbuf_create("", rb->prop_pool);

            rb->prop_name = apr_pstrdup(rb->prop_pool, name);
          }
      }
      break;
    }

  *elem = elm->id;

  return SVN_NO_ERROR;
}
示例#5
0
static int rsync_module(int fd, int i)
{
	int argc=0;
	char *argv[MAX_ARGS];
	char **argp;
	char line[MAXPATHLEN];
	uid_t uid = (uid_t)-2;
	gid_t gid = (gid_t)-2;
	char *p;
	char *addr = client_addr(fd);
	char *host = client_name(fd);
	char *name = lp_name(i);
	int use_chroot = lp_use_chroot(i);
	int start_glob=0;
	int ret;
	char *request=NULL;
	extern int am_sender;
	extern int remote_version;
	extern int am_root;

	if (!allow_access(addr, host, lp_hosts_allow(i), lp_hosts_deny(i))) {
		rprintf(FERROR,"rsync denied on module %s from %s (%s)\n",
			name, client_name(fd), client_addr(fd));
		io_printf(fd,"@ERROR: access denied to %s from %s (%s)\n",
			  name, client_name(fd), client_addr(fd));
		return -1;
	}

	if (!claim_connection(lp_lock_file(i), lp_max_connections(i))) {
		if (errno) {
			rprintf(FERROR,"failed to open lock file %s : %s\n",
				lp_lock_file(i), strerror(errno));
			io_printf(fd,"@ERROR: failed to open lock file %s : %s\n",
				  lp_lock_file(i), strerror(errno));
		} else {
			rprintf(FERROR,"max connections (%d) reached\n",
				lp_max_connections(i));
			io_printf(fd,"@ERROR: max connections (%d) reached - try again later\n", lp_max_connections(i));
		}
		return -1;
	}

	
	auth_user = auth_server(fd, i, addr, "@RSYNCD: AUTHREQD ");

	if (!auth_user) {
		rprintf(FERROR,"auth failed on module %s from %s (%s)\n",
			name, client_name(fd), client_addr(fd));
		io_printf(fd,"@ERROR: auth failed on module %s\n",name);
		return -1;		
	}

	module_id = i;

	if (lp_read_only(i))
		read_only = 1;

	am_root = (getuid() == 0);

	if (am_root) {
		p = lp_uid(i);
		if (!name_to_uid(p, &uid)) {
			if (!isdigit(*p)) {
				rprintf(FERROR,"Invalid uid %s\n", p);
				io_printf(fd,"@ERROR: invalid uid\n");
				return -1;
			} 
			uid = atoi(p);
		}

		p = lp_gid(i);
		if (!name_to_gid(p, &gid)) {
			if (!isdigit(*p)) {
				rprintf(FERROR,"Invalid gid %s\n", p);
				io_printf(fd,"@ERROR: invalid gid\n");
				return -1;
			} 
			gid = atoi(p);
		}
	}

	p = lp_include_from(i);
	add_exclude_file(p, 1, 1);

	p = lp_include(i);
	add_include_line(p);

	p = lp_exclude_from(i);
	add_exclude_file(p, 1, 0);

	p = lp_exclude(i);
	add_exclude_line(p);

	log_open();

	if (use_chroot) {
		if (chroot(lp_path(i))) {
			rprintf(FERROR,"chroot %s failed\n", lp_path(i));
			io_printf(fd,"@ERROR: chroot failed\n");
			return -1;
		}

		if (!push_dir("/", 0)) {
			rprintf(FERROR,"chdir %s failed\n", lp_path(i));
			io_printf(fd,"@ERROR: chdir failed\n");
			return -1;
		}

	} else {
		if (!push_dir(lp_path(i), 0)) {
			rprintf(FERROR,"chdir %s failed\n", lp_path(i));
			io_printf(fd,"@ERROR: chdir failed\n");
			return -1;
		}
	}

	if (am_root) {
		if (setgid(gid)) {
			rprintf(FERROR,"setgid %d failed\n", gid);
			io_printf(fd,"@ERROR: setgid failed\n");
			return -1;
		}

		if (setuid(uid)) {
			rprintf(FERROR,"setuid %d failed\n", uid);
			io_printf(fd,"@ERROR: setuid failed\n");
			return -1;
		}

		am_root = (getuid() == 0);
	}

	io_printf(fd,"@RSYNCD: OK\n");

	argv[argc++] = "rsyncd";

	while (1) {
		if (!read_line(fd, line, sizeof(line)-1)) {
			return -1;
		}

		if (!*line) break;

		p = line;

		argv[argc] = strdup(p);
		if (!argv[argc]) {
			return -1;
		}

		if (start_glob) {
			if (start_glob == 1) {
				request = strdup(p);
				start_glob++;
			}
			glob_expand(name, argv, &argc, MAX_ARGS, !use_chroot);
		} else {
			argc++;
		}

		if (strcmp(line,".") == 0) {
			start_glob = 1;
		}

		if (argc == MAX_ARGS) {
			return -1;
		}
	}

	if (!use_chroot) {
		/*
		 * Note that this is applied to all parameters, whether or not
		 *    they are filenames, but no other legal parameters contain
		 *    the forms that need to be sanitized so it doesn't hurt;
		 *    it is not known at this point which parameters are files
		 *    and which aren't.
		 */
		for (i = 1; i < argc; i++) {
			sanitize_path(argv[i]);
		}
	}

	ret = parse_arguments(argc, argv, 0);

	if (request) {
		if (*auth_user) {
			rprintf(FINFO,"rsync %s %s from %s@%s (%s)\n",
				am_sender?"on":"to",
				request, auth_user, host, addr);
		} else {
			rprintf(FINFO,"rsync %s %s from %s (%s)\n",
				am_sender?"on":"to",
				request, host, addr);
		}
		free(request);
	}

#if !TRIDGE
	/* don't allow the logs to be flooded too fast */
	if (verbose > 1) verbose = 1;
#endif

	argc -= optind;
	argp = argv + optind;
	optind = 0;

	if (remote_version > 17 && am_sender)
		io_start_multiplex_out(fd);

	if (!ret) {
		option_error();
	}

	if (lp_timeout(i)) {
		extern int io_timeout;
		io_timeout = lp_timeout(i);
	}

	start_server(fd, fd, argc, argp);

	return 0;
}
示例#6
0
/* Thread: scan */
static void
process_directory(char *path, int flags)
{
  DIR *dirp;
  struct dirent buf;
  struct dirent *de;
  char entry[PATH_MAX];
  char *deref;
  struct stat sb;
  struct watch_info wi;
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  struct kevent kev;
#endif
  int type;
  int ret;

  DPRINTF(E_DBG, L_SCAN, "Processing directory %s (flags = 0x%x)\n", path, flags);

  dirp = opendir(path);
  if (!dirp)
    {
      DPRINTF(E_LOG, L_SCAN, "Could not open directory %s: %s\n", path, strerror(errno));

      return;
    }

  /* Check if compilation and/or podcast directory */
  type = 0;
  if (check_speciallib(path, "compilations"))
    type |= F_SCAN_TYPE_COMPILATION;
  if (check_speciallib(path, "podcasts"))
    type |= F_SCAN_TYPE_PODCAST;
  if (check_speciallib(path, "audiobooks"))
    type |= F_SCAN_TYPE_AUDIOBOOK;

  for (;;)
    {
      if (scan_exit)
	break;

      ret = readdir_r(dirp, &buf, &de);
      if (ret != 0)
	{
	  DPRINTF(E_LOG, L_SCAN, "readdir_r error in %s: %s\n", path, strerror(errno));

	  break;
	}

      if (de == NULL)
	break;

      if (buf.d_name[0] == '.')
	continue;

      ret = snprintf(entry, sizeof(entry), "%s/%s", path, buf.d_name);
      if ((ret < 0) || (ret >= sizeof(entry)))
	{
	  DPRINTF(E_LOG, L_SCAN, "Skipping %s/%s, PATH_MAX exceeded\n", path, buf.d_name);

	  continue;
	}

      ret = lstat(entry, &sb);
      if (ret < 0)
	{
	  DPRINTF(E_LOG, L_SCAN, "Skipping %s, lstat() failed: %s\n", entry, strerror(errno));

	  continue;
	}

      if (S_ISLNK(sb.st_mode))
	{
	  deref = m_realpath(entry);
	  if (!deref)
	    {
	      DPRINTF(E_LOG, L_SCAN, "Skipping %s, could not dereference symlink: %s\n", entry, strerror(errno));

	      continue;
	    }

	  ret = stat(deref, &sb);
	  if (ret < 0)
	    {
	      DPRINTF(E_LOG, L_SCAN, "Skipping %s, stat() failed: %s\n", deref, strerror(errno));

	      free(deref);
	      continue;
	    }

	  ret = snprintf(entry, sizeof(entry), "%s", deref);
	  free(deref);
	  if ((ret < 0) || (ret >= sizeof(entry)))
	    {
	      DPRINTF(E_LOG, L_SCAN, "Skipping %s, PATH_MAX exceeded\n", deref);

	      continue;
	    }
	}

      if (S_ISREG(sb.st_mode))
	{
	  if (!(flags & F_SCAN_FAST))
	    process_file(entry, sb.st_mtime, sb.st_size, F_SCAN_TYPE_FILE | type, flags);
	}
      else if (S_ISFIFO(sb.st_mode))
	{
	  if (!(flags & F_SCAN_FAST))
	    process_file(entry, sb.st_mtime, sb.st_size, F_SCAN_TYPE_PIPE | type, flags);
	}
      else if (S_ISDIR(sb.st_mode))
	push_dir(&dirstack, entry);
      else
	DPRINTF(E_LOG, L_SCAN, "Skipping %s, not a directory, symlink, pipe nor regular file\n", entry);
    }

  closedir(dirp);

  memset(&wi, 0, sizeof(struct watch_info));

#if defined(__linux__)
  /* Add inotify watch */
  wi.wd = inotify_add_watch(inofd, path, IN_ATTRIB | IN_CREATE | IN_DELETE | IN_CLOSE_WRITE | IN_MOVE | IN_DELETE | IN_MOVE_SELF);
  if (wi.wd < 0)
    {
      DPRINTF(E_WARN, L_SCAN, "Could not create inotify watch for %s: %s\n", path, strerror(errno));

      return;
    }

  if (!(flags & F_SCAN_MOVED))
    {
      wi.cookie = 0;
      wi.path = path;

      db_watch_add(&wi);
    }

#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  memset(&kev, 0, sizeof(struct kevent));

  wi.wd = open(path, O_RDONLY | O_NONBLOCK);
  if (wi.wd < 0)
    {
      DPRINTF(E_WARN, L_SCAN, "Could not open directory %s for watching: %s\n", path, strerror(errno));

      return;
    }

  /* Add kevent */
  EV_SET(&kev, wi.wd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_DELETE | NOTE_WRITE | NOTE_RENAME, 0, NULL);

  ret = kevent(inofd, &kev, 1, NULL, 0, NULL);
  if (ret < 0)
    {
      DPRINTF(E_WARN, L_SCAN, "Could not add kevent for %s: %s\n", path, strerror(errno));

      close(wi.wd);
      return;
    }

  wi.cookie = 0;
  wi.path = path;

  db_watch_add(&wi);
#endif
}
示例#7
0
/* Thread: scan */
static void
kqueue_cb(int fd, short event, void *arg)
{
  struct kevent kev;
  struct timespec ts;
  struct watch_info wi;
  struct watch_enum we;
  struct stacked_dir *rescan;
  struct stacked_dir *d;
  struct stacked_dir *dprev;
  char *path;
  uint32_t wd;
  int d_len;
  int w_len;
  int need_rescan;
  int ret;

  ts.tv_sec = 0;
  ts.tv_nsec = 0;

  we.cookie = 0;

  rescan = NULL;

  DPRINTF(E_DBG, L_SCAN, "Library changed!\n");

  /* We can only monitor directories with kqueue; to monitor files, we'd need
   * to have an open fd on every file in the library, which is totally insane.
   * Unfortunately, that means we only know when directories get renamed,
   * deleted or changed. We don't get directory/file names when directories/files
   * are created/deleted/renamed in the directory, so we have to rescan.
   */
  while (kevent(fd, NULL, 0, &kev, 1, &ts) > 0)
    {
      /* This should not happen, and if it does, we'll end up in
       * an infinite loop.
       */
      if (kev.filter != EVFILT_VNODE)
	continue;

      wi.wd = kev.ident;

      ret = db_watch_get_bywd(&wi);
      if (ret < 0)
	{
	  DPRINTF(E_LOG, L_SCAN, "Found no matching watch for kevent, killing this event\n");

	  close(kev.ident);
	  continue;
	}

      /* Whatever the type of event that happened, disable matching watches and
       * files before we trigger an eventual rescan.
       */
      we.match = wi.path;

      ret = db_watch_enum_start(&we);
      if (ret < 0)
	{
	  free(wi.path);
	  continue;
	}

      while ((db_watch_enum_fetchwd(&we, &wd) == 0) && (wd))
	{
	  close(wd);
	}

      db_watch_enum_end(&we);

      db_watch_delete_bymatch(wi.path);

      close(wi.wd);
      db_watch_delete_bywd(wi.wd);

      /* Disable files */
      db_file_disable_bymatch(wi.path, "", 0);
      db_pl_disable_bymatch(wi.path, "", 0);

      if (kev.flags & EV_ERROR)
	{
	  DPRINTF(E_LOG, L_SCAN, "kevent reports EV_ERROR (%s): %s\n", wi.path, strerror(kev.data));

	  ret = access(wi.path, F_OK);
	  if (ret != 0)
	    {
	      free(wi.path);
	      continue;
	    }

	  /* The directory still exists, so try to add it back to the library */
	  kev.fflags |= NOTE_WRITE;
	}

      /* No further action on NOTE_DELETE & NOTE_RENAME; NOTE_WRITE on the
       * parent directory will trigger a rescan in both cases and the
       * renamed directory will be picked up then.
       */

      if (kev.fflags & NOTE_WRITE)
	{
          DPRINTF(E_DBG, L_SCAN, "Got NOTE_WRITE (%s)\n", wi.path);

	  need_rescan = 1;
	  w_len = strlen(wi.path);

	  /* Abusing stacked_dir a little bit here */
	  dprev = NULL;
	  d = rescan;
	  while (d)
	    {
	      d_len = strlen(d->path);

	      if (d_len > w_len)
		{
		  /* Stacked dir child of watch dir? */
		  if ((d->path[w_len] == '/') && (strncmp(d->path, wi.path, w_len) == 0))
		    {
		      DPRINTF(E_DBG, L_SCAN, "Watched directory is a parent\n");

		      if (dprev)
			dprev->next = d->next;
		      else
			rescan = d->next;

		      free(d->path);
		      free(d);

		      if (dprev)
			d = dprev->next;
		      else
			d = rescan;

		      continue;
		    }
		}
	      else if (w_len > d_len)
		{
		  /* Watch dir child of stacked dir? */
		  if ((wi.path[d_len] == '/') && (strncmp(wi.path, d->path, d_len) == 0))
		    {
		      DPRINTF(E_DBG, L_SCAN, "Watched directory is a child\n");

		      need_rescan = 0;
		      break;
		    }
		}
	      else if (strcmp(wi.path, d->path) == 0)
		{
		  DPRINTF(E_DBG, L_SCAN, "Watched directory already listed\n");

		  need_rescan = 0;
		  break;
		}

	      dprev = d;
	      d = d->next;
	    }

	  if (need_rescan)
	    push_dir(&rescan, wi.path);
	}

      free(wi.path);
    }

  while ((path = pop_dir(&rescan)))
    {
      process_directories(path, 0);

      free(path);

      if (rescan)
	DPRINTF(E_LOG, L_SCAN, "WARNING: unhandled leftover directories\n");
    }

  event_add(&inoev, NULL);
}
示例#8
0
/* Thread: scan */
static void
process_directory(char *path, int flags)
{
  struct stacked_dir *bulkstack;
  DIR *dirp;
  struct dirent buf;
  struct dirent *de;
  char entry[PATH_MAX];
  char *deref;
  struct stat sb;
  struct watch_info wi;
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  struct kevent kev;
#endif
  int compilation;
  int ret;

  if (flags & F_SCAN_BULK)
    {
      /* Save our directory stack so it won't get handled inside
       * the event loop - not its business, we're in bulk mode here.
       */
      bulkstack = dirstack;
      dirstack = NULL;

      /* Run the event loop */
      event_base_loop(evbase_scan, EVLOOP_ONCE | EVLOOP_NONBLOCK);

      /* Restore our directory stack */
      dirstack = bulkstack;

      if (scan_exit)
	return;
    }

  DPRINTF(E_DBG, L_SCAN, "Processing directory %s (flags = 0x%x)\n", path, flags);

  dirp = opendir(path);
  if (!dirp)
    {
      DPRINTF(E_LOG, L_SCAN, "Could not open directory %s: %s\n", path, strerror(errno));

      return;
    }

  /* Check for a compilation directory */
  compilation = check_compilation(path);

  for (;;)
    {
      ret = readdir_r(dirp, &buf, &de);
      if (ret != 0)
	{
	  DPRINTF(E_LOG, L_SCAN, "readdir_r error in %s: %s\n", path, strerror(errno));

	  break;
	}

      if (de == NULL)
	break;

      if (buf.d_name[0] == '.')
	continue;

      ret = snprintf(entry, sizeof(entry), "%s/%s", path, buf.d_name);
      if ((ret < 0) || (ret >= sizeof(entry)))
	{
	  DPRINTF(E_LOG, L_SCAN, "Skipping %s/%s, PATH_MAX exceeded\n", path, buf.d_name);

	  continue;
	}

      ret = lstat(entry, &sb);
      if (ret < 0)
	{
	  DPRINTF(E_LOG, L_SCAN, "Skipping %s, lstat() failed: %s\n", entry, strerror(errno));

	  continue;
	}

      if (S_ISLNK(sb.st_mode))
	{
	  deref = m_realpath(entry);
	  if (!deref)
	    {
	      DPRINTF(E_LOG, L_SCAN, "Skipping %s, could not dereference symlink: %s\n", entry, strerror(errno));

	      continue;
	    }

	  ret = stat(deref, &sb);
	  if (ret < 0)
	    {
	      DPRINTF(E_LOG, L_SCAN, "Skipping %s, stat() failed: %s\n", deref, strerror(errno));

	      free(deref);
	      continue;
	    }

	  ret = snprintf(entry, sizeof(entry), "%s", deref);
	  free(deref);
	  if ((ret < 0) || (ret >= sizeof(entry)))
	    {
	      DPRINTF(E_LOG, L_SCAN, "Skipping %s, PATH_MAX exceeded\n", deref);

	      continue;
	    }
	}

      if (S_ISREG(sb.st_mode))
	process_file(entry, sb.st_mtime, sb.st_size, compilation, flags);
      else if (S_ISDIR(sb.st_mode))
	push_dir(&dirstack, entry);
      else
	DPRINTF(E_LOG, L_SCAN, "Skipping %s, not a directory, symlink nor regular file\n", entry);
    }

  closedir(dirp);

  memset(&wi, 0, sizeof(struct watch_info));

#if defined(__linux__)
  /* Add inotify watch */
  wi.wd = inotify_add_watch(inofd, path, IN_CREATE | IN_DELETE | IN_MODIFY | IN_CLOSE_WRITE | IN_MOVE | IN_DELETE | IN_MOVE_SELF);
  if (wi.wd < 0)
    {
      DPRINTF(E_WARN, L_SCAN, "Could not create inotify watch for %s: %s\n", path, strerror(errno));

      return;
    }

  if (!(flags & F_SCAN_RESCAN))
    {
      wi.cookie = 0;
      wi.path = path;

      db_watch_add(&wi);
    }

#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  memset(&kev, 0, sizeof(struct kevent));

  wi.wd = open(path, O_RDONLY | O_NONBLOCK);
  if (wi.wd < 0)
    {
      DPRINTF(E_WARN, L_SCAN, "Could not open directory %s for watching: %s\n", path, strerror(errno));

      return;
    }

  /* Add kevent */
  EV_SET(&kev, wi.wd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_DELETE | NOTE_WRITE | NOTE_RENAME, 0, NULL);

  ret = kevent(inofd, &kev, 1, NULL, 0, NULL);
  if (ret < 0)
    {
      DPRINTF(E_WARN, L_SCAN, "Could not add kevent for %s: %s\n", path, strerror(errno));

      close(wi.wd);
      return;
    }

  wi.cookie = 0;
  wi.path = path;

  db_watch_add(&wi);
#endif
}
示例#9
0
static void
process_directory(char *path, int parent_id, int flags)
{
  DIR *dirp;
  struct dirent buf;
  struct dirent *de;
  char entry[PATH_MAX];
  char *deref;
  struct stat sb;
  struct watch_info wi;
  int type;
  char virtual_path[PATH_MAX];
  int dir_id;
  int ret;

  DPRINTF(E_DBG, L_SCAN, "Processing directory %s (flags = 0x%x)\n", path, flags);

  dirp = opendir(path);
  if (!dirp)
    {
      DPRINTF(E_LOG, L_SCAN, "Could not open directory %s: %s\n", path, strerror(errno));

      return;
    }

  /* Add/update directories table */

  ret = create_virtual_path(path, virtual_path, sizeof(virtual_path));
  if (ret < 0)
    return;

  dir_id = db_directory_addorupdate(virtual_path, 0, parent_id);
  if (dir_id <= 0)
    {
      DPRINTF(E_LOG, L_SCAN, "Insert or update of directory failed '%s'\n", virtual_path);
    }

  /* Check if compilation and/or podcast directory */
  type = 0;
  if (check_speciallib(path, "compilations"))
    type |= F_SCAN_TYPE_COMPILATION;
  if (check_speciallib(path, "podcasts"))
    type |= F_SCAN_TYPE_PODCAST;
  if (check_speciallib(path, "audiobooks"))
    type |= F_SCAN_TYPE_AUDIOBOOK;

  for (;;)
    {
      if (scan_exit)
	break;

      ret = readdir_r(dirp, &buf, &de);
      if (ret != 0)
	{
	  DPRINTF(E_LOG, L_SCAN, "readdir_r error in %s: %s\n", path, strerror(errno));

	  break;
	}

      if (de == NULL)
	break;

      if (buf.d_name[0] == '.')
	continue;

      ret = snprintf(entry, sizeof(entry), "%s/%s", path, buf.d_name);
      if ((ret < 0) || (ret >= sizeof(entry)))
	{
	  DPRINTF(E_LOG, L_SCAN, "Skipping %s/%s, PATH_MAX exceeded\n", path, buf.d_name);

	  continue;
	}

      ret = lstat(entry, &sb);
      if (ret < 0)
	{
	  DPRINTF(E_LOG, L_SCAN, "Skipping %s, lstat() failed: %s\n", entry, strerror(errno));

	  continue;
	}

      if (S_ISLNK(sb.st_mode))
	{
	  deref = m_realpath(entry);
	  if (!deref)
	    {
	      DPRINTF(E_LOG, L_SCAN, "Skipping %s, could not dereference symlink: %s\n", entry, strerror(errno));

	      continue;
	    }

	  ret = stat(deref, &sb);
	  if (ret < 0)
	    {
	      DPRINTF(E_LOG, L_SCAN, "Skipping %s, stat() failed: %s\n", deref, strerror(errno));

	      free(deref);
	      continue;
	    }

	  ret = snprintf(entry, sizeof(entry), "%s", deref);
	  free(deref);
	  if ((ret < 0) || (ret >= sizeof(entry)))
	    {
	      DPRINTF(E_LOG, L_SCAN, "Skipping %s, PATH_MAX exceeded\n", deref);

	      continue;
	    }
	}

      if (S_ISREG(sb.st_mode))
	{
	  if (!(flags & F_SCAN_FAST))
	    process_file(entry, sb.st_mtime, sb.st_size, F_SCAN_TYPE_FILE | type, flags, dir_id);
	}
      else if (S_ISFIFO(sb.st_mode))
	{
	  if (!(flags & F_SCAN_FAST))
	    process_file(entry, sb.st_mtime, sb.st_size, F_SCAN_TYPE_PIPE | type, flags, dir_id);
	}
      else if (S_ISDIR(sb.st_mode))
	push_dir(&dirstack, entry, dir_id);
      else
	DPRINTF(E_LOG, L_SCAN, "Skipping %s, not a directory, symlink, pipe nor regular file\n", entry);
    }

  closedir(dirp);

  memset(&wi, 0, sizeof(struct watch_info));

  // Add inotify watch (for FreeBSD we limit the flags so only dirs will be
  // opened, otherwise we will be opening way too many files)
#if defined(__linux__)
  wi.wd = inotify_add_watch(inofd, path, IN_ATTRIB | IN_CREATE | IN_DELETE | IN_CLOSE_WRITE | IN_MOVE | IN_DELETE | IN_MOVE_SELF);
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  wi.wd = inotify_add_watch(inofd, path, IN_CREATE | IN_DELETE | IN_MOVE);
#endif
  if (wi.wd < 0)
    {
      DPRINTF(E_WARN, L_SCAN, "Could not create inotify watch for %s: %s\n", path, strerror(errno));

      return;
    }

  if (!(flags & F_SCAN_MOVED))
    {
      wi.cookie = 0;
      wi.path = path;

      db_watch_add(&wi);
    }
}
示例#10
0
文件: main.c 项目: OPSF/uClinux
static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
{
	int status;
	struct file_list *flist;
	char *local_name = NULL;
	char *dir = NULL;
	int save_verbose = verbose;

	if (filesfrom_fd >= 0) {
		/* We can't mix messages with files-from data on the socket,
		 * so temporarily turn off verbose messages. */
		verbose = 0;
	}

	if (verbose > 2) {
		rprintf(FINFO, "server_recv(%d) starting pid=%ld\n",
			argc, (long)getpid());
	}

	if (am_daemon && lp_read_only(module_id)) {
		rprintf(FERROR,"ERROR: module is read only\n");
		exit_cleanup(RERR_SYNTAX);
		return;
	}


	if (argc > 0) {
		dir = argv[0];
		argc--;
		argv++;
		if (!am_daemon && !push_dir(dir)) {
			rsyserr(FERROR, errno, "push_dir#4 %s failed",
				full_fname(dir));
			exit_cleanup(RERR_FILESELECT);
		}
	}

	io_start_buffering_in();
	recv_filter_list(f_in);

	if (filesfrom_fd >= 0) {
		/* We need to send the files-from names to the sender at the
		 * same time that we receive the file-list from them, so we
		 * need the IO routines to automatically write out the names
		 * onto our f_out socket as we read the file-list.  This
		 * avoids both deadlock and extra delays/buffers. */
		io_set_filesfrom_fds(filesfrom_fd, f_out);
		filesfrom_fd = -1;
	}

	flist = recv_file_list(f_in);
	verbose = save_verbose;
	if (!flist) {
		rprintf(FERROR,"server_recv: recv_file_list error\n");
		exit_cleanup(RERR_FILESELECT);
	}
	the_file_list = flist;

	if (argc > 0) {
		if (strcmp(dir,".")) {
			argv[0] += strlen(dir);
			if (argv[0][0] == '/')
				argv[0]++;
		}
		local_name = get_local_name(flist,argv[0]);
	}

	status = do_recv(f_in,f_out,flist,local_name);
	exit_cleanup(status);
}
示例#11
0
文件: main.c 项目: OPSF/uClinux
static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
{
	int i;
	struct file_list *flist;
	char *dir = argv[0];

	if (verbose > 2) {
		rprintf(FINFO, "server_sender starting pid=%ld\n",
			(long)getpid());
	}

	if (am_daemon && lp_write_only(module_id)) {
		rprintf(FERROR, "ERROR: module is write only\n");
		exit_cleanup(RERR_SYNTAX);
		return;
	}
	if (am_daemon && lp_read_only(module_id) && remove_sent_files) {
		rprintf(FERROR,
		    "ERROR: --remove-sent-files cannot be used with a read-only module\n");
		exit_cleanup(RERR_SYNTAX);
		return;
	}

	if (!relative_paths && !push_dir(dir)) {
		rsyserr(FERROR, errno, "push_dir#3 %s failed",
			full_fname(dir));
		exit_cleanup(RERR_FILESELECT);
	}
	argc--;
	argv++;

	if (strcmp(dir,".")) {
		int l = strlen(dir);
		if (strcmp(dir,"/") == 0)
			l = 0;
		for (i = 0; i < argc; i++)
			argv[i] += l+1;
	}

	if (argc == 0 && (recurse || list_only)) {
		argc = 1;
		argv--;
		argv[0] = ".";
	}

	flist = send_file_list(f_out,argc,argv);
	if (!flist || flist->count == 0) {
		exit_cleanup(0);
	}
	the_file_list = flist;

	io_start_buffering_in();
	io_start_buffering_out();

	send_files(flist,f_out,f_in);
	io_flush(FULL_FLUSH);
	handle_stats(f_out);
	if (protocol_version >= 24)
		read_final_goodbye(f_in, f_out);
	io_flush(FULL_FLUSH);
	exit_cleanup(0);
}
示例#12
0
文件: main.c 项目: OPSF/uClinux
int main(int argc,char *argv[])
{
	int ret;
	int orig_argc = argc;
	char **orig_argv = argv;

	signal(SIGUSR1, sigusr1_handler);
	signal(SIGUSR2, sigusr2_handler);
	signal(SIGCHLD, sigchld_handler);
#ifdef MAINTAINER_MODE
	signal(SIGSEGV, rsync_panic_handler);
	signal(SIGFPE, rsync_panic_handler);
	signal(SIGABRT, rsync_panic_handler);
	signal(SIGBUS, rsync_panic_handler);
#endif /* def MAINTAINER_MODE */

	starttime = time(NULL);
	am_root = (MY_UID() == 0);

	memset(&stats, 0, sizeof(stats));

	if (argc < 2) {
		usage(FERROR);
		exit_cleanup(RERR_SYNTAX);
	}

	/* we set a 0 umask so that correct file permissions can be
	 * carried across */
	orig_umask = (int)umask(0);

	if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
		/* FIXME: We ought to call the same error-handling
		 * code here, rather than relying on getopt. */
		option_error();
		exit_cleanup(RERR_SYNTAX);
	}

	signal(SIGINT,SIGNAL_CAST sig_int);
	signal(SIGHUP,SIGNAL_CAST sig_int);
	signal(SIGTERM,SIGNAL_CAST sig_int);

	/* Ignore SIGPIPE; we consistently check error codes and will
	 * see the EPIPE. */
	signal(SIGPIPE, SIG_IGN);

#if defined CONFIG_LOCALE && defined HAVE_SETLOCALE
	setlocale(LC_CTYPE, "");
#endif

	/* Initialize push_dir here because on some old systems getcwd
	 * (implemented by forking "pwd" and reading its output) doesn't
	 * work when there are other child processes.  Also, on all systems
	 * that implement getcwd that way "pwd" can't be found after chroot. */
	push_dir(NULL);

	init_flist();

	if ((write_batch || read_batch) && !am_server) {
		if (write_batch)
			write_batch_shell_file(orig_argc, orig_argv, argc);

		if (read_batch && strcmp(batch_name, "-") == 0)
			batch_fd = STDIN_FILENO;
		else {
			batch_fd = do_open(batch_name,
				   write_batch ? O_WRONLY | O_CREAT | O_TRUNC
				   : O_RDONLY, S_IRUSR | S_IWUSR);
		}
		if (batch_fd < 0) {
			rsyserr(FERROR, errno, "Batch file %s open error",
				full_fname(batch_name));
			exit_cleanup(RERR_FILEIO);
		}
		if (read_batch)
			read_stream_flags(batch_fd);
	}
	if (write_batch < 0)
		dry_run = 1;

	if (am_daemon && !am_server)
		return daemon_main();

	if (argc < 1) {
		usage(FERROR);
		exit_cleanup(RERR_SYNTAX);
	}

	if (am_server) {
		set_nonblocking(STDIN_FILENO);
		set_nonblocking(STDOUT_FILENO);
		if (am_daemon)
			return start_daemon(STDIN_FILENO, STDOUT_FILENO);
		start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
	}

	ret = start_client(argc, argv);
	if (ret == -1)
		exit_cleanup(RERR_STARTCLIENT);
	else
		exit_cleanup(ret);

	return ret;
}