LCOV - code coverage report
Current view: top level - core/db - SPDbFile.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 143 347 41.2 %
Date: 2024-05-12 00:16:13 Functions: 12 22 54.5 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2016-2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023-2024 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #include "SPDbFile.h"
      25             : 
      26             : #include "SPDbAdapter.h"
      27             : #include "SPIO.h"
      28             : #include "SPDbField.h"
      29             : #include "SPDbScheme.h"
      30             : #include "SPDbTransaction.h"
      31             : #include "SPDbWorker.h"
      32             : #include "SPFilesystem.h"
      33             : 
      34             : #if MODULE_STAPPLER_BITMAP
      35             : #include "SPBitmap.h"
      36             : #endif
      37             : 
      38             : namespace STAPPLER_VERSIONIZED stappler::db {
      39             : 
      40         275 : String File::getFilesystemPath(const ApplicationInterface *app, uint64_t oid) {
      41         550 :         return toString(app->getDocumentRoot(), "/uploads/", oid);
      42             : }
      43             : 
      44         100 : static bool File_isImage(const StringView &type) {
      45         100 :         return type == "image/gif"
      46         100 :                         || type == "image/jpeg"
      47         100 :                         || type == "image/pjpeg"
      48         100 :                         || type == "image/png"
      49          75 :                         || type == "image/tiff"
      50          75 :                         || type == "image/webp"
      51         200 :                         || type == "image/svg+xml";
      52             : }
      53             : 
      54          75 : static bool File_validateFileField(const ApplicationInterface *app, const Field &field, size_t writeSize, const StringView &type) {
      55          75 :         auto ffield = static_cast<const FieldFile *>(field.getSlot());
      56             :         // check size
      57          75 :         if (writeSize > ffield->maxSize) {
      58           0 :                 app->error("Storage", "File is larger then max file size in field", Value {
      59           0 :                         std::make_pair("field", Value(field.getName())),
      60           0 :                         std::make_pair("max", Value((int64_t)ffield->maxSize)),
      61           0 :                         std::make_pair("size", Value((int64_t)writeSize))
      62           0 :                 });
      63           0 :                 return false;
      64             :         }
      65             : 
      66             :         // check type
      67          75 :         auto &types = ffield->allowedTypes;
      68          75 :         if (!types.empty()) {
      69           0 :                 bool ret = false;
      70           0 :                 for (auto &it : types) {
      71           0 :                         if (type == it) {
      72           0 :                                 ret = true;
      73           0 :                                 break;
      74             :                         }
      75             :                 }
      76           0 :                 if (!ret) {
      77           0 :                         app->error("Storage", "Invalid file type for field", Value {
      78           0 :                                 std::make_pair("field", Value(field.getName())),
      79           0 :                                 std::make_pair("type", Value(type))
      80           0 :                         });
      81           0 :                         return false;
      82             :                 }
      83             :         }
      84          75 :         return true;
      85             : }
      86             : 
      87          25 : static bool File_validateImageField(const ApplicationInterface *app, const Field &field, size_t writeSize, StringView type, stappler::io::Producer file) {
      88             : #ifndef MODULE_STAPPLER_BITMAP
      89             :         app->error("Storage", "MODULE_STAPPLER_BITMAP was not enabled to support bitmaps within storage");
      90             :         return false;
      91             : #else
      92          25 :         auto ffield = static_cast<const FieldImage *>(field.getSlot());
      93             : 
      94             :         // check size
      95          25 :         if (writeSize > ffield->maxSize) {
      96           0 :                 app->error("Storage", "File is larger then max file size in field", Value{
      97           0 :                         std::make_pair("field", Value(field.getName())),
      98           0 :                         std::make_pair("max", Value((int64_t)ffield->maxSize)),
      99           0 :                         std::make_pair("size", Value((int64_t)writeSize))
     100           0 :                 });
     101           0 :                 return false;
     102             :         }
     103             : 
     104          25 :         if (!File_isImage(type)) {
     105           0 :                 app->error("Storage", "Unknown image type for field", Value {
     106           0 :                         std::make_pair("field", Value(field.getName())),
     107           0 :                         std::make_pair("type", Value(type))
     108           0 :                 });
     109           0 :                 return false;
     110             :         }
     111             : 
     112             :         // check type
     113          25 :         auto &types = ffield->allowedTypes;
     114          25 :         if (!types.empty()) {
     115           0 :                 bool ret = false;
     116           0 :                 for (auto &it : types) {
     117           0 :                         if (type == it) {
     118           0 :                                 ret = true;
     119           0 :                                 break;
     120             :                         }
     121             :                 }
     122           0 :                 if (!ret) {
     123           0 :                         app->error("Storage", "Invalid file type for field", Value{
     124           0 :                                 std::make_pair("field", Value(field.getName())),
     125           0 :                                 std::make_pair("type", Value(type))
     126           0 :                         });
     127           0 :                         return false;
     128             :                 }
     129             :         }
     130             : 
     131          25 :         uint32_t width = 0, height = 0;
     132          25 :         if (!bitmap::getImageSize(file, width, height) && width > 0 && height > 0) {
     133           0 :                 app->error("Storage", "Fail to detect file size with");
     134           0 :                 return false;
     135             :         }
     136             : 
     137          25 :         if (ffield->minImageSize.policy == ImagePolicy::Reject) {
     138          25 :                 if (ffield->minImageSize.width > width || ffield->minImageSize.height > height) {
     139           0 :                         app->error("Storage", "Image is to small, rejected by policy rule", Value{
     140           0 :                                 std::make_pair("min", Value {
     141           0 :                                         std::make_pair("width", Value(ffield->minImageSize.width)),
     142           0 :                                         std::make_pair("height", Value(ffield->minImageSize.height))
     143           0 :                                 }),
     144           0 :                                 std::make_pair("current", Value{
     145           0 :                                         std::make_pair("width", Value(width)),
     146           0 :                                         std::make_pair("height", Value(height))
     147           0 :                                 })
     148           0 :                         });
     149           0 :                         return false;
     150             :                 }
     151             :         }
     152             : 
     153          25 :         if (ffield->maxImageSize.policy == ImagePolicy::Reject) {
     154           0 :                 if (ffield->maxImageSize.width < width || ffield->maxImageSize.height < height) {
     155           0 :                         app->error("Storage", "Image is to large, rejected by policy rule", Value{
     156           0 :                                 std::make_pair("max", Value {
     157           0 :                                         std::make_pair("width", Value(ffield->maxImageSize.width)),
     158           0 :                                         std::make_pair("height", Value(ffield->maxImageSize.height))
     159           0 :                                 }),
     160           0 :                                 std::make_pair("current", Value{
     161           0 :                                         std::make_pair("width", Value(width)),
     162           0 :                                         std::make_pair("height", Value(height))
     163           0 :                                 })
     164           0 :                         });
     165           0 :                         return false;
     166             :                 }
     167             :         }
     168          25 :         return true;
     169             : #endif
     170             : }
     171             : 
     172         100 : bool File::validateFileField(const ApplicationInterface *app, const Field &field, const InputFile &file) {
     173         100 :         if (field.getType() == db::Type::File) {
     174          75 :                 return File_validateFileField(app, field, file.writeSize, file.type);
     175          25 :         } else if (field.getType() == db::Type::Image) {
     176          25 :                 return File_validateImageField(app, field, file.writeSize, file.type, file.file);
     177             :         }
     178           0 :         return true;
     179             : }
     180             : 
     181           0 : bool File::validateFileField(const ApplicationInterface *app, const Field &field, const StringView &type, const BytesView &data) {
     182           0 :         if (field.getType() == db::Type::File) {
     183           0 :                 return File_validateFileField(app, field, data.size(), type);
     184           0 :         } else if (field.getType() == db::Type::Image) {
     185           0 :                 stappler::CoderSource source(data);
     186           0 :                 return File_validateImageField(app, field, data.size(), type, source);
     187             :         }
     188           0 :         return true;
     189             : }
     190             : 
     191         100 : Value File::createFile(const Transaction &t, const Field &f, InputFile &file) {
     192         100 :         auto scheme = t.getAdapter().getApplicationInterface()->getFileScheme();
     193         100 :         Value fileData;
     194         100 :         fileData.setString(file.type, "type");
     195         100 :         fileData.setInteger(file.writeSize, "size");
     196             : 
     197         100 :         if (f.getType() == db::Type::Image || File_isImage(file.type)) {
     198             : #if MODULE_STAPPLER_BITMAP
     199          25 :                 uint32_t width = 0, height = 0;
     200          25 :                 if (bitmap::getImageSize(file.file, width, height)) {
     201          25 :                         auto &val = fileData.emplace("image");
     202          25 :                         val.setInteger(width, "width");
     203          25 :                         val.setInteger(height, "height");
     204             :                 }
     205             : #endif
     206             :         }
     207             : 
     208         100 :         fileData = Worker(*scheme, t).create(fileData, true);
     209         100 :         if (fileData && fileData.isInteger("__oid")) {
     210         100 :                 auto id = fileData.getInteger("__oid");
     211         100 :                 if (file.save(File::getFilesystemPath(t.getAdapter().getApplicationInterface(), id))) {
     212         100 :                         return Value(id);
     213             :                 }
     214             :         }
     215             : 
     216           0 :         file.close();
     217           0 :         return Value();
     218         100 : }
     219             : 
     220         125 : Value File::createFile(const Transaction &t, const StringView &type, const StringView &path, int64_t mtime) {
     221         125 :         auto scheme = t.getAdapter().getApplicationInterface()->getFileScheme();
     222         125 :         Value fileData;
     223         125 :         filesystem::Stat stat;
     224         125 :         if (filesystem::stat(path, stat)) {
     225         125 :                 fileData.setInteger(stat.size, "size");
     226             :         }
     227             : 
     228         125 :         if (mtime) {
     229           0 :                 fileData.setInteger(mtime, "mtime");
     230             :         }
     231             : 
     232             : #if MODULE_STAPPLER_BITMAP
     233         125 :         uint32_t width = 0, height = 0;
     234         125 :         auto file = filesystem::openForReading(StringView(path));
     235         125 :         auto fmt = bitmap::detectFormat(file);
     236         125 :         if ((fmt.second.empty() && fmt.first == bitmap::FileFormat::Custom)
     237         125 :                         || !bitmap::getImageSize(file, width, height)) {
     238           0 :                 fileData.setString(type, "type");
     239             :         } else {
     240         125 :                 auto &val = fileData.emplace("image");
     241         125 :                 val.setInteger(width, "width");
     242         125 :                 val.setInteger(height, "height");
     243         125 :                 if (fmt.first != bitmap::FileFormat::Custom) {
     244         125 :                         fileData.setString(bitmap::getMimeType(fmt.first), "type");
     245             :                 } else {
     246           0 :                         fileData.setString(type, "type");
     247             :                 }
     248             :         }
     249             : #else
     250             :         fileData.setString(type, "type");
     251             : #endif
     252             : 
     253         125 :         fileData = Worker(*scheme, t).create(fileData, true);
     254         125 :         if (fileData && fileData.isInteger("__oid")) {
     255         125 :                 auto id = fileData.getInteger("__oid");
     256         125 :                 if (stappler::filesystem::move(path, File::getFilesystemPath(t.getAdapter().getApplicationInterface(), id))) {
     257         125 :                         return Value(id);
     258             :                 } else {
     259           0 :                         Worker(*scheme, t).remove(fileData.getInteger("__oid"));
     260             :                 }
     261             :         }
     262             : 
     263           0 :         stappler::filesystem::remove(path);
     264           0 :         return Value();
     265         125 : }
     266             : 
     267           0 : Value File::createFile(const Transaction &t, const StringView &type, const BytesView &data, int64_t mtime) {
     268           0 :         auto scheme = t.getAdapter().getApplicationInterface()->getFileScheme();
     269           0 :         auto size = data.size();
     270             : 
     271           0 :         Value fileData;
     272           0 :         fileData.setString(type, "type");
     273           0 :         fileData.setInteger(size, "size");
     274           0 :         if (mtime) {
     275           0 :                 fileData.setInteger(mtime, "mtime");
     276             :         }
     277             : 
     278             : #if MODULE_STAPPLER_BITMAP
     279           0 :         uint32_t width = 0, height = 0;
     280           0 :         stappler::CoderSource source(data);
     281           0 :         if (bitmap::getImageSize(source, width, height)) {
     282           0 :                 auto &val = fileData.emplace("image");
     283           0 :                 val.setInteger(width, "width");
     284           0 :                 val.setInteger(height, "height");
     285             :         }
     286             : #endif
     287             : 
     288           0 :         fileData = Worker(*scheme, t).create(fileData, true);
     289           0 :         if (fileData && fileData.isInteger("__oid")) {
     290           0 :                 auto id = fileData.getInteger("__oid");
     291           0 :                 if (stappler::filesystem::write(File::getFilesystemPath(t.getAdapter().getApplicationInterface(), id), data)) {
     292           0 :                         return Value(id);
     293             :                 } else {
     294           0 :                         Worker(*scheme, t).remove(fileData.getInteger("__oid"));
     295             :                 }
     296             :         }
     297             : 
     298           0 :         return Value();
     299           0 : }
     300             : 
     301             : #if MODULE_STAPPLER_BITMAP
     302         150 : static bool getTargetImageSize(size_t W, size_t H, const MinImageSize &min, const MaxImageSize &max
     303             :                 , size_t &tW, size_t &tH) {
     304             : 
     305         150 :         if (min.width > W || min.height > H) {
     306           0 :                 float scale = 0.0f;
     307           0 :                 if (min.width == 0) {
     308           0 :                         scale = (float)min.height / (float)H;
     309           0 :                 } else if (min.height == 0) {
     310           0 :                         scale = (float)min.width / (float)W;
     311             :                 } else {
     312           0 :                         scale = std::min((float)min.width / (float)W, (float)min.height / (float)H);
     313             :                 }
     314           0 :                 tW = W * scale; tH = H * scale;
     315           0 :                 return true;
     316             :         }
     317             : 
     318         150 :         if ((max.width != 0 && max.width < W) || (max.height != 0 && max.height < H)) {
     319         125 :                 float scale = 0.0f;
     320         125 :                 if (max.width == 0) {
     321           0 :                         scale = (float)max.height / (float)H;
     322         125 :                 } else if (max.height == 0) {
     323           0 :                         scale = (float)max.width / (float)W;
     324             :                 } else {
     325         125 :                         scale = std::min((float)max.width / (float)W, (float)max.height / (float)H);
     326             :                 }
     327         125 :                 tW = (size_t)W * scale; tH = (size_t)H * scale;
     328         125 :                 return true;
     329             :         }
     330             : 
     331          25 :         tW = W; tH = H;
     332          25 :         return false;
     333             : }
     334             : 
     335         125 : static String saveImage(Bitmap &bmp) {
     336         125 :         filesystem::File file = filesystem::File::open_tmp(config::UPLOAD_TMP_IMAGE_PREFIX, false);
     337         125 :         String path(file.path());
     338         125 :         file.close();
     339             : 
     340         125 :         if (!path.empty()) {
     341         125 :                 bool ret = false;
     342         125 :                 auto fmt = bmp.getOriginalFormat();
     343         125 :                 if (fmt == bitmap::FileFormat::Custom) {
     344           0 :                         ret = bmp.save(bmp.getOriginalFormatName(), path);
     345             :                 } else {
     346         125 :                         ret = bmp.save(bmp.getOriginalFormat(), path);
     347             :                 }
     348             : 
     349         125 :                 if (ret) {
     350         125 :                         return String(path);
     351             :                 }
     352             :         }
     353             : 
     354           0 :     return String();
     355         125 : }
     356             : 
     357         125 : static String resizeImage(Bitmap &bmp, size_t width, size_t height) {
     358         125 :         auto newImage = bmp.resample(width, height);
     359         125 :     if (newImage) {
     360         125 :         return saveImage(newImage);
     361             :     }
     362             : 
     363           0 :     return String();
     364         125 : }
     365             : 
     366          25 : static Map<String, String> writeImages(const ApplicationInterface *app, const Field &f, InputFile &file) {
     367          25 :         auto field = static_cast<const FieldImage *>(f.getSlot());
     368             : 
     369          25 :         uint32_t width = 0, height = 0;
     370             :         size_t targetWidth, targetHeight;
     371          25 :         if (!bitmap::getImageSize(file.file, width, height)) {
     372           0 :                 return Map<String, String>();
     373             :         }
     374             : 
     375          25 :         Map<String, String> ret;
     376             : 
     377          25 :         bool needResize = getTargetImageSize(width, height, field->minImageSize, field->maxImageSize, targetWidth, targetHeight);
     378          25 :         if (needResize || field->thumbnails.size() > 0) {
     379          25 :                 BufferTemplate<Interface> data(file.writeSize);
     380          25 :                 stappler::io::Producer prod(file.file);
     381          25 :                 prod.seek(0, stappler::io::Seek::Set);
     382          25 :                 prod.read(data, file.writeSize);
     383             : 
     384          25 :                 Bitmap bmp(data.data(), data.size());
     385          25 :             if (!bmp) {
     386           0 :                 app->error("Storage", "Fail to open image");
     387             :             } else {
     388          25 :                     if (needResize) {
     389           0 :                         auto fpath = resizeImage(bmp, targetWidth, targetHeight);
     390           0 :                         if (!fpath.empty()) {
     391           0 :                                 ret.emplace(f.getName().str<Interface>(), std::move(fpath));
     392             :                         }
     393           0 :                     } else {
     394          25 :                         ret.emplace(f.getName().str<Interface>(), file.file.path());
     395             :                     }
     396             : 
     397          25 :                     if (field->thumbnails.size() > 0) {
     398         150 :                         for (auto &it : field->thumbnails) {
     399         125 :                                 getTargetImageSize(width, height, MinImageSize(), MaxImageSize(it.width, it.height),
     400             :                                                 targetWidth, targetHeight);
     401             : 
     402         125 :                                 auto fpath = resizeImage(bmp, targetWidth, targetHeight);
     403         125 :                                 if (!fpath.empty()) {
     404         125 :                                         ret.emplace(it.name, std::move(fpath));
     405             :                                 }
     406         125 :                         }
     407             :                     }
     408             :             }
     409          25 :         } else {
     410           0 :                 ret.emplace(f.getName().str<Interface>(), file.path);
     411             :         }
     412             : 
     413          25 :         return ret;
     414          25 : }
     415             : 
     416           0 : static Map<String, String> writeImages(const ApplicationInterface *app, const Field &f, const StringView &type, const BytesView &data) {
     417           0 :         auto field = static_cast<const FieldImage *>(f.getSlot());
     418             : 
     419           0 :         uint32_t width = 0, height = 0;
     420             :         size_t targetWidth, targetHeight;
     421           0 :         stappler::CoderSource source(data);
     422           0 :         if (!bitmap::getImageSize(source, width, height)) {
     423           0 :                 return Map<String, String>();
     424             :         }
     425             : 
     426           0 :         Map<String, String> ret;
     427             : 
     428           0 :         bool needResize = getTargetImageSize(width, height, field->minImageSize, field->maxImageSize, targetWidth, targetHeight);
     429           0 :         if (needResize || field->thumbnails.size() > 0) {
     430           0 :                 Bitmap bmp(data);
     431           0 :             if (!bmp) {
     432           0 :                 app->error("Storage", "Fail to open image");
     433             :             } else {
     434           0 :                     if (needResize) {
     435           0 :                         auto fpath = resizeImage(bmp, targetWidth, targetHeight);
     436           0 :                         if (!fpath.empty()) {
     437           0 :                                 ret.emplace(f.getName().str<Interface>(), std::move(fpath));
     438             :                         }
     439           0 :                     } else {
     440           0 :                         auto fpath = saveImage(bmp);
     441           0 :                         if (!fpath.empty()) {
     442           0 :                                 ret.emplace(f.getName().str<Interface>(), std::move(fpath));
     443             :                         }
     444           0 :                     }
     445             : 
     446           0 :                     if (field->thumbnails.size() > 0) {
     447           0 :                         for (auto &it : field->thumbnails) {
     448           0 :                                 getTargetImageSize(width, height, MinImageSize(), MaxImageSize(it.width, it.height),
     449             :                                                 targetWidth, targetHeight);
     450             : 
     451           0 :                                 auto fpath = resizeImage(bmp, targetWidth, targetHeight);
     452           0 :                                 if (!fpath.empty()) {
     453           0 :                                         ret.emplace(it.name, std::move(fpath));
     454             :                                 }
     455           0 :                         }
     456             :                     }
     457             :             }
     458           0 :         } else {
     459           0 :                 filesystem::File file = filesystem::File::open_tmp(config::UPLOAD_TMP_IMAGE_PREFIX, false);
     460           0 :                 file.xsputn((const char *)data.data(), data.size());
     461           0 :                 ret.emplace(f.getName().str<Interface>(), file.path());
     462           0 :                 file.close();
     463           0 :         }
     464             : 
     465           0 :         return ret;
     466           0 : }
     467             : #endif
     468             : 
     469          25 : Value File::createImage(const Transaction &t, const Field &f, InputFile &file) {
     470          25 :         Value ret;
     471             : 
     472             : #if MODULE_STAPPLER_BITMAP
     473          25 :         auto files = writeImages(t.getAdapter().getApplicationInterface(), f, file);
     474         175 :         for (auto & it : files) {
     475         150 :                 if (it.first == f.getName() && it.second == file.path) {
     476          25 :                         auto val = createFile(t, f, file);
     477          25 :                         if (val.isInteger()) {
     478          25 :                                 ret.setValue(std::move(val), it.first);
     479             :                         }
     480          25 :                 } else {
     481         125 :                         auto &field = it.first;
     482         125 :                         auto &filePath = it.second;
     483             : 
     484         125 :                         auto val = createFile(t, file.type, filePath);
     485         125 :                         if (val.isInteger()) {
     486         125 :                                 ret.setValue(std::move(val), field);
     487             :                         }
     488         125 :                 }
     489             :         }
     490             : #endif
     491          50 :         return ret;
     492          25 : }
     493             : 
     494           0 : Value File::createImage(const Transaction &t, const Field &f, const StringView &type, const BytesView &data, int64_t mtime) {
     495           0 :         Value ret;
     496             : 
     497             : #if MODULE_STAPPLER_BITMAP
     498           0 :         auto files = writeImages(t.getAdapter().getApplicationInterface(), f, type, data);
     499           0 :         for (auto & it : files) {
     500           0 :                 auto &field = it.first;
     501           0 :                 auto &filePath = it.second;
     502             : 
     503           0 :                 auto val = createFile(t, type, filePath, mtime);
     504           0 :                 if (val.isInteger()) {
     505           0 :                         ret.setValue(std::move(val), field);
     506             :                 }
     507           0 :         }
     508             : #endif
     509           0 :         return ret;
     510           0 : }
     511             : 
     512           0 : bool File::removeFile(const ApplicationInterface *app, const Value &val) {
     513           0 :         int64_t id = 0;
     514           0 :         if (val.isInteger()) {
     515           0 :                 id = val.asInteger();
     516           0 :         } else if (val.isInteger("__oid")) {
     517           0 :                 id = val.getInteger("__oid");
     518             :         }
     519             : 
     520           0 :         return removeFile(app, id);
     521             : }
     522           0 : bool File::removeFile(const ApplicationInterface *app, int64_t id) {
     523           0 :         if (id) {
     524           0 :                 filesystem::remove(File::getFilesystemPath(app, id));
     525           0 :                 return true;
     526             :         }
     527             : 
     528           0 :         return false;
     529             : }
     530             : 
     531           0 : bool File::purgeFile(const Transaction &t, const Value &val) {
     532           0 :         int64_t id = 0;
     533           0 :         if (val.isInteger()) {
     534           0 :                 id = val.asInteger();
     535           0 :         } else if (val.isInteger("__oid")) {
     536           0 :                 id = val.getInteger("__oid");
     537             :         }
     538           0 :         return purgeFile(t, id);
     539             : }
     540             : 
     541           0 : bool File::purgeFile(const Transaction &t, int64_t id) {
     542           0 :         if (id) {
     543           0 :                 if (auto scheme = t.getAdapter().getApplicationInterface()->getFileScheme()) {
     544           0 :                         Worker(*scheme, t).remove(id);
     545           0 :                         filesystem::remove(File::getFilesystemPath(t.getAdapter().getApplicationInterface(), id));
     546           0 :                         return true;
     547             :                 }
     548             :         }
     549           0 :         return false;
     550             : }
     551             : 
     552           0 : Value File::getData(const Transaction &t, uint64_t id) {
     553           0 :         if (auto scheme = t.getAdapter().getApplicationInterface()->getFileScheme()) {
     554           0 :                 return Worker(*scheme, t).get(id);
     555             :         }
     556           0 :         return Value();
     557             : }
     558             : 
     559           0 : void File::setData(const Transaction &t, uint64_t id, const Value &val) {
     560           0 :         if (auto scheme = t.getAdapter().getApplicationInterface()->getFileScheme()) {
     561           0 :                 Worker(*scheme, t).update(id, val);
     562             :         }
     563           0 : }
     564             : 
     565             : }

Generated by: LCOV version 1.14