Nextcloud Synchronisierung meldet ungültige Änderungszeit – QuickFix

Vor kurzem wurde durch den Nextcloud Client ein Problem verursacht, in dem alle Dateien die synchronisiert werden sollten einen ungültigen Zeitstempel erhalten und als Datum den 01.01.1970 angezeigt haben. Schuld daran war ein Bug in der Client-Version 3.4.0.

Von Nextcloud gibt es aber ein Shell-Skript, mit dem die Daten recht unkompliziert wieder repariert werden können. Allerdings werden dabei die Zeitstempel auf das aktuelle Datum und die aktuelle Uhrzeit gesetzt.

Sie können das Skript einfach vom Ende des Beitrags kopieren und auf dem Server als solvable-files.sh abspeichern.

Zum Starten führen Sie den folgenden Befehl aus:

./solvable_files.sh <data_dir> <mysql|pgsql> <db_host> <db_user> <db_pwd> <db_name> list# 

Zur anschließenden Reparatur der defekten Dateien führen Sie den folgenden Befehl aus, hierbei werden die Dateien auch direkt gescannt und in der Datenbank aktualisiert:

./solvable_files.sh <data_dir> <mysql|pgsql> <db_host> <db_user> <db_pwd> <db_name> fix scan

Nun sind die Dateien wieder aktuell und werden durch den Client synchronisiert.

Skript

#!/bin/bash

set -eu

# Usage: ./solvable_files.sh <data_dir> <mysql|pgsql> <db_host> <db_user> <db_pwd> <db_name> <fix,list> <scan,noscan>

export data_dir="$(realpath "$1")"
export db_type="$2"
export db_host="$3"
export db_user="$4"
export db_pwd="$5"
export db_name="$6"
export action="${7:-list}"
export scan_action="${8:-noscan}"

if [ "${data_dir:0:1}" != "/" ]
then
 echo "data_dir must be absolute."
 exit 1
fi

# 1. Return if fs mtime <= 86400
# 2. Compute username from filepath
# 3. Query mtime from the database with the filename and the username
# 4. Return if mtime_on_fs != mtime_in_db
# 5. Correct the fs mtime with touch
function correct_mtime() {
 filepath="$1"
 relative_filepath="${filepath/#$data_dir\//}"
 mtime_on_fs="$(stat -c '%Y' "$filepath")"
 data_dir_with_trailing_slash="$data_dir/"

 username=$relative_filepath
 while [ "$(dirname "$username")" != "." ]
 do
  username=$(dirname "$username")
 done

 relative_filepath_without_username="${relative_filepath/#$username\//}"

 base64_relative_filepath="$(printf '%s' "$relative_filepath" | base64)"
 base64_relative_filepath_without_username="$(printf '%s' "$relative_filepath_without_username" | base64)"

 if [ "$username" == "__groupfolders" ]
 then
  if [ "$db_type" == "mysql" ]
  then
   mtime_in_db=$(
    mysql \
     --skip-column-names \
     --silent \
     --host="$db_host" \
     --user="$db_user" \
     --password="$db_pwd" \
     --default-character-set=utf8 \
     --execute="\
      SELECT mtime
      FROM oc_storages JOIN oc_filecache ON oc_storages.numeric_id = oc_filecache.storage \
      WHERE oc_storages.id='local::$data_dir/' AND oc_filecache.path=FROM_BASE64('$base64_relative_filepath')" \
     "$db_name"
   )
  elif [ "$db_type" == "pgsql" ]
  then
   mtime_in_db=$(
    psql \
     "postgresql://$db_user:$db_pwd@$db_host/$db_name" \
     --tuples-only \
     --no-align \
     -E 'UTF-8' \
     --command="\
      SELECT mtime
      FROM oc_storages JOIN oc_filecache ON oc_storages.numeric_id = oc_filecache.storage \
      WHERE oc_storages.id='local::$data_dir/' AND oc_filecache.path=CONVERT_FROM(DECODE('$base64_relative_filepath', 'base64'), 'UTF-8')"
   )
  fi
 else
  if [ "$db_type" == "mysql" ]
  then
   mtime_in_db=$(
    mysql \
     --skip-column-names \
     --silent \
     --host="$db_host" \
     --user="$db_user" \
     --password="$db_pwd" \
     --default-character-set=utf8 \
     --execute="\
      SELECT mtime
      FROM oc_storages JOIN oc_filecache ON oc_storages.numeric_id = oc_filecache.storage \
      WHERE oc_storages.id='home::$username' AND oc_filecache.path=FROM_BASE64('$base64_relative_filepath_without_username')" \
     "$db_name"
   )
  elif [ "$db_type" == "pgsql" ]
  then
   mtime_in_db=$(
    psql \
     "postgresql://$db_user:$db_pwd@$db_host/$db_name" \
     --tuples-only \
     --no-align \
     -E 'UTF-8' \
     --command="\
      SELECT mtime
      FROM oc_storages JOIN oc_filecache ON oc_storages.numeric_id = oc_filecache.storage \
      WHERE oc_storages.id='home::$username' AND oc_filecache.path=CONVERT_FROM(DECODE('$base64_relative_filepath_without_username', 'base64'), 'UTF-8')"
   )
  fi
 fi

 if [ "$mtime_in_db" == "" ]
 then
  return
 fi

 if [ "$mtime_in_db" != "$mtime_on_fs" ]
 then
  echo "mtime in database do not match fs mtime (fs: $mtime_on_fs, db: $mtime_in_db). Skipping $filepath"
  return
 fi

 echo "$filepath"

 if [ "$action" == "fix" ]
 then
  touch -c "$filepath"
  if [ "$scan_action" = "scan" ]
  then
   sudo -u www-data php ./occ files:scan --quiet --path="$relative_filepath"
  fi
 fi
}
export -f correct_mtime

find "$data_dir" -type f ! -newermt "@86400" -exec bash -c 'correct_mtime "$0"' {} \;

Quelle: nextcloud-gmbh/mtime_fixer_tool_kit: Tool kit to fix the mtime issue on the server state (github.com)
Hier gibts es ggfs. eine akualisierte Version des Skripts.

Sascha Jelinek