The Samba-Bugzilla – Attachment 945 Details for
Bug 2308
[patch] libsmbclient bug fixes and enhancements
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
patch to provide the specified bug fixes and enhancements
samba3-diffs (text/plain), 90.13 KB, created by
Derrell Lipman
on 2005-02-04 12:16:21 UTC
(
hide
)
Description:
patch to provide the specified bug fixes and enhancements
Filename:
MIME Type:
Creator:
Derrell Lipman
Created:
2005-02-04 12:16:21 UTC
Size:
90.13 KB
patch
obsolete
>Index: libsmb/clientgen.c >=================================================================== >--- libsmb/clientgen.c (revision 4510) >+++ libsmb/clientgen.c (working copy) >@@ -279,6 +279,7 @@ > cli->inbuf = (char *)SMB_MALLOC(cli->bufsize+SAFETY_MARGIN); > cli->oplock_handler = cli_oplock_ack; > cli->case_sensitive = False; >+ cli->smb_rw_error = 0; > > cli->use_spnego = lp_client_use_spnego(); > >Index: libsmb/clisecdesc.c >=================================================================== >--- libsmb/clisecdesc.c (revision 4510) >+++ libsmb/clisecdesc.c (working copy) >@@ -30,6 +30,7 @@ > char *rparam=NULL, *rdata=NULL; > unsigned int rparam_count=0, rdata_count=0; > prs_struct pd; >+ int pd_initialized = False; > SEC_DESC *psd = NULL; > > SIVAL(param, 0, fnum); >@@ -57,6 +58,7 @@ > goto cleanup; > > prs_init(&pd, rdata_count, mem_ctx, UNMARSHALL); >+ pd_initialized = True; > prs_copy_data_in(&pd, rdata, rdata_count); > prs_set_offset(&pd,0); > >@@ -70,7 +72,9 @@ > SAFE_FREE(rparam); > SAFE_FREE(rdata); > >- prs_mem_free(&pd); >+ if (pd_initialized) { >+ prs_mem_free(&pd); >+ } > return psd; > } > >Index: libsmb/clilist.c >=================================================================== >--- libsmb/clilist.c (revision 4510) >+++ libsmb/clilist.c (working copy) >@@ -148,8 +148,13 @@ > #if 0 > int max_matches = 1366; /* Match W2k - was 512. */ > #else >+#if 0 /* djl */ > int max_matches = 512; >+#else >+ /* Sigh. XP Home misses files (sporadically!) if this is larger. */ >+ int max_matches = 24; > #endif >+#endif > int info_level; > char *p, *p2; > pstring mask; >@@ -196,7 +201,11 @@ > SSVAL(param,0,ff_dir_handle); > SSVAL(param,2,max_matches); /* max count */ > SSVAL(param,4,info_level); >+#if 0 /* djl */ > SIVAL(param,6,0); /* ff_resume_key */ >+#else >+ SIVAL(param,6,ff_lastname); /* ff_resume_key */ >+#endif > SSVAL(param,10,8+4+2); /* continue + resume required + close on end */ > p = param+12; > p += clistr_push(cli, param+12, mask, sizeof(param)-12, >Index: libsmb/libsmbclient.c >=================================================================== >--- libsmb/libsmbclient.c (revision 4510) >+++ libsmb/libsmbclient.c (working copy) >@@ -5,7 +5,7 @@ > Copyright (C) Richard Sharpe 2000, 2002 > Copyright (C) John Terpstra 2000 > Copyright (C) Tom Jansen (Ninja ISD) 2002 >- Copyright (C) Derrell Lipman 2003 >+ Copyright (C) Derrell Lipman 2003, 2004 > > This program is free software; you can redistribute it and/or modify > it under the terms of the GNU General Public License as published by >@@ -26,7 +26,22 @@ > > #include "include/libsmb_internal.h" > >+ > /* >+ * DOS Attribute values (used internally) >+ */ >+typedef struct DOS_ATTR_DESC >+{ >+ int mode; >+ unsigned long long size; >+ time_t a_time; >+ time_t c_time; >+ time_t m_time; >+ unsigned long long inode; >+} DOS_ATTR_DESC; >+ >+ >+/* > * Internal flags for extended attributes > */ > >@@ -84,84 +99,113 @@ > return -1; > } > >-static void >-decode_urlpart(char *segment, size_t sizeof_segment) >+/* >+ * smbc_urldecode() >+ * >+ * Convert strings of %xx to their single character equivalent. Each 'x' must >+ * be a valid hexadecimal digit, or that % sequence is left undecoded. >+ * >+ * dest may, but need not be, the same pointer as src. >+ * >+ * Returns the number of % sequences which could not be converted due to lack >+ * of two following hexadecimal digits. >+ */ >+int >+smbc_urldecode(char *dest, char * src, size_t max_dest_len) > { >- int old_length = strlen(segment); >- int new_length = 0; >- int new_length2 = 0; >- int i = 0; >- pstring new_segment; >- char *new_usegment = 0; >+ int old_length = strlen(src); >+ int new_length = 0; >+ int new_length2 = 0; >+ int i = 0; >+ int err_count = 0; >+ pstring temp; >+ char * p; > >- if ( !old_length ) { >- return; >- } >+ if ( old_length == 0 ) { >+ return 0; >+ } > >- /* make a copy of the old one */ >- new_usegment = (char*)SMB_MALLOC( old_length * 3 + 1 ); >+ p = temp; >+ while ( i < old_length ) { >+ unsigned char character = src[ i++ ]; > >- while( i < old_length ) { >- int bReencode = False; >- unsigned char character = segment[ i++ ]; >- if ((character <= ' ') || (character > 127)) >- bReencode = True; >+ if (character == '%') { >+ int a = i+1 < old_length ? hex2int( src[i] ) : -1; >+ int b = i+1 < old_length ? hex2int( src[i+1] ) : -1; > >- new_usegment [ new_length2++ ] = character; >- if (character == '%' ) { >- int a = i+1 < old_length ? hex2int( segment[i] ) : -1; >- int b = i+1 < old_length ? hex2int( segment[i+1] ) : -1; >- if ((a == -1) || (b == -1)) { /* Only replace if sequence is valid */ >- /* Contains stray %, make sure to re-encode! */ >- bReencode = True; >- } else { >- /* Valid %xx sequence */ >- character = a * 16 + b; /* Replace with value of %dd */ >- if (!character) >- break; /* Stop at %00 */ >+ /* Replace valid sequence */ >+ if (a != -1 && b != -1) { > >- new_usegment [ new_length2++ ] = (unsigned char) segment[i++]; >- new_usegment [ new_length2++ ] = (unsigned char) segment[i++]; >- } >- } >- if (bReencode) { >- unsigned int c = character / 16; >- new_length2--; >- new_usegment [ new_length2++ ] = '%'; >+ /* Replace valid %xx sequence with %dd */ >+ character = (a * 16) + b; > >- c += (c > 9) ? ('A' - 10) : '0'; >- new_usegment[ new_length2++ ] = c; >+ if (character == '\0') { >+ break; /* Stop at %00 */ >+ } > >- c = character % 16; >- c += (c > 9) ? ('A' - 10) : '0'; >- new_usegment[ new_length2++ ] = c; >- } >+ i += 2; >+ } else { > >- new_segment [ new_length++ ] = character; >- } >- new_segment [ new_length ] = 0; >+ err_count++; >+ } >+ } > >- free(new_usegment); >+ *p++ = character; >+ } > >- /* realloc it with unix charset */ >- pull_utf8_allocate(&new_usegment, new_segment); >+ *p = '\0'; > >- /* this assumes (very safely) that removing %aa sequences >- only shortens the string */ >- strncpy(segment, new_usegment, sizeof_segment); >+ strncpy(dest, temp, max_dest_len); > >- free(new_usegment); >+ return err_count; > } > > /* >+ * smbc_urlencode() >+ * >+ * Convert any characters not specifically allowed in a URL into their %xx >+ * equivalent. >+ * >+ * Returns the remaining buffer length. >+ */ >+int >+smbc_urlencode(char * dest, char * src, int max_dest_len) >+{ >+ char hex[] = "0123456789ABCDEF"; >+ >+ for (; *src != '\0' && max_dest_len >= 3; src++) { >+ >+ if ((*src < '0' && >+ *src != '-' && >+ *src != '.') || >+ (*src > '9' && >+ *src < 'A') || >+ (*src > 'Z' && >+ *src < 'a' && >+ *src != '_') || >+ (*src > 'z')) { >+ *dest++ = '%'; >+ *dest++ = hex[(*src >> 4) & 0x0f]; >+ *dest++ = hex[*src & 0x0f]; >+ max_dest_len -= 3; >+ } else { >+ *dest++ = *src; >+ max_dest_len--; >+ } >+ } >+ >+ *dest++ = '\0'; >+ max_dest_len--; >+ >+ return max_dest_len; >+} >+ >+/* > * Function to parse a path and turn it into components > * > * The general format of an SMB URI is explain in Christopher Hertel's CIFS > * book, at http://ubiqx.org/cifs/Appendix-D.html. We accept a subset of the >- * general format ("smb:" only; we do not look for "cifs:"), and expand on >- * what he calls "context", herein called "options" to avoid conflict with the >- * SMBCCTX context used throughout this library. We add the "mb" keyword >- * which applies as follows: >+ * general format ("smb:" only; we do not look for "cifs:"). > * > * > * We accept: >@@ -169,37 +213,28 @@ > * > * Meaning of URLs: > * >- * smb:// show all workgroups known by the first master browser found >- * smb://?mb=.any same as smb:// (i.e. without any options) >+ * smb:// Show all workgroups. > * >- * smb://?mb=.all show all workgroups known by every master browser found. >- * Why might you want this? In an "appliance" application >- * where the workgroup/domain being used on the local network >- * is not known ahead of time, but where one wanted to >- * provide network services via samba, a unique workgroup >- * could be used. However, when the appliance is first >- * started, the local samba instance's master browser has not >- * synchronized with the other master browser(s) on the >- * network (and might not synchronize for 12 minutes) and >- * therefore is not aware of the workgroup/ domain names >- * available on the network. This option may be used to >- * overcome the problem of a libsmbclient application >- * arbitrarily selecting the local (still ignorant) master >- * browser to obtain its list of workgroups/domains and >- * getting back a practically emmpty list. By requesting >- * the list of workgroups/domains from each found master >- * browser on the local network, a complete list of >- * workgroups/domains can be built. >+ * The method of locating the list of workgroups varies >+ * depending upon the setting of the context variable >+ * context->options.browse_max_lmb_count. This value >+ * determine the maximum number of local master browsers to >+ * query for the list of workgroups. In order to ensure that >+ * a complete list of workgroups is obtained, all master >+ * browsers must be queried, but if there are many >+ * workgroups, the time spent querying can begin to add up. >+ * For small networks (not many workgroups), it is suggested >+ * that this variable be set to 0, indicating query all local >+ * master browsers. When the network has many workgroups, a >+ * reasonable setting for this variable might be around 3. > * >- * smb://?mb=name NOT YET IMPLEMENTED -- show all workgroups known by the >- * master browser whose name is "name" >- * > * smb://name/ if name<1D> or name<1B> exists, list servers in > * workgroup, else, if name<20> exists, list all shares > * for server ... > * >- * If "options" are provided, this function returns the entire option list as >- * a string, for later parsing by the caller. >+ * If "options" are provided, this function returns the entire option list as a >+ * string, for later parsing by the caller. Note that currently, no options >+ * are supported. > */ > > static const char *smbc_prefix = "smb:"; >@@ -246,7 +281,7 @@ > p += 2; /* Skip the double slash */ > > /* See if any options were specified */ >- if ( (q = strrchr(p, '?')) != NULL ) { >+ if (q = strrchr(p, '?')) { > /* There are options. Null terminate here and point to them */ > *q++ = '\0'; > >@@ -333,11 +368,11 @@ > all_string_sub(path, "/", "\\", 0); > > decoding: >- decode_urlpart(path, path_len); >- decode_urlpart(server, server_len); >- decode_urlpart(share, share_len); >- decode_urlpart(user, user_len); >- decode_urlpart(password, password_len); >+ (void) smbc_urldecode(path, path, path_len); >+ (void) smbc_urldecode(server, server, server_len); >+ (void) smbc_urldecode(share, share, share_len); >+ (void) smbc_urldecode(user, user, user_len); >+ (void) smbc_urldecode(password, password, password_len); > > return 0; > } >@@ -352,28 +387,8 @@ > /* No options at all is always ok */ > if (! *options) return 0; > >- /* >- * For right now, we only support a very few options possibilities. >- * No options are supported if server, share, or path are not empty. >- * If all are empty, then we support the following two choices right >- * now: >- * >- * mb=.any >- * mb=.all >- */ >- if ((*server || *share || *path) && *options) { >- /* Invalid: options provided with server, share, or path */ >- DEBUG(1, ("Found unsupported options (%s) with non-empty server, share, or path\n", options)); >- return -1; >- } >- >- if (strcmp(options, "mb=.any") != 0 && >- strcmp(options, "mb=.all") != 0) { >- DEBUG(1, ("Found unsupported options (%s)\n", options)); >- return -1; >- } >- >- return 0; >+ /* Currently, we don't support any options. */ >+ return -1; > } > > /* >@@ -452,8 +467,6 @@ > > context->callbacks.remove_cached_srv_fn(context, srv); > >- SAFE_FREE(srv); >- > return 0; > } > >@@ -471,7 +484,7 @@ > > srv = context->callbacks.get_cached_srv_fn(context, server, share, > workgroup, username); >- >+ > if (!auth_called && !srv && (!username[0] || !password[0])) { > context->callbacks.auth_fn(server, share, > workgroup, sizeof(fstring), >@@ -512,6 +525,7 @@ > */ > goto check_server_cache; > } >+ > return srv; > } > >@@ -537,10 +551,14 @@ > SMBCSRV *srv=NULL; > struct cli_state c; > struct nmb_name called, calling; >+ char *p; > const char *server_n = server; >+ fstring group; > pstring ipenv; > struct in_addr ip; > int tried_reverse = 0; >+ int port_try_first; >+ int port_try_next; > > zero_ip(&ip); > ZERO_STRUCT(c); >@@ -552,25 +570,56 @@ > > srv = find_server(context, server, share, > workgroup, username, password); >- if (srv) >+ >+ /* >+ * If we found a connection and we're only allowed one share per >+ * server... >+ */ >+ if (srv && *share != '\0' && context->options.one_share_per_server) { >+ >+ /* >+ * ... then if there's no current connection to the share, >+ * connect to it. find_server(), or rather the function >+ * pointed to by context->callbacks.get_cached_srv_fn which >+ * was called by find_server(), will have issued a tree >+ * disconnect if the requested share is not the same as the >+ * one that was already connected. >+ */ >+ if (srv->cli.cnum == (uint16) -1) { >+ /* Ensure we have accurate auth info */ >+ context->callbacks.auth_fn(server, share, >+ workgroup, sizeof(fstring), >+ username, sizeof(fstring), >+ password, sizeof(fstring)); >+ >+ if (! cli_send_tconX(&srv->cli, share, "?????", >+ password, strlen(password)+1)) { >+ >+ errno = smbc_errno(context, &srv->cli); >+ cli_shutdown(&srv->cli); >+ context->callbacks.remove_cached_srv_fn(context, srv); >+ srv = NULL; >+ } >+ >+ /* Regenerate the dev value since it's based on both server and share */ >+ if (srv) { >+ srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); >+ } >+ } >+ } >+ >+ /* If we have a connection... */ >+ if (srv) { >+ >+ /* ... then we're done here. Give 'em what they came for. */ > return srv; >+ } > > make_nmb_name(&calling, context->netbios_name, 0x0); > make_nmb_name(&called , server, 0x20); > > DEBUG(4,("smbc_server: server_n=[%s] server=[%s]\n", server_n, server)); > >-#if 0 /* djl: obsolete code? neither group nor p is used beyond here */ >- if ((p=strchr_m(server_n,'#')) && >- (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) { >- >- fstrcpy(group, server_n); >- p = strchr_m(group,'#'); >- *p = 0; >- >- } >-#endif >- > DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); > > again: >@@ -586,18 +635,31 @@ > > c.timeout = context->timeout; > >- /* Force use of port 139 for first try, so browse lists can work */ >- c.port = 139; >+ /* >+ * Force use of port 139 for first try if share is $IPC, empty, or >+ * null, so browse lists can work >+ */ >+ if (share == NULL || *share == '\0' || strcmp(share, "IPC$") == 0) >+ { >+ port_try_first = 139; >+ port_try_next = 445; >+ } >+ else >+ { >+ port_try_first = 445; >+ port_try_next = 139; >+ } > >+ c.port = port_try_first; >+ > if (!cli_connect(&c, server_n, &ip)) { >- /* >- * Port 139 connection failed. Try port 445 to handle >- * connections to newer (e.g. XP) hosts with NetBIOS disabled. >- */ >- c.port = 445; >+ >+ /* First connection attempt failed. Try alternate port. */ >+ c.port = port_try_next; >+ > if (!cli_connect(&c, server_n, &ip)) { >- cli_shutdown(&c); >- errno = ENETUNREACH; >+ cli_shutdown(&c); >+ errno = ETIMEDOUT; > return NULL; > } > } >@@ -618,7 +680,7 @@ > > if ((rem_ip.s_addr=inet_addr(server)) == INADDR_NONE) { > DEBUG(4, ("Could not convert IP address %s to struct in_addr\n", server)); >- errno = ENOENT; >+ errno = ETIMEDOUT; > return NULL; > } > >@@ -632,7 +694,7 @@ > > } > } >- errno = ENOENT; >+ errno = ETIMEDOUT; > return NULL; > } > >@@ -640,7 +702,7 @@ > > if (!cli_negprot(&c)) { > cli_shutdown(&c); >- errno = ENOENT; >+ errno = ETIMEDOUT; > return NULL; > } > >@@ -724,10 +786,11 @@ > SMBCSRV *ipc_srv=NULL; > > /* >- * See if we've already created this special connection. Reference >- * our "special" share name 'IPC$$'. >+ * See if we've already created this special connection. Reference our >+ * "special" share name '*IPC$', which is an impossible real share name >+ * due to the leading asterisk. > */ >- ipc_srv = find_server(context, server, "IPC$$", >+ ipc_srv = find_server(context, server, "*IPC$", > workgroup, username, password); > if (!ipc_srv) { > >@@ -793,7 +856,7 @@ > errno = 0; /* let cache function set errno if it likes */ > if (context->callbacks.add_cached_srv_fn(context, ipc_srv, > server, >- "IPC$$", >+ "*IPC$", > workgroup, > username)) { > DEBUG(3, (" Failed to add server to cache\n")); >@@ -1613,21 +1676,15 @@ > { > struct smbc_dirent *dirent; > int size; >- char *u_name = NULL, *u_comment = NULL; >- size_t u_name_len = 0, u_comment_len = 0; >+ int name_len = (name == NULL ? 0 : strlen(name)); >+ int comment_len = (comment == NULL ? 0 : strlen(comment)); > >- if (name) >- u_name_len = push_utf8_allocate(&u_name, name); >- if (comment) >- u_comment_len = push_utf8_allocate(&u_comment, comment); >- > /* > * Allocate space for the dirent, which must be increased by the >- * size of the name and the comment and 1 for the null on the comment. >- * The null on the name is already accounted for. >+ * size of the name and the comment and 1 each for the null terminator. > */ > >- size = sizeof(struct smbc_dirent) + u_name_len + u_comment_len + 1; >+ size = sizeof(struct smbc_dirent) + name_len + comment_len + 2; > > dirent = SMB_MALLOC(size); > >@@ -1674,18 +1731,15 @@ > dir->dir_end->dirent = dirent; > > dirent->smbc_type = type; >- dirent->namelen = u_name_len; >- dirent->commentlen = u_comment_len; >+ dirent->namelen = name_len; >+ dirent->commentlen = comment_len; > dirent->dirlen = size; > >- strncpy(dirent->name, (u_name?u_name:""), dirent->namelen + 1); >+ strncpy(dirent->name, (name?name:""), dirent->namelen + 1); > > dirent->comment = (char *)(&dirent->name + dirent->namelen + 1); >- strncpy(dirent->comment, (u_comment?u_comment:""), dirent->commentlen + 1); >+ strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1); > >- SAFE_FREE(u_comment); >- SAFE_FREE(u_name); >- > return 0; > > } >@@ -1799,14 +1853,14 @@ > if (!context || !context->internal || > !context->internal->_initialized) { > DEBUG(4, ("no valid context\n")); >- errno = EINVAL; >+ errno = EINVAL + 8192; > return NULL; > > } > > if (!fname) { > DEBUG(4, ("no valid fname\n")); >- errno = EINVAL; >+ errno = EINVAL + 8193; > return NULL; > } > >@@ -1818,7 +1872,7 @@ > password, sizeof(password), > options, sizeof(options))) { > DEBUG(4, ("no valid path\n")); >- errno = EINVAL; >+ errno = EINVAL + 8194; > return NULL; > } > >@@ -1827,7 +1881,7 @@ > /* Ensure the options are valid */ > if (smbc_check_options(server, share, path, options)) { > DEBUG(4, ("unacceptable options (%s)\n", options)); >- errno = EINVAL; >+ errno = EINVAL + 8195; > return NULL; > } > >@@ -1853,108 +1907,11 @@ > dir->file = False; > dir->dir_list = dir->dir_next = dir->dir_end = NULL; > >- if (server[0] == (char)0 && >- (! *options || strcmp(options, "mb=.any") == 0)) { >- struct in_addr server_ip; >- if (share[0] != (char)0 || path[0] != (char)0) { >+ if (server[0] == (char)0) { > >- errno = EINVAL; >- if (dir) { >- SAFE_FREE(dir->fname); >- SAFE_FREE(dir); >- } >- return NULL; >- } >- >- /* >- * We have server and share and path empty ... so list the >- * workgroups first try to get the LMB for our workgroup, and >- * if that fails, try the DMB >- */ >- >- pstrcpy(workgroup, lp_workgroup()); >- >- if (!find_master_ip(workgroup, &server_ip)) { >- struct user_auth_info u_info; >- struct cli_state *cli; >- >- DEBUG(4, ("Unable to find master browser for workgroup %s\n", >- workgroup)); >- >- /* find the name of the server ... */ >- pstrcpy(u_info.username, user); >- pstrcpy(u_info.password, password); >- >- if (!(cli = get_ipc_connect_master_ip_bcast(workgroup, &u_info))) { >- DEBUG(4, ("Unable to find master browser by " >- "broadcast\n")); >- errno = ENOENT; >- return NULL; >- } >- >- fstrcpy(server, cli->desthost); >- >- cli_shutdown(cli); >- } else { >- /* >- * Do a name status query to find out the name of the >- * master browser. We use <01><02>__MSBROWSE__<02>#01 if >- * *#00 fails because a domain master browser will not >- * respond to a wildcard query (or, at least, an NT4 >- * server acting as the domain master browser will not). >- * >- * We might be able to use ONLY the query on MSBROWSE, but >- * that's not yet been tested with all Windows versions, >- * so until it is, leave the original wildcard query as >- * the first choice and fall back to MSBROWSE if the >- * wildcard query fails. >- */ >- if (!name_status_find("*", 0, 0x20, server_ip, server) && >- !name_status_find(MSBROWSE, 1, 0x1b, server_ip, server)) { >- errno = ENOENT; >- return NULL; >- } >- } >- >- DEBUG(4, ("using workgroup %s %s\n", workgroup, server)); >- >- /* >- * Get a connection to IPC$ on the server if we do not already >- * have one >- */ >- >- srv = smbc_server(context, server, "IPC$", workgroup, user, password); >- if (!srv) { >- >- if (dir) { >- SAFE_FREE(dir->fname); >- SAFE_FREE(dir); >- } >- return NULL; >- } >- >- dir->srv = srv; >- dir->dir_type = SMBC_WORKGROUP; >- >- /* Now, list the stuff ... */ >- >- if (!cli_NetServerEnum(&srv->cli, workgroup, SV_TYPE_DOMAIN_ENUM, list_fn, >- (void *)dir)) { >- >- DEBUG(1, ("Could not enumerate domains using '%s'\n", workgroup)); >- if (dir) { >- SAFE_FREE(dir->fname); >- SAFE_FREE(dir); >- } >- >- return NULL; >- >- } >- } else if (server[0] == (char)0 && >- (! *options || strcmp(options, "mb=.all") == 0)) { >- > int i; > int count; >+ int max_lmb_count; > struct ip_service *ip_list; > struct ip_service server_addr; > struct user_auth_info u_info; >@@ -1962,7 +1919,7 @@ > > if (share[0] != (char)0 || path[0] != (char)0) { > >- errno = EINVAL; >+ errno = EINVAL + 8196; > if (dir) { > SAFE_FREE(dir->fname); > SAFE_FREE(dir); >@@ -1970,6 +1927,11 @@ > return NULL; > } > >+ /* Determine how many local master browsers to query */ >+ max_lmb_count = (context->options.browse_max_lmb_count == 0 >+ ? INT_MAX >+ : context->options.browse_max_lmb_count); >+ > pstrcpy(u_info.username, user); > pstrcpy(u_info.password, password); > >@@ -1993,11 +1955,10 @@ > count = 1; > } > >- for (i = 0; i < count; i++) { >+ for (i = 0; i < count && i < max_lmb_count; i++) { > DEBUG(99, ("Found master browser %s\n", inet_ntoa(ip_list[i].ip))); > > cli = get_ipc_connect_master_ip(&ip_list[i], workgroup, &u_info); >- > /* cli == NULL is the master browser refused to talk or > could not be found */ > if ( !cli ) >@@ -2052,7 +2013,7 @@ > > if (path[0] != (char)0) { /* Should not have empty share with path */ > >- errno = EINVAL; >+ errno = EINVAL + 8197; > if (dir) { > SAFE_FREE(dir->fname); > SAFE_FREE(dir); >@@ -2246,12 +2207,54 @@ > > } > >+static void smbc_readdir_internal(SMBCCTX * context, >+ struct smbc_dirent *dest, >+ struct smbc_dirent *src, >+ int max_namebuf_len) >+{ >+ if (context->options.urlencode_readdir_entries) { >+ >+ /* url-encode the name. get back remaining buffer space */ >+ max_namebuf_len = >+ smbc_urlencode(dest->name, src->name, max_namebuf_len); >+ >+ /* We now know the name length */ >+ dest->namelen = strlen(dest->name); >+ >+ /* Save the pointer to the beginning of the comment */ >+ dest->comment = dest->name + dest->namelen + 1; >+ >+ /* Copy the comment */ >+ strncpy(dest->comment, src->comment, max_namebuf_len); >+ >+ /* Ensure the comment is null terminated */ >+ if (max_namebuf_len > src->commentlen) { >+ dest->comment[src->commentlen] = '\0'; >+ } else { >+ dest->comment[max_namebuf_len - 1] = '\0'; >+ } >+ >+ /* Save other fields */ >+ dest->smbc_type = src->smbc_type; >+ dest->commentlen = strlen(dest->comment); >+ dest->dirlen = ((dest->comment + dest->commentlen + 1) - >+ (char *) dest); >+ } else { >+ >+ /* No encoding. Just copy the entry as is. */ >+ memcpy(dest, src, src->dirlen); >+ dest->comment = (char *)(&dest->name + src->namelen + 1); >+ } >+ >+} >+ > /* > * Routine to get a directory entry > */ > > struct smbc_dirent *smbc_readdir_ctx(SMBCCTX *context, SMBCFILE *dir) > { >+ int maxlen; > struct smbc_dirent *dirp, *dirent; > > /* Check that all is ok first ... */ >@@ -2284,37 +2287,40 @@ > if (!dir->dir_next) { > return NULL; > } >- else { > >- dirent = dir->dir_next->dirent; >- if (!dirent) { >+ dirent = dir->dir_next->dirent; >+ if (!dirent) { > >- errno = ENOENT; >- return NULL; >+ errno = ENOENT; >+ return NULL; > >- } >+ } > >- /* Hmmm, do I even need to copy it? */ >+ dirp = (struct smbc_dirent *)context->internal->_dirent; >+ maxlen = (sizeof(context->internal->_dirent) - >+ sizeof(struct smbc_dirent)); > >- memcpy(context->internal->_dirent, dirent, dirent->dirlen); /* Copy the dirent */ >- dirp = (struct smbc_dirent *)context->internal->_dirent; >- dirp->comment = (char *)(&dirp->name + dirent->namelen + 1); >- dir->dir_next = dir->dir_next->next; >+ smbc_readdir_internal(context, dirp, dirent, maxlen); > >- return (struct smbc_dirent *)context->internal->_dirent; >- } >+ dir->dir_next = dir->dir_next->next; > >+ return dirp; > } > > /* > * Routine to get directory entries > */ > >-static int smbc_getdents_ctx(SMBCCTX *context, SMBCFILE *dir, struct smbc_dirent *dirp, int count) >+static int smbc_getdents_ctx(SMBCCTX *context, >+ SMBCFILE *dir, >+ struct smbc_dirent *dirp, >+ int count) > { >+ int rem = count; >+ int reqd; >+ int maxlen; >+ char *ndir = (char *)dirp; > struct smbc_dir_list *dirlist; >- int rem = count, reqd; >- char *ndir = (char *)dirp; > > /* Check that all is ok first ... */ > >@@ -2356,9 +2362,16 @@ > > } > >- if (rem < (reqd = (sizeof(struct smbc_dirent) + dirlist->dirent->namelen + >- dirlist->dirent->commentlen + 1))) { >+ /* Do urlencoding of next entry, if so selected */ >+ dirent = (struct smbc_dirent *)context->internal->_dirent; >+ maxlen = (sizeof(context->internal->_dirent) - >+ sizeof(struct smbc_dirent)); >+ smbc_readdir_internal(context, dirent, dirlist->dirent, maxlen); > >+ reqd = dirent->dirlen; >+ >+ if (rem < reqd) { >+ > if (rem < count) { /* We managed to copy something */ > > errno = 0; >@@ -2374,12 +2387,12 @@ > > } > >- dirent = dirlist->dirent; >- > memcpy(ndir, dirent, reqd); /* Copy the data in ... */ > > ((struct smbc_dirent *)ndir)->comment = >- (char *)(&((struct smbc_dirent *)ndir)->name + dirent->namelen + 1); >+ (char *)(&((struct smbc_dirent *)ndir)->name + >+ dirent->namelen + >+ 1); > > ndir += reqd; > >@@ -2445,27 +2458,6 @@ > > } > >- /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) { >- >- mode = aDIR | aRONLY; >- >- } >- else if (strncmp(srv->cli.dev, "LPT", 3) == 0) { >- >- if (strcmp(path, "\\") == 0) { >- >- mode = aDIR | aRONLY; >- >- } >- else { >- >- mode = aRONLY; >- smbc_stat_printjob(srv, path, &size, &m_time); >- c_time = a_time = m_time; >- >- } >- else { */ >- > if (!cli_mkdir(&srv->cli, path)) { > > errno = smbc_errno(context, &srv->cli); >@@ -3230,10 +3222,93 @@ > } > > >+/* Obtain the current dos attributes */ >+static DOS_ATTR_DESC *dos_attr_query(SMBCCTX *context, >+ TALLOC_CTX *ctx, >+ const char *filename, >+ SMBCSRV *srv) >+{ >+ time_t m_time = 0, a_time = 0, c_time = 0; >+ size_t size = 0; >+ uint16 mode = 0; >+ SMB_INO_T inode = 0; >+ DOS_ATTR_DESC *ret; >+ >+ ret = talloc(ctx, sizeof(DOS_ATTR_DESC)); >+ if (!ret) { >+ errno = ENOMEM; >+ return NULL; >+ } >+ >+ /* Obtain the DOS attributes */ >+ if (!smbc_getatr(context, srv, (char *) filename, &mode, &size, >+ &c_time, &a_time, &m_time, &inode)) { >+ >+ errno = smbc_errno(context, &srv->cli); >+ DEBUG(5, ("dos_attr_query Failed to query old attributes\n")); >+ return NULL; >+ >+ } >+ >+ ret->mode = mode; >+ ret->size = size; >+ ret->a_time = a_time; >+ ret->c_time = c_time; >+ ret->m_time = m_time; >+ ret->inode = inode; >+ >+ return ret; >+} >+ >+ >+/* parse a ascii version of a security descriptor */ >+static void dos_attr_parse(SMBCCTX *context, >+ DOS_ATTR_DESC *dad, >+ SMBCSRV *srv, >+ char *str) >+{ >+ const char *p = str; >+ fstring tok; >+ >+ while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) { >+ >+ if (StrnCaseCmp(tok, "MODE:", 5) == 0) { >+ dad->mode = strtol(tok+5, NULL, 16); >+ continue; >+ } >+ >+ if (StrnCaseCmp(tok, "SIZE:", 5) == 0) { >+ dad->size = strtoll(tok+5, NULL, 10); >+ continue; >+ } >+ >+ if (StrnCaseCmp(tok, "A_TIME:", 7) == 0) { >+ dad->a_time = strtoll(tok+7, NULL, 10); >+ continue; >+ } >+ >+ if (StrnCaseCmp(tok, "C_TIME:", 7) == 0) { >+ dad->c_time = strtoll(tok+7, NULL, 10); >+ continue; >+ } >+ >+ if (StrnCaseCmp(tok, "M_TIME:", 7) == 0) { >+ dad->m_time = strtoll(tok+7, NULL, 10); >+ continue; >+ } >+ >+ if (StrnCaseCmp(tok, "INODE:", 6) == 0) { >+ dad->inode = strtoll(tok+6, NULL, 10); >+ continue; >+ } >+ } >+} >+ >+ > /***************************************************** > retrieve the acls for a file > *******************************************************/ >-static int cacl_get(TALLOC_CTX *ctx, struct cli_state *cli, >+static int cacl_get(SMBCCTX *context, TALLOC_CTX *ctx, SMBCSRV *srv, > struct cli_state *ipc_cli, POLICY_HND *pol, > char *filename, char *name, char *buf, int bufsize) > { >@@ -3241,166 +3316,446 @@ > int n = 0; > int n_used; > BOOL all; >+ BOOL all_nt; >+ BOOL all_dos; >+ BOOL some_nt; >+ BOOL some_dos; > BOOL numeric = True; > BOOL determine_size = (bufsize == 0); > int fnum = -1; > SEC_DESC *sd; > fstring sidstr; > char *p; >+ time_t m_time = 0, a_time = 0, c_time = 0; >+ size_t size = 0; >+ uint16 mode = 0; >+ SMB_INO_T ino = 0; >+ struct cli_state *cli = &srv->cli; > >- fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ); >+ all = (StrnCaseCmp(name, "system.*", 8) == 0); >+ all_nt = (StrnCaseCmp(name, "system.nt_sec_desc.*", 20) == 0); >+ all_dos = (StrnCaseCmp(name, "system.dos_attr.*", 17) == 0); >+ some_nt = (StrnCaseCmp(name, "system.nt_sec_desc.", 19) == 0); >+ some_dos = (StrnCaseCmp(name, "system.dos_attr.", 16) == 0); >+ numeric = (* (name + strlen(name) - 1) != '+'); > >- if (fnum == -1) { >- DEBUG(5, ("cacl_get failed to open %s: %s\n", >- filename, cli_errstr(cli))); >- errno = 0; >- return -1; >- } >+ n_used = 0; > >- sd = cli_query_secdesc(cli, fnum, ctx); >+ /* >+ * If we are (possibly) talking to an NT or new system and some NT >+ * attributes have been requested... >+ */ >+ if (ipc_cli && (all || some_nt)) { >+ /* Point to the portion after "system.nt_sec_desc." */ >+ name += 19; /* if (all) this will be invalid but unused */ > >- if (!sd) { >- DEBUG(5, ("cacl_get Failed to query old descriptor\n")); >- errno = 0; >- return -1; >- } >+ /* ... then obtain any NT attributes which were requested */ >+ fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ); > >- cli_close(cli, fnum); >+ if (fnum == -1) { >+ DEBUG(5, ("cacl_get failed to open %s: %s\n", >+ filename, cli_errstr(cli))); >+ errno = 0; >+ return -1; >+ } > >- all = (*name == '*'); >- numeric = (* (name + strlen(name) - 1) != '+'); >+ sd = cli_query_secdesc(cli, fnum, ctx); > >- n_used = 0; >+ if (!sd) { >+ DEBUG(5, >+ ("cacl_get Failed to query old descriptor\n")); >+ errno = 0; >+ return -1; >+ } > >- if (all) { >- if (determine_size) { >- p = talloc_asprintf(ctx, >- "REVISION:%d", sd->revision); >- if (!p) { >- errno = ENOMEM; >- return -1; >+ cli_close(cli, fnum); >+ >+ if (all || all_nt) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, >+ "REVISION:%d", >+ sd->revision); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, >+ "REVISION:%d", sd->revision); > } >- n = strlen(p); >+ } else if (StrCaseCmp(name, "revision") == 0) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, "%d", sd->revision); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, "%d", sd->revision); >+ } >+ } >+ >+ if (!determine_size && n > bufsize) { >+ errno = ERANGE; >+ return -1; >+ } >+ buf += n; >+ n_used += n; >+ bufsize -= n; >+ >+ /* Get owner and group sid */ >+ >+ if (sd->owner_sid) { >+ convert_sid_to_string(ipc_cli, pol, >+ sidstr, numeric, sd->owner_sid); > } else { >- n = snprintf(buf, bufsize, >- "REVISION:%d", sd->revision); >+ fstrcpy(sidstr, ""); > } >- } else if (StrCaseCmp(name, "revision") == 0) { >- if (determine_size) { >- p = talloc_asprintf(ctx, "%d", sd->revision); >- if (!p) { >- errno = ENOMEM; >- return -1; >+ >+ if (all || all_nt) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, ",OWNER:%s", sidstr); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, >+ ",OWNER:%s", sidstr); > } >- n = strlen(p); >+ } else if (StrnCaseCmp(name, "owner", 5) == 0) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, "%s", sidstr); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, "%s", sidstr); >+ } >+ } >+ >+ if (!determine_size && n > bufsize) { >+ errno = ERANGE; >+ return -1; >+ } >+ buf += n; >+ n_used += n; >+ bufsize -= n; >+ >+ if (sd->grp_sid) { >+ convert_sid_to_string(ipc_cli, pol, >+ sidstr, numeric, sd->grp_sid); > } else { >- n = snprintf(buf, bufsize, "%d", sd->revision); >+ fstrcpy(sidstr, ""); > } >- } >- >- if (!determine_size && n > bufsize) { >- errno = ERANGE; >- return -1; >- } >- buf += n; >- n_used += n; >- bufsize -= n; > >- /* Get owner and group sid */ >+ if (all || all_nt) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, ",GROUP:%s", sidstr); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, >+ ",GROUP:%s", sidstr); >+ } >+ } else if (StrnCaseCmp(name, "group", 5) == 0) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, "%s", sidstr); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, "%s", sidstr); >+ } >+ } > >- if (sd->owner_sid) { >- convert_sid_to_string(ipc_cli, pol, >- sidstr, numeric, sd->owner_sid); >- } else { >- fstrcpy(sidstr, ""); >- } >+ if (!determine_size && n > bufsize) { >+ errno = ERANGE; >+ return -1; >+ } >+ buf += n; >+ n_used += n; >+ bufsize -= n; > >- if (all) { >- if (determine_size) { >- p = talloc_asprintf(ctx, ",OWNER:%s", sidstr); >- if (!p) { >- errno = ENOMEM; >- return -1; >+ /* Add aces to value buffer */ >+ for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) { >+ >+ SEC_ACE *ace = &sd->dacl->ace[i]; >+ convert_sid_to_string(ipc_cli, pol, >+ sidstr, numeric, &ace->trustee); >+ >+ if (all || all_nt) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, >+ ",ACL:" >+ "%s:%d/%d/0x%08x", >+ sidstr, >+ ace->type, >+ ace->flags, >+ ace->info.mask); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, >+ ",ACL:%s:%d/%d/0x%08x", >+ sidstr, >+ ace->type, >+ ace->flags, >+ ace->info.mask); >+ } >+ } else if ((StrnCaseCmp(name, "acl", 3) == 0 && >+ StrCaseCmp(name + 3, sidstr) == 0) || >+ (StrnCaseCmp(name, "acl+", 4) == 0 && >+ StrCaseCmp(name + 4, sidstr) == 0)) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, >+ "%d/%d/0x%08x", >+ ace->type, >+ ace->flags, >+ ace->info.mask); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, >+ "%d/%d/0x%08x", >+ ace->type, >+ ace->flags, >+ ace->info.mask); >+ } > } >- n = strlen(p); >- } else { >- n = snprintf(buf, bufsize, ",OWNER:%s", sidstr); >- } >- } else if (StrnCaseCmp(name, "owner", 5) == 0) { >- if (determine_size) { >- p = talloc_asprintf(ctx, "%s", sidstr); >- if (!p) { >- errno = ENOMEM; >+ if (n > bufsize) { >+ errno = ERANGE; > return -1; > } >- n = strlen(p); >- } else { >- n = snprintf(buf, bufsize, "%s", sidstr); >+ buf += n; >+ n_used += n; >+ bufsize -= n; > } >- } > >- if (!determine_size && n > bufsize) { >- errno = ERANGE; >- return -1; >+ /* Restore name pointer to its original value */ >+ name -= 19; > } >- buf += n; >- n_used += n; >- bufsize -= n; > >- if (sd->grp_sid) { >- convert_sid_to_string(ipc_cli, pol, >- sidstr, numeric, sd->grp_sid); >- } else { >- fstrcpy(sidstr, ""); >- } >+ if (all || some_dos) { >+ /* Point to the portion after "system.dos_attr." */ >+ name += 16; /* if (all) this will be invalid but unused */ > >- if (all) { >- if (determine_size) { >- p = talloc_asprintf(ctx, ",GROUP:%s", sidstr); >- if (!p) { >- errno = ENOMEM; >- return -1; >+ /* Obtain the DOS attributes */ >+ if (!smbc_getatr(context, srv, filename, &mode, &size, >+ &c_time, &a_time, &m_time, &ino)) { >+ >+ errno = smbc_errno(context, &srv->cli); >+ return -1; >+ >+ } >+ >+ if (all || all_dos) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, >+ "%sMODE:0x%x", >+ (ipc_cli && >+ (all || some_nt) >+ ? "," >+ : ""), >+ mode); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, >+ "%sMODE:0x%x", >+ (ipc_cli && >+ (all || some_nt) >+ ? "," >+ : ""), >+ mode); > } >- n = strlen(p); >- } else { >- n = snprintf(buf, bufsize, ",GROUP:%s", sidstr); >+ } else if (StrCaseCmp(name, "mode") == 0) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, "0x%x", mode); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, "0x%x", mode); >+ } > } >- } else if (StrnCaseCmp(name, "group", 5) == 0) { >- if (determine_size) { >- p = talloc_asprintf(ctx, "%s", sidstr); >- if (!p) { >- errno = ENOMEM; >- return -1; >+ >+ if (!determine_size && n > bufsize) { >+ errno = ERANGE; >+ return -1; >+ } >+ buf += n; >+ n_used += n; >+ bufsize -= n; >+ >+ if (all || all_dos) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, >+ ",SIZE:%llu", >+ (unsigned long long) size); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, >+ ",SIZE:%llu", >+ (unsigned long long) size); > } >- n = strlen(p); >- } else { >- n = snprintf(buf, bufsize, "%s", sidstr); >+ } else if (StrCaseCmp(name, "size") == 0) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, >+ "%llu", >+ (unsigned long long) size); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, >+ "%llu", >+ (unsigned long long) size); >+ } > } >- } >+ >+ if (!determine_size && n > bufsize) { >+ errno = ERANGE; >+ return -1; >+ } >+ buf += n; >+ n_used += n; >+ bufsize -= n; > >- if (!determine_size && n > bufsize) { >- errno = ERANGE; >- return -1; >- } >- buf += n; >- n_used += n; >- bufsize -= n; >+ if (all || all_dos) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, >+ ",C_TIME:%lu", c_time); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, >+ ",C_TIME:%lu", c_time); >+ } >+ } else if (StrCaseCmp(name, "c_time") == 0) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, "%lu", c_time); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, "%lu", c_time); >+ } >+ } >+ >+ if (!determine_size && n > bufsize) { >+ errno = ERANGE; >+ return -1; >+ } >+ buf += n; >+ n_used += n; >+ bufsize -= n; > >- /* Add aces to value buffer */ >- for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) { >+ if (all || all_dos) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, >+ ",A_TIME:%lu", a_time); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, >+ ",A_TIME:%lu", a_time); >+ } >+ } else if (StrCaseCmp(name, "a_time") == 0) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, "%lu", a_time); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, "%lu", a_time); >+ } >+ } >+ >+ if (!determine_size && n > bufsize) { >+ errno = ERANGE; >+ return -1; >+ } >+ buf += n; >+ n_used += n; >+ bufsize -= n; > >- SEC_ACE *ace = &sd->dacl->ace[i]; >- convert_sid_to_string(ipc_cli, pol, >- sidstr, numeric, &ace->trustee); >+ if (all || all_dos) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, >+ ",M_TIME:%lu", m_time); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, >+ ",M_TIME:%lu", m_time); >+ } >+ } else if (StrCaseCmp(name, "m_time") == 0) { >+ if (determine_size) { >+ p = talloc_asprintf(ctx, "%lu", m_time); >+ if (!p) { >+ errno = ENOMEM; >+ return -1; >+ } >+ n = strlen(p); >+ } else { >+ n = snprintf(buf, bufsize, "%lu", m_time); >+ } >+ } >+ >+ if (!determine_size && n > bufsize) { >+ errno = ERANGE; >+ return -1; >+ } >+ buf += n; >+ n_used += n; >+ bufsize -= n; > >- if (all) { >+ if (all || all_dos) { > if (determine_size) { >- p = talloc_asprintf(ctx, >- ",ACL:%s:%d/%d/0x%08x", >- sidstr, >- ace->type, >- ace->flags, >- ace->info.mask); >+ p = talloc_asprintf(ctx, >+ ",INODE:%llu", >+ (unsigned long long) ino); > if (!p) { > errno = ENOMEM; > return -1; >@@ -3408,22 +3763,14 @@ > n = strlen(p); > } else { > n = snprintf(buf, bufsize, >- ",ACL:%s:%d/%d/0x%08x", >- sidstr, >- ace->type, >- ace->flags, >- ace->info.mask); >+ ",INODE:%llu", >+ (unsigned long long) ino); > } >- } else if ((StrnCaseCmp(name, "acl", 3) == 0 && >- StrCaseCmp(name + 3, sidstr) == 0) || >- (StrnCaseCmp(name, "acl+", 4) == 0 && >- StrCaseCmp(name + 4, sidstr) == 0)) { >+ } else if (StrCaseCmp(name, "inode") == 0) { > if (determine_size) { >- p = talloc_asprintf(ctx, >- "%d/%d/0x%08x", >- ace->type, >- ace->flags, >- ace->info.mask); >+ p = talloc_asprintf(ctx, >+ "%llu", >+ (unsigned long long) ino); > if (!p) { > errno = ENOMEM; > return -1; >@@ -3431,23 +3778,28 @@ > n = strlen(p); > } else { > n = snprintf(buf, bufsize, >- "%d/%d/0x%08x", >- ace->type, ace->flags, ace->info.mask); >+ "%llu", >+ (unsigned long long) ino); > } > } >- if (n > bufsize) { >+ >+ if (!determine_size && n > bufsize) { > errno = ERANGE; > return -1; > } > buf += n; > n_used += n; > bufsize -= n; >- } > >+ /* Restore name pointer to its original value */ >+ name -= 16; >+ } >+ > if (n_used == 0) { > errno = ENOATTR; > return -1; > } >+ > return n_used; > } > >@@ -3645,12 +3997,14 @@ > int flags) > { > int ret; >+ int ret2; > SMBCSRV *srv; > SMBCSRV *ipc_srv; > fstring server, share, user, password, workgroup; > pstring path; > TALLOC_CTX *ctx; > POLICY_HND pol; >+ DOS_ATTR_DESC *dad; > > if (!context || !context->internal || > !context->internal->_initialized) { >@@ -3690,11 +4044,13 @@ > return -1; /* errno set by smbc_server */ > } > >- ipc_srv = smbc_attr_server(context, server, share, >- workgroup, user, password, >- &pol); >- if (!ipc_srv) { >- return -1; >+ if (! srv->no_nt_session) { >+ ipc_srv = smbc_attr_server(context, server, share, >+ workgroup, user, password, >+ &pol); >+ srv->no_nt_session = True; >+ } else { >+ ipc_srv = NULL; > } > > ctx = talloc_init("smbc_setxattr"); >@@ -3704,6 +4060,71 @@ > } > > /* >+ * Are they asking to set the entire set of known attributes? >+ */ >+ if (StrCaseCmp(name, "system.*") == 0 || >+ StrCaseCmp(name, "system.*+") == 0) { >+ /* Yup. */ >+ char *namevalue = >+ talloc_asprintf(ctx, "%s:%s", name+7, (char *) value); >+ if (! namevalue) { >+ errno = ENOMEM; >+ ret = -1; >+ return -1; >+ } >+ >+ if (ipc_srv) { >+ ret = cacl_set(ctx, &srv->cli, >+ &ipc_srv->cli, &pol, path, >+ namevalue, >+ (*namevalue == '*' >+ ? SMBC_XATTR_MODE_SET >+ : SMBC_XATTR_MODE_ADD), >+ flags); >+ } else { >+ ret = 0; >+ } >+ >+ /* get a DOS Attribute Descriptor with current attributes */ >+ dad = dos_attr_query(context, ctx, path, srv); >+ if (dad) { >+ /* Overwrite old with new, using what was provided */ >+ dos_attr_parse(context, dad, srv, namevalue); >+ >+ /* Set the new DOS attributes */ >+#warning "Should try Set Path Info first, but it's not yet implemented" >+#if 0 /* not yet implemented */ >+ if (! cli_setpathinfo(&srv->cli, path, >+ dad->c_time, >+ dad->a_time, >+ dad->m_time, >+ dad->mode)) { >+ if (!cli_setatr(&srv->cli, path, >+ dad->mode, dad->m_time)) { >+ errno = smbc_errno(context, &srv->cli); >+ } >+ } >+#else >+ if (!cli_setatr(&srv->cli, path, >+ dad->mode, dad->m_time)) { >+ errno = smbc_errno(context, &srv->cli); >+ } >+#endif >+ } >+ >+ /* we only fail if both NT and DOS sets failed */ >+ if (ret < 0 && ! dad) { >+ ret = -1; /* in case dad was null */ >+ } >+ else { >+ ret = 0; >+ } >+ >+ talloc_destroy(ctx); >+ return ret; >+ } >+ >+ /* > * Are they asking to set an access control element or to set > * the entire access control list? > */ >@@ -3716,7 +4137,11 @@ > /* Yup. */ > char *namevalue = > talloc_asprintf(ctx, "%s:%s", name+19, (char *) value); >- if (! namevalue) { >+ >+ if (! ipc_srv) { >+ ret = -1; /* errno set by smbc_server() */ >+ } >+ else if (! namevalue) { > errno = ENOMEM; > ret = -1; > } else { >@@ -3741,7 +4166,12 @@ > /* Yup. */ > char *namevalue = > talloc_asprintf(ctx, "%s:%s", name+19, (char *) value); >- if (! namevalue) { >+ >+ if (! ipc_srv) { >+ >+ ret = -1; /* errno set by smbc_server() */ >+ } >+ else if (! namevalue) { > errno = ENOMEM; > ret = -1; > } else { >@@ -3762,7 +4192,12 @@ > /* Yup. */ > char *namevalue = > talloc_asprintf(ctx, "%s:%s", name+19, (char *) value); >- if (! namevalue) { >+ >+ if (! ipc_srv) { >+ /* errno set by smbc_server() */ >+ ret = -1; >+ } >+ else if (! namevalue) { > errno = ENOMEM; > ret = -1; > } else { >@@ -3774,6 +4209,67 @@ > return ret; > } > >+ /* >+ * Are they asking to set a DOS attribute? >+ */ >+ if (StrCaseCmp(name, "system.dos_attr.*") == 0 || >+ StrCaseCmp(name, "system.dos_attr.mode") == 0 || >+ StrCaseCmp(name, "system.dos_attr.c_time") == 0 || >+ StrCaseCmp(name, "system.dos_attr.a_time") == 0 || >+ StrCaseCmp(name, "system.dos_attr.m_time") == 0) { >+ >+ /* get a DOS Attribute Descriptor with current attributes */ >+ dad = dos_attr_query(context, ctx, path, srv); >+ if (dad) { >+ char *namevalue = >+ talloc_asprintf(ctx, "%s:%s", name+16, (char *) value); >+ if (! namevalue) { >+ errno = ENOMEM; >+ ret = -1; >+ } else { >+ /* Overwrite old with provided new params */ >+ dos_attr_parse(context, dad, srv, namevalue); >+ >+ /* Set the new DOS attributes */ >+#warning "Should try Set Path Info first, but it's not yet implemented" >+#if 0 /* not yet implemented */ >+ ret2 = cli_setpathinfo(&srv->cli, path, >+ dad->c_time, >+ dad->a_time, >+ dad->m_time, >+ dad->mode); >+ if (! ret2) { >+ ret2 = cli_setatr(&srv->cli, path, >+ dad->mode, >+ dad->m_time); >+ if (! ret2) { >+ errno = smbc_errno(context, >+ &srv->cli); >+ } >+ } >+#else >+ ret2 = cli_setatr(&srv->cli, path, >+ dad->mode, dad->m_time); >+ if (! ret2) { >+ errno = smbc_errno(context, &srv->cli); >+ } >+#endif >+ >+ /* ret2 has True (success) / False (failure) */ >+ if (ret2) { >+ ret = 0; >+ } else { >+ ret = -1; >+ } >+ } >+ } else { >+ ret = -1; >+ } >+ >+ talloc_destroy(ctx); >+ return ret; >+ } >+ > /* Unsupported attribute name */ > talloc_destroy(ctx); > errno = EINVAL; >@@ -3794,6 +4290,7 @@ > TALLOC_CTX *ctx; > POLICY_HND pol; > >+ > if (!context || !context->internal || > !context->internal->_initialized) { > >@@ -3831,11 +4328,15 @@ > return -1; /* errno set by smbc_server */ > } > >- ipc_srv = smbc_attr_server(context, server, share, >- workgroup, user, password, >- &pol); >- if (!ipc_srv) { >- return -1; >+ if (! srv->no_nt_session) { >+ ipc_srv = smbc_attr_server(context, server, share, >+ workgroup, user, password, >+ &pol); >+ if (! ipc_srv) { >+ srv->no_nt_session = True; >+ } >+ } else { >+ ipc_srv = NULL; > } > > ctx = talloc_init("smbc:getxattr"); >@@ -3845,7 +4346,9 @@ > } > > /* Are they requesting a supported attribute? */ >- if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 || >+ if (StrCaseCmp(name, "system.*") == 0 || >+ StrCaseCmp(name, "system.*+") == 0 || >+ StrCaseCmp(name, "system.nt_sec_desc.*") == 0 || > StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 || > StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 || > StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 || >@@ -3853,12 +4356,20 @@ > StrCaseCmp(name, "system.nt_sec_desc.group") == 0 || > StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 || > StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 || >- StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) { >+ StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0 || >+ StrCaseCmp(name, "system.dos_attr.*") == 0 || >+ StrCaseCmp(name, "system.dos_attr.mode") == 0 || >+ StrCaseCmp(name, "system.dos_attr.size") == 0 || >+ StrCaseCmp(name, "system.dos_attr.c_time") == 0 || >+ StrCaseCmp(name, "system.dos_attr.a_time") == 0 || >+ StrCaseCmp(name, "system.dos_attr.m_time") == 0 || >+ StrCaseCmp(name, "system.dos_attr.inode") == 0) { > > /* Yup. */ >- ret = cacl_get(ctx, &srv->cli, >- &ipc_srv->cli, &pol, >- (char *) path, (char *) name + 19, >+ ret = cacl_get(context, ctx, srv, >+ ipc_srv == NULL ? NULL : &ipc_srv->cli, >+ &pol, >+ (char *) path, (char *) name, > (char *) value, size); > if (ret < 0 && errno == 0) { > errno = smbc_errno(context, &srv->cli); >@@ -3923,20 +4434,19 @@ > return -1; /* errno set by smbc_server */ > } > >- ipc_srv = smbc_attr_server(context, server, share, >- workgroup, user, password, >- &pol); >- if (!ipc_srv) { >- return -1; >+ if (! srv->no_nt_session) { >+ ipc_srv = smbc_attr_server(context, server, share, >+ workgroup, user, password, >+ &pol); >+ srv->no_nt_session = True; >+ } else { >+ ipc_srv = NULL; > } > >- ipc_srv = smbc_attr_server(context, server, share, >- workgroup, user, password, >- &pol); >- if (!ipc_srv) { >- return -1; >+ if (! ipc_srv) { >+ return -1; /* errno set by smbc_attr_server */ > } >- >+ > ctx = talloc_init("smbc_removexattr"); > if (!ctx) { > errno = ENOMEM; >@@ -3988,10 +4498,12 @@ > { > /* > * This isn't quite what listxattr() is supposed to do. This returns >- * the complete set of attributes, always, rather than only those >+ * the complete set of attribute names, always, rather than only those > * attribute names which actually exist for a file. Hmmm... > */ > const char supported[] = >+ "system.*\0" >+ "system.*+\0" > "system.nt_sec_desc.revision\0" > "system.nt_sec_desc.owner\0" > "system.nt_sec_desc.owner+\0" >@@ -4001,6 +4513,11 @@ > "system.nt_sec_desc.acl+\0" > "system.nt_sec_desc.*\0" > "system.nt_sec_desc.*+\0" >+ "system.dos_attr.*\0" >+ "system.dos_attr.mode\0" >+ "system.dos_attr.c_time\0" >+ "system.dos_attr.a_time\0" >+ "system.dos_attr.m_time\0" > ; > > if (size == 0) { >@@ -4294,37 +4811,41 @@ > context->debug = 0; > context->timeout = 20000; /* 20 seconds */ > >- context->open = smbc_open_ctx; >- context->creat = smbc_creat_ctx; >- context->read = smbc_read_ctx; >- context->write = smbc_write_ctx; >- context->close = smbc_close_ctx; >- context->unlink = smbc_unlink_ctx; >- context->rename = smbc_rename_ctx; >- context->lseek = smbc_lseek_ctx; >- context->stat = smbc_stat_ctx; >- context->fstat = smbc_fstat_ctx; >- context->opendir = smbc_opendir_ctx; >- context->closedir = smbc_closedir_ctx; >- context->readdir = smbc_readdir_ctx; >- context->getdents = smbc_getdents_ctx; >- context->mkdir = smbc_mkdir_ctx; >- context->rmdir = smbc_rmdir_ctx; >- context->telldir = smbc_telldir_ctx; >- context->lseekdir = smbc_lseekdir_ctx; >- context->fstatdir = smbc_fstatdir_ctx; >- context->chmod = smbc_chmod_ctx; >- context->utimes = smbc_utimes_ctx; >- context->setxattr = smbc_setxattr_ctx; >- context->getxattr = smbc_getxattr_ctx; >- context->removexattr = smbc_removexattr_ctx; >- context->listxattr = smbc_listxattr_ctx; >- context->open_print_job = smbc_open_print_job_ctx; >- context->print_file = smbc_print_file_ctx; >- context->list_print_jobs = smbc_list_print_jobs_ctx; >- context->unlink_print_job = smbc_unlink_print_job_ctx; >+ context->options.browse_max_lmb_count = 3; /* # LMBs to query */ >+ context->options.urlencode_readdir_entries = False;/* backward compat */ >+ context->options.one_share_per_server = False;/* backward compat */ > >- context->callbacks.check_server_fn = smbc_check_server; >+ context->open = smbc_open_ctx; >+ context->creat = smbc_creat_ctx; >+ context->read = smbc_read_ctx; >+ context->write = smbc_write_ctx; >+ context->close = smbc_close_ctx; >+ context->unlink = smbc_unlink_ctx; >+ context->rename = smbc_rename_ctx; >+ context->lseek = smbc_lseek_ctx; >+ context->stat = smbc_stat_ctx; >+ context->fstat = smbc_fstat_ctx; >+ context->opendir = smbc_opendir_ctx; >+ context->closedir = smbc_closedir_ctx; >+ context->readdir = smbc_readdir_ctx; >+ context->getdents = smbc_getdents_ctx; >+ context->mkdir = smbc_mkdir_ctx; >+ context->rmdir = smbc_rmdir_ctx; >+ context->telldir = smbc_telldir_ctx; >+ context->lseekdir = smbc_lseekdir_ctx; >+ context->fstatdir = smbc_fstatdir_ctx; >+ context->chmod = smbc_chmod_ctx; >+ context->utimes = smbc_utimes_ctx; >+ context->setxattr = smbc_setxattr_ctx; >+ context->getxattr = smbc_getxattr_ctx; >+ context->removexattr = smbc_removexattr_ctx; >+ context->listxattr = smbc_listxattr_ctx; >+ context->open_print_job = smbc_open_print_job_ctx; >+ context->print_file = smbc_print_file_ctx; >+ context->list_print_jobs = smbc_list_print_jobs_ctx; >+ context->unlink_print_job = smbc_unlink_print_job_ctx; >+ >+ context->callbacks.check_server_fn = smbc_check_server; > context->callbacks.remove_unused_server_fn = smbc_remove_unused_server; > > smbc_default_cache_functions(context); >@@ -4540,3 +5061,11 @@ > > return context; > } >+ >+ >+/* Return the verion of samba, and thus libsmbclient */ >+const char * >+smbc_version(void) >+{ >+ return samba_version_string(); >+} >Index: libsmb/cliconnect.c >=================================================================== >--- libsmb/cliconnect.c (revision 4510) >+++ libsmb/cliconnect.c (working copy) >@@ -989,7 +989,12 @@ > if (!cli_receive_smb(cli)) > return False; > >- return !cli_is_error(cli); >+ if (cli_is_error(cli)) { >+ return False; >+ } >+ >+ cli->cnum = -1; >+ return True; > } > > /**************************************************************************** >@@ -1292,12 +1297,12 @@ > if (getenv("LIBSMB_PROG")) { > cli->fd = sock_exec(getenv("LIBSMB_PROG")); > } else { >- /* try 445 first, then 139 */ >- int port = cli->port?cli->port:445; >+ /* try 139 first, then 445, so browse lists work */ >+ int port = cli->port?cli->port:139; > cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, > port, cli->timeout); > if (cli->fd == -1 && cli->port == 0) { >- port = 139; >+ port = 445; > cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, > port, cli->timeout); > } >Index: libsmb/libsmb_cache.c >=================================================================== >--- libsmb/libsmb_cache.c (revision 4510) >+++ libsmb/libsmb_cache.c (working copy) >@@ -1,3 +1,4 @@ >+ > /* > Unix SMB/CIFS implementation. > SMB client library implementation (server cache) >@@ -23,12 +24,8 @@ > > #include "includes.h" > >-/* >- * Define this to get the real SMBCFILE and SMBCSRV structures >- */ >-#define _SMBC_INTERNAL > #include "include/libsmbclient.h" >- >+#include "../include/libsmb_internal.h" > /* > * Structure we use if internal caching mechanism is used > * nothing fancy here. >@@ -115,11 +112,53 @@ > > /* Search the cache lines */ > for (srv=((struct smbc_server_cache *)context->server_cache);srv;srv=srv->next) { >+ > if (strcmp(server,srv->server_name) == 0 && >- strcmp(share,srv->share_name) == 0 && > strcmp(workgroup,srv->workgroup) == 0 && >- strcmp(user, srv->username) == 0) >- return srv->server; >+ strcmp(user, srv->username) == 0) { >+ >+ /* If the share name matches, we're cool */ >+ if (strcmp(share, srv->share_name) == 0) { >+ return srv->server; >+ } >+ >+ /* >+ * We only return an empty share name or the attribute >+ * server on an exact match (which would have been >+ * caught above). >+ */ >+ if (*share == '\0' || strcmp(share, "*IPC$") == 0) >+ continue; >+ >+ /* >+ * Never return an empty share name or the attribute >+ * server if it wasn't what was requested. >+ */ >+ if (*srv->share_name == '\0' || >+ strcmp(srv->share_name, "*IPC$") == 0) >+ continue; >+ >+ /* >+ * If we're only allowing one share per server, then >+ * a connection to the server (other than the >+ * attribute server connection) is cool. >+ */ >+ if (context->options.one_share_per_server) { >+ /* >+ * The currently connected share name >+ * doesn't match the requested share, so >+ * disconnect from the current share. >+ */ >+ if (! cli_tdis(&srv->server->cli)) { >+ /* Sigh. Couldn't disconnect. */ >+ cli_shutdown(&srv->server->cli); >+ context->callbacks.remove_cached_srv_fn(context, srv->server); >+ continue; >+ } >+ >+ return srv->server; >+ } >+ } > } > > return NULL; >Index: include/libsmb_internal.h >=================================================================== >--- include/libsmb_internal.h (revision 4510) >+++ include/libsmb_internal.h (working copy) >@@ -13,6 +13,7 @@ > struct cli_state cli; > dev_t dev; > BOOL no_pathinfo2; >+ BOOL no_nt_session; > int server_fd; > > SMBCSRV *next, *prev; >@@ -50,9 +51,18 @@ > */ > int _initialized; > >- /** INTERNAL: dirent pointer location >- */ >- char _dirent[512]; >+ /** INTERNAL: dirent pointer location >+ * >+ * Leave room for any urlencoded filename and the comment field. >+ * >+ * We really should use sizeof(struct smbc_dirent) plus (NAME_MAX * 3) >+ * plus whatever the max length of a comment is, plus a couple of null >+ * terminators (one after the filename, one after the comment). >+ * >+ * According to <linux/limits.h>, NAME_MAX is 255. Is it longer >+ * anyplace else? >+ */ >+ char _dirent[1024]; > > /** INTERNAL: server connection list > */ >Index: include/libsmbclient.h >=================================================================== >--- include/libsmbclient.h (revision 4510) >+++ include/libsmbclient.h (working copy) >@@ -125,6 +125,19 @@ > #define SMBC_XATTR_FLAG_REPLACE 0x2 /* fail if attr does not exist */ > > >+/* >+ * Mappings of the DOS mode bits, as returned by smbc_getxattr() when the >+ * attribute name "system.dos_attr.mode" (or "system.dos_attr.*" or >+ * "system.*") is specified. >+ */ >+#define SMBC_DOS_MODE_READONLY 0x01 >+#define SMBC_DOS_MODE_HIDDEN 0x02 >+#define SMBC_DOS_MODE_SYSTEM 0x04 >+#define SMBC_DOS_MODE_VOLUME_ID 0x08 >+#define SMBC_DOS_MODE_DIRECTORY 0x10 >+#define SMBC_DOS_MODE_ARCHIVE 0x20 >+ >+ > #ifndef ENOATTR > # define ENOATTR ENOENT /* No such attribute */ > #endif >@@ -349,6 +362,67 @@ > */ > int timeout; > >+ /** user options selections that apply to this session >+ */ >+ struct _smbc_options { >+ >+ /* >+ * From how many local master browsers should the list of >+ * workgroups be retrieved? It can take up to 12 minutes or >+ * longer after a server becomes a local master browser, for >+ * it to have the entire browse list (the list of >+ * workgroups/domains) from an entire network. Since a client >+ * never knows which local master browser will be found first, >+ * the one which is found first and used to retrieve a browse >+ * list may have an incomplete or empty browse list. By >+ * requesting the browse list from multiple local master >+ * browsers, a more complete list can be generated. For small >+ * networks (few workgroups), it is recommended that this >+ * value be set to 0, causing the browse lists from all found >+ * local master browsers to be retrieved and merged. For >+ * networks with many workgroups, a suitable value for this >+ * variable is probably somewhere around 3. (Default: 3). >+ */ >+ int browse_max_lmb_count; >+ >+ /* >+ * There is a difference in the desired return strings from >+ * smbc_readdir() depending upon whether the filenames are to >+ * be displayed to the user, or whether they are to be >+ * appended to the path name passed to smbc_opendir() to call >+ * a further smbc_ function (e.g. open the file with >+ * smbc_open()). In the former case, the filename should be >+ * in "human readable" form. In the latter case, the smbc_ >+ * functions expect a URL which must be url-encoded. Those >+ * functions decode the URL. If, for example, smbc_readdir() >+ * returned a file name of "abc%20def.txt", passing a path >+ * with this file name attached to smbc_open() would cause >+ * smbc_open to attempt to open the file "abc def.txt" since >+ * the %20 is decoded into a space. >+ * >+ * Set this option to True if the names returned by >+ * smbc_readdir() should be url-encoded such that they can be >+ * passed back to another smbc_ call. Set it to False if the >+ * names returned by smbc_readdir() are to be presented to the >+ * user. >+ * >+ * For backwards compatibility, this option defaults to False. >+ */ >+ int urlencode_readdir_entries; >+ >+ /* >+ * Some Windows versions appear to have a limit to the number >+ * of concurrent SESSIONs and/or TREE CONNECTions. In >+ * one-shot programs (i.e. the program runs and then quickly >+ * ends, thereby shutting down all connections), it is >+ * probably reasonable to establish a new connection for each >+ * share. In long-running applications, the limitation can be >+ * avoided by using only a single connection to each server, >+ * and issuing a new TREE CONNECT when the share is accessed. >+ */ >+ int one_share_per_server; >+ } options; >+ > /** callable functions for files: > * For usage and return values see the smbc_* functions > */ >@@ -458,7 +532,6 @@ > > }; > >- > /**@ingroup misc > * Create a new SBMCCTX (a context). > * >@@ -2179,4 +2252,75 @@ > } > #endif > >+/**@ingroup directory >+ * Convert strings of %xx to their single character equivalent. >+ * >+ * @param dest A pointer to a buffer in which the resulting decoded >+ * string should be placed. This may be a pointer to the >+ * same buffer as src_segment. >+ * >+ * @param src A pointer to the buffer containing the URL to be decoded. >+ * Any %xx sequences herein are converted to their single >+ * character equivalent. Each 'x' must be a valid hexadecimal >+ * digit, or that % sequence is left undecoded. >+ * >+ * @param max_dest_len >+ * The size of the buffer pointed to by dest_segment. >+ * >+ * @return The number of % sequences which could not be converted >+ * due to lack of two following hexadecimal digits. >+ */ >+#ifdef __cplusplus >+extern "C" { >+#endif >+int >+smbc_urldecode(char *dest, char * src, size_t max_dest_len); >+#ifdef __cplusplus >+} >+#endif >+ >+ >+/* >+ * Convert any characters not specifically allowed in a URL into their %xx >+ * equivalent. >+ * >+ * @param dest A pointer to a buffer in which the resulting encoded >+ * string should be placed. Unlike smbc_urldecode(), this >+ * must be a buffer unique from src. >+ * >+ * @param src A pointer to the buffer containing the string to be encoded. >+ * Any character not specifically allowed in a URL is converted >+ * into its hexadecimal value and encoded as %xx. >+ * >+ * @param max_dest_len >+ * The size of the buffer pointed to by dest_segment. >+ * >+ * @returns The remaining buffer length. >+ */ >+#ifdef __cplusplus >+extern "C" { >+#endif >+int >+smbc_urlencode(char * dest, char * src, int max_dest_len); >+#ifdef __cplusplus >+} >+#endif >+ >+ >+/**@ingroup directory >+ * Return the version of the linked Samba code, and thus the version of the >+ * libsmbclient code. >+ * >+ * @return The version string. >+ */ >+#ifdef __cplusplus >+extern "C" { >+#endif >+const char * >+smbc_version(void); >+#ifdef __cplusplus >+} >+#endif >+ >+ > #endif /* SMBCLIENT_H_INCLUDED */
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 2308
: 945 |
1027