1. Detecting shares using walk_dir()
- Posted by ZNorQ Dec 04, 2014
- 1742 views
Hi,
I'm trying to create a program that logs files on certain servers, but I'd like it to automatically detect the (public) shares.
Example;
some-server\<arbitrary public shares>\
I'm currently using walk_dir() to log the files, but it wont accept;
object nResult = walk_dir("\\some-server\", routine_id("myWDRoutine"), true )
The above code results in no output, even if there where shares for that server. Is there another way I can solve this?
Kenneth aka ZNorQ
2. Re: Detecting shares using walk_dir()
- Posted by petelomax Dec 04, 2014
- 1718 views
What happens when you map a network drive? Unfortunately I have nothing to test it on here.
Erm, belay that, can you explain/expand that example? What are you actually doing there, as in an example terminal session. What OS are you on?
Pete
3. Re: Detecting shares using walk_dir()
- Posted by ghaberek (admin) Dec 04, 2014
- 1736 views
This code works for me. Make sure you're properly escaping your backslashes as shown below (in your example you are not).
include std/console.e include std/filesys.e function look_at( sequence path, sequence item ) display( item[D_NAME] ) return 0 end function walk_dir( "\\\\localhost\\c$", routine_id("look_at") )
4. Re: Detecting shares using walk_dir()
- Posted by jimcbrown (admin) Dec 04, 2014
- 1684 views
This code works for me. Make sure you're properly escaping your backslashes as shown below (in your example you are not).
include std/console.e include std/filesys.e function look_at( sequence path, sequence item ) display( item[D_NAME] ) return 0 end function walk_dir( "\\\\localhost\\c$", routine_id("look_at") )
Not sure this helps .. the OP wants to get the list of shares on a machine, not look inside a specific share. Something akin to "smbclient -L machine" IIUC.
What OS are you on?
Again, I'm not sure if this helps, but it's probably safe to say that the OP is using some version of windoze.
5. Re: Detecting shares using walk_dir()
- Posted by ghaberek (admin) Dec 04, 2014
- 1701 views
Not sure this helps .. the OP wants to get the list of shares on a machine, not look inside a specific share. Something akin to "smbclient -L machine" IIUC.
Yeah, I kind of overshot that one, didn't I? I saw the mis-escaped backslashes and figured that was his problem.
I believe the trick here is to use WNetEnumResource. Here is a wrapper for the necessary API functions to get started. I will actually wrap them into a better "enumerate shares" function if I have time later.
Also, I should point out that walk_dir() and other functions do not work here, because the resource \\some-server is not a directory. It is a "container" and the shares inside may point to either a disk or a printer. So we're concerned about enumerating the disk shares, which we can then inspect with walk_dir(), etc.
-- file: mpr.e include std/dll.e include std/machine.e include std/math.e public constant RESOURCE_CONNECTED = 1, RESOURCE_GLOBALNET = 2, RESOURCE_REMEMBERED = 3, RESOURCE_RECENT = 4, RESOURCE_CONTEXT = 5, $ public constant RESOURCETYPE_ANY = 0, RESOURCETYPE_DISK = 1, RESOURCETYPE_PRINT = 2, RESOURCETYPE_RESERVED = 8, RESOURCETYPE_UNKNOWN = #FFFFFFFF, $ public constant RESOURCEUSAGE_CONNECTABLE = #00000001, RESOURCEUSAGE_CONTAINER = #00000002, RESOURCEUSAGE_NOLOCALDEVICE = #00000004, RESOURCEUSAGE_SIBLING = #00000008, RESOURCEUSAGE_ATTACHED = #00000010, RESOURCEUSAGE_ALL = or_all({ RESOURCEUSAGE_CONNECTABLE, RESOURCEUSAGE_CONTAINER, RESOURCEUSAGE_ATTACHED }), RESOURCEUSAGE_RESERVED = #80000000, $ public constant RESOURCEDISPLAYTYPE_GENERIC = 0, RESOURCEDISPLAYTYPE_DOMAIN = 1, RESOURCEDISPLAYTYPE_SERVER = 2, RESOURCEDISPLAYTYPE_SHARE = 3, RESOURCEDISPLAYTYPE_FILE = 4, RESOURCEDISPLAYTYPE_GROUP = 5, RESOURCEDISPLAYTYPE_NETWORK = 6, RESOURCEDISPLAYTYPE_ROOT = 7, RESOURCEDISPLAYTYPE_SHAREADMIN = 8, RESOURCEDISPLAYTYPE_DIRECTORY = 9, RESOURCEDISPLAYTYPE_TREE = 10, $ public constant -- structure NETRESOURCE__dwScope = 0, -- DWORD NETRESOURCE__dwType = 4, -- DWORD NETRESOURCE__dwDisplayType = 8, -- DWORD NETRESOURCE__dwUsage = 12, -- DWORD NETRESOURCE__lpLocalName = 16, -- LPTSTR NETRESOURCE__lpRemoteName = 20, -- LPTSTR NETRESOURCE__lpComment = 24, -- LPTSTR NETRESOURCE__lpProvider = 28, -- LPTSTR SIZEOF_NETRESOURCE = 32, $ public atom mpr_dll = open_dll( "mpr.dll" ) public constant xWNetCloseEnum = define_c_func( mpr_dll, "WNetCloseEnum", {C_HANDLE}, C_DWORD ), xWNetEnumResource = define_c_func( mpr_dll, "WNetEnumResourceA", {C_HANDLE,C_POINTER,C_POINTER,C_POINTER}, C_DWORD ), xWNetOpenEnum = define_c_func( mpr_dll, "WNetOpenEnumA", {C_DWORD,C_DWORD,C_DWORD,C_POINTER,C_POINTER}, C_DWORD ), $ public function WNetCloseEnum( atom hEnum ) return c_func( xWNetCloseEnum, {hEnum} ) end function public function WNetEnumResource( atom hEnum, atom lpcCount, atom lpBuffer, atom lpBufferSize ) return c_func( xWNetEnumResource, {hEnum,lpcCount,lpBuffer,lpBufferSize} ) end function public function WNetOpenEnum( atom dwScope, atom dwType, atom dwUsage, atom lpNetResource, atom lphEnum ) return c_func( xWNetOpenEnum, {dwScope,dwType,dwUsage,lpNetResource,lphEnum} ) end function
-Greg
6. Re: Detecting shares using walk_dir()
- Posted by ZNorQ Dec 05, 2014
- 1627 views
What happens when you map a network drive? Unfortunately I have nothing to test it on here.
Erm, belay that, can you explain/expand that example? What are you actually doing there, as in an example terminal session. What OS are you on?
Pete
The point of the program is not to map a network drive, but to walk through all public shares (and folders/files) on certain servers; so I know the server names (i.e. "someserver", "someotherserver", etc.), but the (public) shares on each server may vary. Over time there might be some new shares, some shares are dropped, etc.
Oh, and yes, it is Windows.
PS! I know the server names starts with backslash-backslash, but the Creole for this seems to be newline, and I'm not sure how to override the Creole..
Regards Kenneth aka ZNorQ.
7. Re: Detecting shares using walk_dir()
- Posted by ZNorQ Dec 05, 2014
- 1622 views
This code works for me. Make sure you're properly escaping your backslashes as shown below (in your example you are not).
include std/console.e include std/filesys.e function look_at( sequence path, sequence item ) display( item[D_NAME] ) return 0 end function walk_dir( "\\\\localhost\\c$", routine_id("look_at") )
Not sure this helps .. the OP wants to get the list of shares on a machine, not look inside a specific share. Something akin to "smbclient -L machine" IIUC.
What OS are you on?
Again, I'm not sure if this helps, but it's probably safe to say that the OP is using some version of windoze.
I know the server names, I don't know the shares. Over time they may even be changed (new added, old removed, etc)
And sorry, yes, it is windows (forgot to mention that in my post).
Kenneth aka ZNorQ.
8. Re: Detecting shares using walk_dir()
- Posted by ZNorQ Dec 05, 2014
- 1680 views
Not sure this helps .. the OP wants to get the list of shares on a machine, not look inside a specific share. Something akin to "smbclient -L machine" IIUC.
Yeah, I kind of overshot that one, didn't I? I saw the mis-escaped backslashes and figured that was his problem.
I believe the trick here is to use WNetEnumResource. Here is a wrapper for the necessary API functions to get started. I will actually wrap them into a better "enumerate shares" function if I have time later.
Also, I should point out that walk_dir() and other functions do not work here, because the resource \\some-server is not a directory. It is a "container" and the shares inside may point to either a disk or a printer. So we're concerned about enumerating the disk shares, which we can then inspect with walk_dir(), etc.
<eucode> snipped
-Greg
"Also, I should point out that walk_dir() and other functions do not work here, because the resource \\some-server is not a directory. It is a "container" and the shares inside may point to either a disk or a printer."
Wouldn't it be a good addition to the walk_dir() function to detect and process the public shares (and ignore the printers) if possible?
When it comes to windows-functionality, I'm pretty weak. I'm learning, but I wouldn't know where to start using the code above.
Kenneth aka ZNorQ.
PS! Thanks for the great feedback!
9. Re: Detecting shares using walk_dir()
- Posted by jimcbrown (admin) Dec 05, 2014
- 1640 views
Wouldn't it be a good addition to the walk_dir() function to detect and process the public shares (and ignore the printers) if possible?
No. As ghaberek already explained,
"Also, I should point out that walk_dir() and other functions do not work here, because the resource \\some-server is not a directory. It is a "container"
So imvho this functionality is better off living in the enumerate_shares() function that ghaberek will hopefully get around to writing soon.
10. Re: Detecting shares using walk_dir()
- Posted by ghaberek (admin) Dec 05, 2014
- 1601 views
So imvho this functionality is better off living in the enumerate_shares() function that ghaberek will hopefully get around to writing soon.
And here it is!
You can use scan_network() to scan the network for available servers and/or call enumerate_shares() against a specific host (e.g. \\some-server).
This won't display any hidden shares (like C$ or admin$) because, well... they're hidden. But you can still use walk_dir() against those shares.
-- file: shares.e include std/dll.e include std/machine.e include mpr.e -- WNet* functions and constants constant KB = 1024 -- one kilobyte public constant -- possible results codes NO_ERROR = 0, ERROR_INVALID_HANDLE = 6, ERROR_INVALID_PARAMETER = 87, ERROR_MORE_DATA = 234, ERROR_NO_MORE_ITEMS = 259, ERROR_INVALID_ADDRESS = 487, ERROR_NO_NET_OR_BAD_PATH = 1203, ERROR_NOT_CONTAINER = 1207, ERROR_EXTENDED_ERROR = 1208, ERROR_NO_NETWORK = 1222, $ public enum -- values returned by get_NETRESOURCE() NETRESOURCE_SCOPE, NETRESOURCE_TYPE, NETRESOURCE_DISPLAY_TYPE, NETRESOURCE_USAGE, NETRESOURCE_LOCAL_NAME, NETRESOURCE_REMOTE_NAME, NETRESOURCE_COMMENT, NETRESOURCE_PROVIDER, $ --** -- Allocate a NETRESOURCE structure. -- function new_NETRESOURCE( atom dwScope, atom dwType, atom dwDisplayType, atom dwUsage, sequence szLocalName = "", sequence szRemoteName = "", sequence szComment = "", sequence szProvider = "" ) integer nBufferSize, nOffset atom lpNetResource, lpLocalName, lpRemoteName, lpComment, lpProvider -- calculate the total buffer size nBufferSize = SIZEOF_NETRESOURCE + 4 -- four NULL terminators + length( szLocalName ) + length( szRemoteName ) + length( szComment ) + length( szProvider ) -- allocate the entire buffer lpNetResource = allocate_data( nBufferSize ) mem_set( lpNetResource, NULL, nBufferSize ) nOffset = SIZEOF_NETRESOURCE if length( szLocalName ) = 0 then lpLocalName = NULL else lpLocalName = lpNetResource + nOffset poke( lpLocalName, szLocalName & NULL ) end if nOffset += length( szLocalName ) + 1 if length( szRemoteName ) = 0 then lpRemoteName = NULL else lpRemoteName = lpNetResource + nOffset poke( lpRemoteName, szRemoteName & NULL ) end if nOffset += length( szRemoteName ) + 1 if length( szComment ) = 0 then lpComment = NULL else lpComment = lpNetResource + nOffset poke( lpComment, szComment & NULL ) end if nOffset += length( lpComment ) + 1 if length( szProvider ) = 0 then lpProvider = NULL else lpProvider = lpNetResource + nOffset poke( lpProvider, szProvider & NULL ) end if poke4( lpNetResource + NETRESOURCE__dwScope, dwScope ) poke4( lpNetResource + NETRESOURCE__dwType, dwType ) poke4( lpNetResource + NETRESOURCE__dwDisplayType, dwDisplayType ) poke4( lpNetResource + NETRESOURCE__dwUsage, dwUsage ) poke4( lpNetResource + NETRESOURCE__lpLocalName, lpLocalName ) poke4( lpNetResource + NETRESOURCE__lpRemoteName, lpRemoteName ) poke4( lpNetResource + NETRESOURCE__lpComment, lpComment ) poke4( lpNetResource + NETRESOURCE__lpProvider, lpProvider ) return lpNetResource end function --** -- Read a NETRESOURCE structure from memory. -- function get_NETRESOURCE( atom lpNetResource, integer nCount = 1 ) sequence data = repeat( {}, nCount ) atom offset = 0 for i = 1 to nCount do -- peek the whole structure (eight 4-byte values) data[i] = peek4u({ lpNetResource + offset, 8 }) -- values 5-8 are really strings for j = 5 to 8 do if data[i][j] = 0 then -- null (empty) string data[i][j] = "" else -- peek the string value data[i][j] = peek_string( data[i][j] ) end if end for -- increment the offset offset += SIZEOF_NETRESOURCE end for return data end function --** -- Translate an error code into a descriptive string. -- public function get_net_error( integer error ) sequence string switch error do case NO_ERROR then string = "success" case ERROR_INVALID_HANDLE then string = "invalid handle" case ERROR_INVALID_PARAMETER then string = "invalid parameter" case ERROR_MORE_DATA then string = "more data available" case ERROR_NO_MORE_ITEMS then string = "no more items" case ERROR_INVALID_ADDRESS then string = "invalid address" case ERROR_NO_NET_OR_BAD_PATH then string = "no network or bad path" case ERROR_NOT_CONTAINER then string = "not a container" case ERROR_EXTENDED_ERROR then string = "extended error" case ERROR_NO_NETWORK then string = "no network available" case else string = "unknown error" end switch return "Error: " & string end function --** -- Scan the network for available resources. -- -- dwScope can be one of the following: -- -- RESOURCE_CONNECTED Enumerate all currently connected resources. The function ignores the dwUsage parameter. -- -- RESOURCE_CONTEXT Enumerate only resources in the network context of the caller. Specify this -- value for a Network Neighborhood view. The function ignores the dwUsage parameter. -- -- RESOURCE_GLOBALNET Enumerate all resources on the network. -- -- RESOURCE_REMEMBERED Enumerate all remembered (persistent) connections. The function ignores the dwUsage parameter. -- -- dwType can be one of the following: -- -- RESOURCETYPE_ANY All resources. This value cannot be combined with RESOURCETYPE_DISK or RESOURCETYPE_PRINT. -- -- RESOURCETYPE_DISK All disk resources. -- -- RESOURCETYPE_PRINT All print resources. -- -- dwUsage can be one of the following: -- -- 0 All resources. -- -- RESOURCEUSAGE_CONNECTABLE All connectable resources. -- -- RESOURCEUSAGE_CONTAINER All container resources. -- -- RESOURCEUSAGE_ATTACHED Setting this value forces WNetOpenEnum to fail if the user is not authenticated. -- The function fails even if the network allows enumeration without authentication. -- -- RESOURCEUSAGE_ALL Setting this value is equivalent to setting RESOURCEUSAGE_CONNECTABLE, -- RESOURCEUSAGE_CONTAINER, and RESOURCEUSAGE_ATTACHED. -- public function scan_network( atom dwScope = RESOURCE_CONTEXT, atom dwType = RESOURCETYPE_ANY, atom dwUsage = 0 ) atom lpNetResource = NULL -- Scan the entire network. atom lphEnum = allocate_data( 4 ) -- Pointer to an enumeration handle. object hResult = NO_ERROR hResult = WNetOpenEnum( dwScope, dwType, dwUsage, lpNetResource, lphEnum ) if hResult != NO_ERROR then -- WNetOpenEnum() failed. return hResult end if atom hEnum = peek4u( lphEnum ) -- Get the enumeration handle. free( lphEnum ) integer nBufferSize = 16 * KB -- N.B. MS docs recommend 16KB here. atom lpcCount = allocate_data( 4 ) poke4( lpcCount, -1 ) -- Get as many entries as possible. atom lpBuffer = allocate_data( nBufferSize ) atom lpBufferSize = allocate_data( 4 ) poke4( lpBufferSize, nBufferSize ) hResult = WNetEnumResource( hEnum, lpcCount, lpBuffer, lpBufferSize ) while hResult = ERROR_MORE_DATA do -- We need to allocate more memory. nBufferSize += 16 * KB poke4( lpBufferSize, nBufferSize ) free( lpBuffer ) lpBuffer = allocate_data( nBufferSize ) hResult = WNetEnumResource( hEnum, lpcCount, lpBuffer, lpBufferSize ) end while if hResult = NO_ERROR then -- Get the NETRESOURCE items. integer nCount = peek4u( lpcCount ) hResult = get_NETRESOURCE( lpBuffer, nCount ) elsif hResult = ERROR_NO_MORE_ITEMS then -- Return an empty set. hResult = {} end if free( lpBufferSize ) free( lpBuffer ) free( lpcCount ) WNetCloseEnum( hEnum ) return hResult end function --** -- Enumerate the shares provided by server at szRemoteName -- -- dwType can be one of the following: -- -- RESOURCETYPE_ANY All resources. This value cannot be combined with RESOURCETYPE_DISK or RESOURCETYPE_PRINT. -- -- RESOURCETYPE_DISK All disk resources. -- -- RESOURCETYPE_PRINT All print resources. -- -- dwUsage can be one of the following: -- -- 0 All resources. -- -- RESOURCEUSAGE_CONNECTABLE All connectable resources. -- -- RESOURCEUSAGE_CONTAINER All container resources. -- -- RESOURCEUSAGE_ATTACHED Setting this value forces WNetOpenEnum to fail if the user is not authenticated. -- The function fails even if the network allows enumeration without authentication. -- -- RESOURCEUSAGE_ALL Setting this value is equivalent to setting RESOURCEUSAGE_CONNECTABLE, -- RESOURCEUSAGE_CONTAINER, and RESOURCEUSAGE_ATTACHED. -- public function enumerate_shares( sequence szRemoteName, atom dwType = RESOURCETYPE_ANY, atom dwUsage = 0 ) atom dwScope = RESOURCE_GLOBALNET -- Enumerate all resources on the server. atom lpNetResource = new_NETRESOURCE( dwScope, dwType, NULL, dwUsage, "", szRemoteName, "", "" ) atom lphEnum = allocate_data( 4 ) -- Pointer to an enumeration handle. object hResult = NO_ERROR hResult = WNetOpenEnum( dwScope, dwType, dwUsage, lpNetResource, lphEnum ) if hResult != NO_ERROR then -- WNetOpenEnum() failed. return hResult end if atom hEnum = peek4u( lphEnum ) -- Get the enumeration handle. free( lphEnum ) integer nBufferSize = 16 * KB -- N.B. MS docs recommend 16KB here. atom lpcCount = allocate_data( 4 ) poke4( lpcCount, -1 ) -- Get as many entries as possible. atom lpBuffer = allocate_data( nBufferSize ) atom lpBufferSize = allocate_data( 4 ) poke4( lpBufferSize, nBufferSize ) hResult = WNetEnumResource( hEnum, lpcCount, lpBuffer, lpBufferSize ) while hResult = ERROR_MORE_DATA do -- We need to allocate more memory. nBufferSize += 16 * KB poke4( lpBufferSize, nBufferSize ) free( lpBuffer ) lpBuffer = allocate_data( nBufferSize ) hResult = WNetEnumResource( hEnum, lpcCount, lpBuffer, lpBufferSize ) end while if hResult = NO_ERROR then -- Get the NETRESOURCE items. integer nCount = peek4u( lpcCount ) hResult = get_NETRESOURCE( lpBuffer, nCount ) elsif hResult = ERROR_NO_MORE_ITEMS then -- Return an empty set. hResult = {} end if free( lpNetResource ) free( lpBufferSize ) free( lpBuffer ) free( lpcCount ) WNetCloseEnum( hEnum ) return hResult end function
Example:
include std/error.e include shares.e object network = scan_network() if atom( network ) then crash( get_net_error(network) ) end if for i = 1 to length( network ) do sequence remoteName = network[i][NETRESOURCE_REMOTE_NAME] if length( remoteName ) then printf( 1, "%s\n", {remoteName} ) else -- empty remote name is the "Network" container puts( 1, "Network Neighborhood\n" ) end if object shares = enumerate_shares( remoteName ) if atom( shares ) then -- you could also just 'continue' here crash( get_net_error(shares) ) end if for j = 1 to length( shares ) do sequence shareName = shares[j][NETRESOURCE_REMOTE_NAME] printf( 1, "\t%s\n", {shareName} ) end for end for
-Greg
11. Re: Detecting shares using walk_dir()
- Posted by ZNorQ Dec 09, 2014
- 1547 views
This is exactly what I'm looking for; thank you for excellent work!
Will this be part of the euphoria includes?
Regards Kenneth aka ZNorQ.