client: browse doesn't work with only win98 in workgroup

Derrell.Lipman at UnwiredUniverse.com Derrell.Lipman at UnwiredUniverse.com
Fri Feb 28 19:47:50 GMT 2003


"Christopher R. Hertel" <crh at ubiqx.mn.org> writes:

> I am interested in looking into this, but I won't have time until the 
> weekend.

Great.  Thanks for the response!

In the mean time, I have modified smbw_dir.c to include a new function
smbw_browse_workgroup_alternate() with the following patch.  The code is
basically stolen from nmblookup.c.

Since there is now some duplicated code pertaining to allocating and
initializing the smbw_dir structure, I also created a function to do that,
which is called from a couple of places.

This modification affects only the opendir()/readdir() functionality.  I think
that it does not solve the problem in the more generic case.  From smbsh, "ls
/smb/WORKGROUP" still fails although my test program (attached at bottom)
which uses opendir() and readdir() now succeeds.  I haven't looked at the 'ls'
source code, but I suspect that it is doing stat() calls after the readdir,
and that is failing.

------------------------------------------------------------------------------

diff -u samba-2.2.7.sandbox-orig/source/smbwrapper/smbw_dir.c samba-2.2.7.sandbox-test/source/smbwrapper/smbw_dir.c
--- samba-2.2.7.sandbox-orig/source/smbwrapper/smbw_dir.c	Wed Jan 29 11:24:58 2003
+++ samba-2.2.7.sandbox-test/source/smbwrapper/smbw_dir.c	Fri Feb 28 11:57:01 2003
@@ -27,9 +27,10 @@
 extern struct bitmap *smbw_file_bmap;
 extern int smbw_busy;
 
-static struct smbw_dir *smbw_dirs;
+static struct smbw_dir *smbw_dirs = NULL;
 static int ServerFD= -1;
 
+static void *smbw_browse_workgroup_alternate(char *path, char *workgroup);
 
 /***************************************************** 
 map a fd to a smbw_dir structure
@@ -72,6 +73,11 @@
 	SAFE_FREE(dir);
 }
 
+void smbw_free_dir(void *dir)
+{
+        free_dir((struct smbw_dir *) dir);
+}
+
 
 static struct smbw_dir *cur_dir;
 
@@ -113,8 +119,8 @@
 /***************************************************** 
 add a entry to a directory listing
 *******************************************************/
-static void smbw_share_add(const char *share, uint32 type, 
-                           const char *comment, void *state)
+void smbw_share_add(const char *share, uint32 type, 
+                    const char *comment, void *state)
 {
 	struct smbw_file_info finfo;
 
@@ -157,8 +163,8 @@
 /***************************************************** 
 add a server to a directory listing
 *******************************************************/
-static void smbw_server_add(const char *name, uint32 type, 
-			    const char *comment, void *state)
+void smbw_server_add(const char *name, uint32 type, 
+                     const char *comment, void *state)
 {
         int count;
 	struct smbw_file_info finfo;
@@ -195,6 +201,31 @@
 }
 
 
+
+/******************************************************
+allocate an smbw_dir structure and initialize it.
+*******************************************************/
+void *smbw_dir_alloc(struct smbw_server *srv, int fd, char *path)
+{
+        struct smbw_dir *dir;
+
+	dir = (struct smbw_dir *)malloc(sizeof(*dir));
+	if (!dir)
+                return NULL;
+
+	ZERO_STRUCTP(dir);
+
+        dir->srv = srv;
+        dir->fd = fd;
+        dir->path = (path == NULL ? NULL : strdup(path));
+        bitmap_set(smbw_file_bmap, fd);
+
+	cur_dir = dir;
+
+        return dir;
+}
+
+
 /***************************************************** 
 open a directory on the server
 *******************************************************/
@@ -223,22 +254,24 @@
 	/* get a connection to the server */
 	srv = smbw_server(server, share);
 	if (!srv) {
-		/* smbw_server sets errno */
-		goto failed;
+		/* smbw_server sets errno.  try alt method if workgroup */
+                if ((p=strstr(server,"#1D"))) {
+                        DEBUG(4, ("dir_open workgroup: trying alternate method"));
+                        *p = '\0';
+                        if (p > server && p[-1] == ':')
+                                p[-1] = '\0';
+                        if ((dir = smbw_browse_workgroup_alternate((char *) fname, server)))
+                                return dir->fd;
+                }
+                goto failed;
 	}
 
-	dir = (struct smbw_dir *)malloc(sizeof(*dir));
+	dir = smbw_dir_alloc(srv, 0, NULL);
 	if (!dir) {
 		errno = ENOMEM;
 		goto failed;
 	}
 
-	ZERO_STRUCTP(dir);
-
-	cur_dir = dir;
-
-	dir->srv = srv;
-
 	slprintf(mask, sizeof(mask)-1, "%s\\*", path);
 	all_string_sub(mask,"\\\\","\\",0);
 
@@ -772,3 +805,74 @@
 	return smbw_dir_lseek(d->fd,0,SEEK_CUR);
 }
 
+
+
+/*
+ * smbw_browse_workgroup_alternate()
+ *
+ * The normal smbwrapper method of browsing for host names doesn't work if the
+ * master browser for the workgroup is a Windows 98 or Windows 95 system.
+ * This function tries a different method of enumerating hosts.
+ */
+static void *smbw_browse_workgroup_alternate(char *path, char *workgroup)
+{
+        int                 i;
+        int                 j;
+        int                 fd;
+        int                 count;
+        int                 flags;
+        struct in_addr *    ip_list = NULL;
+        struct in_addr *    bcast;
+        struct nmb_name     nname;
+        struct node_status *status;
+        struct smbw_dir *   dir;
+
+        if ((fd = open_socket_in(SOCK_DGRAM, 137, 0,
+                                 interpret_addr("0.0.0.0"),
+                                 TRUE)) == -1)
+                return NULL;
+    
+        set_socket_options(fd, "SO_BROADCAST");
+
+        for (j = iface_count() - 1; ip_list == NULL && j >= 0; j--) {
+                bcast = iface_n_bcast(j);
+                ip_list = name_query(fd, workgroup, 0x0,
+                                     TRUE, TRUE,
+                                     *bcast, &count, &flags);
+        }
+
+        if (ip_list == NULL) {
+                close(fd);
+                return NULL;
+        }
+
+        /*
+         * We can only do find_status if the ip address returned was valid -
+         * ie. name_query returned true.
+         */
+        make_nmb_name(&nname, workgroup, 0x0);
+        if ((status = node_status_query(fd, &nname, ip_list[0], &count)) != NULL) {
+                if (count > 0) {
+                        /* Allocate a dir structure */
+                        if ((dir = smbw_dir_alloc(NULL, fd, path)) == NULL) {
+                                close(fd);
+                                return NULL;
+                        }
+
+                        DLIST_ADD(smbw_dirs, dir);
+
+                        for (i = 0; i < count; i++)
+                                if (status[i].type == 0x0 && (status[i].flags & 0x80) == 0)
+                                        smbw_server_add(status[i].name, 0, "", NULL);
+                } else {
+                        close(fd);
+                }
+                        
+
+                SAFE_FREE(status);
+        }
+
+        SAFE_FREE(ip_list);
+
+        return (count > 0 ? dir : NULL);
+}

------------------------------------------------------------------------------

Here's my very simple test program...

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>

int main(int argc, char * argv[])
{
    DIR *           hDir;
    struct dirent * pDirent;

    if (argc != 2)
    {
        printf("usage: %s <path>\n", argv[0]);
        return 1;
    }

    if ((hDir = opendir(argv[1])) == NULL)
    {
        printf("Could not open %s (%s)\n", argv[1], strerror(errno));
        return 1;
    }

    while ((pDirent = readdir(hDir)) != NULL)
    {
        printf("%s\n", pDirent->d_name);
    }

    closedir(hDir);

    return 0;
}


More information about the samba-technical mailing list