之前我们发现回调函数my_smbc_get_auth_data_with_context_fn内能获取到用户名和工作组等,并且都是我设置的值,在这个回调中打个断点看看,我们再次调试
看到左侧的调用栈,红框中的几个函数都是libsmbclient的源码内的,我们查找samba源码(4.0.26版本):
int smbc_open(const char *furl,
int flags,
mode_t mode)
{
SMBCFILE * file;
int fd;
file = smbc_getFunctionOpen(statcont)(statcont, furl, flags, mode);
if (!file)
return -1;
fd = add_fd(file);
if (fd == -1)
smbc_getFunctionClose(statcont)(statcont, file);
return fd;
}
smbc_open_fn smbc_getFunctionOpen(SMBCCTX *c)
{
return c->open;
}
这里的smbc_open_fn其实是这样的:
typedef SMBCFILE * (*smbc_open_fn)(SMBCCTX *c,
const char *fname,
int flags,
mode_t mode);
smbc_open_fn smbc_getFunctionOpen(SMBCCTX *c);
void smbc_setFunctionOpen(SMBCCTX *c, smbc_open_fn fn);
而SMBCCTX为
typedef struct _SMBCCTX SMBCCTX;
struct _SMBCCTX
{
/**
* debug level
*
* DEPRECATED:
* Use smbc_getDebug() and smbc_setDebug()
*/
int debug DEPRECATED_SMBC_INTERFACE;
/**
* netbios name used for making connections
*
* DEPRECATED:
* Use smbc_getNetbiosName() and smbc_setNetbiosName()
*/
char * netbios_name DEPRECATED_SMBC_INTERFACE;
/**
* workgroup name used for making connections
*
* DEPRECATED:
* Use smbc_getWorkgroup() and smbc_setWorkgroup()
*/
char * workgroup DEPRECATED_SMBC_INTERFACE;
/**
* username used for making connections
*
* DEPRECATED:
* Use smbc_getUser() and smbc_setUser()
*/
char * user DEPRECATED_SMBC_INTERFACE;
/**
* timeout used for waiting on connections / response data (in
* milliseconds)
*
* DEPRECATED:
* Use smbc_getTimeout() and smbc_setTimeout()
*/
int timeout DEPRECATED_SMBC_INTERFACE;
/**
* callable functions for files:
* For usage and return values see the SMBC_* functions
*
* DEPRECATED:
*
* Use smbc_getFunction*() and smbc_setFunction*(), e.g.
* smbc_getFunctionOpen(), smbc_setFunctionUnlink(), etc.
*/
smbc_open_fn open DEPRECATED_SMBC_INTERFACE;
smbc_creat_fn creat DEPRECATED_SMBC_INTERFACE;
smbc_read_fn read DEPRECATED_SMBC_INTERFACE;
smbc_write_fn write DEPRECATED_SMBC_INTERFACE;
smbc_unlink_fn unlink DEPRECATED_SMBC_INTERFACE;
smbc_rename_fn rename DEPRECATED_SMBC_INTERFACE;
smbc_lseek_fn lseek DEPRECATED_SMBC_INTERFACE;
smbc_stat_fn stat DEPRECATED_SMBC_INTERFACE;
smbc_fstat_fn fstat DEPRECATED_SMBC_INTERFACE;
#if 0 /* internal */
smbc_ftruncate_fn ftruncate_fn;
#endif
smbc_close_fn close_fn DEPRECATED_SMBC_INTERFACE;
smbc_opendir_fn opendir DEPRECATED_SMBC_INTERFACE;
smbc_closedir_fn closedir DEPRECATED_SMBC_INTERFACE;
smbc_readdir_fn readdir DEPRECATED_SMBC_INTERFACE;
smbc_getdents_fn getdents DEPRECATED_SMBC_INTERFACE;
smbc_mkdir_fn mkdir DEPRECATED_SMBC_INTERFACE;
smbc_rmdir_fn rmdir DEPRECATED_SMBC_INTERFACE;
smbc_telldir_fn telldir DEPRECATED_SMBC_INTERFACE;
smbc_lseekdir_fn lseekdir DEPRECATED_SMBC_INTERFACE;
smbc_fstatdir_fn fstatdir DEPRECATED_SMBC_INTERFACE;
smbc_chmod_fn chmod DEPRECATED_SMBC_INTERFACE;
smbc_utimes_fn utimes DEPRECATED_SMBC_INTERFACE;
smbc_setxattr_fn setxattr DEPRECATED_SMBC_INTERFACE;
smbc_getxattr_fn getxattr DEPRECATED_SMBC_INTERFACE;
smbc_removexattr_fn removexattr DEPRECATED_SMBC_INTERFACE;
smbc_listxattr_fn listxattr DEPRECATED_SMBC_INTERFACE;
/* Printing-related functions */
smbc_print_file_fn print_file DEPRECATED_SMBC_INTERFACE;
smbc_open_print_job_fn open_print_job DEPRECATED_SMBC_INTERFACE;
smbc_list_print_jobs_fn list_print_jobs DEPRECATED_SMBC_INTERFACE;
smbc_unlink_print_job_fn unlink_print_job DEPRECATED_SMBC_INTERFACE;
/*
** Callbacks
*
* DEPRECATED:
*
* See the comment above each field, for the getter and setter
* functions that should now be used.
*/
struct _smbc_callbacks
{
/**
* authentication function callback: called upon auth requests
*
* DEPRECATED:
* Use smbc_getFunctionAuthData(), smbc_setFunctionAuthData()
*/
smbc_get_auth_data_fn auth_fn DEPRECATED_SMBC_INTERFACE;
/**
* check if a server is still good
*
* DEPRECATED:
* Use smbc_getFunctionCheckServer(),
* smbc_setFunctionCheckServer()
*/
smbc_check_server_fn check_server_fn DEPRECATED_SMBC_INTERFACE;
/**
* remove a server if unused
*
* DEPRECATED:
* Use smbc_getFunctionRemoveUnusedServer(),
* smbc_setFunctionCheckServer()
*/
smbc_remove_unused_server_fn remove_unused_server_fn DEPRECATED_SMBC_INTERFACE;
/** Cache subsystem
*
* For an example cache system see
* samba/source/libsmb/libsmb_cache.c
*
* Cache subsystem * functions follow.
*/
/**
* server cache addition
*
* DEPRECATED:
* Use smbc_getFunctionAddCachedServer(),
* smbc_setFunctionAddCachedServer()
*/
smbc_add_cached_srv_fn add_cached_srv_fn DEPRECATED_SMBC_INTERFACE;
/**
* server cache lookup
*
* DEPRECATED:
* Use smbc_getFunctionGetCachedServer(),
* smbc_setFunctionGetCachedServer()
*/
smbc_get_cached_srv_fn get_cached_srv_fn DEPRECATED_SMBC_INTERFACE;
/**
* server cache removal
*
* DEPRECATED:
* Use smbc_getFunctionRemoveCachedServer(),
* smbc_setFunctionRemoveCachedServer()
*/
smbc_remove_cached_srv_fn remove_cached_srv_fn DEPRECATED_SMBC_INTERFACE;
/**
* server cache purging, try to remove all cached servers
* (disconnect)
*
* DEPRECATED:
* Use smbc_getFunctionPurgeCachedServers(),
* smbc_setFunctionPurgeCachedServers()
*/
smbc_purge_cached_fn purge_cached_fn DEPRECATED_SMBC_INTERFACE;
} callbacks;
/**
* Space where the private data of the server cache used to be
*
* DEPRECATED:
* Use smbc_getServerCacheData(), smbc_setServerCacheData()
*/
void * reserved DEPRECATED_SMBC_INTERFACE;
/*
* Very old configuration options.
*
* DEPRECATED:
* Use one of the following functions instead:
* smbc_setOptionUseKerberos()
* smbc_getOptionUseKerberos()
* smbc_setOptionFallbackAfterKerberos()
* smbc_getOptionFallbackAfterKerberos()
* smbc_setOptionNoAutoAnonymousLogin()
* smbc_getOptionNoAutoAnonymousLogin()
*/
int flags DEPRECATED_SMBC_INTERFACE;
/**
* user options selections that apply to this session
*
* NEW OPTIONS ARE NOT ADDED HERE!
*
* DEPRECATED:
* To set and retrieve options, use the smbc_setOption*() and
* smbc_getOption*() functions.
*/
struct _smbc_options {
int browse_max_lmb_count DEPRECATED_SMBC_INTERFACE;
int urlencode_readdir_entries DEPRECATED_SMBC_INTERFACE;
int one_share_per_server DEPRECATED_SMBC_INTERFACE;
} options DEPRECATED_SMBC_INTERFACE;
/** INTERNAL DATA
* do _NOT_ touch this from your program !
*/
struct SMBC_internal_data * internal;
};
通过上面代码看出c->open,_SMBCCTX的open的类型就是smbc_open_fn
而statcont是一个SMBCCTX*的全局变量,在这里初始化了
static SMBCCTX * statcont = NULL;
int smbc_init(smbc_get_auth_data_fn fn,
int debug)
{
if (!smbc_compat_initialized) {
statcont = smbc_new_context();
if (!statcont)
return -1;
smbc_setDebug(statcont, debug);
smbc_setFunctionAuthData(statcont, fn);
if (!smbc_init_context(statcont)) {
smbc_free_context(statcont, False);
return -1;
}
smbc_compat_initialized = 1;
return 0;
}
return 0;
}
所以smbc_getFunctionOpen(statcont)() == statcont->open()
所以,file = smbc_getFunctionOpen(statcont)(statcont, furl, flags, mode)实质就是执行了smbc_open_fn()
在smbc_open_fn申明的下方有个这个:
void smbc_setFunctionOpen(SMBCCTX *c, smbc_open_fn fn);
源码为:
void
smbc_setFunctionOpen(SMBCCTX *c, smbc_open_fn fn)
{
c->open = fn;
}
从这个smbc_setFunctionOpen可以推断,此函数是为SMBCCTX的open成员赋值用的
果不其然,在smbc_new_context里的确设置了这一open成员
/*
* Get a new empty handle to fill in with your own info
*/
SMBCCTX *
smbc_new_context(void)
{
SMBCCTX *context;
TALLOC_CTX *frame = talloc_stackframe();
/* The first call to this function should initialize the module */
SMB_THREAD_ONCE(&SMBC_initialized, SMBC_module_init, NULL);
/*
* All newly added context fields should be placed in
* SMBC_internal_data, not directly in SMBCCTX.
*/
context = SMB_MALLOC_P(SMBCCTX);
if (!context) {
TALLOC_FREE(frame);
errno = ENOMEM;
return NULL;
}
ZERO_STRUCTP(context);
context->internal = SMB_MALLOC_P(struct SMBC_internal_data);
if (!context->internal) {
TALLOC_FREE(frame);
SAFE_FREE(context);
errno = ENOMEM;
return NULL;
}
/* Initialize the context and establish reasonable defaults */
ZERO_STRUCTP(context->internal);
smbc_setDebug(context, 0);
smbc_setTimeout(context, 20000);
smbc_setOptionFullTimeNames(context, False);
smbc_setOptionOpenShareMode(context, SMBC_SHAREMODE_DENY_NONE);
smbc_setOptionSmbEncryptionLevel(context, SMBC_ENCRYPTLEVEL_NONE);
smbc_setOptionUseCCache(context, True);
smbc_setOptionCaseSensitive(context, False);
smbc_setOptionBrowseMaxLmbCount(context, 3); /* # LMBs to query */
smbc_setOptionUrlEncodeReaddirEntries(context, False);
smbc_setOptionOneSharePerServer(context, False);
if (getenv("LIBSMBCLIENT_NO_CCACHE") == NULL) {
smbc_setOptionUseCCache(context, true);
}
smbc_setFunctionAuthData(context, SMBC_get_auth_data);
smbc_setFunctionCheckServer(context, SMBC_check_server);
smbc_setFunctionRemoveUnusedServer(context, SMBC_remove_unused_server);
smbc_setOptionUserData(context, NULL);
smbc_setFunctionAddCachedServer(context, SMBC_add_cached_server);
smbc_setFunctionGetCachedServer(context, SMBC_get_cached_server);
smbc_setFunctionRemoveCachedServer(context, SMBC_remove_cached_server);
smbc_setFunctionPurgeCachedServers(context, SMBC_purge_cached_servers);
smbc_setFunctionOpen(context, SMBC_open_ctx);
smbc_setFunctionCreat(context, SMBC_creat_ctx);
smbc_setFunctionRead(context, SMBC_read_ctx);
smbc_setFunctionWrite(context, SMBC_write_ctx);
smbc_setFunctionClose(context, SMBC_close_ctx);
smbc_setFunctionUnlink(context, SMBC_unlink_ctx);
smbc_setFunctionRename(context, SMBC_rename_ctx);
smbc_setFunctionLseek(context, SMBC_lseek_ctx);
smbc_setFunctionFtruncate(context, SMBC_ftruncate_ctx);
smbc_setFunctionStat(context, SMBC_stat_ctx);
smbc_setFunctionStatVFS(context, SMBC_statvfs_ctx);
smbc_setFunctionFstatVFS(context, SMBC_fstatvfs_ctx);
smbc_setFunctionFstat(context, SMBC_fstat_ctx);
smbc_setFunctionOpendir(context, SMBC_opendir_ctx);
smbc_setFunctionClosedir(context, SMBC_closedir_ctx);
smbc_setFunctionReaddir(context, SMBC_readdir_ctx);
smbc_setFunctionGetdents(context, SMBC_getdents_ctx);
smbc_setFunctionMkdir(context, SMBC_mkdir_ctx);
smbc_setFunctionRmdir(context, SMBC_rmdir_ctx);
smbc_setFunctionTelldir(context, SMBC_telldir_ctx);
smbc_setFunctionLseekdir(context, SMBC_lseekdir_ctx);
smbc_setFunctionFstatdir(context, SMBC_fstatdir_ctx);
smbc_setFunctionChmod(context, SMBC_chmod_ctx);
smbc_setFunctionUtimes(context, SMBC_utimes_ctx);
smbc_setFunctionSetxattr(context, SMBC_setxattr_ctx);
smbc_setFunctionGetxattr(context, SMBC_getxattr_ctx);
smbc_setFunctionRemovexattr(context, SMBC_removexattr_ctx);
smbc_setFunctionListxattr(context, SMBC_listxattr_ctx);
smbc_setFunctionOpenPrintJob(context, SMBC_open_print_job_ctx);
smbc_setFunctionPrintFile(context, SMBC_print_file_ctx);
smbc_setFunctionListPrintJobs(context, SMBC_list_print_jobs_ctx);
smbc_setFunctionUnlinkPrintJob(context, SMBC_unlink_print_job_ctx);
TALLOC_FREE(frame);
return context;
}
通过下面这句代码,我们可以定位到SMBC_open_ctx
smbc_setFunctionOpen(context, SMBC_open_ctx);
SMBC_open_ctx,正是红色方框调用栈中的其中一个小伙伴
我们来看下它的源码:
SMBCFILE * SMBC_open_ctx(SMBCCTX *context,
const char *fname,
int flags,
mode_t mode)
{
char *server = NULL;
char *share = NULL;
char *user = NULL;
char *password = NULL;
char *workgroup = NULL;
char *path = NULL;
char *targetpath = NULL;
struct cli_state *targetcli = NULL;
SMBCSRV *srv = NULL;
SMBCFILE *file = NULL;
uint16_t fd;
NTSTATUS status = NT_STATUS_OBJECT_PATH_INVALID;
TALLOC_CTX *frame = talloc_stackframe();
if (!context || !context->internal->initialized) {
errno = EINVAL; /* Best I can think of ... */
TALLOC_FREE(frame);
return NULL;
}
if (!fname) {
errno = EINVAL;
TALLOC_FREE(frame);
return NULL;
}
if (SMBC_parse_path(frame,
context,
fname,
&workgroup,
&server,
&share,
&path,
&user,
&password,
NULL)) {
errno = EINVAL;
TALLOC_FREE(frame);
return NULL;
}
if (!user || user[0] == (char)0) {
user = talloc_strdup(frame, smbc_getUser(context));
if (!user) {
errno = ENOMEM;
TALLOC_FREE(frame);
return NULL;
}
}
srv = SMBC_server(frame, context, True,
server, share, &workgroup, &user, &password);
if (!srv) {
if (errno == EPERM) errno = EACCES;
TALLOC_FREE(frame);
return NULL; /* SMBC_server sets errno */
}
/* Hmmm, the test for a directory is suspect here ... FIXME */
if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
status = NT_STATUS_OBJECT_PATH_INVALID;
} else {
file = SMB_MALLOC_P(SMBCFILE);
if (!file) {
errno = ENOMEM;
TALLOC_FREE(frame);
return NULL;
}
ZERO_STRUCTP(file);
/*d_printf(">>>open: resolving %s\n", path);*/
status = cli_resolve_path(
frame, "", context->internal->auth_info,
srv->cli, path, &targetcli, &targetpath);
if (!NT_STATUS_IS_OK(status)) {
d_printf("Could not resolve %s\n", path);
errno = ENOENT;
SAFE_FREE(file);
TALLOC_FREE(frame);
return NULL;
}
/*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/
status = cli_open(targetcli, targetpath, flags,
context->internal->share_mode, &fd);
if (!NT_STATUS_IS_OK(status)) {
/* Handle the error ... */
SAFE_FREE(file);
errno = SMBC_errno(context, targetcli);
TALLOC_FREE(frame);
return NULL;
}
/* Fill in file struct */
file->cli_fd = fd;
file->fname = SMB_STRDUP(fname);
file->srv = srv;
file->offset = 0;
file->file = True;
DLIST_ADD(context->internal->files, file);
/*
* If the file was opened in O_APPEND mode, all write
* operations should be appended to the file. To do that,
* though, using this protocol, would require a getattrE()
* call for each and every write, to determine where the end
* of the file is. (There does not appear to be an append flag
* in the protocol.) Rather than add all of that overhead of
* retrieving the current end-of-file offset prior to each
* write operation, we'll assume that most append operations
* will continuously write, so we'll just set the offset to
* the end of the file now and hope that's adequate.
*
* Note to self: If this proves inadequate, and O_APPEND
* should, in some cases, be forced for each write, add a
* field in the context options structure, for
* "strict_append_mode" which would select between the current
* behavior (if FALSE) or issuing a getattrE() prior to each
* write and forcing the write to the end of the file (if
* TRUE). Adding that capability will likely require adding
* an "append" flag into the _SMBCFILE structure to track
* whether a file was opened in O_APPEND mode. -- djl
*/
if (flags & O_APPEND) {
if (SMBC_lseek_ctx(context, file, 0, SEEK_END) < 0) {
(void) SMBC_close_ctx(context, file);
errno = ENXIO;
TALLOC_FREE(frame);
return NULL;
}
}
TALLOC_FREE(frame);
return file;
}
/* Check if opendir needed ... */
if (!NT_STATUS_IS_OK(status)) {
int eno = 0;
eno = SMBC_errno(context, srv->cli);
file = smbc_getFunctionOpendir(context)(context, fname);
if (!file) errno = eno;
TALLOC_FREE(frame);
return file;
}
errno = EINVAL; /* FIXME, correct errno ? */
TALLOC_FREE(frame);
return NULL;
}
从函数的参数类型和返回类型就可以断定,这正是我们所希望的SMBC_open_ctx(符合预期)
再次看到红框中调用栈,的确是smbc_open_ctx调用了smbc_server,也符合代码中写得那样
srv = SMBC_server(frame, context, True,
server, share, &workgroup, &user, &password);
我们先找到smbc_server的源码
SMBCSRV *
SMBC_server(TALLOC_CTX *ctx,
SMBCCTX *context,
bool connect_if_not_found,
const char *server,
const char *share,
char **pp_workgroup,
char **pp_username,
char **pp_password)
{
SMBCSRV *srv=NULL;
bool in_cache = false;
srv = SMBC_server_internal(ctx, context, connect_if_not_found,
server, share, pp_workgroup,
pp_username, pp_password, &in_cache);
if (!srv) {
return NULL;
}
if (in_cache) {
return srv;
}
/* Now add it to the cache (internal or external) */
/* Let the cache function set errno if it wants to */
errno = 0;
if (smbc_getFunctionAddCachedServer(context)(context, srv,
server, share,
*pp_workgroup,
*pp_username)) {
int saved_errno = errno;
DEBUG(3, (" Failed to add server to cache\n"));
errno = saved_errno;
if (errno == 0) {
errno = ENOMEM;
}
SAFE_FREE(srv);
return NULL;
}
DEBUG(2, ("Server connect ok: //%s/%s: %p\n",
server, share, srv));
DLIST_ADD(context->internal->servers, srv);
return srv;
}
发现此函数又一次符合预期(红框)的调用了SMBC_server_internal函数,此时,内心会问:这里的password和username等直接就从smbc_server传入了SMBC_server_internal,那么password和username等信息是不是在SMBC_server_internal里面才处理的呢?
为了方便阅读,我就不一一去贴出下面将要调用的SMBC_find_server的代码了,直接说答案:并没有!
其实是在SMBC_parse_path进行处理的(smbc_open_ctx中的)
if (SMBC_parse_path(frame,
context,
fname,
&workgroup,
&server,
&share,
&path,
&user,
&password,
NULL)) {
errno = EINVAL;
TALLOC_FREE(frame);
return NULL;
}
SMBC_parse_path的代码如下:
#define SMBC_PREFIX "smb:"
int SMBC_parse_path(TALLOC_CTX *ctx,
SMBCCTX *context,
const char *fname,
char **pp_workgroup,
char **pp_server,
char **pp_share,
char **pp_path,
char **pp_user,
char **pp_password,
char **pp_options)
{
char *s;
const char *p;
char *q, *r;
char *workgroup = NULL;
int len;
/* Ensure these returns are at least valid pointers. */
*pp_server = talloc_strdup(ctx, "");
*pp_share = talloc_strdup(ctx, "");
*pp_path = talloc_strdup(ctx, "");
*pp_user = talloc_strdup(ctx, "");
*pp_password = talloc_strdup(ctx, "");
if (!*pp_server || !*pp_share || !*pp_path ||
!*pp_user || !*pp_password) {
return -1;
}
/*
* Assume we wont find an authentication domain to parse, so default
* to the workgroup in the provided context.
*/
if (pp_workgroup != NULL) {
*pp_workgroup =
talloc_strdup(ctx, smbc_getWorkgroup(context));
}
if (pp_options) {
*pp_options = talloc_strdup(ctx, "");
}
s = talloc_strdup(ctx, fname);
/* see if it has the right prefix */
len = strlen(SMBC_PREFIX);
if (strncmp(s,SMBC_PREFIX,len) || (s[len] != '/' && s[len] != 0)) {
return -1; /* What about no smb: ? */
}
p = s + len;
/* Watch the test below, we are testing to see if we should exit */
if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) {
DEBUG(1, ("Invalid path (does not begin with smb://"));
return -1;
}
p += 2; /* Skip the double slash */
/* See if any options were specified */
if ((q = strrchr(p, '?')) != NULL ) {
/* There are options. Null terminate here and point to them */
*q++ = '\0';
DEBUG(4, ("Found options '%s'", q));
/* Copy the options */
if (pp_options && *pp_options != NULL) {
TALLOC_FREE(*pp_options);
*pp_options = talloc_strdup(ctx, q);
}
}
if (*p == '\0') {
goto decoding;
}
if (*p == '/') {
int wl = strlen(smbc_getWorkgroup(context));
if (wl > 16) {
wl = 16;
}
*pp_server = talloc_strdup(ctx, smbc_getWorkgroup(context));
if (!*pp_server) {
return -1;
}
(*pp_server)[wl] = '\0';
return 0;
}
/*
* ok, its for us. Now parse out the server, share etc.
*
* However, we want to parse out [[domain;]user[:password]@] if it
* exists ...
*/
/* check that '@' occurs before '/', if '/' exists at all */
q = strchr_m(p, '@');
r = strchr_m(p, '/');
if (q && (!r || q < r)) {
char *userinfo = NULL;
const char *u;
next_token_no_ltrim_talloc(ctx, &p, &userinfo, "@");
if (!userinfo) {
return -1;
}
u = userinfo;
if (strchr_m(u, ';')) {
next_token_no_ltrim_talloc(ctx, &u, &workgroup, ";");
if (!workgroup) {
return -1;
}
if (pp_workgroup) {
*pp_workgroup = workgroup;
}
}
if (strchr_m(u, ':')) {
next_token_no_ltrim_talloc(ctx, &u, pp_user, ":");
if (!*pp_user) {
return -1;
}
*pp_password = talloc_strdup(ctx, u);
if (!*pp_password) {
return -1;
}
} else {
*pp_user = talloc_strdup(ctx, u);
if (!*pp_user) {
return -1;
}
}
}
if (!next_token_talloc(ctx, &p, pp_server, "/")) {
return -1;
}
if (*p == (char)0) {
goto decoding; /* That's it ... */
}
if (!next_token_talloc(ctx, &p, pp_share, "/")) {
return -1;
}
/*
* Prepend a leading slash if there's a file path, as required by
* NetApp filers.
*/
if (*p != '\0') {
*pp_path = talloc_asprintf(ctx,
"\\%s",
p);
} else {
*pp_path = talloc_strdup(ctx, "");
}
if (!*pp_path) {
return -1;
}
string_replace(*pp_path, '/', '\\');
decoding:
(void) urldecode_talloc(ctx, pp_path, *pp_path);
(void) urldecode_talloc(ctx, pp_server, *pp_server);
(void) urldecode_talloc(ctx, pp_share, *pp_share);
(void) urldecode_talloc(ctx, pp_user, *pp_user);
(void) urldecode_talloc(ctx, pp_password, *pp_password);
if (!workgroup) {
workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context));
}
if (!workgroup) {
return -1;
}
/* set the credentials to make DFS work */
smbc_set_credentials_with_fallback(context,
workgroup,
*pp_user,
*pp_password);
return 0;
}
粗略阅读,发现这个函数就是对url进行字符串处理的
其中包括url中的“@”和“/”等
(我当时很傻,通过此段代码来反推smb链接的传参规则)
我们直接看到上方的注释(因为在定义与注释之间有个宏吸引了我:#define SMBC_PREFIX "smb:")
/*
* 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:").
*
*
* We accept:
* smb://[[[domain;]user[:password]@]server[/share[/path[/file]]]][?options]
*
* Meaning of URLs:
*
* smb:// Show all workgroups.
*
* 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
* determines 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://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. Note that currently, no options
* are supported.
*/
#define SMBC_PREFIX "smb:"
在注释中,我么终于找到了答案
/*
....
* We accept:
* smb://[[[domain;]user[:password]@]server[/share[/path[/file]]]][?options]
...
*/