FilesystemDataProvider.java 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * Nextcloud Android client application
  3. *
  4. * Copyright (C) 2017 Mario Danic
  5. * Copyright (C) 2017 Nextcloud.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  9. * License as published by the Free Software Foundation; either
  10. * version 3 of the License, or any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public
  18. * License along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. package com.owncloud.android.datamodel;
  21. import android.content.ContentResolver;
  22. import android.content.ContentValues;
  23. import android.database.Cursor;
  24. import android.net.Uri;
  25. import com.owncloud.android.db.ProviderMeta;
  26. import com.owncloud.android.lib.common.utils.Log_OC;
  27. import com.owncloud.android.utils.SyncedFolderUtils;
  28. import java.io.BufferedInputStream;
  29. import java.io.File;
  30. import java.io.FileInputStream;
  31. import java.io.IOException;
  32. import java.io.InputStream;
  33. import java.util.HashSet;
  34. import java.util.Set;
  35. import java.util.zip.CRC32;
  36. /**
  37. * Provider for stored filesystem data.
  38. */
  39. public class FilesystemDataProvider {
  40. static private final String TAG = FilesystemDataProvider.class.getSimpleName();
  41. private ContentResolver contentResolver;
  42. public FilesystemDataProvider(ContentResolver contentResolver) {
  43. if (contentResolver == null) {
  44. throw new IllegalArgumentException("Cannot create an instance with a NULL contentResolver");
  45. }
  46. this.contentResolver = contentResolver;
  47. }
  48. public int deleteAllEntriesForSyncedFolder(String syncedFolderId) {
  49. return contentResolver.delete(
  50. ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
  51. ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ?",
  52. new String[]{syncedFolderId}
  53. );
  54. }
  55. public void updateFilesystemFileAsSentForUpload(String path, String syncedFolderId) {
  56. ContentValues cv = new ContentValues();
  57. cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD, 1);
  58. contentResolver.update(
  59. ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
  60. cv,
  61. ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH + " = ? and " +
  62. ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ?",
  63. new String[]{path, syncedFolderId}
  64. );
  65. }
  66. public Set<String> getFilesForUpload(String localPath, String syncedFolderId) {
  67. Set<String> localPathsToUpload = new HashSet<>();
  68. String likeParam = localPath + "%";
  69. Cursor cursor = contentResolver.query(
  70. ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
  71. null,
  72. ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH + " LIKE ? and " +
  73. ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ? and " +
  74. ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD + " = ? and " +
  75. ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_IS_FOLDER + " = ?",
  76. new String[]{likeParam, syncedFolderId, "0", "0"},
  77. null);
  78. if (cursor != null) {
  79. if (cursor.moveToFirst()) {
  80. do {
  81. String value = cursor.getString(cursor.getColumnIndexOrThrow(
  82. ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH));
  83. if (value == null) {
  84. Log_OC.e(TAG, "Cannot get local path");
  85. } else {
  86. File file = new File(value);
  87. if (!file.exists()) {
  88. Log_OC.d(TAG, "Ignoring file for upload (doesn't exist): " + value);
  89. } else if (!SyncedFolderUtils.isQualifiedFolder(file.getParent())) {
  90. Log_OC.d(TAG, "Ignoring file for upload (unqualified folder): " + value);
  91. } else if (!SyncedFolderUtils.isFileNameQualifiedForAutoUpload(file.getName())) {
  92. Log_OC.d(TAG, "Ignoring file for upload (unqualified file): " + value);
  93. } else {
  94. localPathsToUpload.add(value);
  95. }
  96. }
  97. } while (cursor.moveToNext());
  98. }
  99. cursor.close();
  100. }
  101. return localPathsToUpload;
  102. }
  103. public void storeOrUpdateFileValue(String localPath, long modifiedAt, boolean isFolder, SyncedFolder syncedFolder) {
  104. FileSystemDataSet data = getFilesystemDataSet(localPath, syncedFolder);
  105. int isFolderValue = 0;
  106. if (isFolder) {
  107. isFolderValue = 1;
  108. }
  109. ContentValues cv = new ContentValues();
  110. cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_FOUND_RECENTLY, System.currentTimeMillis());
  111. cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_MODIFIED, modifiedAt);
  112. if (data == null) {
  113. cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH, localPath);
  114. cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_IS_FOLDER, isFolderValue);
  115. cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD, Boolean.FALSE);
  116. cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID, syncedFolder.getId());
  117. long newCrc32 = getFileChecksum(localPath);
  118. if (newCrc32 != -1) {
  119. cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_CRC32, Long.toString(newCrc32));
  120. }
  121. Uri result = contentResolver.insert(ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM, cv);
  122. if (result == null) {
  123. Log_OC.v(TAG, "Failed to insert filesystem data with local path: " + localPath);
  124. }
  125. } else {
  126. if (data.getModifiedAt() != modifiedAt) {
  127. long newCrc32 = getFileChecksum(localPath);
  128. if (data.getCrc32() == null || (newCrc32 != -1 && !data.getCrc32().equals(Long.toString(newCrc32)))) {
  129. cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_CRC32, Long.toString(newCrc32));
  130. cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD, 0);
  131. }
  132. }
  133. int result = contentResolver.update(
  134. ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
  135. cv,
  136. ProviderMeta.ProviderTableMeta._ID + "=?",
  137. new String[]{String.valueOf(data.getId())}
  138. );
  139. if (result == 0) {
  140. Log_OC.v(TAG, "Failed to update filesystem data with local path: " + localPath);
  141. }
  142. }
  143. }
  144. private FileSystemDataSet getFilesystemDataSet(String localPathParam, SyncedFolder syncedFolder) {
  145. Cursor cursor = contentResolver.query(
  146. ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
  147. null,
  148. ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH + " = ? and " +
  149. ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ?",
  150. new String[]{localPathParam, Long.toString(syncedFolder.getId())},
  151. null
  152. );
  153. FileSystemDataSet dataSet = null;
  154. if (cursor != null) {
  155. if (cursor.moveToFirst()) {
  156. int id = cursor.getInt(cursor.getColumnIndexOrThrow(ProviderMeta.ProviderTableMeta._ID));
  157. String localPath = cursor.getString(cursor.getColumnIndexOrThrow(
  158. ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH));
  159. long modifiedAt = cursor.getLong(cursor.getColumnIndexOrThrow(
  160. ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_MODIFIED));
  161. boolean isFolder = false;
  162. if (cursor.getInt(cursor.getColumnIndexOrThrow(
  163. ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_IS_FOLDER)) != 0) {
  164. isFolder = true;
  165. }
  166. long foundAt = cursor.getLong(cursor.getColumnIndexOrThrow(ProviderMeta.
  167. ProviderTableMeta.FILESYSTEM_FILE_FOUND_RECENTLY));
  168. boolean isSentForUpload = false;
  169. if (cursor.getInt(cursor.getColumnIndexOrThrow(
  170. ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD)) != 0) {
  171. isSentForUpload = true;
  172. }
  173. String crc32 = cursor.getString(cursor.getColumnIndexOrThrow(ProviderMeta.ProviderTableMeta.FILESYSTEM_CRC32));
  174. if (id == -1) {
  175. Log_OC.e(TAG, "Arbitrary value could not be created from cursor");
  176. } else {
  177. dataSet = new FileSystemDataSet(id, localPath, modifiedAt, isFolder, isSentForUpload, foundAt,
  178. syncedFolder.getId(), crc32);
  179. }
  180. }
  181. cursor.close();
  182. } else {
  183. Log_OC.e(TAG, "DB error restoring arbitrary values.");
  184. }
  185. return dataSet;
  186. }
  187. private long getFileChecksum(String filepath) {
  188. try (InputStream inputStream = new BufferedInputStream(new FileInputStream(filepath))){
  189. CRC32 crc = new CRC32();
  190. int cnt;
  191. while ((cnt = inputStream.read()) != -1) {
  192. crc.update(cnt);
  193. }
  194. return crc.getValue();
  195. } catch (IOException e) {
  196. return -1;
  197. }
  198. }
  199. }