Ejemplo n.º 1
0
/* Normally, this module uses get and put. But for creation of new files
 * with owncloud_creat, write is still needed.
 */
static ssize_t owncloud_write(csync_vio_method_handle_t *fhandle, const void *buf, size_t count) {

  struct transfer_context *writeCtx;
  int rc = 0;
  int neon_stat;
  const ne_status *status;

  writeCtx = (struct transfer_context*) fhandle;

  if (fhandle == NULL) {
      errno = EBADF;
      rc = -1;
  }

  ne_set_request_body_buffer(writeCtx->req, buf, count );

  /* Start the request. */
  neon_stat = ne_request_dispatch( writeCtx->req );
  set_errno_from_neon_errcode( neon_stat );

  status = ne_get_status( writeCtx->req );
  if( status->klass != 2 ) {
    DEBUG_WEBDAV("sendfile request failed with http status %d!", status->code);
    set_errno_from_http_errcode( status->code );
    /* decide if soft error or hard error that stops the whole sync. */
    /* Currently all problems concerning one file are soft errors */
    if( status->klass == 4 /* Forbidden and stuff, soft error */ ) {
      rc = 1;
    } else if( status->klass == 5 /* Server errors and such */ ) {
      rc = 1; /* No Abort on individual file errors. */
    } else {
      rc = 1;
    }
  } else {
    DEBUG_WEBDAV("write request all ok, result code %d", status->code);
  }

  return rc;
}
Ejemplo n.º 2
0
static int fetch_resource_list( const char *uri,
                                int depth,
                                struct listdir_context *fetchCtx )
{
  int ret = 0;
  ne_propfind_handler *hdl = NULL;
  ne_request *request = NULL;
  const char *content_type = NULL;
  char *curi = NULL;
  const ne_status *req_status = NULL;

  curi = _cleanPath( uri );

  if (!fetchCtx) {
    errno = ENOMEM;
    SAFE_FREE(curi);
    return -1;
  }
  fetchCtx->list = NULL;
  fetchCtx->target = curi;
  fetchCtx->currResource = NULL;

  /* do a propfind request and parse the results in the results function, set as callback */
  hdl = ne_propfind_create(dav_session.ctx, curi, depth);

  if(hdl) {
    ret = ne_propfind_named(hdl, ls_props, results, fetchCtx);
    request = ne_propfind_get_request( hdl );
    req_status = ne_get_status( request );
  }

  if( ret == NE_OK ) {
    fetchCtx->currResource = fetchCtx->list;
    /* Check the request status. */
    if( req_status && req_status->klass != 2 ) {
      set_errno_from_http_errcode(req_status->code);
      DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
                   req_status->reason_phrase);
      ret = NE_CONNECT;
      set_error_message(req_status->reason_phrase);
    }
    DEBUG_WEBDAV("Simple propfind result code %d.", req_status ? req_status->code : -1);
  } else {
    if( ret == NE_ERROR && req_status->code == 404) {
      errno = ENOENT;
    } else {
      set_errno_from_neon_errcode(ret);
    }
  }

  if( ret == NE_OK ) {
    /* Check the content type. If the server has a problem, ie. database is gone or such,
        * the content type is not xml but a html error message. Stop on processing if it's
        * not XML.
        * FIXME: Generate user error message from the reply content.
        */
    content_type =  ne_get_response_header( request, "Content-Type" );
    if( !(content_type && c_streq(content_type, "application/xml; charset=utf-8") ) ) {
      DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
                   content_type ?  content_type: "<empty>");
      errno = ERRNO_WRONG_CONTENT;
      set_error_message("Server error: PROPFIND reply is not XML formatted!");
      ret = NE_CONNECT;
    }
  }
#ifndef NDEBUG
  if( ret != NE_OK ) {
    const char *err = ne_get_error(dav_session.ctx);
    DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
  }
#endif /* NDEBUG */

  if (hdl != NULL) {
    ne_propfind_destroy(hdl);
  }

#ifndef NDEBUG
  if (ret == NE_REDIRECT) {
    const ne_uri *redir_ne_uri = ne_redirect_location(dav_session.ctx);
    if (redir_ne_uri) {
      char *redir_uri = ne_uri_unparse(redir_ne_uri);
      DEBUG_WEBDAV("Permanently moved to %s", redir_uri);
    }
  }
#endif /* NDEBUG */

  if( ret != NE_OK ) {
    free_fetchCtx(fetchCtx);
    return -1;
  }

  return 0;
}
Ejemplo n.º 3
0
/* Gets a file from the owncloud url to the open file descriptor. */
static int owncloud_get(csync_vio_method_handle_t *flocal,
                        csync_vio_method_handle_t *fremote,
                        csync_vio_file_stat_t *vfs) {
  int rc = 0;
  int neon_stat;
  const ne_status *status;
  int fd;

  struct transfer_context *write_ctx = (struct transfer_context*) fremote;
  (void) vfs; /* stat information of the source file */

  fd = csync_vio_getfd(flocal);
  if (fd == -1) {
    errno = EINVAL;
    return -1;
  }

  /* GET a file to the open file descriptor */
  if( write_ctx == NULL ) {
    errno = EINVAL;
    return -1;
  }

  if( write_ctx->req == NULL ) {
    errno = EINVAL;
    return -1;
  }

  DEBUG_WEBDAV("  -- GET on %s", write_ctx->url);

  write_ctx->fd = fd;

  /* Allow compressed content by setting the header */
  ne_add_request_header( write_ctx->req, "Accept-Encoding", "gzip,deflate" );

  /* hook called before the content is parsed to set the correct reader,
         * either the compressed- or uncompressed reader.
         */
  ne_hook_post_headers( dav_session.ctx, install_content_reader, write_ctx );

  neon_stat = ne_request_dispatch(write_ctx->req );
  /* possible return codes are:
   *  NE_OK, NE_AUTH, NE_CONNECT, NE_TIMEOUT, NE_ERROR (from ne_request.h)
   */

  if( neon_stat != NE_OK ) {
    set_errno_from_neon_errcode(neon_stat);
    DEBUG_WEBDAV("Error GET: Neon: %d, errno %d", neon_stat, errno);
    rc = -1;
  } else {
    status = ne_get_status( write_ctx->req );
    if( status->klass != 2 ) {
      DEBUG_WEBDAV("sendfile request failed with http status %d!", status->code);
      set_errno_from_http_errcode( status->code );
      /* decide if soft error or hard error that stops the whole sync. */
      /* Currently all problems concerning one file are soft errors */
      if( status->klass == 4 /* Forbidden and stuff, soft error */ ) {
        rc = 1;
      } else if( status->klass == 5 /* Server errors and such */ ) {
        rc = 1; /* No Abort on individual file errors. */
      } else {
        rc = 1;
      }
    } else {
      DEBUG_WEBDAV("http request all cool, result code %d (%s)", status->code,
                   status->reason_phrase ? status->reason_phrase : "<empty>");
    }
  }

  /* delete the hook again, otherwise they get chained as they are with the session */
  ne_unhook_post_headers( dav_session.ctx, install_content_reader, write_ctx );

  /* if the compression handle is set through the post_header hook, delete it. */
  if( write_ctx->decompress ) {
    ne_decompress_destroy( write_ctx->decompress );
  }

  return rc;
}
Ejemplo n.º 4
0
/*
 * Puts a file read from the open file descriptor to the ownCloud URL.
*/
static int owncloud_put(csync_vio_method_handle_t *flocal,
                        csync_vio_method_handle_t *fremote,
                        csync_vio_file_stat_t *vfs) {
  int rc = 0;
  int neon_stat;
  const ne_status *status;
  csync_stat_t sb;
  struct transfer_context *write_ctx = (struct transfer_context*) fremote;
  int fd;
  ne_request *request = NULL;

  fd = csync_vio_getfd(flocal);
  if (fd == -1) {
      errno = EINVAL;
      return -1;
  }

  if( write_ctx == NULL ) {
      errno = EINVAL;
      return -1;
  }
  request = write_ctx->req;

  if( request == NULL) {
    errno = EINVAL;
    return -1;
  }

  /* stat the source-file to get the file size. */
  if( fstat( fd, &sb ) == 0 ) {
    if( sb.st_size != vfs->size ) {
      DEBUG_WEBDAV("WRN: Stat size differs from vfs size!");
    }
    /* Attach the request to the file descriptor */
    ne_set_request_body_fd(request, fd, 0, sb.st_size);
    DEBUG_WEBDAV("Put file size: %lld, variable sizeof: %ld", (long long int) sb.st_size,
                 sizeof(sb.st_size));

    /* Start the request. */
    neon_stat = ne_request_dispatch( write_ctx->req );
    set_errno_from_neon_errcode( neon_stat );

    status = ne_get_status( request );
    if( status->klass != 2 ) {
      DEBUG_WEBDAV("sendfile request failed with http status %d!", status->code);
      set_errno_from_http_errcode( status->code );
      /* decide if soft error or hard error that stops the whole sync. */
      /* Currently all problems concerning one file are soft errors */
      if( status->klass == 4 /* Forbidden and stuff, soft error */ ) {
        rc = 1;
      } else if( status->klass == 5 /* Server errors and such */ ) {
        rc = 1; /* No Abort on individual file errors. */
      } else {
        rc = 1;
      }
    } else {
      DEBUG_WEBDAV("http request all cool, result code %d", status->code);
    }
  } else {
    DEBUG_WEBDAV("Could not stat file descriptor");
    rc = 1;
  }

  return rc;
}
void fetch_resource_list_recursive(const char *uri, const char *curi)
{
    int ret = 0;
    ne_propfind_handler *hdl = NULL;
    ne_request *request = NULL;
    const char *content_type = NULL;
    const ne_status *req_status = NULL;
    int depth = NE_DEPTH_INFINITE;

    DEBUG_WEBDAV("fetch_resource_list_recursive Starting recursive propfind %s %s", uri, curi);

    /* do a propfind request and parse the results in the results function, set as callback */
    hdl = ne_propfind_create(dav_session.ctx, curi, depth);

    if(hdl) {
        ret = ne_propfind_named(hdl, ls_props, propfind_results_recursive, (void*)curi);
        request = ne_propfind_get_request( hdl );
        req_status = ne_get_status( request );
    }

    if( ret == NE_OK ) {
        /* Check the request status. */
        if( req_status && req_status->klass != 2 ) {
            set_errno_from_http_errcode(req_status->code);
            DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
                         req_status->reason_phrase);
            ret = NE_CONNECT;
            set_error_message(req_status->reason_phrase);
        }
        DEBUG_WEBDAV("Recursive propfind result code %d.", req_status ? req_status->code : 0);
    } else {
        if( ret == NE_ERROR && req_status->code == 404) {
            errno = ENOENT;
        } else {
            set_errno_from_neon_errcode(ret);
        }
    }

    if( ret == NE_OK ) {
        /* Check the content type. If the server has a problem, ie. database is gone or such,
         * the content type is not xml but a html error message. Stop on processing if it's
         * not XML.
         * FIXME: Generate user error message from the reply content.
         */
        content_type =  ne_get_response_header( request, "Content-Type" );
        if( !(content_type && c_streq(content_type, "application/xml; charset=utf-8") ) ) {
            DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
                         content_type ?  content_type: "<empty>");
            errno = ERRNO_WRONG_CONTENT;
            set_error_message("Server error: PROPFIND reply is not XML formatted!");
            ret = NE_CONNECT;
        }
    }

    if( ret != NE_OK ) {
        const char *err = NULL;

        err = ne_get_error( dav_session.ctx );
        DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
    }

    if( hdl )
        ne_propfind_destroy(hdl);

    if( ret != NE_OK ) {
        return;
    }

    return;
}
Ejemplo n.º 6
0
/*
 * fetches a resource list from the WebDAV server. This is equivalent to list dir.
 */
static struct listdir_context *fetch_resource_list(const char *uri, int depth)
{
    struct listdir_context *fetchCtx;
    int ret = 0;
    ne_propfind_handler *hdl = NULL;
    ne_request *request = NULL;
    const char *content_type = NULL;
    char *curi = NULL;
    const ne_status *req_status = NULL;

    curi = _cleanPath( uri );

    /* The old legacy one-level PROPFIND cache. Also gets filled
       by the recursive cache if 'infinity' did not suceed. */
    if (propfind_cache) {
        if (c_streq(curi, propfind_cache->target)) {
            DEBUG_WEBDAV("fetch_resource_list Using simple PROPFIND cache %s", curi);
            propfind_cache->ref++;
            SAFE_FREE(curi);
            return propfind_cache;
        }
    }

    fetchCtx = c_malloc( sizeof( struct listdir_context ));
    if (!fetchCtx) {
        errno = ENOMEM;
        SAFE_FREE(curi);
        return NULL;
    }
    fetchCtx->list = NULL;
    fetchCtx->target = curi;
    fetchCtx->currResource = NULL;
    fetchCtx->ref = 1;

    /* do a propfind request and parse the results in the results function, set as callback */
    hdl = ne_propfind_create(dav_session.ctx, curi, depth);

    if(hdl) {
        ret = ne_propfind_named(hdl, ls_props, results, fetchCtx);
        request = ne_propfind_get_request( hdl );
        req_status = ne_get_status( request );
    }

    if( ret == NE_OK ) {
        fetchCtx->currResource = fetchCtx->list;
        /* Check the request status. */
        if( req_status && req_status->klass != 2 ) {
            set_errno_from_http_errcode(req_status->code);
            DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
                         req_status->reason_phrase);
            ret = NE_CONNECT;
            set_error_message(req_status->reason_phrase);
            oc_notify_progress( uri, CSYNC_NOTIFY_ERROR,
                                req_status->code,
                                (intptr_t)(req_status->reason_phrase) );
        }
        DEBUG_WEBDAV("Simple propfind result code %d.", req_status->code);
    } else {
        if( ret == NE_ERROR && req_status->code == 404) {
            errno = ENOENT;
        } else {
            set_errno_from_neon_errcode(ret);
        }
    }

    if( ret == NE_OK ) {
        /* Check the content type. If the server has a problem, ie. database is gone or such,
         * the content type is not xml but a html error message. Stop on processing if it's
         * not XML.
         * FIXME: Generate user error message from the reply content.
         */
        content_type =  ne_get_response_header( request, "Content-Type" );
        if( !(content_type && c_streq(content_type, "application/xml; charset=utf-8") ) ) {
            DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
                         content_type ?  content_type: "<empty>");
            errno = ERRNO_WRONG_CONTENT;
            set_error_message("Server error: PROPFIND reply is not XML formatted!");
            ret = NE_CONNECT;
        }
    }

    if( ret != NE_OK ) {
        const char *err = NULL;
        set_errno_from_neon_errcode(ret);

        err = ne_get_error( dav_session.ctx );
        if(err) {
            set_error_message(err);
        }
        DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
    }

    if( hdl )
        ne_propfind_destroy(hdl);

    if( ret != NE_OK ) {
        free_fetchCtx(fetchCtx);
        return NULL;
    }

    free_fetchCtx(propfind_cache);
    propfind_cache = fetchCtx;
    propfind_cache->ref++;
    return fetchCtx;
}
Ejemplo n.º 7
0
static const char* owncloud_get_etag( const char *path )
{
    ne_request *req    = NULL;
    const char *header = NULL;
    char *uri          = _cleanPath(path);
    char *cbuf   = NULL;
    csync_vio_file_stat_t *fs = NULL;
    bool doHeadRequest = false;

    if (_id_cache.uri && c_streq(path, _id_cache.uri)) {
        header = _id_cache.id;
    }

    doHeadRequest= false; /* ownCloud server doesn't have good support for HEAD yet */

    if( !header && doHeadRequest ) {
        int neon_stat;
        /* Perform an HEAD request to the resource. HEAD delivers the
         * ETag header back. */
        req = ne_request_create(dav_session.ctx, "HEAD", uri);
        neon_stat = ne_request_dispatch(req);
        set_errno_from_neon_errcode( neon_stat );

        header = ne_get_response_header(req, "etag");
    }
    /* If the request went wrong or the server did not respond correctly
     * (that can happen for collections) a stat call is done which translates
     * into a PROPFIND request.
     */
    if( ! header ) {
        /* ... and do a stat call. */
        fs = csync_vio_file_stat_new();
        if(fs == NULL) {
            DEBUG_WEBDAV( "owncloud_get_etag: memory fault.");
            errno = ENOMEM;
            return NULL;
        }
        if( owncloud_stat( path, fs ) == 0 ) {
            header = fs->etag;
        }
    }

    /* In case the result is surrounded by "" cut them away. */
    if( header ) {
        cbuf = csync_normalize_etag(header);
    }

    /* fix server problem: If we end up with an empty string, set something strange... */
    if( c_streq(cbuf, "") || c_streq(cbuf, "\"\"") ) {
        SAFE_FREE(cbuf);
        cbuf = c_strdup("empty_etag");
    }

    DEBUG_WEBDAV("Get file ID for %s: %s", path, cbuf ? cbuf:"<null>");
    if( fs ) csync_vio_file_stat_destroy(fs);
    if( req ) ne_request_destroy(req);
    SAFE_FREE(uri);


    return cbuf;
}