0

I am trying to delete file from file system, and check whether are directory and its parent directories containing it are empty to delete them also:

Path filePath = Paths.get(document.getUrl());
Files.delete(filePath);

Path directory = filePath.getParent();

// check if is it necessary to delete any parent dirs

while(!Files.list(directory).findAny().isPresent() && !directory.endsWith(DOCUMENT_ROOT)){
    Files.delete(directory);
    directory = directory.getParent();
}

When I try to delete file that is only one in directory it deletes it but fails to delete directory that is containing it without throwing java.ioIOException. After that when I try to save another file to that directory I get java.nio.file.AccessDeniedException:

java.nio.file.AccessDeniedException: C:\Users\mjo\git\attendo5\media\doc\2020\6\1
at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:89)
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.WindowsFileSystemProvider.createDirectory(WindowsFileSystemProvider.java:506)
at java.base/java.nio.file.Files.createDirectory(Files.java:693)
at java.base/java.nio.file.Files.createAndCheckIsDirectory(Files.java:800)
at java.base/java.nio.file.Files.createDirectories(Files.java:786)
at com.attendo.server.webapp.common.DocumentManagerServiceImpl.saveDocument(DocumentManagerServiceImpl.java:46)
at com.attendo.server.webapp.app.panel.humanresources.service.ContractServiceImpl.addDocuments_aroundBody4(ContractServiceImpl.java:222)
at com.attendo.server.webapp.app.panel.humanresources.service.ContractServiceImpl$AjcClosure5.run(ContractServiceImpl.java:1)
at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96cproceed(AbstractTransactionAspect.aj:66)
at org.springframework.transaction.aspectj.AbstractTransactionAspect$AbstractTransactionAspect$1.proceedWithInvocation(AbstractTransactionAspect.aj:72)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:366)
at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(AbstractTransactionAspect.aj:70)
at com.attendo.server.webapp.app.panel.humanresources.service.ContractServiceImpl.addDocuments(ContractServiceImpl.java:211)
at com.attendo.server.webapp.app.panel.humanresources.service.ContractServiceImpl$$FastClassBySpringCGLIB$$2fa3d507.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:69)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
at com.attendo.server.webapp.app.panel.humanresources.service.ContractServiceImpl$$EnhancerBySpringCGLIB$$1de4496.addDocuments(<generated>)
at com.attendo.server.webapp.app.panel.humanresources.api.controller.general.ContractController.addDocument(ContractController.java:143)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:152)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:830)

I can't figure out what is going on and any help would be welcomed.

Edit: It works perfectly well if I use java.io and apache.commons.io:

    File file = new File(document.getUrl());
    if(!file.delete()){
        throw new AttendoException("error.file_could_not_be_deleted");
    }

    File directory = new File(file.getParent());

    // check if is it necessary to delete any parent dirs
    while((directory.isDirectory()) && (directory.list().length == 0) && !directory.getAbsolutePath().endsWith(DOCUMENT_ROOT)){
        FileUtils.deleteDirectory(directory);
        directory = new File(directory.getParent());
    }
mjo
  • 43
  • 6
  • Please include the exception messages and stacktraces – Stephen C Jun 01 '20 at 13:11
  • If you read the exception messages you could clearly see that you cannot delete it: AccessDeniedException tells you about the ACSESS problems. –  Jun 01 '20 at 13:19
  • @Joakim Danielson. The stacktrace tells you about the reasons of a failed action. He wanted to delete a directory but he hasn't the privilege to do that. –  Jun 01 '20 at 13:23
  • @Joe I get exception when I try to create another file on path of directories that should be deleted, but it is apparently not. I do not get exception when I call Files.delete() on directory and it is void function so I don't know how to check if delete was success? – mjo Jun 01 '20 at 13:24
  • @Joakin Danielson the last exception is usually the true reason. And here: the createDirectory caused the exception because of insufficient privilege –  Jun 01 '20 at 13:29
  • @mjo you could check for its existence with the exists() –  Jun 01 '20 at 13:34
  • @Joe I think you are missing the point of my question. I have submitted code that in my opinion is not working properly but it is not throwing IOException. After that I get this exception when I try to recreate this directory if it is necessary. It works perfectly well if I never delete anything in it before that. So, I am fairly certain that code I have submitted leaves some kind of lock on directory it is trying to delete and does not delete it, but I can not figure out why. Therefore I have submitted question here to try to get an answer about it. – mjo Jun 01 '20 at 13:39
  • @mjo. It seems to me that you are NOT clear about IOException. Click here to see when IOException is thrown:https://stackoverflow.com/questions/13216148/java-what-throws-an-ioexception –  Jun 01 '20 at 13:50
  • @Joe It creates directories perfectly well if they do not exist, but if I try to delete them with the code above it goes through without exception. Exception is thrown when I try to recreate deleted directories. If I didn't have sufficient privileges it wouldn't work the first time either. So as I said I suspect the code above leaves some kind of lock on directories I am trying to delete and does not delete it and therefore after I get java.nio.file.AccessDeniedException when I try to access them but I can not figure out why. – mjo Jun 01 '20 at 14:04
  • @mjo Have you checked manually if the directory contains any invisible files? – Joakim Danielson Jun 01 '20 at 14:09
  • @JoakimDanielson Yes I did. After delete function is executed directory is not deleted at all but I get AccessDenied if I try to open it on file system. – mjo Jun 01 '20 at 14:11

1 Answers1

1

Unlike File.list() which is self contained scan of the directory, note that Javadoc for Files.list(directory) says its should be used with "try-with-resources statement or similar control structure". So see if rewrite with the Files.list(directory) in try() block changes whether there is a lingering lock/access to a sub-directory which stops the Files.delete higher up, something like:

while(!directory.endsWith(DOCUMENT_ROOT)) {
    try(var stream = Files.list(directory))  {
        if (stream.findAny().isPresent()) {
            // do the delete you want here
        }
    }
}
DuncG
  • 12,137
  • 2
  • 21
  • 33