MKDIR command locks subdir !?

Hi all,

I have written a small class in Lotusscript in which I create a temporary subdir, so that I can detach one or several attachments into it, so that the can easily be processed. Works well, but … I can’t remove the subdir. It’s locked by the Notes Client ! Even from the OS I can’t remove it, until I leave the Lotus Notes Client.

Is that intention ? If yes, what exactly is it good for and is there a way to remove the lock from inside Lotus Notes programatically ?

TIA

Joe

Subject: This has always been the case…

  • I’ve been doing LS for years and years, and this has happened since R4. It’s the same thing if the server does it, except it can’t be deleted until Domino is bounced. Notes & Domino have always been very lax about releasing resources when they should by rights be done with them, and this seems particularly the case with files/directories.

  • It also doesn’t matter if your Agent is LS or Java, so it’s something in the API. Consistency is good, at any rate.

  • In the Grand Scheme O’ Flakiness, this ranks pretty low in my book. Doesn’t make it right, just means I don’t care if it works this way or not. Every few months, when I know Domino has been bounced, I go to the server and delete a few hundred or thousand empty directories. (shrug) Since there are far bigger fish to fry, so to speak, I’m delighted to accept this so Lotus can direct their energies at more pressing concerns. The only sad part is in all those years and years Lotus has always had more pressing concerns to address.

Hope this helps…

Subject: MKDIR does not lock the directory.

Just tested it and I couldn’t reproduce.

All I did was:

mkdir “c:\temp\d1”

Then from the cmd line I could delete it. It is possible that the creation of the files are not being correctly closed or the agent is somehow moving you into that folder.

If you have a small example to reproduce I can test.

Subject: MKDIR command locks somtines the subdir

Simon,

I made some tests and indeed in simple constructs, MKDIR works as it should work. I played around with several scenarios and it seems that only happens if the entire scenario is complex enough, it keeps on locking the subdir, although no process/file lock needs it anymore. In my case I detach files from a document and attach them to another. But this is only a subprocess. But the other processes have nothing to do wit hthis subdir, files or attachments.

I assume that an internal error in Notes is captured internally and does a kind of reset or removes things from the stack … so that Notes simply “forgets” to remove the subdir lock. Created for a test the subdir in the database script (queryopen) and tried to deleted it there also (Queryclose). If I just enter the db and leave it, it works as expected. But if I enter one of those docs with the attachments and detach only 1 file … locked.

As its probably something internal inside Notes I can’t invest any more time into it. I instead will work now on a workaround. Keep you guys informed.

Joe

Subject: Now a kill path$+“.” does not work correct …

Hello,

as promised, a short follow up:

Created a work around with an agent that is triggered when you start the application agaqin and that tries to remove any subdir(s), that Notes has locked and “forgotten” to unlock again while the clients was running. This will not work on the server though. Client only workaround.

But I run into other trouble trying to ensure that the subdirs are empty after being used: kill". in Lotus Notes does also not work like the corresponding OS command is doing; in my case it does not delete a detached file. As I can deleted the file “by hand” I will now try to use the SHELL command in Notes to use a direct OS command (DEL) as another workaround. This is unfortunately platform dependent, so I have to add a special method for it.

As the implementation of these commands in Notes seems to be a bit “tricky”, it seems to make sense to create a class that directly uses OS specific OS commands instead.

Joe

Subject: Workaround for KILL command in LS

Hi,

as announced I wrote a class that allows me to execute those commands on OS-Level to go around the limitations of those commands in Notes.

Using the Shell command in a direct way did not work. The final version writes a 1 line batch file and calls it then via SHELL. That works like a charm !

Finally I could delete all(!) files in my subdir and solve this problem. When I have time I will test the MKDIR and RMDIR commands also. Lost too much time for this workaround already, so please don’t expect this soon. If someone has enough time to test it and publish here … I would very much appreciated it !

If one wants this class also for an OS other than windows one has to implement whats OS specific in that class.

Joe

Subject: I beg to differ…

  • Code to create dirs:

    ',--------------------------------------------------------------------------[ C R E A T E D I R S ]-----

    '| What : CREATEDIRS LotusScript Property

    '| Who : Dave “Rags” Gilmore, Highland Technology Services, Inc.

    '| When : April 10, 2007

    '| Why : Make sure all directories of a path exist, ala the Java File.createDirs() method.

    ‘’------------------------------------------------------------------------------------------------------

    Private Function createDirs(path As String) As Boolean

      On Error Goto CP_DOH
    
      Dim drive As String
    
      Dim orgDir As String
    
      Dim part As String
    
      Dim rest As String
    
      Dim ndx As Long
    
      Dim first As Boolean
    
      '
    
      part=""
    
      drive=""
    
      createDirs=True
    
      first=True
    
      orgDir=Curdir$
    
      rest=path
    
      ndx=Instr(rest, "\")
    
      Me.pl.add |DFile is creating dirs for '|+path+|"|
    
      While(ndx>0)
    
      	If(part="") Then part=Left$(rest, ndx-1) Else part=part+"\"+Left$(rest, ndx-1)
    
      	rest=Mid$(rest, ndx+1)
    
      	If(first And Instr(part, ":")>0) Then
    
      		Me.pl.add |- Set drive |+part
    
      		drive=Curdrive$
    
      		Chdrive part
    
      		first=False
    
      	Else
    
      		If(Dir$(part, ATTR_DIRECTORY)="") Then
    
      			Me.pl.add |- Mkdir |+part
    
      			Mkdir(part)
    
      		Else
    
      			Me.pl.add |- Reuse |+part
    
      		End If
    
      	End If
    
      	ndx=Instr(rest, "\")
    
      Wend
    
      If(Instr(rest, ".")<1 And rest<>"") Then
    
      	part=part+"\"+rest
    
      	If(Dir$(part)="") Then Mkdir(part)
    
      End If
    

CP_DONE:

	If(drive<>"") Then Chdrive drive

	Chdir orgDir

	Exit Function

CP_DOH:

	createDirs=False

	Me.pl.err Err, | line | & Erl & | of createDirs: "|+Error$+|"|

	Resume CP_DONE

End Function
  • As you can see, it caches the current drive and directory, and returns to them on exit, even if the error handler runs. This must be done because LotusScript uses a global directory, and if it’s not restored the code will break other places, like trying to open a database that should default relative to the notes/data directory, but doesn’t.

  • Here’s one of several places that uses createDirs:

      	path=Me.lit.CLIENT_BASE_PATH+"\"
    
      	If(Me.edID="") Then path=path+Me.note.noteID Else path=path+Me.edID
    
      	path=path+"\"+Me.embed.source
    
      	createDirs(path)
    
      	noFile=(Dir$(path)="")
    
      	If(noFile) Then Me.embed.extractFile(path)
    
      	' --- what is done with file omitted ----
    
      	If(noFile And Dir$(path)<>"") Then		' We extracted, we delete
    
      		Me.pl.add |  Nuking: "|+path+|"|
    
      		Kill path				' file
    
      		path=Strleftback(path, "\")		' See in the "debugger"
    
      		Me.pl.add |  Rmdir: "|+path+|"|
    
      		Rmdir path			' noteID/edID directory
    
      	End If
    
  • This doesn’t change the current directory at all, unless Dir$() does that, but I’ve never noticed it doing that, and help doesn’t say it does that. And the log created by the above code:

DFile is creating dirs for 'C:\WebSvc\eDocs\Files\0901e24080714a5f\EXEC-2010-006716.pdf"

  • Set drive C:

  • Reuse C:\WebSvc

  • Reuse C:\WebSvc\eDocs

  • Reuse C:\WebSvc\eDocs\Files

  • Mkdir C:\WebSvc\eDocs\Files\0901e24080714a5f

    Nuking: “C:\WebSvc\eDocs\Files\0901e24080714a5f\EXEC-2010-006716.pdf”

    Rmdir: “C:\WebSvc\eDocs\Files\0901e24080714a5f”

Error(75): line 413 of DFile.digest(C:\WebSvc\eDocs\Files\0901e24080714a5f): “Path/file access error”

  • So it deletes the file but it won’t remove the subdirectory it created. One may say, well the directory isn’t empty, but it is - if I go to the server where this code runs nothing exists in the directory it fails to remove, and if I attempt to remove it manually I get an “in use” violation. If I use a tool to look at who has a handle to that directory, it’s Domino that has ahold of it and won’t let it go. This error always happens, and has always happened any time I extract a file and attempt to delete it’s (temporary) sudbdirectory. Since it doesn’t break anything I’ve always ignored it.

  • In the past I’ve seen this over and over and over with files, when I create them using LotusScript. For instance, I may write data to a file and then close it. Even after the Agent is done, Domino refuses to let go of the file until it’s bounced. It happened so consistently that I put code in to mangle file names, with a digit sequence for uniqueness, so the Agent wouldn’t barf because it could not append to its own file. Domino had that file and gosh darn it no one could touch it, not even Domino.

  • But, as mentioned, in the Grand Scheme of flakiness, this ranks next to zero. It’s trivially simple to work around or plain ignore. In terms of operation I could care less. But declaring this doesn’t happen does not actually make it so, and people searching this forum should be fully aware of how this operates.

Hope this helps…

Subject: Any chance narrowing it down?

The following tech note details the level of code Development will go through.

http://www-01.ibm.com/support/docview.wss?rs=899&uid=swg27003069

Don’t have a server access at the moment. The only thing that stands out (but not tested here).

“Chdir orgDir”

If you have moved into the directory you are trying to remove then it will fail. You will need to leave the directory in your code prior to removing it.

Subject: No.

  • I appreciate your response, Simon, but the text fully explained everything even if the code were ignored. Specific to your concern:

"As you can see, it caches the current drive and directory, and returns to them on exit, even if the error handler runs. "

The line you mention is it setting the directory back where it started, away from the directory it will fail to delete later. All other access to the file placed in that directory is done via full path specifications without changing the current directory again. In fact, the only reason the current directory gets changed at all is to build the directory tree the file will be put in. Don’t recall why I did it that way but I surmise it’s a hack, er, workaround, for some other flakiness with path-only use and directory creation. The current directory is such a mess in LotusScript that I willingly go far, far out of my way to avoid changing it unless there is no other solution.

  • Also:

“But, as mentioned, in the Grand Scheme of flakiness, this ranks next to zero.”

I have less than no interest in seeing this fixed. I was simply pointing out that it does in fact happen whether Lotus is able to reproduce it or not, and it has happened for over a decade in numerous different bits of code, none of which are copy/paste from one to the other. I feel it’s important that others searching the forum find out it can happen, and work around it, rather than have them believe it’s not possible because Lotus hasn’t reproduced it. Nothing more.

Thanks for your time…

Subject: Well I solved your code issue.

Ok the issue is not related to MKDIR. Appears to be related to DIR$.

I had some spare time, so here is what I did.

  1. Cleaned up your code to a much smaller sample.

  2. Ran it and deleted the directories from the command prompt. Worked fine.

  3. Ran it twice, as the logic is different the second time. Attempting to delete the directories the second last in the tree could not be removed (eg. “c:\a\b\c\d” directory c could not be removed).

  4. Tested it a few times on different directory structures and confirmed it is related to the second last directory.

  5. Moved the DIR$ out of the IF conditional statements to determine if they are connected. Could still reproduce the issue.

  6. Now that I know the issue is related to DIR$ I checked for existing SPRs. I found JDYU6679FJ. this is a crash issue (which turned out not to be an issue). Not directly related to this issue, but mentioned that if DIR$ is called with parameters the CAPI code is put into a loop holding the directory. It is only returned if an error condition happens.

  7. To test this I added a line at the end of the code to do DIR$(“C:\temp”). As it has no parameters it should break the loop. Testing with this I was no longer able to recreate the issue.

Created SPR SODY85SM84 which details this issue so development can investigate further. I will do up a tech note later on it.

Here is the sample code if your interested. Hope all this helps.


Option Public

Option Declare

Const ATTR_DIRECTORY = 16

Sub Initialize()

Const testDirectory = "c:\temp\simon\11\22\33\" ' requires \ at the end of the string or will fail.

createDirs(testDirectory)

End Sub

Private Function createDirs(path As String) As Boolean

On Error GoTo CP_DOH

Dim drive As String

Dim orgDir As String

Dim part As String

Dim rest As String

Dim ndx As Long

Dim first As Boolean

Dim dirCheck As string

part=“”

drive=“”

createDirs=True

first=True

orgDir=CurDir$

rest=path

ndx=InStr(rest, "")

Print |Creating dirs for '|+path+|"|

While(ndx>0)

If(part="") Then 

	part=Left$(rest, ndx-1) 

Else 

	part=part+"\"+Left$(rest, ndx-1)

End If



rest=Mid$(rest, ndx+1)



If(first And InStr(part, ":")>0) Then

	Print  |- Set drive |+part

	

	drive=CurDrive$

	ChDrive part

	first=False

Else

	dirCheck = Dir$(part, ATTR_DIRECTORY)

	Print "Dir$ = " + dirCheck



	If(dirCheck = "" ) Then

		Print  |- Mkdir |+part

		MkDir(part)

	Else

		Print  |- Reuse |+part

	End If

End If



ndx=InStr(rest, "\")

Wend

’ This line will stop the locking from occurring.

’ Appears to be related to SPR JDYU6679FJ

’ ***********************************************

’ dirCheck = Dir$(“c:\temp”) ’ Force without parameters

CP_DONE:

If(drive<>“”) Then

ChDrive drive

End If

’ return to original directory.

ChDir orgDir

Exit Function

CP_DOH:

createDirs=False

print | line | & Erl & | of createDirs: “|+Error$+|”|

Resume CP_DONE

End Function

Subject: Again I wish BP had access to the SPR database…

  • I could have discovered this myself years ago, most likely, known it was a bug in the Dir$() implementation (or code it calls - not relevant from LS), and possibly figured out how avoid it. I confess I didn’t search for a tech note on it. (sheepish grin) Turns out one doesn’t exist, but that’s not relevant to my failure to seek first.

  • Thanks for taking that time, Simon. Looks simple enough to fix…

Subject: Ditto - access to the SPR db would save a TON of everybody’s time.

I’m glad you found the problem Simon. I do find it (sadly?) amusing that we’re all spending so much time wrapped up in a function that absolutely, positively, guaranteed will never be fixed. The DIR$ command in Lotusscript? Yeahhhh… 0% chance of that happening. If I had to bet that internal SPR is years old.

If I recall I opened a PMR reporting that DIR$ isn’t even fully-Unicode-character compatible (along with nearly all of the other non-NotesStream LS file-handling methods) and nobody cares.

David, have you tried rewriting your own davdiDIR() function using the NotesStream classes? That’s effectively what we’ve done… Kill(), Rename(), Mkdir(), etc. have all been replaced by our own wrapping functions that either use NotesStream or other calls to perform things correctly.

And I echo David’s thanks, Simon. Even though you may not be able to fix a problem the fact that you’re taking the time here to peruse the forum and at least trying to help is definitely appreciated.

Subject: I’ve seen this on servers too.

Andre Guirard will be the first to admit that LS reference pointers/counters get screwy sometimes with garbage collection. It’s possible that this is related in some way to being placed in a user-defined class, are you doing that? Have you tried pressing shift-F5 to log out, without actually closing Notes completely? That can fix a myriad of handle-related problems, especially when working with COM objects through LS.

Subject: I had also tried.

mkdir running from within a class, from on the server as well as on the client and could not reproduce.

So there are probably more conditions to the cause of it happening.

If I was to guess the most common is a file left open in the directory or the code has moved you to that directory in some way and won’t return until you close the client. Or maybe some anti-virus or indexing software running.

OP, If you can reproduce please post steps. Also there is an app called Filemon which you can filter it to the directory you create. Might tell you what is touching it.