hierynomus / smbj

Server Message Block (SMB2, SMB3) implementation in Java
Other
713 stars 180 forks source link

We are getting STATUS_OBJECT_NAME_COLLISION in upload file even though file is not already exist on given path #551

Closed harisingh-highq closed 4 years ago

harisingh-highq commented 4 years ago

@hierynomus @pepijnve Can you please help me to sort out this issue? I'm getting STATUS_OBJECT_NAME_COLLISION error although file is not already exist on below path

com.hierynomus.mssmb2.SMBApiException: STATUS_OBJECT_NAME_COLLISION (0xc0000035): Create failed for \fileserver1ind1.hqdev.india\data\HYBRID_APPLIANCE_SMBJ_REPO_Hari\\enc\griffin\HYB92\75286\ at com.hierynomus.smbj.share.Share.receive(Share.java:366) at com.hierynomus.smbj.share.Share.sendReceive(Share.java:346) at com.hierynomus.smbj.share.Share.createFile(Share.java:159) at com.hierynomus.smbj.share.DiskShare.createFileAndResolve(DiskShare.java:97) at com.hierynomus.smbj.share.DiskShare.resolveAndCreateFile(DiskShare.java:79) at com.hierynomus.smbj.share.DiskShare.open(DiskShare.java:66) at com.hierynomus.smbj.share.DiskShare.openDirectory(DiskShare.java:130) at com.hierynomus.smbj.share.DiskShare.mkdir(DiskShare.java:240) at com.hybridintegration.repository.SMBJRepo.mkDirs(SMBJRepo.java:3286)

This is create file code in share object:- share.openFile(filePath, EnumSet.of(AccessMask.GENERIC_WRITE, AccessMask.GENERIC_READ), null, null, SMB2CreateDisposition.FILE_OVERWRITE_IF, null);

hierynomus commented 4 years ago

As the server is returning that, I would investigate why it is returning that? THere is nothing the SMBJ library can do about this return code, except return it to you to deal with it.

https://stackoverflow.com/questions/54113855/what-does-status-object-name-collision-from-a-samba-share-really-mean-and-could

harisingh-highq commented 4 years ago

@hierynomus Thanks for your prompt response.

As per above logs, i think issue is in creating mkdir() method of DiskShare. at com.hierynomus.smbj.share.DiskShare.openDirectory(DiskShare.java:130) at com.hierynomus.smbj.share.DiskShare.mkdir(DiskShare.java:240)

I looked into source code of mkdir() as per suggestion here:- https://stackoverflow.com/questions/54113855/what-does-status-object-name-collision-from-a-samba-share-really-mean-and-could image

I think there should be FILE_OVERWRITE_IF in SMBcreateDisposition parameter value.

What do you suggest in this case? Can this fix would resolve the issue?

hierynomus commented 4 years ago

Actually before calling mkdir you should be checking existence. Depending on the semantics of the FILE_OVERWRITE_IF for a folder it could be bad practice. This is not a bug but desired behavior to get an exception if you try to create a directory that already exists.

harisingh-highq commented 4 years ago

I have already check for folder exist before calling mkdir as like below code:- if (!share.folderExists(folderPath)) { String[] list =folderPath.split("\\\\"); List<String> pathList = new ArrayList<>(Arrays.asList(list)); mkDirs(share, pathList); } But in case of concurrent simultaneous file upload case its failing to attempt folder exist and it may try to call mkdir for same folder which is throwing STATUS_OBJECT_NAME_COLLISION error.

hierynomus commented 4 years ago

You need to do your own concurrency control for your code. So use a Lock, Monitor, Semaphore, synchronized block or one of the many other concurrency primitives.

ecki commented 4 years ago

You can just ignore the exception, if it is thrown you know that the directory already exists.

Alternatively you can try to create the file and only if that fails try to create the parent directories, this is the fastest method (least roundtrips)

harisingh-highq commented 4 years ago

You can just ignore the exception, if it is thrown you know that the directory already exists.

Alternatively you can try to create the file and only if that fails try to create the parent directories, this is the fastest method (least roundtrips)

Thanks @ecki for your suggestion. I appreciate your help.

Yes i think it would be good to handle this exception and try to create the file on this folder. Let me try to fix in this way.

Just a quick question is there any other possibility of throwing same error in any other case in mkdir?

harisingh-highq commented 4 years ago

You need to do your own concurrency control for your code. So use a Lock, Monitor, Semaphore, synchronized block or one of the many other concurrency primitives.

Thanks @hierynomus for your reply

ecki commented 4 years ago

Hard to say, the name collision error code sounds pretty specific.

Btw: There is one case where one of the directories in the path are not directories but files. I don't know what error would be thrown in that case. It is always good to log that very clearly if /a/b is a file and you want to create a file in /a/b/c/d it should log that b is a file (and not that /a/b/c is no directory Or that it cannot create c. If those directories come and go nobody would know what to look for if it's not clearly logged).