From cce4693aea0b04069a5aa0f26c69470cd9a0665e Mon Sep 17 00:00:00 2001 From: Ludy Date: Sat, 11 Jan 2025 22:06:11 +0100 Subject: [PATCH] Fix: `NoSuchFileException` if `configs\db\backup` is not present on first start (#2665) # Description ```bash 20:38:21.452 [restartedMain] ERROR s.s.S.c.s.database.DatabaseService - Error reading backup directory: configs\db\backup java.nio.file.NoSuchFileException: configs\db\backup at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:85) at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103) at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:108) at java.base/sun.nio.fs.WindowsDirectoryStream.(WindowsDirectoryStream.java:86) at java.base/sun.nio.fs.WindowsFileSystemProvider.newDirectoryStream(WindowsFileSystemProvider.java:541) at java.base/java.nio.file.Files.newDirectoryStream(Files.java:613) at stirling.software.SPDF.config.security.database.DatabaseService.getBackupList(DatabaseService.java:80) at stirling.software.SPDF.config.security.database.DatabaseService.exportDatabase(DatabaseService.java:156) at stirling.software.SPDF.config.security.UserService.saveUser(UserService.java:214) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:723) at stirling.software.SPDF.config.security.UserService$$SpringCGLIB$$3.saveUser() at stirling.software.SPDF.config.security.InitialSecuritySetup.createDefaultAdminUser(InitialSecuritySetup.java:76) at stirling.software.SPDF.config.security.InitialSecuritySetup.initializeAdminUser(InitialSecuritySetup.java:67) at stirling.software.SPDF.config.security.InitialSecuritySetup.init(InitialSecuritySetup.java:42) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMethod.invoke(InitDestroyAnnotationBeanPostProcessor.java:457) at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:401) at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:219) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:423) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:336) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:289) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:334) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) at org.springframework.beans.factory.support.DefaultListableBeanFactory.instantiateSingleton(DefaultListableBeanFactory.java:1122) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingleton(DefaultListableBeanFactory.java:1093) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:1030) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:987) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:627) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) at stirling.software.SPDF.SPDFApplication.main(SPDFApplication.java:117) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) ``` ## Checklist - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] I have performed a self-review of my own code - [ ] I have attached images of the change if it is UI based - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] If my code has heavily changed functionality I have updated relevant docs on [Stirling-PDFs doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) - [x] My changes generate no new warnings - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) --- .../security/database/DatabaseService.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/stirling/software/SPDF/config/security/database/DatabaseService.java b/src/main/java/stirling/software/SPDF/config/security/database/DatabaseService.java index f11acda3..7d413947 100644 --- a/src/main/java/stirling/software/SPDF/config/security/database/DatabaseService.java +++ b/src/main/java/stirling/software/SPDF/config/security/database/DatabaseService.java @@ -55,6 +55,7 @@ public class DatabaseService implements DatabaseInterface { */ @Override public boolean hasBackup() { + createBackupDirectory(); Path filePath = Paths.get(BACKUP_DIR); if (Files.exists(filePath)) { @@ -74,6 +75,8 @@ public class DatabaseService implements DatabaseInterface { List backupFiles = new ArrayList<>(); if (isH2Database()) { + createBackupDirectory(); + Path backupPath = Paths.get(BACKUP_DIR); try (DirectoryStream stream = @@ -110,6 +113,18 @@ public class DatabaseService implements DatabaseInterface { return backupFiles; } + private void createBackupDirectory() { + Path backupPath = Paths.get(BACKUP_DIR); + if (!Files.exists(backupPath)) { + try { + Files.createDirectories(backupPath); + log.debug("create backup directory: {}", BACKUP_DIR); + } catch (IOException e) { + log.error("Error create backup directory: {}", e.getMessage(), e); + } + } + } + @Override public void importDatabase() { if (!hasBackup()) throw new BackupNotFoundException("No backup scripts were found."); @@ -255,6 +270,7 @@ public class DatabaseService implements DatabaseInterface { * @return the Path object for the given file name */ public Path getBackupFilePath(String fileName) { + createBackupDirectory(); Path filePath = Paths.get(BACKUP_DIR, fileName).normalize(); if (!filePath.startsWith(BACKUP_DIR)) { throw new SecurityException("Path traversal detected");