Beispiel #1
0
/**
 * g_vfs_ftp_task_release_connection:
 * @task: a task
 *
 * Releases the connection in use by @task to the backend's connection pool,
 * or frees it if it is in an error state. You must use this function to free
 * a @task's connection, never use g_vfs_ftp_connection_free() directly. If
 * the task does not have a current connection, this function just returns.
 *
 * This function also closes all potentially open data connections.
 **/
static void
g_vfs_ftp_task_release_connection (GVfsFtpTask *task)
{
  g_return_if_fail (task != NULL);

  /* we allow task->conn == NULL to ease error cases */
  if (task->conn == NULL)
    return;

  g_vfs_ftp_task_close_data_connection (task);

  g_mutex_lock (&task->backend->mutex);
  if (task->backend->queue && g_vfs_ftp_connection_is_usable (task->conn))
    {
      g_queue_push_tail (task->backend->queue, task->conn);
      g_cond_signal (&task->backend->cond);
    }
  else
    {
      task->backend->connections--;
      g_vfs_ftp_connection_free (task->conn);
    }
  g_mutex_unlock (&task->backend->mutex);
  task->conn = NULL;
}
Beispiel #2
0
static GVfsFtpDirCacheEntry *
g_vfs_ftp_dir_cache_lookup_entry (GVfsFtpDirCache *  cache,
                                  GVfsFtpTask *      task,
                                  const GVfsFtpFile *dir,
                                  guint              stamp)
{
  GVfsFtpDirCacheEntry *entry;

  g_mutex_lock (cache->lock);
  entry = g_hash_table_lookup (cache->directories, dir);
  if (entry)
    g_vfs_ftp_dir_cache_entry_ref (entry);
  g_mutex_unlock (cache->lock);
  if (entry && entry->stamp < stamp)
    g_vfs_ftp_dir_cache_entry_unref (entry);
  else if (entry)
    return entry;

  if (g_vfs_ftp_task_send (task,
        	           G_VFS_FTP_PASS_550,
        		   "CWD %s", g_vfs_ftp_file_get_ftp_path (dir)) == 550)
    {
      g_set_error_literal (&task->error,
        	           G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY,
        		   _("The file is not a directory"));
    }
  g_vfs_ftp_task_setup_data_connection (task);
  g_vfs_ftp_task_send (task,
        	       G_VFS_FTP_PASS_100 | G_VFS_FTP_FAIL_200,
                       "%s", cache->funcs->command);
  g_vfs_ftp_task_open_data_connection (task);
  if (g_vfs_ftp_task_is_in_error (task))
    return NULL;

  entry = g_vfs_ftp_dir_cache_entry_new (stamp);
  cache->funcs->process (g_io_stream_get_input_stream (g_vfs_ftp_connection_get_data_stream (task->conn)),
                         g_vfs_ftp_connection_get_debug_id (task->conn),
                         dir,
                         entry,
                         task->cancellable,
                         &task->error);
  g_vfs_ftp_task_close_data_connection (task);
  g_vfs_ftp_task_receive (task, 0, NULL);
  if (g_vfs_ftp_task_is_in_error (task))
    {
      g_vfs_ftp_dir_cache_entry_unref (entry);
      return NULL;
    }
  g_mutex_lock (cache->lock);
  g_hash_table_insert (cache->directories,
                       g_vfs_ftp_file_copy (dir),
                       g_vfs_ftp_dir_cache_entry_ref (entry));
  g_mutex_unlock (cache->lock);
  return entry;
}
Beispiel #3
0
/**
 * g_vfs_ftp_task_send_and_check:
 * @task: the sending task
 * @flags: response flags to use when sending
 * @funcs: %NULL or %NULL-terminated array of functions used to determine the
 *         exact failure case upon a "550 Operation Failed" reply. This is
 *         often necessary
 * @data: data to pass to @funcs.
 * @reply: %NULL or pointer to take a char array containing the full reply of
 *         the ftp server upon successful reply. Use g_strfreev() to free
 *         after use.
 * @format: format string to construct command from
 *          (without trailing \r\n)
 * @...: arguments to format string
 *
 * Takes an ftp command in printf-style @format, potentially acquires a
 * connection automatically, sends the command and waits for an answer from
 * the ftp server. Without any @flags, FTP response codes other than 2xx cause
 * an error. If @reply is not %NULL, the full reply will be put into a
 * %NULL-terminated string array that must be freed with g_strfreev() after
 * use.
 * If @funcs is set, the 550 response code will cause all of these functions to
 * be called in order passing them the @task and @data arguments given to this
 * function until one of them sets an error on @task. This error will then be
 * returned from this function. If none of those functions sets an error, the
 * generic error for the 550 response will be used.
 * If an error has been set on @task previously, this function will do nothing.
 *
 * Returns: 0 on error or the received FTP code otherwise.
 **/
guint
g_vfs_ftp_task_send_and_check (GVfsFtpTask *           task,
                               GVfsFtpResponseFlags    flags,
                               const GVfsFtpErrorFunc *funcs,
                               gpointer                data,
                               char ***                reply,
                               const char *            format,
                               ...)
{
  va_list varargs;
  guint response;

  g_return_val_if_fail (task != NULL, 0);
  g_return_val_if_fail (format != NULL, 0);
  g_return_val_if_fail (funcs == NULL || funcs[0] != NULL, 0);

  if (funcs)
    {
      g_return_val_if_fail ((flags & G_VFS_FTP_PASS_550) == 0, 0);
      flags |= G_VFS_FTP_PASS_550;
    }

  va_start (varargs, format);
  response = g_vfs_ftp_task_sendv (task,
        			   flags,
                                   reply,
        			   format,
        			   varargs);
  va_end (varargs);

  if (response == 550 && funcs)
    {
      /* close a potentially open data connection, the error handlers
       * might try to open new ones and that would cause assertions */
      g_vfs_ftp_task_close_data_connection (task);

      while (*funcs && !g_vfs_ftp_task_is_in_error (task))
        {
          (*funcs) (task, data);
          funcs++;
        }
      if (!g_vfs_ftp_task_is_in_error (task))
          g_vfs_ftp_task_set_error_from_response (task, response);
      response = 0;
    }

  return response;
}