Node exists but file is in trash

Hi. I’m trying to diagnose an issue and I need help.

I have files in the trashbin that I am trying to restore via the webDAV TrashBin API. If I look throuhg the filesystem, the files are in the trash and not in the user’s files. However, I get this error when trying to restore them: The destination node already exists

I can’t figure out where the “node” information is coming from. When I look at the database, I only find the files in the trash table. Where is it getting that information?

With that amount of information, unfortunately only guessing is possible:

Filesystem and DB might be out of sync due to some ‘behind the scene’ operations.

BTW, as we don’t know how your API-call looks like:

 <s:message>The destination node already exists, and the overwrite header is set to false</s:message>

I’m sure they are out of sync but where can I look in the DB? I tried one file as an example and I could only find a “trash” version of it in the DB. What I mean is that I can’t find the information that would tell the DB that the file exists outside of the trash. As I mentioned, it doesn’t exist in the filesystem.

My API call is virtually identical to the example in the manual, except that I’m not using variables for the host, user, etc. It looks likes this:

curl "http://owncloud.server/remote.php/dav/trash-bin/user1/1234567/" \
  -H 'Overwrite: F' \
  -H 'Destination: http://owncloud.server/remote.php/dav/files/user1/Graphics/BMP/file001.bmp' \
  -X MOVE \
  --user "user1:pass"

If it helps:

This is the error (as shown in the docs):

File Already Exists

If the Overwrite header is set to F and a file exists with the same name as specified in the Destination string, then an HTTP 412 (Precondition Failed) status code is returned, along with the following XML response:

<?xml version="1.0" encoding="utf-8"?>
<d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
  <s:exception>Sabre\DAV\Exception\PreconditionFailed</s:exception>
  <s:message>The destination node already exists, and the overwrite header is set to false</s:message>
  <s:header>Overwrite</s:header>

Using one file as an example, I checked the actual directory and the file is not there. I scanned the entire database for the filename. The only tables that have a match are oc_filecache and oc_files_trash. In oc_filecache, it’s in the trash and not the “restore” destination.

oc_activity shows a record of it being deleted but not restored.

Is there someplace else that ownCloud would check?

I don’t know from where you have your file-id of ‘123456’, I strongly assume it is an example but not valid. :wink:

The proper way is to request a list of the trash-bin content and then traverse this response to get the correct properties of the files you want to restore.

You’ll get everything you need for proceeding:

<d:response>
  <d:href>/remote.php/dav/trash-bin/abu/8</d:href>
  <d:propstat>
    <d:prop>
      <oc:trashbin-original-filename>Squirrel.jpg</oc:trashbin-original-filename>
      <oc:trashbin-original-location>Photos/Squirrel.jpg</oc:trashbin-original-location>
      <oc:trashbin-delete-datetime>Mon, 04 Jan 2021 07:48:06 GMT</oc:trashbin-delete-datetime>
      <d:getcontentlength>233724</d:getcontentlength>
      <d:resourcetype/>
    </d:prop>
    <d:status>HTTP/1.1 200 OK</d:status>
  </d:propstat>
</d:response>

I did a brief test, everything works as expected.

Right, 1234567 is of course, fictional :wink:

Using propfind is how I got my list of deleted files. But propfind doesn’t give you the fileid, which the documentation cites for the restore call:

Restore Deleted File

Restore a file from the trash bin.
    Path: remote.php/dav/trash-bin/<username>/<fileid>
    Method: MOVE

Request Parameters
Attribute 	Type 	Description

username       string      The username of the user to list files for.
fileid         integer     The id of the file to [restore].

Nevertheless, getting a list of files in the trash correctly shows the files. But I can’t restore them because they “already exist” at the destination, which is incorrect.

Where is that information stored in the database? I can’t find it.

Wait, you really get that “node exist” message by requesting the MOVE with the correct file-id you got from PROPFIND? In my tests, the message is thrown only if a fantasy number was used.

BTW, the file-id is at the end of <d:href>.

<d:href>/remote.php/dav/trash-bin/abu/8</d:href>

The file-id could also be extracted from the oc_filecache table.

(8, 1, 'files_trashbin/files/Squirrel.jpg.d1609830365', '16dea2ebca39f7e552686cff6a5c1284', 19, 'Squirrel.jpg.d1609830365', 15, 3, 233724, 1592755927, 1592755927, 0, 0, '7846d9c2441c1956c7c845a76a14cdb5', 27, '')

However, I think it is not recommended skimming the DB directly if an API exist for retrieving that information. Just my 2 cents.

Wait, you really get that “node exist” message by requesting the MOVE with the correct file-id you got from PROPFIND? In my tests, the message is thrown only if a fantasy number was used.

Yes, of course, I’m not using the API with a made-up file ID. :wink: The steps I am going through are straightforward. I just repeated the process, using a known file ID:

  1. Use cURL to call the MOVE (restore) function, as per the docs.
    Result:
<?xml version="1.0" encoding="utf-8"?>
<d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
  <s:exception>Sabre\DAV\Exception\PreconditionFailed</s:exception>
  <s:message>The destination node already exists, and the overwrite header is set to false</s:message>
  <s:header>Overwrite</s:header>
</d:error>
  1. Check the filesystem:
    $ ls -l PATH/FILE
    Result:
ls: cannot access PATH/FILE': No such file or directory
  1. Check oc_filecache:
    MariaDB> SELECT path, name FROM oc_filecache WHERE name LIKE "FILE%";
    Result:
+---------------------------------------+------------------+
| path                                  | name             |
+---------------------------------------+------------------+
| files_trashbin/files/FILE.d1607533946 | FILE.d1607533946 |
+---------------------------------------+------------------+

(I replaced the real path and file with PATH and FILE, respectively)

In oc_filecache the only instance is files_trashbin/files/FILE. There are no rows showing the restored location. So how can the file “already exist”?

Thanks for pointing that out. I see it now. It would be helpful if the documentation explained that. It’s not clear at all that part of href is the fileid that is referenced later on.