Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FilePathDisk.newDirectoryStream() may fail on remote drive on Windows due to AccessDeniedException in Path.toRealPath() #3486

Closed
vishi-vaghela opened this issue Apr 18, 2022 · 18 comments · Fixed by #3495

Comments

@vishi-vaghela
Copy link

No description provided.

@katzyn
Copy link
Contributor

katzyn commented Apr 19, 2022

If H2 is launched on 32-bit Windows or in 64-bit JVM on 64-bit Windows, you need to check access permissions of C:\Program Files\nt directory.

If H2 is launched in 32-bit JVM on 64-bit Windows, you need to check access permissions of C:\Program Files (x86)\nt directory.

Some anti-virus software also may prevent write access to these directories for regular applications, Program Files is usually a bad place to store your data.

@vishi-vaghela
Copy link
Author

Thanks for response. My actual folder is on Shared drive S:\h2store_2\nt folder.
I have a webservice which is running as svc user which eventually creates this folder and .mv.db files as well. Everyting was running fine with v1.4 but after uprading it to v2.1.210 it throws access denied error. I verified folder permissions for svc user and it has full permission for read, write, execute etc.

@katzyn
Copy link
Contributor

katzyn commented Apr 19, 2022

New versions of H2 use NIO.2 API (introduced in Java 7) to work with files, old versions use old API from Java 1.0. These APIs may be implemented with different system functions on Windows, so hypothetically something may work in different way with them.

Do you have a complete stack trace?

@katzyn
Copy link
Contributor

katzyn commented Apr 19, 2022

My actual folder is on Shared drive

Remote directories (drives) aren't really suitable for database files, they have various issues.

You can try to add ;FILE_LOCK=FILE to JDBC URL, it is required for some file systems with limited capabilities.

@vishi-vaghela
Copy link
Author

2022-04-19 03:51:18 database: opening S:/myfolders/var/global/wx/h2Stores_2/nt/nt-h2-store
org.h2.message.DbException: IO Exception: "java.nio.file.AccessDeniedException: S:\myfolders\var\global\wx\h2Stores_2\nt"; "S:/myfolders/var/global/wx/h2Stores_2/nt" [90031-210]
at org.h2.message.DbException.get(DbException.java:216)
at org.h2.message.DbException.convertIOException(DbException.java:461)
at org.h2.store.fs.disk.FilePathDisk.newDirectoryStream(FilePathDisk.java:219)
at org.h2.store.fs.FileUtils.newDirectoryStream(FileUtils.java:195)
at org.h2.engine.Database.deleteOldTempFiles(Database.java:1547)
at org.h2.engine.Database.(Database.java:320)
at org.h2.engine.Engine.openSession(Engine.java:92)
at org.h2.engine.Engine.openSession(Engine.java:222)
at org.h2.engine.Engine.createSession(Engine.java:201)
at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:338)
at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:122)
at org.h2.jdbcx.JdbcDataSource.getXAConnection(JdbcDataSource.java:322)
at org.h2.jdbcx.JdbcDataSource.getPooledConnection(JdbcDataSource.java:352)
at org.h2.jdbcx.JdbcConnectionPool.getConnectionNow(JdbcConnectionPool.java:233)
at org.h2.jdbcx.JdbcConnectionPool.getConnection(JdbcConnectionPool.java:198)
at com.netbackup.h2.H2JDBCConnectionPool.getConnection(H2JDBCConnectionPool.java:54)
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)
at org.hibernate.internal.NonContextualJdbcConnectionAccess.obtainConnection(NonContextualJdbcConnectionAccess.java:38)
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:108)
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:138)
at org.hibernate.internal.SessionImpl.connection(SessionImpl.java:480)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:152)
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:421)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager.java:400)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:595)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:382)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at com.sun.proxy.$Proxy365.count(Unknown Source)
at com.netbackup.eventlog.service.EventLogServiceImpl.getntCount(EventLogServiceImpl.java:245)
at sun.reflect.GeneratedMethodAccessor2919.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at com.sun.proxy.$Proxy367.getntCount(Unknown Source)
at com.netbackup.eventlog.service.EventLogCleanupService.startCleanup(EventLogCleanupService.java:44)
at com.netbackup.eventlog.config.EventLogCleanupTask.lambda$runCleanupTask$1(EventLogCleanupTask.java:87)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:95)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:750)
Caused by: org.h2.jdbc.JdbcSQLNonTransientException: IO Exception: "java.nio.file.AccessDeniedException: S:\myfolders\var\global\wx\h2Stores_2\nt"; "S:/myfolders/var/global/wx/h2Stores_2/nt" [90031-210]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:573)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:496)
... 61 more
Caused by: java.nio.file.AccessDeniedException: S:\myfolders\var\global\wx\h2Stores_2\nt
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:83)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:90)
at sun.nio.fs.WindowsLinkSupport.getRealPath(WindowsLinkSupport.java:259)
at sun.nio.fs.WindowsPath.toRealPath(WindowsPath.java:836)
at sun.nio.fs.WindowsPath.toRealPath(WindowsPath.java:44)
at org.h2.store.fs.disk.FilePathDisk.newDirectoryStream(FilePathDisk.java:214)

@vishi-vaghela
Copy link
Author

i m using below connection url-
Url=jdbc:h2:file:S:/myfolders/var/global/wx/h2Stores_2/nt/nt-h2-store;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false;CIPHER=FOG;MODE=LEGACY;INIT=RUNSCRIPT FROM 'classpath:scripts/sample-db-schema.sql';

@katzyn
Copy link
Contributor

katzyn commented Apr 19, 2022

The cause of this issue is unusual.
java.nio.Path.toRealPath() throws AccessDeniedException for your remote directory on Windows. Perhaps H2 should catch and ignore such exceptions.

But, again, it is a bad idea to use remote directories (drives) for database files.

@katzyn
Copy link
Contributor

katzyn commented Apr 19, 2022

You can also try to write a some simple test case (with Path.toRealPath()) and if it fails too, this issue should be reported as a bug in JDK.

I found a similar bug, but in your case exception is different:
https://bugs.openjdk.java.net/browse/JDK-8172711

@vishi-vaghela
Copy link
Author

Thank you for suggestions. I had tried POC around toRealPath() and find out that this method requires access for each folder and drives in order to run without any issues. so have to give permission to S:/ drive, plus all of the folders in my path.
But this solution wont work for me as i need to give access to service folder only. i cannot give permission to drive and few folders due to setup issues.

@katzyn
Copy link
Contributor

katzyn commented Apr 22, 2022

Does toAbsolutePath() work in the same configuration where toRealPath() fails?

@vishi-vaghela
Copy link
Author

i tried same my POC with toAbsolutePath() and it works fine. It returns me the path of folder.

@vishi-vaghela
Copy link
Author

Hi Katzyn,

is below commit contains changes from H2 v1.4 to H2 v2.1.210 ?

2b159d1

[h2/src/main/org/h2/store/fs/FilePathDisk.java] - line no. 200 - newDirectoryStream()(2b159d1#diff-e26da4e5126a84ed38b1b9d09b77712ed127b3f5f6e3a316074fde68950bb213)

@vishi-vaghela
Copy link
Author

I tried to handle the error in my local & it seems resolved my issue. Below is my change: machineh2\h2database\h2\src\main\org\h2\store\fs\disk\FilePathDisk.java---

Below is the function in which i have commented one line and replace it with "return Collections.emptyList();"

@OverRide
public List newDirectoryStream() {
try (Stream files = Files.list(Paths.get(name).toRealPath())) {
return files.collect(ArrayList::new, (t, u) -> t.add(getPath(u.toString())), ArrayList::addAll);
} catch (NoSuchFileException e) {
return Collections.emptyList();
} catch (IOException e) {
return Collections.emptyList();
//throw DbException.convertIOException(e, name);
}
}

Please let me know if this is the correct way to handle this error ? can we make this change ?

@katzyn
Copy link
Contributor

katzyn commented May 3, 2022

No, it isn't correct. We need these files anyway.

@katzyn katzyn changed the title After upgrading to v2.1.210 facing issue of access denied error and not creating .mv.db file. Below is the error message database: opening C:\Program Files\nt\nt-h2-store org.h2.message.DbException: IO Exception: "java.nio.file.AccessDeniedException: C:\\Program Files\\nt"; FilePathDisk.newDirectoryStream() may fail on remote drive on Windows due to AccessDeniedException in Path.toRealPath() May 3, 2022
@katzyn
Copy link
Contributor

katzyn commented May 3, 2022

If you can compile H2 from its current sources, please re-test this issue in your environment.

Building instructions are here:
https://h2database.com/html/build.html#building
You need a jar target.

@vishi-vaghela
Copy link
Author

Thanks Katzyn..!!! :-)

@vishi-vaghela
Copy link
Author

i have verified the updated jar and its working as expected.

@vishi-vaghela
Copy link
Author

Any ETA when we are going to release this fix in new version ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants