mirror of
https://github.com/samba-team/samba.git
synced 2025-03-27 22:50:26 +03:00
Initial revamp of the libsmbclient interface.
The libsmbclient interface has suffered from difficulty of improvement and feature enrichment without causing ABI breakage. Although there were a number of issues, the primary ones were: (a) the user of the library would manually manipulate the context structure members, meaning that nothing in the context structure could change other than adding stuff at the end; (b) there were three methods of setting options: setting bits in a flags field within the context structure, setting explicit options variables within an options structure in the context structure, and by calling the smbc_option_set() function; (c) the authentication callback did not traditionally provide enough information to the callee which required adding an option for a callback with a different signature, and now there are requests for even more information at the callback, requiring yet a third signature and option to set it (if we implement that feature). This commit provides a reorganization of the code which fixes (a) and (b). The context structure is now entirely opaque, and there are setter and getter functions for manipulating it. This makes maintaining ABI consistency much, much easier. Additionally, the options setting/getting has been unified into a single mechanism using smbc_option_set() and smbc_option_get(). Yet to be completed is a refactoring of the authentication callback (c). The test programs in examples/libsmbclient have been modified (if necessary; some applications require no changes at all) for the new API and a few have been minimally tested. Derrell (This used to be commit d4b4bae8ded824d06ad5ab0e219f71187ee5c771)
This commit is contained in:
parent
422af9a516
commit
257b7b0929
@ -174,11 +174,11 @@ static void do_init(StartupType startupType)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
smbw_ctx->debug = debug_level;
|
||||
smbw_ctx->callbacks.auth_fn = get_auth_data_fn;
|
||||
smbw_ctx->options.browse_max_lmb_count = 0;
|
||||
smbw_ctx->options.urlencode_readdir_entries = 1;
|
||||
smbw_ctx->options.one_share_per_server = 1;
|
||||
smbc_setDebug(smbw_ctx, debug_level);
|
||||
smbc_setFunctionAuthData(smbw_ctx, get_auth_data_fn);
|
||||
smbc_option_set(smbw_ctx, "browse_max_lmb_count", 0);
|
||||
smbc_option_set(smbw_ctx, "urlencode_readdir_entries", 1);
|
||||
smbc_option_set(smbw_ctx, "one_share_per_server", 1);
|
||||
|
||||
if (smbc_init_context(smbw_ctx) == NULL) {
|
||||
fprintf(stderr, "Could not initialize context.\n");
|
||||
|
@ -108,7 +108,8 @@ main(int argc, char * argv[])
|
||||
}
|
||||
|
||||
/* Set mandatory options (is that a contradiction in terms?) */
|
||||
context->debug = debug;
|
||||
smbc_setDebug(context, debug);
|
||||
#if 0
|
||||
if (context_auth) {
|
||||
context->callbacks.auth_fn = NULL;
|
||||
smbc_option_set(context,
|
||||
@ -119,6 +120,11 @@ main(int argc, char * argv[])
|
||||
context->callbacks.auth_fn =
|
||||
(no_auth ? no_auth_data_fn : get_auth_data_fn);
|
||||
}
|
||||
#else
|
||||
#warning "temporarily remove setting alternate auth function"
|
||||
smbc_setFunctionAuthData(context,
|
||||
(no_auth ? no_auth_data_fn : get_auth_data_fn));
|
||||
#endif
|
||||
|
||||
/* If we've been asked to log to stderr instead of stdout, ... */
|
||||
if (debug_stderr) {
|
||||
|
@ -93,8 +93,8 @@ SMBCCTX* create_smbctx(){
|
||||
|
||||
if ((ctx = smbc_new_context()) == NULL) return NULL;
|
||||
|
||||
ctx->debug = debuglevel;
|
||||
ctx->callbacks.auth_fn = smbc_auth_fn;
|
||||
smbc_setDebug(ctx, debuglevel);
|
||||
smbc_setFunctionAuthData(ctx, smbc_auth_fn);
|
||||
|
||||
if (smbc_init_context(ctx) == NULL){
|
||||
smbc_free_context(ctx, 1);
|
||||
@ -105,7 +105,7 @@ SMBCCTX* create_smbctx(){
|
||||
}
|
||||
|
||||
void delete_smbctx(SMBCCTX* ctx){
|
||||
ctx->callbacks.purge_cached_fn(ctx);
|
||||
smbc_getFunctionPurgeCachedServers(ctx)(ctx);
|
||||
smbc_free_context(ctx, 1);
|
||||
}
|
||||
|
||||
@ -114,8 +114,9 @@ smbitem* get_smbitem_list(SMBCCTX *ctx, char *smb_path){
|
||||
struct smbc_dirent *dirent;
|
||||
smbitem *list = NULL, *item;
|
||||
|
||||
if ((fd = ctx->opendir(ctx, smb_path)) == NULL) return NULL;
|
||||
while((dirent = ctx->readdir(ctx, fd)) != NULL){
|
||||
if ((fd = smbc_getFunctionOpendir(ctx)(ctx, smb_path)) == NULL)
|
||||
return NULL;
|
||||
while((dirent = smbc_getFunctionReaddir(ctx)(ctx, fd)) != NULL){
|
||||
if (strcmp(dirent->name, "") == 0) continue;
|
||||
if (strcmp(dirent->name, ".") == 0) continue;
|
||||
if (strcmp(dirent->name, "..") == 0) continue;
|
||||
@ -128,7 +129,7 @@ smbitem* get_smbitem_list(SMBCCTX *ctx, char *smb_path){
|
||||
strcpy(item->name, dirent->name);
|
||||
list = item;
|
||||
}
|
||||
ctx->close_fn(ctx, fd);
|
||||
smbc_getFunctionClose(ctx)(ctx, fd);
|
||||
return /* smbitem_list_sort */ (list);
|
||||
|
||||
}
|
||||
@ -167,7 +168,7 @@ void recurse(SMBCCTX *ctx, char *smb_group, char *smb_path, int maxlen){
|
||||
delete_smbctx(ctx1);
|
||||
}else{
|
||||
recurse(ctx, smb_group, smb_path, maxlen);
|
||||
ctx->callbacks.purge_cached_fn(ctx);
|
||||
smbc_getFunctionPurgeCachedServers(ctx)(ctx);
|
||||
}
|
||||
break;
|
||||
case SMBC_FILE_SHARE:
|
||||
@ -181,7 +182,7 @@ void recurse(SMBCCTX *ctx, char *smb_group, char *smb_path, int maxlen){
|
||||
if (list->type != SMBC_FILE){
|
||||
recurse(ctx, smb_group, smb_path, maxlen);
|
||||
if (list->type == SMBC_FILE_SHARE)
|
||||
ctx->callbacks.purge_cached_fn(ctx);
|
||||
smbc_getFunctionPurgeCachedServers(ctx)(ctx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -763,8 +763,18 @@ RPCCLIENT_OBJ = $(RPCCLIENT_OBJ1) \
|
||||
PAM_WINBIND_OBJ = nsswitch/pam_winbind.o $(WBCOMMON_OBJ) \
|
||||
$(LIBREPLACE_OBJ) @BUILD_INIPARSER@
|
||||
|
||||
LIBSMBCLIENT_OBJ0 = libsmb/libsmbclient.o libsmb/libsmb_compat.o \
|
||||
LIBSMBCLIENT_OBJ0 = \
|
||||
libsmb/libsmb_cache.o \
|
||||
libsmb/libsmb_compat.o \
|
||||
libsmb/libsmb_context.o \
|
||||
libsmb/libsmb_dir.o \
|
||||
libsmb/libsmb_file.o \
|
||||
libsmb/libsmb_misc.o \
|
||||
libsmb/libsmb_path.o \
|
||||
libsmb/libsmb_printjob.o \
|
||||
libsmb/libsmb_server.o \
|
||||
libsmb/libsmb_stat.o \
|
||||
libsmb/libsmb_xattr.o \
|
||||
$(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
|
||||
$(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
|
||||
$(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(RPC_PARSE_OBJ) \
|
||||
|
@ -1,12 +1,71 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
SMB client library implementation
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
Copyright (C) Richard Sharpe 2000, 2002
|
||||
Copyright (C) John Terpstra 2000
|
||||
Copyright (C) Tom Jansen (Ninja ISD) 2002
|
||||
Copyright (C) Derrell Lipman 2003-2008
|
||||
Copyright (C) Jeremy Allison 2007, 2008
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
|
||||
#ifndef _LIBSMB_INTERNAL_H_
|
||||
#define _LIBSMB_INTERNAL_H_
|
||||
|
||||
#include "../include/libsmbclient.h"
|
||||
|
||||
#define SMBC_MAX_NAME 1023
|
||||
#define SMBC_FILE_MODE (S_IFREG | 0444)
|
||||
#define SMBC_DIR_MODE (S_IFDIR | 0555)
|
||||
|
||||
/*
|
||||
* DOS Attribute values (used internally)
|
||||
*/
|
||||
typedef struct DOS_ATTR_DESC {
|
||||
int mode;
|
||||
SMB_OFF_T size;
|
||||
time_t create_time;
|
||||
time_t access_time;
|
||||
time_t write_time;
|
||||
time_t change_time;
|
||||
SMB_INO_T inode;
|
||||
} DOS_ATTR_DESC;
|
||||
|
||||
#include "include/libsmbclient.h"
|
||||
|
||||
/*
|
||||
* Internal flags for extended attributes
|
||||
*/
|
||||
|
||||
/* internal mode values */
|
||||
#define SMBC_XATTR_MODE_ADD 1
|
||||
#define SMBC_XATTR_MODE_REMOVE 2
|
||||
#define SMBC_XATTR_MODE_REMOVE_ALL 3
|
||||
#define SMBC_XATTR_MODE_SET 4
|
||||
#define SMBC_XATTR_MODE_CHOWN 5
|
||||
#define SMBC_XATTR_MODE_CHGRP 6
|
||||
|
||||
#define CREATE_ACCESS_READ READ_CONTROL_ACCESS
|
||||
|
||||
/*We should test for this in configure ... */
|
||||
#ifndef ENOTSUP
|
||||
#define ENOTSUP EOPNOTSUPP
|
||||
#endif
|
||||
|
||||
|
||||
struct _SMBCSRV {
|
||||
@ -46,12 +105,28 @@ struct _SMBCFILE {
|
||||
};
|
||||
|
||||
|
||||
struct smbc_internal_data {
|
||||
/*
|
||||
* Context structure
|
||||
*/
|
||||
struct _SMBCCTX {
|
||||
|
||||
/*
|
||||
* Is this handle initialized ?
|
||||
*/
|
||||
bool _initialized;
|
||||
/* True when this handle is initialized */
|
||||
bool initialized;
|
||||
|
||||
/* Netbios name used for making connections */
|
||||
char * netbios_name;
|
||||
|
||||
/* Workgroup used for making connections */
|
||||
char * workgroup;
|
||||
|
||||
/* Username used for making connections */
|
||||
char * user;
|
||||
|
||||
/* Debug level */
|
||||
int debug;
|
||||
|
||||
/* Connection timeout value */
|
||||
int timeout;
|
||||
|
||||
/* dirent pointer location
|
||||
*
|
||||
@ -64,22 +139,22 @@ struct smbc_internal_data {
|
||||
* According to <linux/limits.h>, NAME_MAX is 255. Is it longer
|
||||
* anyplace else?
|
||||
*/
|
||||
char _dirent[1024];
|
||||
char dirent[1024];
|
||||
|
||||
/*
|
||||
* server connection list
|
||||
*/
|
||||
SMBCSRV * _servers;
|
||||
SMBCSRV * servers;
|
||||
|
||||
/*
|
||||
* open file/dir list
|
||||
*/
|
||||
SMBCFILE * _files;
|
||||
SMBCFILE * files;
|
||||
|
||||
/*
|
||||
* Log to standard error instead of the more typical standard output
|
||||
*/
|
||||
bool _debug_stderr;
|
||||
bool debug_stderr;
|
||||
|
||||
/*
|
||||
* Support "Create Time" in get/set with the *xattr() functions, if
|
||||
@ -88,33 +163,456 @@ struct smbc_internal_data {
|
||||
* CREATE_TIME. Default is FALSE, i.e. to use the old-style shorter
|
||||
* names and to not support CREATE time, for backward compatibility.
|
||||
*/
|
||||
bool _full_time_names;
|
||||
bool full_time_names;
|
||||
|
||||
/*
|
||||
* The share mode of a file being opened. To match POSIX semantics
|
||||
* (and maintain backward compatibility), DENY_NONE is the default.
|
||||
*/
|
||||
smbc_share_mode _share_mode;
|
||||
|
||||
/*
|
||||
* Authentication function which includes the context. This will be
|
||||
* used if set; otherwise context->callbacks.auth_fn() will be used.
|
||||
*/
|
||||
smbc_get_auth_data_with_context_fn _auth_fn_with_context;
|
||||
smbc_share_mode share_mode;
|
||||
|
||||
/*
|
||||
* An opaque (to this library) user data handle which can be set
|
||||
* and retrieved with smbc_option_set() and smbc_option_get().
|
||||
*/
|
||||
void * _user_data;
|
||||
void * user_data;
|
||||
|
||||
/*
|
||||
* Should we attempt UNIX smb encryption ?
|
||||
* Set to 0 if we should never attempt, set to 1 if
|
||||
* encryption requested, set to 2 if encryption required.
|
||||
*/
|
||||
int _smb_encryption_level;
|
||||
int smb_encryption_level;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
bool 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.
|
||||
*/
|
||||
bool one_share_per_server;
|
||||
|
||||
/* Kerberos-related flags */
|
||||
bool use_kerberos;
|
||||
bool fallback_after_kerberos;
|
||||
|
||||
/* Don't try to do automatic anonymous login */
|
||||
bool no_auto_anonymous_login;
|
||||
|
||||
/* Server-related functions */
|
||||
struct
|
||||
{
|
||||
smbc_get_auth_data_fn get_auth_data_fn;
|
||||
smbc_check_server_fn check_server_fn;
|
||||
smbc_remove_unused_server_fn remove_unused_server_fn;
|
||||
} server;
|
||||
|
||||
/* Cache-related functions */
|
||||
struct
|
||||
{
|
||||
struct smbc_server_cache * server_cache_data;
|
||||
smbc_add_cached_srv_fn add_cached_server_fn;
|
||||
smbc_get_cached_srv_fn get_cached_server_fn;
|
||||
smbc_remove_cached_srv_fn remove_cached_server_fn;
|
||||
smbc_purge_cached_srv_fn purge_cached_server_fn;
|
||||
} cache;
|
||||
|
||||
/* POSIX emulation functions */
|
||||
struct
|
||||
{
|
||||
smbc_open_fn open_fn;
|
||||
smbc_creat_fn creat_fn;
|
||||
smbc_read_fn read_fn;
|
||||
smbc_write_fn write_fn;
|
||||
smbc_unlink_fn unlink_fn;
|
||||
smbc_rename_fn rename_fn;
|
||||
smbc_lseek_fn lseek_fn;
|
||||
smbc_ftruncate_fn ftruncate_fn;
|
||||
smbc_stat_fn stat_fn;
|
||||
smbc_fstat_fn fstat_fn;
|
||||
smbc_close_fn close_fn;
|
||||
smbc_opendir_fn opendir_fn;
|
||||
smbc_closedir_fn closedir_fn;
|
||||
smbc_readdir_fn readdir_fn;
|
||||
smbc_getdents_fn getdents_fn;
|
||||
smbc_mkdir_fn mkdir_fn;
|
||||
smbc_rmdir_fn rmdir_fn;
|
||||
smbc_telldir_fn telldir_fn;
|
||||
smbc_lseekdir_fn lseekdir_fn;
|
||||
smbc_fstatdir_fn fstatdir_fn;
|
||||
smbc_chmod_fn chmod_fn;
|
||||
smbc_utimes_fn utimes_fn;
|
||||
smbc_setxattr_fn setxattr_fn;
|
||||
smbc_getxattr_fn getxattr_fn;
|
||||
smbc_removexattr_fn removexattr_fn;
|
||||
smbc_listxattr_fn listxattr_fn;
|
||||
} posix_emu;
|
||||
|
||||
/* Printing-related functions */
|
||||
struct
|
||||
{
|
||||
smbc_print_file_fn print_file_fn;
|
||||
smbc_open_print_job_fn open_print_job_fn;
|
||||
smbc_list_print_jobs_fn list_print_jobs_fn;
|
||||
smbc_unlink_print_job_fn unlink_print_job_fn;
|
||||
} printing;
|
||||
|
||||
#if 0 /* not yet */
|
||||
/* SMB high-level functions */
|
||||
struct
|
||||
{
|
||||
} smb;
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Functions in libsmb_cache.c */
|
||||
int
|
||||
SMBC_add_cached_server(SMBCCTX * context,
|
||||
SMBCSRV * newsrv,
|
||||
const char * server,
|
||||
const char * share,
|
||||
const char * workgroup,
|
||||
const char * username);
|
||||
|
||||
SMBCSRV *
|
||||
SMBC_get_cached_server(SMBCCTX * context,
|
||||
const char * server,
|
||||
const char * share,
|
||||
const char * workgroup,
|
||||
const char * user);
|
||||
|
||||
int
|
||||
SMBC_remove_cached_server(SMBCCTX * context,
|
||||
SMBCSRV * server);
|
||||
|
||||
int
|
||||
SMBC_purge_cached_servers(SMBCCTX * context);
|
||||
|
||||
|
||||
/* Functions in libsmb_dir.c */
|
||||
int
|
||||
SMBC_check_options(char *server,
|
||||
char *share,
|
||||
char *path,
|
||||
char *options);
|
||||
|
||||
SMBCFILE *
|
||||
SMBC_opendir_ctx(SMBCCTX *context,
|
||||
const char *fname);
|
||||
|
||||
int
|
||||
SMBC_closedir_ctx(SMBCCTX *context,
|
||||
SMBCFILE *dir);
|
||||
|
||||
struct smbc_dirent *
|
||||
SMBC_readdir_ctx(SMBCCTX *context,
|
||||
SMBCFILE *dir);
|
||||
|
||||
int
|
||||
SMBC_getdents_ctx(SMBCCTX *context,
|
||||
SMBCFILE *dir,
|
||||
struct smbc_dirent *dirp,
|
||||
int count);
|
||||
|
||||
int
|
||||
SMBC_mkdir_ctx(SMBCCTX *context,
|
||||
const char *fname,
|
||||
mode_t mode);
|
||||
|
||||
int
|
||||
SMBC_rmdir_ctx(SMBCCTX *context,
|
||||
const char *fname);
|
||||
|
||||
off_t
|
||||
SMBC_telldir_ctx(SMBCCTX *context,
|
||||
SMBCFILE *dir);
|
||||
|
||||
int
|
||||
SMBC_lseekdir_ctx(SMBCCTX *context,
|
||||
SMBCFILE *dir,
|
||||
off_t offset);
|
||||
|
||||
int
|
||||
SMBC_fstatdir_ctx(SMBCCTX *context,
|
||||
SMBCFILE *dir,
|
||||
struct stat *st);
|
||||
|
||||
int
|
||||
SMBC_chmod_ctx(SMBCCTX *context,
|
||||
const char *fname,
|
||||
mode_t newmode);
|
||||
|
||||
int
|
||||
SMBC_utimes_ctx(SMBCCTX *context,
|
||||
const char *fname,
|
||||
struct timeval *tbuf);
|
||||
|
||||
int
|
||||
SMBC_unlink_ctx(SMBCCTX *context,
|
||||
const char *fname);
|
||||
|
||||
int
|
||||
SMBC_rename_ctx(SMBCCTX *ocontext,
|
||||
const char *oname,
|
||||
SMBCCTX *ncontext,
|
||||
const char *nname);
|
||||
|
||||
|
||||
/* Functions in libsmb_file.c */
|
||||
SMBCFILE *
|
||||
SMBC_open_ctx(SMBCCTX *context,
|
||||
const char *fname,
|
||||
int flags,
|
||||
mode_t mode);
|
||||
|
||||
SMBCFILE *
|
||||
SMBC_creat_ctx(SMBCCTX *context,
|
||||
const char *path,
|
||||
mode_t mode);
|
||||
|
||||
ssize_t
|
||||
SMBC_read_ctx(SMBCCTX *context,
|
||||
SMBCFILE *file,
|
||||
void *buf,
|
||||
size_t count);
|
||||
|
||||
ssize_t
|
||||
SMBC_write_ctx(SMBCCTX *context,
|
||||
SMBCFILE *file,
|
||||
void *buf,
|
||||
size_t count);
|
||||
|
||||
int
|
||||
SMBC_close_ctx(SMBCCTX *context,
|
||||
SMBCFILE *file);
|
||||
|
||||
bool
|
||||
SMBC_getatr(SMBCCTX * context,
|
||||
SMBCSRV *srv,
|
||||
char *path,
|
||||
uint16 *mode,
|
||||
SMB_OFF_T *size,
|
||||
struct timespec *create_time_ts,
|
||||
struct timespec *access_time_ts,
|
||||
struct timespec *write_time_ts,
|
||||
struct timespec *change_time_ts,
|
||||
SMB_INO_T *ino);
|
||||
|
||||
bool
|
||||
SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path,
|
||||
time_t create_time,
|
||||
time_t access_time,
|
||||
time_t write_time,
|
||||
time_t change_time,
|
||||
uint16 mode);
|
||||
|
||||
off_t
|
||||
SMBC_lseek_ctx(SMBCCTX *context,
|
||||
SMBCFILE *file,
|
||||
off_t offset,
|
||||
int whence);
|
||||
|
||||
int
|
||||
SMBC_ftruncate_ctx(SMBCCTX *context,
|
||||
SMBCFILE *file,
|
||||
off_t length);
|
||||
|
||||
|
||||
/* Functions in libsmb_misc.c */
|
||||
int
|
||||
SMBC_dlist_contains(SMBCFILE * list, SMBCFILE *p);
|
||||
|
||||
int
|
||||
SMBC_errno(SMBCCTX *context,
|
||||
struct cli_state *c);
|
||||
|
||||
|
||||
/* Functions in libsmb_path.c */
|
||||
int
|
||||
SMBC_urldecode(char *dest,
|
||||
char *src,
|
||||
size_t max_dest_len);
|
||||
|
||||
int
|
||||
SMBC_urlencode(char *dest,
|
||||
char *src,
|
||||
int max_dest_len);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
/* Functions in libsmb_printjob.c */
|
||||
SMBCFILE *
|
||||
SMBC_open_print_job_ctx(SMBCCTX *context,
|
||||
const char *fname);
|
||||
|
||||
int
|
||||
SMBC_print_file_ctx(SMBCCTX *c_file,
|
||||
const char *fname,
|
||||
SMBCCTX *c_print,
|
||||
const char *printq);
|
||||
|
||||
int
|
||||
SMBC_list_print_jobs_ctx(SMBCCTX *context,
|
||||
const char *fname,
|
||||
smbc_list_print_job_fn fn);
|
||||
|
||||
int
|
||||
SMBC_unlink_print_job_ctx(SMBCCTX *context,
|
||||
const char *fname,
|
||||
int id);
|
||||
|
||||
|
||||
/* Functions in libsmb_server.c */
|
||||
int
|
||||
SMBC_check_server(SMBCCTX * context,
|
||||
SMBCSRV * server);
|
||||
|
||||
int
|
||||
SMBC_remove_unused_server(SMBCCTX * context,
|
||||
SMBCSRV * srv);
|
||||
|
||||
void
|
||||
SMBC_call_auth_fn(TALLOC_CTX *ctx,
|
||||
SMBCCTX *context,
|
||||
const char *server,
|
||||
const char *share,
|
||||
char **pp_workgroup,
|
||||
char **pp_username,
|
||||
char **pp_password);
|
||||
|
||||
void
|
||||
SMBC_get_auth_data(const char *server, const char *share,
|
||||
char *workgroup_buf, int workgroup_buf_len,
|
||||
char *username_buf, int username_buf_len,
|
||||
char *password_buf, int password_buf_len);
|
||||
|
||||
SMBCSRV *
|
||||
SMBC_find_server(TALLOC_CTX *ctx,
|
||||
SMBCCTX *context,
|
||||
const char *server,
|
||||
const char *share,
|
||||
char **pp_workgroup,
|
||||
char **pp_username,
|
||||
char **pp_password);
|
||||
|
||||
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 *
|
||||
SMBC_attr_server(TALLOC_CTX *ctx,
|
||||
SMBCCTX *context,
|
||||
const char *server,
|
||||
const char *share,
|
||||
char **pp_workgroup,
|
||||
char **pp_username,
|
||||
char **pp_password);
|
||||
|
||||
|
||||
/* Functions in libsmb_stat.c */
|
||||
int
|
||||
SMBC_stat_ctx(SMBCCTX *context,
|
||||
const char *fname,
|
||||
struct stat *st);
|
||||
|
||||
int
|
||||
SMBC_fstat_ctx(SMBCCTX *context,
|
||||
SMBCFILE *file,
|
||||
struct stat *st);
|
||||
|
||||
|
||||
/* Functions in libsmb_xattr.c */
|
||||
int
|
||||
SMBC_setxattr_ctx(SMBCCTX *context,
|
||||
const char *fname,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size,
|
||||
int flags);
|
||||
|
||||
int
|
||||
SMBC_getxattr_ctx(SMBCCTX *context,
|
||||
const char *fname,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size);
|
||||
|
||||
int
|
||||
SMBC_removexattr_ctx(SMBCCTX *context,
|
||||
const char *fname,
|
||||
const char *name);
|
||||
|
||||
int
|
||||
SMBC_listxattr_ctx(SMBCCTX *context,
|
||||
const char *fname,
|
||||
char *list,
|
||||
size_t size);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -386,221 +386,310 @@ typedef int (*smbc_remove_cached_srv_fn)(SMBCCTX * c, SMBCSRV *srv);
|
||||
* @return 0 when found and removed. 1 on failure.
|
||||
*
|
||||
*/
|
||||
typedef int (*smbc_purge_cached_fn) (SMBCCTX * c);
|
||||
typedef int (*smbc_purge_cached_srv_fn) (SMBCCTX * c);
|
||||
|
||||
|
||||
/**@ingroup structure
|
||||
* Structure that contains a client context information
|
||||
* This structure is know as SMBCCTX
|
||||
/** Get the debug level */
|
||||
int smbc_getDebug(SMBCCTX *c);
|
||||
|
||||
/** Set the debug level */
|
||||
void smbc_setDebug(SMBCCTX *c, int debug);
|
||||
|
||||
/** Get the netbios name used for making connections */
|
||||
char * smbc_getNetbiosName(SMBCCTX *c);
|
||||
|
||||
/** Set the netbios name used for making connections */
|
||||
void smbc_setNetbiosName(SMBCCTX *c, char * netbios_name);
|
||||
|
||||
/** Get the workgroup used for making connections */
|
||||
char * smbc_getWorkgroup(SMBCCTX *c);
|
||||
|
||||
/** Set the workgroup used for making connections */
|
||||
void smbc_setWorkgroup(SMBCCTX *c, char * workgroup);
|
||||
|
||||
/** Get the username used for making connections */
|
||||
char * smbc_getUser(SMBCCTX *c);
|
||||
|
||||
/** Set the username used for making connections */
|
||||
void smbc_setUser(SMBCCTX *c, char * user);
|
||||
|
||||
/**
|
||||
* Get the timeout used for waiting on connections and response data
|
||||
* (in milliseconds)
|
||||
*/
|
||||
struct _SMBCCTX {
|
||||
/** debug level
|
||||
*/
|
||||
int debug;
|
||||
|
||||
/** netbios name used for making connections
|
||||
*/
|
||||
char * netbios_name;
|
||||
int smbc_getTimeout(SMBCCTX *c);
|
||||
|
||||
/** workgroup name used for making connections
|
||||
*/
|
||||
char * workgroup;
|
||||
/**
|
||||
* Set the timeout used for waiting on connections and response data
|
||||
* (in milliseconds)
|
||||
*/
|
||||
void smbc_setTimeout(SMBCCTX *c, int timeout);
|
||||
|
||||
/** username used for making connections
|
||||
*/
|
||||
char * user;
|
||||
/** Get the function for obtaining authentication data */
|
||||
smbc_get_auth_data_fn smbc_getFunctionAuthData(SMBCCTX *c);
|
||||
|
||||
/** timeout used for waiting on connections / response data (in milliseconds)
|
||||
*/
|
||||
int timeout;
|
||||
/** Set the function for obtaining authentication data */
|
||||
void smbc_setFunctionAuthData(SMBCCTX *c, smbc_get_auth_data_fn f);
|
||||
|
||||
/** callable functions for files:
|
||||
* For usage and return values see the smbc_* functions
|
||||
*/
|
||||
SMBCFILE * (*open) (SMBCCTX *c, const char *fname, int flags, mode_t mode);
|
||||
SMBCFILE * (*creat) (SMBCCTX *c, const char *path, mode_t mode);
|
||||
ssize_t (*read) (SMBCCTX *c, SMBCFILE *file, void *buf, size_t count);
|
||||
ssize_t (*write) (SMBCCTX *c, SMBCFILE *file, void *buf, size_t count);
|
||||
int (*unlink) (SMBCCTX *c, const char *fname);
|
||||
int (*rename) (SMBCCTX *ocontext, const char *oname,
|
||||
SMBCCTX *ncontext, const char *nname);
|
||||
off_t (*lseek) (SMBCCTX *c, SMBCFILE * file, off_t offset, int whence);
|
||||
int (*stat) (SMBCCTX *c, const char *fname, struct stat *st);
|
||||
int (*fstat) (SMBCCTX *c, SMBCFILE *file, struct stat *st);
|
||||
/* ftruncate added near _internal for ABI compatibility */
|
||||
|
||||
int (*close_fn) (SMBCCTX *c, SMBCFILE *file);
|
||||
/** Get the function for checking if a server is still good */
|
||||
smbc_check_server_fn smbc_getFunctionCheckServer(SMBCCTX *c);
|
||||
|
||||
/** callable functions for dirs
|
||||
*/
|
||||
SMBCFILE * (*opendir) (SMBCCTX *c, const char *fname);
|
||||
int (*closedir)(SMBCCTX *c, SMBCFILE *dir);
|
||||
struct smbc_dirent * (*readdir)(SMBCCTX *c, SMBCFILE *dir);
|
||||
int (*getdents)(SMBCCTX *c, SMBCFILE *dir,
|
||||
struct smbc_dirent *dirp, int count);
|
||||
int (*mkdir) (SMBCCTX *c, const char *fname, mode_t mode);
|
||||
int (*rmdir) (SMBCCTX *c, const char *fname);
|
||||
off_t (*telldir) (SMBCCTX *c, SMBCFILE *dir);
|
||||
int (*lseekdir)(SMBCCTX *c, SMBCFILE *dir, off_t offset);
|
||||
int (*fstatdir)(SMBCCTX *c, SMBCFILE *dir, struct stat *st);
|
||||
int (*chmod)(SMBCCTX *c, const char *fname, mode_t mode);
|
||||
int (*utimes)(SMBCCTX *c,
|
||||
const char *fname, struct timeval *tbuf);
|
||||
int (*setxattr)(SMBCCTX *context,
|
||||
const char *fname,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size,
|
||||
int flags);
|
||||
int (*getxattr)(SMBCCTX *context,
|
||||
const char *fname,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size);
|
||||
int (*removexattr)(SMBCCTX *context,
|
||||
const char *fname,
|
||||
const char *name);
|
||||
int (*listxattr)(SMBCCTX *context,
|
||||
/** Set the function for checking if a server is still good */
|
||||
void smbc_setFunctionCheckServer(SMBCCTX *c, smbc_check_server_fn f);
|
||||
|
||||
/** Get the function for removing a server if unused */
|
||||
smbc_remove_unused_server_fn smbc_getFunctionRemoveUnusedServer(SMBCCTX *c);
|
||||
|
||||
/** Set the function for removing a server if unused */
|
||||
void smbc_setFunctionRemoveUnusedServer(SMBCCTX *c,
|
||||
smbc_remove_unused_server_fn f);
|
||||
|
||||
/** Get the function for adding a cached server */
|
||||
smbc_add_cached_srv_fn smbc_getFunctionAddCachedServer(SMBCCTX *c);
|
||||
|
||||
/** Set the function for adding a cached server */
|
||||
void smbc_setFunctionAddCachedServer(SMBCCTX *c, smbc_add_cached_srv_fn f);
|
||||
|
||||
/** Get the function for server cache lookup */
|
||||
smbc_get_cached_srv_fn smbc_getFunctionGetCachedServer(SMBCCTX *c);
|
||||
|
||||
/** Set the function for server cache lookup */
|
||||
void smbc_setFunctionGetCachedServer(SMBCCTX *c, smbc_get_cached_srv_fn f);
|
||||
|
||||
/** Get the function for server cache removal */
|
||||
smbc_remove_cached_srv_fn smbc_getFunctionRemoveCachedServer(SMBCCTX *c);
|
||||
|
||||
/** Set the function for server cache removal */
|
||||
void smbc_setFunctionRemoveCachedServer(SMBCCTX *c,
|
||||
smbc_remove_cached_srv_fn f);
|
||||
|
||||
/**
|
||||
* Get the function for server cache purging. This function tries to
|
||||
* remove all cached servers (e.g. on disconnect)
|
||||
*/
|
||||
smbc_purge_cached_srv_fn smbc_getFunctionPurgeCachedServers(SMBCCTX *c);
|
||||
|
||||
/**
|
||||
* Set the function for server cache purging. This function tries to
|
||||
* remove all cached servers (e.g. on disconnect)
|
||||
*/
|
||||
void smbc_setFunctionPurgeCachedServers(SMBCCTX *c,
|
||||
smbc_purge_cached_srv_fn f);
|
||||
|
||||
/** Get the function to store private data of the server cache */
|
||||
struct smbc_server_cache * smbc_getServerCacheData(SMBCCTX *c);
|
||||
|
||||
/** Set the function to store private data of the server cache */
|
||||
void smbc_setServerCacheData(SMBCCTX *c, struct smbc_server_cache * cache);
|
||||
|
||||
|
||||
/**
|
||||
* Callable functions for files.
|
||||
*/
|
||||
|
||||
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 f);
|
||||
|
||||
typedef SMBCFILE * (*smbc_creat_fn)(SMBCCTX *c,
|
||||
const char *path,
|
||||
mode_t mode);
|
||||
smbc_creat_fn smbc_getFunctionCreat(SMBCCTX *c);
|
||||
void smbc_setFunctionCreat(SMBCCTX *c, smbc_creat_fn);
|
||||
|
||||
typedef ssize_t (*smbc_read_fn)(SMBCCTX *c,
|
||||
SMBCFILE *file,
|
||||
void *buf,
|
||||
size_t count);
|
||||
smbc_read_fn smbc_getFunctionRead(SMBCCTX *c);
|
||||
void smbc_setFunctionRead(SMBCCTX *c, smbc_read_fn f);
|
||||
|
||||
typedef ssize_t (*smbc_write_fn)(SMBCCTX *c,
|
||||
SMBCFILE *file,
|
||||
void *buf,
|
||||
size_t count);
|
||||
smbc_write_fn smbc_getFunctionWrite(SMBCCTX *c);
|
||||
void smbc_setFunctionWrite(SMBCCTX *c, smbc_write_fn f);
|
||||
|
||||
typedef int (*smbc_unlink_fn)(SMBCCTX *c,
|
||||
const char *fname);
|
||||
smbc_unlink_fn smbc_getFunctionUnlink(SMBCCTX *c);
|
||||
void smbc_setFunctionUnlink(SMBCCTX *c, smbc_unlink_fn f);
|
||||
|
||||
typedef int (*smbc_rename_fn)(SMBCCTX *ocontext,
|
||||
const char *oname,
|
||||
SMBCCTX *ncontext,
|
||||
const char *nname);
|
||||
smbc_rename_fn smbc_getFunctionRename(SMBCCTX *c);
|
||||
void smbc_setFunctionRename(SMBCCTX *c, smbc_rename_fn f);
|
||||
|
||||
typedef off_t (*smbc_lseek_fn)(SMBCCTX *c,
|
||||
SMBCFILE * file,
|
||||
off_t offset,
|
||||
int whence);
|
||||
smbc_lseek_fn smbc_getFunctionLseek(SMBCCTX *c);
|
||||
void smbc_setFunctionLseek(SMBCCTX *c, smbc_lseek_fn f);
|
||||
|
||||
typedef int (*smbc_stat_fn)(SMBCCTX *c,
|
||||
const char *fname,
|
||||
struct stat *st);
|
||||
smbc_stat_fn smbc_getFunctionStat(SMBCCTX *c);
|
||||
void smbc_setFunctionStat(SMBCCTX *c, smbc_stat_fn f);
|
||||
|
||||
typedef int (*smbc_fstat_fn)(SMBCCTX *c,
|
||||
SMBCFILE *file,
|
||||
struct stat *st);
|
||||
smbc_fstat_fn smbc_getFunctionFstat(SMBCCTX *c);
|
||||
void smbc_setFunctionFstat(SMBCCTX *c, smbc_fstat_fn f);
|
||||
|
||||
typedef int (*smbc_ftruncate_fn)(SMBCCTX *c,
|
||||
SMBCFILE *f,
|
||||
off_t size);
|
||||
smbc_ftruncate_fn smbc_getFunctionFtruncate(SMBCCTX *c);
|
||||
void smbc_setFunctionFtruncate(SMBCCTX *c, smbc_ftruncate_fn f);
|
||||
|
||||
typedef int (*smbc_close_fn)(SMBCCTX *c,
|
||||
SMBCFILE *file);
|
||||
smbc_close_fn smbc_getFunctionClose(SMBCCTX *c);
|
||||
void smbc_setFunctionClose(SMBCCTX *c, smbc_close_fn f);
|
||||
|
||||
|
||||
/**
|
||||
* Callable functions for directories.
|
||||
*/
|
||||
|
||||
typedef SMBCFILE * (*smbc_opendir_fn)(SMBCCTX *c,
|
||||
const char *fname);
|
||||
smbc_opendir_fn smbc_getFunctionOpendir(SMBCCTX *c);
|
||||
void smbc_setFunctionOpendir(SMBCCTX *c, smbc_opendir_fn f);
|
||||
|
||||
typedef int (*smbc_closedir_fn)(SMBCCTX *c,
|
||||
SMBCFILE *dir);
|
||||
smbc_closedir_fn smbc_getFunctionClosedir(SMBCCTX *c);
|
||||
void smbc_setFunctionClosedir(SMBCCTX *c, smbc_closedir_fn f);
|
||||
|
||||
typedef struct smbc_dirent * (*smbc_readdir_fn)(SMBCCTX *c,
|
||||
SMBCFILE *dir);
|
||||
smbc_readdir_fn smbc_getFunctionReaddir(SMBCCTX *c);
|
||||
void smbc_setFunctionReaddir(SMBCCTX *c, smbc_readdir_fn f);
|
||||
|
||||
typedef int (*smbc_getdents_fn)(SMBCCTX *c,
|
||||
SMBCFILE *dir,
|
||||
struct smbc_dirent *dirp,
|
||||
int count);
|
||||
smbc_getdents_fn smbc_getFunctionGetdents(SMBCCTX *c);
|
||||
void smbc_setFunctionGetdents(SMBCCTX *c, smbc_getdents_fn f);
|
||||
|
||||
typedef int (*smbc_mkdir_fn)(SMBCCTX *c,
|
||||
const char *fname,
|
||||
mode_t mode);
|
||||
smbc_mkdir_fn smbc_getFunctionMkdir(SMBCCTX *c);
|
||||
void smbc_setFunctionMkdir(SMBCCTX *c, smbc_mkdir_fn f);
|
||||
|
||||
typedef int (*smbc_rmdir_fn)(SMBCCTX *c,
|
||||
const char *fname);
|
||||
smbc_rmdir_fn smbc_getFunctionRmdir(SMBCCTX *c);
|
||||
void smbc_setFunctionRmdir(SMBCCTX *c, smbc_rmdir_fn f);
|
||||
|
||||
typedef off_t (*smbc_telldir_fn)(SMBCCTX *c,
|
||||
SMBCFILE *dir);
|
||||
smbc_telldir_fn smbc_getFunctionTelldir(SMBCCTX *c);
|
||||
void smbc_setFunctionTelldir(SMBCCTX *c, smbc_telldir_fn f);
|
||||
|
||||
typedef int (*smbc_lseekdir_fn)(SMBCCTX *c,
|
||||
SMBCFILE *dir,
|
||||
off_t offset);
|
||||
smbc_lseekdir_fn smbc_getFunctionLseekdir(SMBCCTX *c);
|
||||
void smbc_setFunctionLseekdir(SMBCCTX *c, smbc_lseekdir_fn f);
|
||||
|
||||
typedef int (*smbc_fstatdir_fn)(SMBCCTX *c,
|
||||
SMBCFILE *dir,
|
||||
struct stat *st);
|
||||
smbc_fstatdir_fn smbc_getFunctionFstatdir(SMBCCTX *c);
|
||||
void smbc_setFunctionFstatdir(SMBCCTX *c, smbc_fstatdir_fn f);
|
||||
|
||||
|
||||
/**
|
||||
* Callable functions applicable to both files and directories.
|
||||
*/
|
||||
|
||||
typedef int (*smbc_chmod_fn)(SMBCCTX *c,
|
||||
const char *fname,
|
||||
mode_t mode);
|
||||
smbc_chmod_fn smbc_getFunctionChmod(SMBCCTX *c);
|
||||
void smbc_setFunctionChmod(SMBCCTX *c, smbc_chmod_fn f);
|
||||
|
||||
typedef int (*smbc_utimes_fn)(SMBCCTX *c,
|
||||
const char *fname,
|
||||
struct timeval *tbuf);
|
||||
smbc_utimes_fn smbc_getFunctionUtimes(SMBCCTX *c);
|
||||
void smbc_setFunctionUtimes(SMBCCTX *c, smbc_utimes_fn f);
|
||||
|
||||
typedef int (*smbc_setxattr_fn)(SMBCCTX *context,
|
||||
const char *fname,
|
||||
char *list,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size,
|
||||
int flags);
|
||||
smbc_setxattr_fn smbc_getFunctionSetxattr(SMBCCTX *c);
|
||||
void smbc_setFunctionSetxattr(SMBCCTX *c, smbc_setxattr_fn f);
|
||||
|
||||
typedef int (*smbc_getxattr_fn)(SMBCCTX *context,
|
||||
const char *fname,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size);
|
||||
smbc_getxattr_fn smbc_getFunctionGetxattr(SMBCCTX *c);
|
||||
void smbc_setFunctionGetxattr(SMBCCTX *c, smbc_getxattr_fn f);
|
||||
|
||||
/** callable functions for printing
|
||||
*/
|
||||
int (*print_file)(SMBCCTX *c_file, const char *fname,
|
||||
SMBCCTX *c_print, const char *printq);
|
||||
SMBCFILE * (*open_print_job)(SMBCCTX *c, const char *fname);
|
||||
int (*list_print_jobs)(SMBCCTX *c, const char *fname, smbc_list_print_job_fn fn);
|
||||
int (*unlink_print_job)(SMBCCTX *c, const char *fname, int id);
|
||||
typedef int (*smbc_removexattr_fn)(SMBCCTX *context,
|
||||
const char *fname,
|
||||
const char *name);
|
||||
smbc_removexattr_fn smbc_getFunctionRemovexattr(SMBCCTX *c);
|
||||
void smbc_setFunctionRemovexattr(SMBCCTX *c, smbc_removexattr_fn f);
|
||||
|
||||
typedef int (*smbc_listxattr_fn)(SMBCCTX *context,
|
||||
const char *fname,
|
||||
char *list,
|
||||
size_t size);
|
||||
smbc_listxattr_fn smbc_getFunctionListxattr(SMBCCTX *c);
|
||||
void smbc_setFunctionListxattr(SMBCCTX *c, smbc_listxattr_fn f);
|
||||
|
||||
|
||||
/*
|
||||
** Callbacks
|
||||
* These callbacks _always_ have to be initialized because they will
|
||||
* not be checked at dereference for increased speed.
|
||||
*/
|
||||
struct _smbc_callbacks {
|
||||
/** authentication function callback: called upon auth requests
|
||||
*/
|
||||
smbc_get_auth_data_fn auth_fn;
|
||||
|
||||
/** check if a server is still good
|
||||
*/
|
||||
smbc_check_server_fn check_server_fn;
|
||||
/**
|
||||
* Callable functions related to printing
|
||||
*/
|
||||
|
||||
/** remove a server if unused
|
||||
*/
|
||||
smbc_remove_unused_server_fn remove_unused_server_fn;
|
||||
typedef int (*smbc_print_file_fn)(SMBCCTX *c_file,
|
||||
const char *fname,
|
||||
SMBCCTX *c_print,
|
||||
const char *printq);
|
||||
smbc_print_file_fn smbc_getFunctionPrintFile(SMBCCTX *c);
|
||||
void smbc_setFunctionPrintFile(SMBCCTX *c, smbc_print_file_fn f);
|
||||
|
||||
/** Cache subsystem
|
||||
* For an example cache system see samba/source/libsmb/libsmb_cache.c
|
||||
* Cache subsystem functions follow.
|
||||
*/
|
||||
typedef SMBCFILE * (*smbc_open_print_job_fn)(SMBCCTX *c,
|
||||
const char *fname);
|
||||
smbc_open_print_job_fn smbc_getFunctionOpenPrintJob(SMBCCTX *c);
|
||||
void smbc_setFunctionOpenPrintJob(SMBCCTX *c,
|
||||
smbc_open_print_job_fn f);
|
||||
|
||||
/** server cache addition
|
||||
*/
|
||||
smbc_add_cached_srv_fn add_cached_srv_fn;
|
||||
typedef int (*smbc_list_print_jobs_fn)(SMBCCTX *c,
|
||||
const char *fname,
|
||||
smbc_list_print_job_fn fn);
|
||||
smbc_list_print_jobs_fn smbc_getFunctionListPrintJobs(SMBCCTX *c);
|
||||
void smbc_setFunctionListPrintJobs(SMBCCTX *c,
|
||||
smbc_list_print_jobs_fn f);
|
||||
|
||||
/** server cache lookup
|
||||
*/
|
||||
smbc_get_cached_srv_fn get_cached_srv_fn;
|
||||
typedef int (*smbc_unlink_print_job_fn)(SMBCCTX *c,
|
||||
const char *fname,
|
||||
int id);
|
||||
smbc_unlink_print_job_fn smbc_getFunctionUnlinkPrintJob(SMBCCTX *c);
|
||||
void smbc_setFunctionUnlinkPrintJob(SMBCCTX *c,
|
||||
smbc_unlink_print_job_fn f);
|
||||
|
||||
/** server cache removal
|
||||
*/
|
||||
smbc_remove_cached_srv_fn remove_cached_srv_fn;
|
||||
|
||||
/** server cache purging, try to remove all cached servers (disconnect)
|
||||
*/
|
||||
smbc_purge_cached_fn purge_cached_fn;
|
||||
} callbacks;
|
||||
|
||||
|
||||
/** Space to store private data of the server cache.
|
||||
*/
|
||||
struct smbc_server_cache * server_cache;
|
||||
|
||||
int flags;
|
||||
|
||||
/** user options selections that apply to this session
|
||||
*
|
||||
* NEW OPTIONS ARE NOT ADDED HERE!
|
||||
*
|
||||
* We must maintain ABI backward compatibility. We now use
|
||||
* smbc_option_set() and smbc_option_get() for all newly added
|
||||
* options.
|
||||
*/
|
||||
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;
|
||||
|
||||
/* Add additional functions here for ABI backward compatibility */
|
||||
int (*ftruncate)(SMBCCTX *c, SMBCFILE *f, off_t size);
|
||||
|
||||
/** INTERNAL DATA
|
||||
* do _NOT_ touch this from your program !
|
||||
*/
|
||||
struct smbc_internal_data * internal;
|
||||
};
|
||||
|
||||
/* Flags for SMBCCTX->flags */
|
||||
#define SMB_CTX_FLAG_USE_KERBEROS (1 << 0)
|
||||
#define SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS (1 << 1)
|
||||
#define SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON (1 << 2) /* don't try to do automatic anon login */
|
||||
|
||||
/**@ingroup misc
|
||||
* Create a new SBMCCTX (a context).
|
||||
|
@ -22,11 +22,8 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "include/libsmbclient.h"
|
||||
#include "../include/libsmb_internal.h"
|
||||
|
||||
int smbc_default_cache_functions(SMBCCTX * context);
|
||||
#include "libsmbclient.h"
|
||||
#include "libsmb_internal.h"
|
||||
|
||||
/*
|
||||
* Structure we use if internal caching mechanism is used
|
||||
@ -48,9 +45,13 @@ struct smbc_server_cache {
|
||||
* Add a new connection to the server cache.
|
||||
* This function is only used if the external cache is not enabled
|
||||
*/
|
||||
static int smbc_add_cached_server(SMBCCTX * context, SMBCSRV * newsrv,
|
||||
const char * server, const char * share,
|
||||
const char * workgroup, const char * username)
|
||||
int
|
||||
SMBC_add_cached_server(SMBCCTX * context,
|
||||
SMBCSRV * newsrv,
|
||||
const char * server,
|
||||
const char * share,
|
||||
const char * workgroup,
|
||||
const char * username)
|
||||
{
|
||||
struct smbc_server_cache * srvcache = NULL;
|
||||
|
||||
@ -88,7 +89,7 @@ static int smbc_add_cached_server(SMBCCTX * context, SMBCSRV * newsrv,
|
||||
goto failed;
|
||||
}
|
||||
|
||||
DLIST_ADD((context->server_cache), srvcache);
|
||||
DLIST_ADD((context->cache.server_cache_data), srvcache);
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
@ -108,13 +109,17 @@ static int smbc_add_cached_server(SMBCCTX * context, SMBCSRV * newsrv,
|
||||
* returns server handle on success, NULL on error (not found)
|
||||
* This function is only used if the external cache is not enabled
|
||||
*/
|
||||
static SMBCSRV * smbc_get_cached_server(SMBCCTX * context, const char * server,
|
||||
const char * share, const char * workgroup, const char * user)
|
||||
SMBCSRV *
|
||||
SMBC_get_cached_server(SMBCCTX * context,
|
||||
const char * server,
|
||||
const char * share,
|
||||
const char * workgroup,
|
||||
const char * user)
|
||||
{
|
||||
struct smbc_server_cache * srv = NULL;
|
||||
|
||||
/* Search the cache lines */
|
||||
for (srv=((struct smbc_server_cache *)context->server_cache);srv;srv=srv->next) {
|
||||
for (srv = context->cache.server_cache_data; srv; srv = srv->next) {
|
||||
|
||||
if (strcmp(server,srv->server_name) == 0 &&
|
||||
strcmp(workgroup,srv->workgroup) == 0 &&
|
||||
@ -146,7 +151,7 @@ static SMBCSRV * smbc_get_cached_server(SMBCCTX * context, const char * server,
|
||||
* a connection to the server (other than the
|
||||
* attribute server connection) is cool.
|
||||
*/
|
||||
if (context->options.one_share_per_server) {
|
||||
if (context->one_share_per_server) {
|
||||
/*
|
||||
* The currently connected share name
|
||||
* doesn't match the requested share, so
|
||||
@ -156,7 +161,7 @@ static SMBCSRV * smbc_get_cached_server(SMBCCTX * context, const char * server,
|
||||
/* Sigh. Couldn't disconnect. */
|
||||
cli_shutdown(srv->server->cli);
|
||||
srv->server->cli = NULL;
|
||||
context->callbacks.remove_cached_srv_fn(context, srv->server);
|
||||
context->cache.remove_cached_server_fn(context, srv->server);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -171,7 +176,7 @@ static SMBCSRV * smbc_get_cached_server(SMBCCTX * context, const char * server,
|
||||
/* Out of memory. */
|
||||
cli_shutdown(srv->server->cli);
|
||||
srv->server->cli = NULL;
|
||||
context->callbacks.remove_cached_srv_fn(context, srv->server);
|
||||
context->cache.remove_cached_server_fn(context, srv->server);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -190,15 +195,17 @@ static SMBCSRV * smbc_get_cached_server(SMBCCTX * context, const char * server,
|
||||
* returns 0 on success
|
||||
* This function is only used if the external cache is not enabled
|
||||
*/
|
||||
static int smbc_remove_cached_server(SMBCCTX * context, SMBCSRV * server)
|
||||
int
|
||||
SMBC_remove_cached_server(SMBCCTX * context,
|
||||
SMBCSRV * server)
|
||||
{
|
||||
struct smbc_server_cache * srv = NULL;
|
||||
|
||||
for (srv=((struct smbc_server_cache *)context->server_cache);srv;srv=srv->next) {
|
||||
for (srv = context->cache.server_cache_data; srv; srv = srv->next) {
|
||||
if (server == srv->server) {
|
||||
|
||||
/* remove this sucker */
|
||||
DLIST_REMOVE(context->server_cache, srv);
|
||||
DLIST_REMOVE(context->cache.server_cache_data, srv);
|
||||
SAFE_FREE(srv->server_name);
|
||||
SAFE_FREE(srv->share_name);
|
||||
SAFE_FREE(srv->workgroup);
|
||||
@ -216,40 +223,23 @@ static int smbc_remove_cached_server(SMBCCTX * context, SMBCSRV * server)
|
||||
* Try to remove all the servers in cache
|
||||
* returns 1 on failure and 0 if all servers could be removed.
|
||||
*/
|
||||
static int smbc_purge_cached(SMBCCTX * context)
|
||||
int
|
||||
SMBC_purge_cached_servers(SMBCCTX * context)
|
||||
{
|
||||
struct smbc_server_cache * srv;
|
||||
struct smbc_server_cache * next;
|
||||
int could_not_purge_all = 0;
|
||||
|
||||
for (srv = ((struct smbc_server_cache *) context->server_cache),
|
||||
next = (srv ? srv->next :NULL);
|
||||
for (srv = context->cache.server_cache_data,
|
||||
next = (srv ? srv->next :NULL);
|
||||
srv;
|
||||
srv = next, next = (srv ? srv->next : NULL)) {
|
||||
srv = next,
|
||||
next = (srv ? srv->next : NULL)) {
|
||||
|
||||
if (smbc_remove_unused_server(context, srv->server)) {
|
||||
if (SMBC_remove_unused_server(context, srv->server)) {
|
||||
/* could not be removed */
|
||||
could_not_purge_all = 1;
|
||||
}
|
||||
}
|
||||
return could_not_purge_all;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This functions initializes all server-cache related functions
|
||||
* to the default (internal) system.
|
||||
*
|
||||
* We use this to make the rest of the cache system static.
|
||||
*/
|
||||
|
||||
int smbc_default_cache_functions(SMBCCTX * context)
|
||||
{
|
||||
context->callbacks.add_cached_srv_fn = smbc_add_cached_server;
|
||||
context->callbacks.get_cached_srv_fn = smbc_get_cached_server;
|
||||
context->callbacks.remove_cached_srv_fn = smbc_remove_cached_server;
|
||||
context->callbacks.purge_cached_fn = smbc_purge_cached;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
Copyright (C) Richard Sharpe 2000
|
||||
Copyright (C) John Terpstra 2000
|
||||
Copyright (C) Tom Jansen (Ninja ISD) 2002
|
||||
Copyright (C) Derrell Lipman 2003
|
||||
Copyright (C) Derrell Lipman 2003, 2008
|
||||
|
||||
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
|
||||
@ -23,8 +23,7 @@
|
||||
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "include/libsmb_internal.h"
|
||||
#include "libsmb_internal.h"
|
||||
|
||||
struct smbc_compat_fdlist {
|
||||
SMBCFILE * file;
|
||||
@ -39,7 +38,8 @@ static struct smbc_compat_fdlist * smbc_compat_fd_in_use = NULL;
|
||||
static struct smbc_compat_fdlist * smbc_compat_fd_avail = NULL;
|
||||
|
||||
/* Find an fd and return the SMBCFILE * or NULL on failure */
|
||||
static SMBCFILE * find_fd(int fd)
|
||||
static SMBCFILE *
|
||||
find_fd(int fd)
|
||||
{
|
||||
struct smbc_compat_fdlist * f = smbc_compat_fd_in_use;
|
||||
while (f) {
|
||||
@ -51,7 +51,8 @@ static SMBCFILE * find_fd(int fd)
|
||||
}
|
||||
|
||||
/* Add an fd, returns 0 on success, -1 on error with errno set */
|
||||
static int add_fd(SMBCFILE * file)
|
||||
static int
|
||||
add_fd(SMBCFILE * file)
|
||||
{
|
||||
struct smbc_compat_fdlist * f = smbc_compat_fd_avail;
|
||||
|
||||
@ -90,7 +91,8 @@ static int add_fd(SMBCFILE * file)
|
||||
|
||||
|
||||
/* Delete an fd, returns 0 on success */
|
||||
static int del_fd(int fd)
|
||||
static int
|
||||
del_fd(int fd)
|
||||
{
|
||||
struct smbc_compat_fdlist * f = smbc_compat_fd_in_use;
|
||||
|
||||
@ -112,15 +114,17 @@ static int del_fd(int fd)
|
||||
|
||||
|
||||
|
||||
int smbc_init(smbc_get_auth_data_fn fn, int debug)
|
||||
int
|
||||
smbc_init(smbc_get_auth_data_fn fn,
|
||||
int debug)
|
||||
{
|
||||
if (!smbc_compat_initialized) {
|
||||
statcont = smbc_new_context();
|
||||
if (!statcont)
|
||||
return -1;
|
||||
|
||||
statcont->debug = debug;
|
||||
statcont->callbacks.auth_fn = fn;
|
||||
smbc_setDebug(statcont, debug);
|
||||
smbc_setFunctionAuthData(statcont, fn);
|
||||
|
||||
if (!smbc_init_context(statcont)) {
|
||||
smbc_free_context(statcont, False);
|
||||
@ -135,7 +139,8 @@ int smbc_init(smbc_get_auth_data_fn fn, int debug)
|
||||
}
|
||||
|
||||
|
||||
SMBCCTX *smbc_set_context(SMBCCTX * context)
|
||||
SMBCCTX *
|
||||
smbc_set_context(SMBCCTX * context)
|
||||
{
|
||||
SMBCCTX *old_context = statcont;
|
||||
|
||||
@ -151,307 +156,387 @@ SMBCCTX *smbc_set_context(SMBCCTX * context)
|
||||
}
|
||||
|
||||
|
||||
int smbc_open(const char *furl, int flags, mode_t mode)
|
||||
int
|
||||
smbc_open(const char *furl,
|
||||
int flags,
|
||||
mode_t mode)
|
||||
{
|
||||
SMBCFILE * file;
|
||||
int fd;
|
||||
|
||||
file = (statcont->open)(statcont, furl, flags, mode);
|
||||
file = smbc_getFunctionOpen(statcont)(statcont, furl, flags, mode);
|
||||
if (!file)
|
||||
return -1;
|
||||
|
||||
fd = add_fd(file);
|
||||
if (fd == -1)
|
||||
(statcont->close_fn)(statcont, file);
|
||||
smbc_getFunctionClose(statcont)(statcont, file);
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
int smbc_creat(const char *furl, mode_t mode)
|
||||
int
|
||||
smbc_creat(const char *furl,
|
||||
mode_t mode)
|
||||
{
|
||||
SMBCFILE * file;
|
||||
int fd;
|
||||
|
||||
file = (statcont->creat)(statcont, furl, mode);
|
||||
file = smbc_getFunctionCreat(statcont)(statcont, furl, mode);
|
||||
if (!file)
|
||||
return -1;
|
||||
|
||||
fd = add_fd(file);
|
||||
if (fd == -1) {
|
||||
/* Hmm... should we delete the file too ? I guess we could try */
|
||||
(statcont->close_fn)(statcont, file);
|
||||
(statcont->unlink)(statcont, furl);
|
||||
smbc_getFunctionClose(statcont)(statcont, file);
|
||||
smbc_getFunctionUnlink(statcont)(statcont, furl);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
ssize_t smbc_read(int fd, void *buf, size_t bufsize)
|
||||
ssize_t
|
||||
smbc_read(int fd,
|
||||
void *buf,
|
||||
size_t bufsize)
|
||||
{
|
||||
SMBCFILE * file = find_fd(fd);
|
||||
return (statcont->read)(statcont, file, buf, bufsize);
|
||||
return smbc_getFunctionRead(statcont)(statcont, file, buf, bufsize);
|
||||
}
|
||||
|
||||
ssize_t smbc_write(int fd, void *buf, size_t bufsize)
|
||||
ssize_t
|
||||
smbc_write(int fd,
|
||||
void *buf,
|
||||
size_t bufsize)
|
||||
{
|
||||
SMBCFILE * file = find_fd(fd);
|
||||
return (statcont->write)(statcont, file, buf, bufsize);
|
||||
return smbc_getFunctionWrite(statcont)(statcont, file, buf, bufsize);
|
||||
}
|
||||
|
||||
off_t smbc_lseek(int fd, off_t offset, int whence)
|
||||
off_t
|
||||
smbc_lseek(int fd,
|
||||
off_t offset,
|
||||
int whence)
|
||||
{
|
||||
SMBCFILE * file = find_fd(fd);
|
||||
return (statcont->lseek)(statcont, file, offset, whence);
|
||||
return smbc_getFunctionLseek(statcont)(statcont, file, offset, whence);
|
||||
}
|
||||
|
||||
int smbc_close(int fd)
|
||||
int
|
||||
smbc_close(int fd)
|
||||
{
|
||||
SMBCFILE * file = find_fd(fd);
|
||||
del_fd(fd);
|
||||
return (statcont->close_fn)(statcont, file);
|
||||
return smbc_getFunctionClose(statcont)(statcont, file);
|
||||
}
|
||||
|
||||
int smbc_unlink(const char *fname)
|
||||
int
|
||||
smbc_unlink(const char *fname)
|
||||
{
|
||||
return (statcont->unlink)(statcont, fname);
|
||||
return smbc_getFunctionUnlink(statcont)(statcont, fname);
|
||||
}
|
||||
|
||||
int smbc_rename(const char *ourl, const char *nurl)
|
||||
int
|
||||
smbc_rename(const char *ourl,
|
||||
const char *nurl)
|
||||
{
|
||||
return (statcont->rename)(statcont, ourl, statcont, nurl);
|
||||
return smbc_getFunctionRename(statcont)(statcont, ourl,
|
||||
statcont, nurl);
|
||||
}
|
||||
|
||||
int smbc_opendir(const char *durl)
|
||||
int
|
||||
smbc_opendir(const char *durl)
|
||||
{
|
||||
SMBCFILE * file;
|
||||
int fd;
|
||||
|
||||
file = (statcont->opendir)(statcont, durl);
|
||||
file = smbc_getFunctionOpendir(statcont)(statcont, durl);
|
||||
if (!file)
|
||||
return -1;
|
||||
|
||||
fd = add_fd(file);
|
||||
if (fd == -1)
|
||||
(statcont->closedir)(statcont, file);
|
||||
smbc_getFunctionClosedir(statcont)(statcont, file);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int smbc_closedir(int dh)
|
||||
int
|
||||
smbc_closedir(int dh)
|
||||
{
|
||||
SMBCFILE * file = find_fd(dh);
|
||||
del_fd(dh);
|
||||
return (statcont->closedir)(statcont, file);
|
||||
return smbc_getFunctionClosedir(statcont)(statcont, file);
|
||||
}
|
||||
|
||||
int smbc_getdents(unsigned int dh, struct smbc_dirent *dirp, int count)
|
||||
int
|
||||
smbc_getdents(unsigned int dh,
|
||||
struct smbc_dirent *dirp,
|
||||
int count)
|
||||
{
|
||||
SMBCFILE * file = find_fd(dh);
|
||||
return (statcont->getdents)(statcont, file,dirp, count);
|
||||
return smbc_getFunctionGetdents(statcont)(statcont, file, dirp, count);
|
||||
}
|
||||
|
||||
struct smbc_dirent* smbc_readdir(unsigned int dh)
|
||||
struct smbc_dirent *
|
||||
smbc_readdir(unsigned int dh)
|
||||
{
|
||||
SMBCFILE * file = find_fd(dh);
|
||||
return (statcont->readdir)(statcont, file);
|
||||
return smbc_getFunctionReaddir(statcont)(statcont, file);
|
||||
}
|
||||
|
||||
off_t smbc_telldir(int dh)
|
||||
off_t
|
||||
smbc_telldir(int dh)
|
||||
{
|
||||
SMBCFILE * file = find_fd(dh);
|
||||
return (statcont->telldir)(statcont, file);
|
||||
return smbc_getFunctionTelldir(statcont)(statcont, file);
|
||||
}
|
||||
|
||||
int smbc_lseekdir(int fd, off_t offset)
|
||||
int
|
||||
smbc_lseekdir(int fd,
|
||||
off_t offset)
|
||||
{
|
||||
SMBCFILE * file = find_fd(fd);
|
||||
return (statcont->lseekdir)(statcont, file, offset);
|
||||
return smbc_getFunctionLseekdir(statcont)(statcont, file, offset);
|
||||
}
|
||||
|
||||
int smbc_mkdir(const char *durl, mode_t mode)
|
||||
int
|
||||
smbc_mkdir(const char *durl,
|
||||
mode_t mode)
|
||||
{
|
||||
return (statcont->mkdir)(statcont, durl, mode);
|
||||
return smbc_getFunctionMkdir(statcont)(statcont, durl, mode);
|
||||
}
|
||||
|
||||
int smbc_rmdir(const char *durl)
|
||||
int
|
||||
smbc_rmdir(const char *durl)
|
||||
{
|
||||
return (statcont->rmdir)(statcont, durl);
|
||||
return smbc_getFunctionRmdir(statcont)(statcont, durl);
|
||||
}
|
||||
|
||||
int smbc_stat(const char *url, struct stat *st)
|
||||
int
|
||||
smbc_stat(const char *url,
|
||||
struct stat *st)
|
||||
{
|
||||
return (statcont->stat)(statcont, url, st);
|
||||
return smbc_getFunctionStat(statcont)(statcont, url, st);
|
||||
}
|
||||
|
||||
int smbc_fstat(int fd, struct stat *st)
|
||||
int
|
||||
smbc_fstat(int fd,
|
||||
struct stat *st)
|
||||
{
|
||||
SMBCFILE * file = find_fd(fd);
|
||||
return (statcont->fstat)(statcont, file, st);
|
||||
return smbc_getFunctionFstat(statcont)(statcont, file, st);
|
||||
}
|
||||
|
||||
int smbc_ftruncate(int fd, off_t size)
|
||||
int
|
||||
smbc_ftruncate(int fd,
|
||||
off_t size)
|
||||
{
|
||||
SMBCFILE * file = find_fd(fd);
|
||||
return (statcont->ftruncate)(statcont, file, size);
|
||||
return smbc_getFunctionFtruncate(statcont)(statcont, file, size);
|
||||
}
|
||||
|
||||
int smbc_chmod(const char *url, mode_t mode)
|
||||
int
|
||||
smbc_chmod(const char *url,
|
||||
mode_t mode)
|
||||
{
|
||||
return (statcont->chmod)(statcont, url, mode);
|
||||
return smbc_getFunctionChmod(statcont)(statcont, url, mode);
|
||||
}
|
||||
|
||||
int smbc_utimes(const char *fname, struct timeval *tbuf)
|
||||
int
|
||||
smbc_utimes(const char *fname,
|
||||
struct timeval *tbuf)
|
||||
{
|
||||
return (statcont->utimes)(statcont, fname, tbuf);
|
||||
return smbc_getFunctionUtimes(statcont)(statcont, fname, tbuf);
|
||||
}
|
||||
|
||||
#ifdef HAVE_UTIME_H
|
||||
int smbc_utime(const char *fname, struct utimbuf *utbuf)
|
||||
int
|
||||
smbc_utime(const char *fname,
|
||||
struct utimbuf *utbuf)
|
||||
{
|
||||
struct timeval tv[2];
|
||||
|
||||
if (utbuf == NULL)
|
||||
return (statcont->utimes)(statcont, fname, NULL);
|
||||
return smbc_getFunctionUtimes(statcont)(statcont, fname, NULL);
|
||||
|
||||
tv[0].tv_sec = utbuf->actime;
|
||||
tv[1].tv_sec = utbuf->modtime;
|
||||
tv[0].tv_usec = tv[1].tv_usec = 0;
|
||||
|
||||
return (statcont->utimes)(statcont, fname, tv);
|
||||
return smbc_getFunctionUtimes(statcont)(statcont, fname, tv);
|
||||
}
|
||||
#endif
|
||||
|
||||
int smbc_setxattr(const char *fname,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size,
|
||||
int flags)
|
||||
int
|
||||
smbc_setxattr(const char *fname,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size,
|
||||
int flags)
|
||||
{
|
||||
return (statcont->setxattr)(statcont, fname, name, value, size, flags);
|
||||
return smbc_getFunctionSetxattr(statcont)(statcont,
|
||||
fname, name,
|
||||
value, size, flags);
|
||||
}
|
||||
|
||||
int smbc_lsetxattr(const char *fname,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size,
|
||||
int flags)
|
||||
int
|
||||
smbc_lsetxattr(const char *fname,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size,
|
||||
int flags)
|
||||
{
|
||||
return (statcont->setxattr)(statcont, fname, name, value, size, flags);
|
||||
return smbc_getFunctionSetxattr(statcont)(statcont,
|
||||
fname, name,
|
||||
value, size, flags);
|
||||
}
|
||||
|
||||
int smbc_fsetxattr(int fd,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size,
|
||||
int flags)
|
||||
int
|
||||
smbc_fsetxattr(int fd,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size,
|
||||
int flags)
|
||||
{
|
||||
SMBCFILE * file = find_fd(fd);
|
||||
if (file == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
return (statcont->setxattr)(statcont, file->fname,
|
||||
name, value, size, flags);
|
||||
return smbc_getFunctionSetxattr(statcont)(statcont,
|
||||
file->fname, name,
|
||||
value, size, flags);
|
||||
}
|
||||
|
||||
int smbc_getxattr(const char *fname,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size)
|
||||
int
|
||||
smbc_getxattr(const char *fname,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size)
|
||||
{
|
||||
return (statcont->getxattr)(statcont, fname, name, value, size);
|
||||
return smbc_getFunctionGetxattr(statcont)(statcont,
|
||||
fname, name,
|
||||
value, size);
|
||||
}
|
||||
|
||||
int smbc_lgetxattr(const char *fname,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size)
|
||||
int
|
||||
smbc_lgetxattr(const char *fname,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size)
|
||||
{
|
||||
return (statcont->getxattr)(statcont, fname, name, value, size);
|
||||
return smbc_getFunctionGetxattr(statcont)(statcont,
|
||||
fname, name,
|
||||
value, size);
|
||||
}
|
||||
|
||||
int smbc_fgetxattr(int fd,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size)
|
||||
int
|
||||
smbc_fgetxattr(int fd,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size)
|
||||
{
|
||||
SMBCFILE * file = find_fd(fd);
|
||||
if (file == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
return (statcont->getxattr)(statcont, file->fname, name, value, size);
|
||||
return smbc_getFunctionGetxattr(statcont)(statcont,
|
||||
file->fname, name,
|
||||
value, size);
|
||||
}
|
||||
|
||||
int smbc_removexattr(const char *fname,
|
||||
const char *name)
|
||||
int
|
||||
smbc_removexattr(const char *fname,
|
||||
const char *name)
|
||||
{
|
||||
return (statcont->removexattr)(statcont, fname, name);
|
||||
return smbc_getFunctionRemovexattr(statcont)(statcont, fname, name);
|
||||
}
|
||||
|
||||
int smbc_lremovexattr(const char *fname,
|
||||
const char *name)
|
||||
int
|
||||
smbc_lremovexattr(const char *fname,
|
||||
const char *name)
|
||||
{
|
||||
return (statcont->removexattr)(statcont, fname, name);
|
||||
return smbc_getFunctionRemovexattr(statcont)(statcont, fname, name);
|
||||
}
|
||||
|
||||
int smbc_fremovexattr(int fd,
|
||||
const char *name)
|
||||
int
|
||||
smbc_fremovexattr(int fd,
|
||||
const char *name)
|
||||
{
|
||||
SMBCFILE * file = find_fd(fd);
|
||||
if (file == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
return (statcont->removexattr)(statcont, file->fname, name);
|
||||
return smbc_getFunctionRemovexattr(statcont)(statcont,
|
||||
file->fname, name);
|
||||
}
|
||||
|
||||
int smbc_listxattr(const char *fname,
|
||||
char *list,
|
||||
size_t size)
|
||||
int
|
||||
smbc_listxattr(const char *fname,
|
||||
char *list,
|
||||
size_t size)
|
||||
{
|
||||
return (statcont->listxattr)(statcont, fname, list, size);
|
||||
return smbc_getFunctionListxattr(statcont)(statcont,
|
||||
fname, list, size);
|
||||
}
|
||||
|
||||
int smbc_llistxattr(const char *fname,
|
||||
char *list,
|
||||
size_t size)
|
||||
int
|
||||
smbc_llistxattr(const char *fname,
|
||||
char *list,
|
||||
size_t size)
|
||||
{
|
||||
return (statcont->listxattr)(statcont, fname, list, size);
|
||||
return smbc_getFunctionListxattr(statcont)(statcont,
|
||||
fname, list, size);
|
||||
}
|
||||
|
||||
int smbc_flistxattr(int fd,
|
||||
char *list,
|
||||
size_t size)
|
||||
int
|
||||
smbc_flistxattr(int fd,
|
||||
char *list,
|
||||
size_t size)
|
||||
{
|
||||
SMBCFILE * file = find_fd(fd);
|
||||
if (file == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
return (statcont->listxattr)(statcont, file->fname, list, size);
|
||||
return smbc_getFunctionListxattr(statcont)(statcont,
|
||||
file->fname, list, size);
|
||||
}
|
||||
|
||||
int smbc_print_file(const char *fname, const char *printq)
|
||||
int
|
||||
smbc_print_file(const char *fname,
|
||||
const char *printq)
|
||||
{
|
||||
return (statcont->print_file)(statcont, fname, statcont, printq);
|
||||
return smbc_getFunctionPrintFile(statcont)(statcont, fname,
|
||||
statcont, printq);
|
||||
}
|
||||
|
||||
int smbc_open_print_job(const char *fname)
|
||||
int
|
||||
smbc_open_print_job(const char *fname)
|
||||
{
|
||||
SMBCFILE * file = (statcont->open_print_job)(statcont, fname);
|
||||
SMBCFILE * file;
|
||||
|
||||
file = smbc_getFunctionOpenPrintJob(statcont)(statcont, fname);
|
||||
if (!file) return -1;
|
||||
return file->cli_fd;
|
||||
}
|
||||
|
||||
int smbc_list_print_jobs(const char *purl, smbc_list_print_job_fn fn)
|
||||
int
|
||||
smbc_list_print_jobs(const char *purl,
|
||||
smbc_list_print_job_fn fn)
|
||||
{
|
||||
return (statcont->list_print_jobs)(statcont, purl, fn);
|
||||
return smbc_getFunctionListPrintJobs(statcont)(statcont, purl, fn);
|
||||
}
|
||||
|
||||
int smbc_unlink_print_job(const char *purl, int id)
|
||||
int
|
||||
smbc_unlink_print_job(const char *purl,
|
||||
int id)
|
||||
{
|
||||
return (statcont->unlink_print_job)(statcont, purl, id);
|
||||
return smbc_getFunctionUnlinkPrintJob(statcont)(statcont, purl, id);
|
||||
}
|
||||
|
||||
|
||||
|
1283
source3/libsmb/libsmb_context.c
Normal file
1283
source3/libsmb/libsmb_context.c
Normal file
File diff suppressed because it is too large
Load Diff
1928
source3/libsmb/libsmb_dir.c
Normal file
1928
source3/libsmb/libsmb_dir.c
Normal file
File diff suppressed because it is too large
Load Diff
859
source3/libsmb/libsmb_file.c
Normal file
859
source3/libsmb/libsmb_file.c
Normal file
@ -0,0 +1,859 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
SMB client library implementation
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
Copyright (C) Richard Sharpe 2000, 2002
|
||||
Copyright (C) John Terpstra 2000
|
||||
Copyright (C) Tom Jansen (Ninja ISD) 2002
|
||||
Copyright (C) Derrell Lipman 2003-2008
|
||||
Copyright (C) Jeremy Allison 2007, 2008
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libsmbclient.h"
|
||||
#include "libsmb_internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Routine to open() a file ...
|
||||
*/
|
||||
|
||||
SMBCFILE *
|
||||
SMBC_open_ctx(SMBCCTX *context,
|
||||
const char *fname,
|
||||
int flags,
|
||||
mode_t mode)
|
||||
{
|
||||
char *server = NULL, *share = NULL, *user = NULL, *password = NULL, *workgroup = NULL;
|
||||
char *path = NULL;
|
||||
char *targetpath = NULL;
|
||||
struct cli_state *targetcli = NULL;
|
||||
SMBCSRV *srv = NULL;
|
||||
SMBCFILE *file = NULL;
|
||||
int fd;
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
if (!context || !context->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, context->user);
|
||||
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] == '\\') {
|
||||
fd = -1;
|
||||
} 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);*/
|
||||
if (!cli_resolve_path(frame, "", srv->cli, path, &targetcli, &targetpath)) {
|
||||
d_printf("Could not resolve %s\n", path);
|
||||
SAFE_FREE(file);
|
||||
TALLOC_FREE(frame);
|
||||
return NULL;
|
||||
}
|
||||
/*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/
|
||||
|
||||
if ((fd = cli_open(targetcli, targetpath, flags,
|
||||
context->share_mode)) < 0) {
|
||||
|
||||
/* 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->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 (fd == -1) {
|
||||
int eno = 0;
|
||||
|
||||
eno = SMBC_errno(context, srv->cli);
|
||||
file = (context->posix_emu.opendir_fn)(context, fname);
|
||||
if (!file) errno = eno;
|
||||
TALLOC_FREE(frame);
|
||||
return file;
|
||||
|
||||
}
|
||||
|
||||
errno = EINVAL; /* FIXME, correct errno ? */
|
||||
TALLOC_FREE(frame);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to create a file
|
||||
*/
|
||||
|
||||
static int creat_bits = O_WRONLY | O_CREAT | O_TRUNC; /* FIXME: Do we need this */
|
||||
|
||||
SMBCFILE *
|
||||
SMBC_creat_ctx(SMBCCTX *context,
|
||||
const char *path,
|
||||
mode_t mode)
|
||||
{
|
||||
|
||||
if (!context || !context->initialized) {
|
||||
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
return SMBC_open_ctx(context, path, creat_bits, mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to read() a file ...
|
||||
*/
|
||||
|
||||
ssize_t
|
||||
SMBC_read_ctx(SMBCCTX *context,
|
||||
SMBCFILE *file,
|
||||
void *buf,
|
||||
size_t count)
|
||||
{
|
||||
int ret;
|
||||
char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
|
||||
char *path = NULL;
|
||||
char *targetpath = NULL;
|
||||
struct cli_state *targetcli = NULL;
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
/*
|
||||
* offset:
|
||||
*
|
||||
* Compiler bug (possibly) -- gcc (GCC) 3.3.5 (Debian 1:3.3.5-2) --
|
||||
* appears to pass file->offset (which is type off_t) differently than
|
||||
* a local variable of type off_t. Using local variable "offset" in
|
||||
* the call to cli_read() instead of file->offset fixes a problem
|
||||
* retrieving data at an offset greater than 4GB.
|
||||
*/
|
||||
off_t offset;
|
||||
|
||||
if (!context || !context->initialized) {
|
||||
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count));
|
||||
|
||||
if (!file || !SMBC_dlist_contains(context->files, file)) {
|
||||
errno = EBADF;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
offset = file->offset;
|
||||
|
||||
/* Check that the buffer exists ... */
|
||||
|
||||
if (buf == NULL) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
/*d_printf(">>>read: parsing %s\n", file->fname);*/
|
||||
if (SMBC_parse_path(frame,
|
||||
context,
|
||||
file->fname,
|
||||
NULL,
|
||||
&server,
|
||||
&share,
|
||||
&path,
|
||||
&user,
|
||||
&password,
|
||||
NULL)) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*d_printf(">>>read: resolving %s\n", path);*/
|
||||
if (!cli_resolve_path(frame, "", file->srv->cli, path,
|
||||
&targetcli, &targetpath)) {
|
||||
d_printf("Could not resolve %s\n", path);
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
/*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
|
||||
|
||||
ret = cli_read(targetcli, file->cli_fd, (char *)buf, offset, count);
|
||||
|
||||
if (ret < 0) {
|
||||
|
||||
errno = SMBC_errno(context, targetcli);
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
file->offset += ret;
|
||||
|
||||
DEBUG(4, (" --> %d\n", ret));
|
||||
|
||||
TALLOC_FREE(frame);
|
||||
return ret; /* Success, ret bytes of data ... */
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to write() a file ...
|
||||
*/
|
||||
|
||||
ssize_t
|
||||
SMBC_write_ctx(SMBCCTX *context,
|
||||
SMBCFILE *file,
|
||||
void *buf,
|
||||
size_t count)
|
||||
{
|
||||
int ret;
|
||||
off_t offset;
|
||||
char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
|
||||
char *path = NULL;
|
||||
char *targetpath = NULL;
|
||||
struct cli_state *targetcli = NULL;
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
/* First check all pointers before dereferencing them */
|
||||
|
||||
if (!context || !context->initialized) {
|
||||
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
if (!file || !SMBC_dlist_contains(context->files, file)) {
|
||||
errno = EBADF;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check that the buffer exists ... */
|
||||
|
||||
if (buf == NULL) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
offset = file->offset; /* See "offset" comment in SMBC_read_ctx() */
|
||||
|
||||
/*d_printf(">>>write: parsing %s\n", file->fname);*/
|
||||
if (SMBC_parse_path(frame,
|
||||
context,
|
||||
file->fname,
|
||||
NULL,
|
||||
&server,
|
||||
&share,
|
||||
&path,
|
||||
&user,
|
||||
&password,
|
||||
NULL)) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*d_printf(">>>write: resolving %s\n", path);*/
|
||||
if (!cli_resolve_path(frame, "", file->srv->cli, path,
|
||||
&targetcli, &targetpath)) {
|
||||
d_printf("Could not resolve %s\n", path);
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
/*d_printf(">>>write: resolved path as %s\n", targetpath);*/
|
||||
|
||||
ret = cli_write(targetcli, file->cli_fd, 0, (char *)buf, offset, count);
|
||||
|
||||
if (ret <= 0) {
|
||||
errno = SMBC_errno(context, targetcli);
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
file->offset += ret;
|
||||
|
||||
TALLOC_FREE(frame);
|
||||
return ret; /* Success, 0 bytes of data ... */
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to close() a file ...
|
||||
*/
|
||||
|
||||
int
|
||||
SMBC_close_ctx(SMBCCTX *context,
|
||||
SMBCFILE *file)
|
||||
{
|
||||
SMBCSRV *srv;
|
||||
char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
|
||||
char *path = NULL;
|
||||
char *targetpath = NULL;
|
||||
struct cli_state *targetcli = NULL;
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
if (!context || !context->initialized) {
|
||||
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!file || !SMBC_dlist_contains(context->files, file)) {
|
||||
errno = EBADF;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* IS a dir ... */
|
||||
if (!file->file) {
|
||||
TALLOC_FREE(frame);
|
||||
return (context->posix_emu.closedir_fn)(context, file);
|
||||
}
|
||||
|
||||
/*d_printf(">>>close: parsing %s\n", file->fname);*/
|
||||
if (SMBC_parse_path(frame,
|
||||
context,
|
||||
file->fname,
|
||||
NULL,
|
||||
&server,
|
||||
&share,
|
||||
&path,
|
||||
&user,
|
||||
&password,
|
||||
NULL)) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*d_printf(">>>close: resolving %s\n", path);*/
|
||||
if (!cli_resolve_path(frame, "", file->srv->cli, path,
|
||||
&targetcli, &targetpath)) {
|
||||
d_printf("Could not resolve %s\n", path);
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
/*d_printf(">>>close: resolved path as %s\n", targetpath);*/
|
||||
|
||||
if (!cli_close(targetcli, file->cli_fd)) {
|
||||
|
||||
DEBUG(3, ("cli_close failed on %s. purging server.\n",
|
||||
file->fname));
|
||||
/* Deallocate slot and remove the server
|
||||
* from the server cache if unused */
|
||||
errno = SMBC_errno(context, targetcli);
|
||||
srv = file->srv;
|
||||
DLIST_REMOVE(context->files, file);
|
||||
SAFE_FREE(file->fname);
|
||||
SAFE_FREE(file);
|
||||
(context->server.remove_unused_server_fn)(context, srv);
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
DLIST_REMOVE(context->files, file);
|
||||
SAFE_FREE(file->fname);
|
||||
SAFE_FREE(file);
|
||||
TALLOC_FREE(frame);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get info from an SMB server on a file. Use a qpathinfo call first
|
||||
* and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
|
||||
*/
|
||||
bool
|
||||
SMBC_getatr(SMBCCTX * context,
|
||||
SMBCSRV *srv,
|
||||
char *path,
|
||||
uint16 *mode,
|
||||
SMB_OFF_T *size,
|
||||
struct timespec *create_time_ts,
|
||||
struct timespec *access_time_ts,
|
||||
struct timespec *write_time_ts,
|
||||
struct timespec *change_time_ts,
|
||||
SMB_INO_T *ino)
|
||||
{
|
||||
char *fixedpath = NULL;
|
||||
char *targetpath = NULL;
|
||||
struct cli_state *targetcli = NULL;
|
||||
time_t write_time;
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
if (!context || !context->initialized) {
|
||||
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* path fixup for . and .. */
|
||||
if (strequal(path, ".") || strequal(path, "..")) {
|
||||
fixedpath = talloc_strdup(frame, "\\");
|
||||
if (!fixedpath) {
|
||||
errno = ENOMEM;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
fixedpath = talloc_strdup(frame, path);
|
||||
if (!fixedpath) {
|
||||
errno = ENOMEM;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
trim_string(fixedpath, NULL, "\\..");
|
||||
trim_string(fixedpath, NULL, "\\.");
|
||||
}
|
||||
DEBUG(4,("SMBC_getatr: sending qpathinfo\n"));
|
||||
|
||||
if (!cli_resolve_path(frame, "", srv->cli, fixedpath,
|
||||
&targetcli, &targetpath)) {
|
||||
d_printf("Couldn't resolve %s\n", path);
|
||||
TALLOC_FREE(frame);
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!srv->no_pathinfo2 &&
|
||||
cli_qpathinfo2(targetcli, targetpath,
|
||||
create_time_ts,
|
||||
access_time_ts,
|
||||
write_time_ts,
|
||||
change_time_ts,
|
||||
size, mode, ino)) {
|
||||
TALLOC_FREE(frame);
|
||||
return True;
|
||||
}
|
||||
|
||||
/* if this is NT then don't bother with the getatr */
|
||||
if (targetcli->capabilities & CAP_NT_SMBS) {
|
||||
errno = EPERM;
|
||||
TALLOC_FREE(frame);
|
||||
return False;
|
||||
}
|
||||
|
||||
if (cli_getatr(targetcli, targetpath, mode, size, &write_time)) {
|
||||
|
||||
struct timespec w_time_ts;
|
||||
|
||||
w_time_ts = convert_time_t_to_timespec(write_time);
|
||||
|
||||
if (write_time_ts != NULL) {
|
||||
*write_time_ts = w_time_ts;
|
||||
}
|
||||
|
||||
if (create_time_ts != NULL) {
|
||||
*create_time_ts = w_time_ts;
|
||||
}
|
||||
|
||||
if (access_time_ts != NULL) {
|
||||
*access_time_ts = w_time_ts;
|
||||
}
|
||||
|
||||
if (change_time_ts != NULL) {
|
||||
*change_time_ts = w_time_ts;
|
||||
}
|
||||
|
||||
srv->no_pathinfo2 = True;
|
||||
TALLOC_FREE(frame);
|
||||
return True;
|
||||
}
|
||||
|
||||
errno = EPERM;
|
||||
TALLOC_FREE(frame);
|
||||
return False;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Set file info on an SMB server. Use setpathinfo call first. If that
|
||||
* fails, use setattrE..
|
||||
*
|
||||
* Access and modification time parameters are always used and must be
|
||||
* provided. Create time, if zero, will be determined from the actual create
|
||||
* time of the file. If non-zero, the create time will be set as well.
|
||||
*
|
||||
* "mode" (attributes) parameter may be set to -1 if it is not to be set.
|
||||
*/
|
||||
bool
|
||||
SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path,
|
||||
time_t create_time,
|
||||
time_t access_time,
|
||||
time_t write_time,
|
||||
time_t change_time,
|
||||
uint16 mode)
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
/*
|
||||
* First, try setpathinfo (if qpathinfo succeeded), for it is the
|
||||
* modern function for "new code" to be using, and it works given a
|
||||
* filename rather than requiring that the file be opened to have its
|
||||
* attributes manipulated.
|
||||
*/
|
||||
if (srv->no_pathinfo ||
|
||||
! cli_setpathinfo(srv->cli, path,
|
||||
create_time,
|
||||
access_time,
|
||||
write_time,
|
||||
change_time,
|
||||
mode)) {
|
||||
|
||||
/*
|
||||
* setpathinfo is not supported; go to plan B.
|
||||
*
|
||||
* cli_setatr() does not work on win98, and it also doesn't
|
||||
* support setting the access time (only the modification
|
||||
* time), so in all cases, we open the specified file and use
|
||||
* cli_setattrE() which should work on all OS versions, and
|
||||
* supports both times.
|
||||
*/
|
||||
|
||||
/* Don't try {q,set}pathinfo() again, with this server */
|
||||
srv->no_pathinfo = True;
|
||||
|
||||
/* Open the file */
|
||||
if ((fd = cli_open(srv->cli, path, O_RDWR, DENY_NONE)) < 0) {
|
||||
|
||||
errno = SMBC_errno(context, srv->cli);
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set the new attributes */
|
||||
ret = cli_setattrE(srv->cli, fd,
|
||||
change_time,
|
||||
access_time,
|
||||
write_time);
|
||||
|
||||
/* Close the file */
|
||||
cli_close(srv->cli, fd);
|
||||
|
||||
/*
|
||||
* Unfortunately, setattrE() doesn't have a provision for
|
||||
* setting the access mode (attributes). We'll have to try
|
||||
* cli_setatr() for that, and with only this parameter, it
|
||||
* seems to work on win98.
|
||||
*/
|
||||
if (ret && mode != (uint16) -1) {
|
||||
ret = cli_setatr(srv->cli, path, mode, 0);
|
||||
}
|
||||
|
||||
if (! ret) {
|
||||
errno = SMBC_errno(context, srv->cli);
|
||||
TALLOC_FREE(frame);
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
TALLOC_FREE(frame);
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
* A routine to lseek() a file
|
||||
*/
|
||||
|
||||
off_t
|
||||
SMBC_lseek_ctx(SMBCCTX *context,
|
||||
SMBCFILE *file,
|
||||
off_t offset,
|
||||
int whence)
|
||||
{
|
||||
SMB_OFF_T size;
|
||||
char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
|
||||
char *path = NULL;
|
||||
char *targetpath = NULL;
|
||||
struct cli_state *targetcli = NULL;
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
if (!context || !context->initialized) {
|
||||
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!file || !SMBC_dlist_contains(context->files, file)) {
|
||||
|
||||
errno = EBADF;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
if (!file->file) {
|
||||
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1; /* Can't lseek a dir ... */
|
||||
|
||||
}
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
file->offset = offset;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
file->offset += offset;
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
/*d_printf(">>>lseek: parsing %s\n", file->fname);*/
|
||||
if (SMBC_parse_path(frame,
|
||||
context,
|
||||
file->fname,
|
||||
NULL,
|
||||
&server,
|
||||
&share,
|
||||
&path,
|
||||
&user,
|
||||
&password,
|
||||
NULL)) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*d_printf(">>>lseek: resolving %s\n", path);*/
|
||||
if (!cli_resolve_path(frame, "", file->srv->cli, path,
|
||||
&targetcli, &targetpath)) {
|
||||
d_printf("Could not resolve %s\n", path);
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
/*d_printf(">>>lseek: resolved path as %s\n", targetpath);*/
|
||||
|
||||
if (!cli_qfileinfo(targetcli, file->cli_fd, NULL,
|
||||
&size, NULL, NULL, NULL, NULL, NULL))
|
||||
{
|
||||
SMB_OFF_T b_size = size;
|
||||
if (!cli_getattrE(targetcli, file->cli_fd,
|
||||
NULL, &b_size, NULL, NULL, NULL))
|
||||
{
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
} else
|
||||
size = b_size;
|
||||
}
|
||||
file->offset = size + offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
TALLOC_FREE(frame);
|
||||
return file->offset;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Routine to truncate a file given by its file descriptor, to a specified size
|
||||
*/
|
||||
|
||||
int
|
||||
SMBC_ftruncate_ctx(SMBCCTX *context,
|
||||
SMBCFILE *file,
|
||||
off_t length)
|
||||
{
|
||||
SMB_OFF_T size = length;
|
||||
char *server = NULL;
|
||||
char *share = NULL;
|
||||
char *user = NULL;
|
||||
char *password = NULL;
|
||||
char *path = NULL;
|
||||
char *targetpath = NULL;
|
||||
struct cli_state *targetcli = NULL;
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
if (!context || !context->initialized) {
|
||||
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!file || !SMBC_dlist_contains(context->files, file)) {
|
||||
errno = EBADF;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!file->file) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*d_printf(">>>fstat: parsing %s\n", file->fname);*/
|
||||
if (SMBC_parse_path(frame,
|
||||
context,
|
||||
file->fname,
|
||||
NULL,
|
||||
&server,
|
||||
&share,
|
||||
&path,
|
||||
&user,
|
||||
&password,
|
||||
NULL)) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*d_printf(">>>fstat: resolving %s\n", path);*/
|
||||
if (!cli_resolve_path(frame, "", file->srv->cli, path,
|
||||
&targetcli, &targetpath)) {
|
||||
d_printf("Could not resolve %s\n", path);
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
/*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
|
||||
|
||||
if (!cli_ftruncate(targetcli, file->cli_fd, size)) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
TALLOC_FREE(frame);
|
||||
return 0;
|
||||
|
||||
}
|
73
source3/libsmb/libsmb_misc.c
Normal file
73
source3/libsmb/libsmb_misc.c
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
SMB client library implementation
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
Copyright (C) Richard Sharpe 2000, 2002
|
||||
Copyright (C) John Terpstra 2000
|
||||
Copyright (C) Tom Jansen (Ninja ISD) 2002
|
||||
Copyright (C) Derrell Lipman 2003-2008
|
||||
Copyright (C) Jeremy Allison 2007, 2008
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libsmbclient.h"
|
||||
#include "libsmb_internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* check if an element is part of the list.
|
||||
*/
|
||||
int
|
||||
SMBC_dlist_contains(SMBCFILE * list, SMBCFILE *p)
|
||||
{
|
||||
if (!p || !list) return False;
|
||||
do {
|
||||
if (p == list) return True;
|
||||
list = list->next;
|
||||
} while (list);
|
||||
return False;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert an SMB error into a UNIX error ...
|
||||
*/
|
||||
int
|
||||
SMBC_errno(SMBCCTX *context,
|
||||
struct cli_state *c)
|
||||
{
|
||||
int ret = cli_errno(c);
|
||||
|
||||
if (cli_is_dos_error(c)) {
|
||||
uint8 eclass;
|
||||
uint32 ecode;
|
||||
|
||||
cli_dos_error(c, &eclass, &ecode);
|
||||
|
||||
DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n",
|
||||
(int)eclass, (int)ecode, (int)ecode, ret));
|
||||
} else {
|
||||
NTSTATUS status;
|
||||
|
||||
status = cli_nt_error(c);
|
||||
|
||||
DEBUG(3,("smbc errno %s -> %d\n",
|
||||
nt_errstr(status), ret));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
399
source3/libsmb/libsmb_path.c
Normal file
399
source3/libsmb/libsmb_path.c
Normal file
@ -0,0 +1,399 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
SMB client library implementation
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
Copyright (C) Richard Sharpe 2000, 2002
|
||||
Copyright (C) John Terpstra 2000
|
||||
Copyright (C) Tom Jansen (Ninja ISD) 2002
|
||||
Copyright (C) Derrell Lipman 2003-2008
|
||||
Copyright (C) Jeremy Allison 2007, 2008
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libsmbclient.h"
|
||||
#include "libsmb_internal.h"
|
||||
|
||||
|
||||
/* Used by urldecode_talloc() */
|
||||
static int
|
||||
hex2int( unsigned int _char )
|
||||
{
|
||||
if ( _char >= 'A' && _char <='F')
|
||||
return _char - 'A' + 10;
|
||||
if ( _char >= 'a' && _char <='f')
|
||||
return _char - 'a' + 10;
|
||||
if ( _char >= '0' && _char <='9')
|
||||
return _char - '0';
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SMBC_urldecode()
|
||||
* and urldecode_talloc() (internal fn.)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
static int
|
||||
urldecode_talloc(TALLOC_CTX *ctx, char **pp_dest, const char *src)
|
||||
{
|
||||
int old_length = strlen(src);
|
||||
int i = 0;
|
||||
int err_count = 0;
|
||||
size_t newlen = 1;
|
||||
char *p, *dest;
|
||||
|
||||
if (old_length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*pp_dest = NULL;
|
||||
for (i = 0; i < old_length; ) {
|
||||
unsigned char character = src[i++];
|
||||
|
||||
if (character == '%') {
|
||||
int a = i+1 < old_length ? hex2int(src[i]) : -1;
|
||||
int b = i+1 < old_length ? hex2int(src[i+1]) : -1;
|
||||
|
||||
/* Replace valid sequence */
|
||||
if (a != -1 && b != -1) {
|
||||
/* Replace valid %xx sequence with %dd */
|
||||
character = (a * 16) + b;
|
||||
if (character == '\0') {
|
||||
break; /* Stop at %00 */
|
||||
}
|
||||
i += 2;
|
||||
} else {
|
||||
err_count++;
|
||||
}
|
||||
}
|
||||
newlen++;
|
||||
}
|
||||
|
||||
dest = TALLOC_ARRAY(ctx, char, newlen);
|
||||
if (!dest) {
|
||||
return err_count;
|
||||
}
|
||||
|
||||
err_count = 0;
|
||||
for (p = dest, i = 0; i < old_length; ) {
|
||||
unsigned char character = src[i++];
|
||||
|
||||
if (character == '%') {
|
||||
int a = i+1 < old_length ? hex2int(src[i]) : -1;
|
||||
int b = i+1 < old_length ? hex2int(src[i+1]) : -1;
|
||||
|
||||
/* Replace valid sequence */
|
||||
if (a != -1 && b != -1) {
|
||||
/* Replace valid %xx sequence with %dd */
|
||||
character = (a * 16) + b;
|
||||
if (character == '\0') {
|
||||
break; /* Stop at %00 */
|
||||
}
|
||||
i += 2;
|
||||
} else {
|
||||
err_count++;
|
||||
}
|
||||
}
|
||||
*p++ = character;
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
*pp_dest = dest;
|
||||
return err_count;
|
||||
}
|
||||
|
||||
int
|
||||
SMBC_urldecode(char *dest,
|
||||
char *src,
|
||||
size_t max_dest_len)
|
||||
{
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
char *pdest;
|
||||
int ret = urldecode_talloc(frame, &pdest, src);
|
||||
|
||||
if (pdest) {
|
||||
strlcpy(dest, pdest, max_dest_len);
|
||||
}
|
||||
TALLOC_FREE(frame);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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:").
|
||||
*
|
||||
*
|
||||
* 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->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.
|
||||
*/
|
||||
|
||||
static const char *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;
|
||||
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, context->workgroup);
|
||||
}
|
||||
|
||||
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 != NULL) {
|
||||
TALLOC_FREE(*pp_options);
|
||||
*pp_options = talloc_strdup(ctx, q);
|
||||
}
|
||||
}
|
||||
|
||||
if (*p == '\0') {
|
||||
goto decoding;
|
||||
}
|
||||
|
||||
if (*p == '/') {
|
||||
int wl = strlen(context->workgroup);
|
||||
|
||||
if (wl > 16) {
|
||||
wl = 16;
|
||||
}
|
||||
|
||||
*pp_server = talloc_strdup(ctx, context->workgroup);
|
||||
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, ';')) {
|
||||
char *workgroup;
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
334
source3/libsmb/libsmb_printjob.c
Normal file
334
source3/libsmb/libsmb_printjob.c
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
SMB client library implementation
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
Copyright (C) Richard Sharpe 2000, 2002
|
||||
Copyright (C) John Terpstra 2000
|
||||
Copyright (C) Tom Jansen (Ninja ISD) 2002
|
||||
Copyright (C) Derrell Lipman 2003-2008
|
||||
Copyright (C) Jeremy Allison 2007, 2008
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libsmbclient.h"
|
||||
#include "libsmb_internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Open a print file to be written to by other calls
|
||||
*/
|
||||
|
||||
SMBCFILE *
|
||||
SMBC_open_print_job_ctx(SMBCCTX *context,
|
||||
const char *fname)
|
||||
{
|
||||
char *server = NULL;
|
||||
char *share = NULL;
|
||||
char *user = NULL;
|
||||
char *password = NULL;
|
||||
char *path = NULL;
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
if (!context || !context->initialized) {
|
||||
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!fname) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG(4, ("SMBC_open_print_job_ctx(%s)\n", fname));
|
||||
|
||||
if (SMBC_parse_path(frame,
|
||||
context,
|
||||
fname,
|
||||
NULL,
|
||||
&server,
|
||||
&share,
|
||||
&path,
|
||||
&user,
|
||||
&password,
|
||||
NULL)) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* What if the path is empty, or the file exists? */
|
||||
|
||||
TALLOC_FREE(frame);
|
||||
return (context->posix_emu.open_fn)(context, fname, O_WRONLY, 666);
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to print a file on a remote server ...
|
||||
*
|
||||
* We open the file, which we assume to be on a remote server, and then
|
||||
* copy it to a print file on the share specified by printq.
|
||||
*/
|
||||
|
||||
int
|
||||
SMBC_print_file_ctx(SMBCCTX *c_file,
|
||||
const char *fname,
|
||||
SMBCCTX *c_print,
|
||||
const char *printq)
|
||||
{
|
||||
SMBCFILE *fid1;
|
||||
SMBCFILE *fid2;
|
||||
int bytes;
|
||||
int saverr;
|
||||
int tot_bytes = 0;
|
||||
char buf[4096];
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
if (!c_file || !c_file->initialized ||
|
||||
!c_print || !c_print->initialized) {
|
||||
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
if (!fname && !printq) {
|
||||
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
/* Try to open the file for reading ... */
|
||||
|
||||
if ((long)(fid1 = smbc_getFunctionOpen(c_file)(c_file, fname, O_RDONLY, 0666)) < 0) {
|
||||
DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno));
|
||||
TALLOC_FREE(frame);
|
||||
return -1; /* smbc_open sets errno */
|
||||
}
|
||||
|
||||
/* Now, try to open the printer file for writing */
|
||||
|
||||
if ((long)(fid2 = smbc_getFunctionOpenPrintJob(c_print)(c_print, printq)) < 0) {
|
||||
|
||||
saverr = errno; /* Save errno */
|
||||
smbc_getFunctionClose(c_file)(c_file, fid1);
|
||||
errno = saverr;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
while ((bytes = smbc_getFunctionRead(c_file)(c_file, fid1,
|
||||
buf, sizeof(buf))) > 0) {
|
||||
|
||||
tot_bytes += bytes;
|
||||
|
||||
if ((smbc_getFunctionWrite(c_print)(c_print, fid2,
|
||||
buf, bytes)) < 0) {
|
||||
|
||||
saverr = errno;
|
||||
smbc_getFunctionClose(c_file)(c_file, fid1);
|
||||
smbc_getFunctionClose(c_print)(c_print, fid2);
|
||||
errno = saverr;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
saverr = errno;
|
||||
|
||||
smbc_getFunctionClose(c_file)(c_file, fid1); /* We have to close these anyway */
|
||||
smbc_getFunctionClose(c_print)(c_print, fid2);
|
||||
|
||||
if (bytes < 0) {
|
||||
|
||||
errno = saverr;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
TALLOC_FREE(frame);
|
||||
return tot_bytes;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to list print jobs on a printer share ...
|
||||
*/
|
||||
|
||||
int
|
||||
SMBC_list_print_jobs_ctx(SMBCCTX *context,
|
||||
const char *fname,
|
||||
smbc_list_print_job_fn fn)
|
||||
{
|
||||
SMBCSRV *srv = NULL;
|
||||
char *server = NULL;
|
||||
char *share = NULL;
|
||||
char *user = NULL;
|
||||
char *password = NULL;
|
||||
char *workgroup = NULL;
|
||||
char *path = NULL;
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
if (!context || !context->initialized) {
|
||||
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!fname) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname));
|
||||
|
||||
if (SMBC_parse_path(frame,
|
||||
context,
|
||||
fname,
|
||||
&workgroup,
|
||||
&server,
|
||||
&share,
|
||||
&path,
|
||||
&user,
|
||||
&password,
|
||||
NULL)) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!user || user[0] == (char)0) {
|
||||
user = talloc_strdup(frame, context->user);
|
||||
if (!user) {
|
||||
errno = ENOMEM;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
srv = SMBC_server(frame, context, True,
|
||||
server, share, &workgroup, &user, &password);
|
||||
|
||||
if (!srv) {
|
||||
TALLOC_FREE(frame);
|
||||
return -1; /* errno set by SMBC_server */
|
||||
}
|
||||
|
||||
if (cli_print_queue(srv->cli,
|
||||
(void (*)(struct print_job_info *))fn) < 0) {
|
||||
errno = SMBC_errno(context, srv->cli);
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
TALLOC_FREE(frame);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a print job from a remote printer share
|
||||
*/
|
||||
|
||||
int
|
||||
SMBC_unlink_print_job_ctx(SMBCCTX *context,
|
||||
const char *fname,
|
||||
int id)
|
||||
{
|
||||
SMBCSRV *srv = NULL;
|
||||
char *server = NULL;
|
||||
char *share = NULL;
|
||||
char *user = NULL;
|
||||
char *password = NULL;
|
||||
char *workgroup = NULL;
|
||||
char *path = NULL;
|
||||
int err;
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
if (!context || !context->initialized) {
|
||||
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!fname) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname));
|
||||
|
||||
if (SMBC_parse_path(frame,
|
||||
context,
|
||||
fname,
|
||||
&workgroup,
|
||||
&server,
|
||||
&share,
|
||||
&path,
|
||||
&user,
|
||||
&password,
|
||||
NULL)) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!user || user[0] == (char)0) {
|
||||
user = talloc_strdup(frame, context->user);
|
||||
if (!user) {
|
||||
errno = ENOMEM;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
srv = SMBC_server(frame, context, True,
|
||||
server, share, &workgroup, &user, &password);
|
||||
|
||||
if (!srv) {
|
||||
|
||||
TALLOC_FREE(frame);
|
||||
return -1; /* errno set by SMBC_server */
|
||||
|
||||
}
|
||||
|
||||
if ((err = cli_printjob_del(srv->cli, id)) != 0) {
|
||||
|
||||
if (err < 0)
|
||||
errno = SMBC_errno(context, srv->cli);
|
||||
else if (err == ERRnosuchprintjob)
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
TALLOC_FREE(frame);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
675
source3/libsmb/libsmb_server.c
Normal file
675
source3/libsmb/libsmb_server.c
Normal file
@ -0,0 +1,675 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
SMB client library implementation
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
Copyright (C) Richard Sharpe 2000, 2002
|
||||
Copyright (C) John Terpstra 2000
|
||||
Copyright (C) Tom Jansen (Ninja ISD) 2002
|
||||
Copyright (C) Derrell Lipman 2003-2008
|
||||
Copyright (C) Jeremy Allison 2007, 2008
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libsmbclient.h"
|
||||
#include "libsmb_internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Check a server for being alive and well.
|
||||
* returns 0 if the server is in shape. Returns 1 on error
|
||||
*
|
||||
* Also useable outside libsmbclient to enable external cache
|
||||
* to do some checks too.
|
||||
*/
|
||||
int
|
||||
SMBC_check_server(SMBCCTX * context,
|
||||
SMBCSRV * server)
|
||||
{
|
||||
socklen_t size;
|
||||
struct sockaddr addr;
|
||||
|
||||
size = sizeof(addr);
|
||||
return (getpeername(server->cli->fd, &addr, &size) == -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a server from the cached server list it's unused.
|
||||
* On success, 0 is returned. 1 is returned if the server could not be removed.
|
||||
*
|
||||
* Also useable outside libsmbclient
|
||||
*/
|
||||
int
|
||||
SMBC_remove_unused_server(SMBCCTX * context,
|
||||
SMBCSRV * srv)
|
||||
{
|
||||
SMBCFILE * file;
|
||||
|
||||
/* are we being fooled ? */
|
||||
if (!context || !context->initialized || !srv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check all open files/directories for a relation with this server */
|
||||
for (file = context->files; file; file = file->next) {
|
||||
if (file->srv == srv) {
|
||||
/* Still used */
|
||||
DEBUG(3, ("smbc_remove_usused_server: "
|
||||
"%p still used by %p.\n",
|
||||
srv, file));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
DLIST_REMOVE(context->servers, srv);
|
||||
|
||||
cli_shutdown(srv->cli);
|
||||
srv->cli = NULL;
|
||||
|
||||
DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv));
|
||||
|
||||
(context->cache.remove_cached_server_fn)(context, srv);
|
||||
|
||||
SAFE_FREE(srv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* Call the auth_fn with fixed size (fstring) buffers.
|
||||
***************************************************************/
|
||||
void
|
||||
SMBC_call_auth_fn(TALLOC_CTX *ctx,
|
||||
SMBCCTX *context,
|
||||
const char *server,
|
||||
const char *share,
|
||||
char **pp_workgroup,
|
||||
char **pp_username,
|
||||
char **pp_password)
|
||||
{
|
||||
fstring workgroup;
|
||||
fstring username;
|
||||
fstring password;
|
||||
|
||||
strlcpy(workgroup, *pp_workgroup, sizeof(workgroup));
|
||||
strlcpy(username, *pp_username, sizeof(username));
|
||||
strlcpy(password, *pp_password, sizeof(password));
|
||||
|
||||
(context->server.get_auth_data_fn)(
|
||||
server, share,
|
||||
workgroup, sizeof(workgroup),
|
||||
username, sizeof(username),
|
||||
password, sizeof(password));
|
||||
|
||||
TALLOC_FREE(*pp_workgroup);
|
||||
TALLOC_FREE(*pp_username);
|
||||
TALLOC_FREE(*pp_password);
|
||||
|
||||
*pp_workgroup = talloc_strdup(ctx, workgroup);
|
||||
*pp_username = talloc_strdup(ctx, username);
|
||||
*pp_password = talloc_strdup(ctx, password);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SMBC_get_auth_data(const char *server, const char *share,
|
||||
char *workgroup_buf, int workgroup_buf_len,
|
||||
char *username_buf, int username_buf_len,
|
||||
char *password_buf, int password_buf_len)
|
||||
{
|
||||
/* Default function just uses provided data. Nothing to do. */
|
||||
}
|
||||
|
||||
|
||||
|
||||
SMBCSRV *
|
||||
SMBC_find_server(TALLOC_CTX *ctx,
|
||||
SMBCCTX *context,
|
||||
const char *server,
|
||||
const char *share,
|
||||
char **pp_workgroup,
|
||||
char **pp_username,
|
||||
char **pp_password)
|
||||
{
|
||||
SMBCSRV *srv;
|
||||
int auth_called = 0;
|
||||
|
||||
check_server_cache:
|
||||
|
||||
srv = (context->cache.get_cached_server_fn)(context,
|
||||
server, share,
|
||||
*pp_workgroup,
|
||||
*pp_username);
|
||||
|
||||
if (!auth_called && !srv && (!*pp_username || !(*pp_username)[0] ||
|
||||
!*pp_password || !(*pp_password)[0])) {
|
||||
SMBC_call_auth_fn(ctx, context, server, share,
|
||||
pp_workgroup, pp_username, pp_password);
|
||||
|
||||
if (!pp_workgroup || !pp_username || !pp_password) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* However, smbc_auth_fn may have picked up info relating to
|
||||
* an existing connection, so try for an existing connection
|
||||
* again ...
|
||||
*/
|
||||
auth_called = 1;
|
||||
goto check_server_cache;
|
||||
|
||||
}
|
||||
|
||||
if (srv) {
|
||||
if ((context->server.check_server_fn)(context, srv)) {
|
||||
/*
|
||||
* This server is no good anymore
|
||||
* Try to remove it and check for more possible
|
||||
* servers in the cache
|
||||
*/
|
||||
if ((context->server.remove_unused_server_fn)(context,
|
||||
srv)) {
|
||||
/*
|
||||
* We could not remove the server completely,
|
||||
* remove it from the cache so we will not get
|
||||
* it again. It will be removed when the last
|
||||
* file/dir is closed.
|
||||
*/
|
||||
(context->cache.remove_cached_server_fn)(context,
|
||||
srv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Maybe there are more cached connections to this
|
||||
* server
|
||||
*/
|
||||
goto check_server_cache;
|
||||
}
|
||||
|
||||
return srv;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect to a server, possibly on an existing connection
|
||||
*
|
||||
* Here, what we want to do is: If the server and username
|
||||
* match an existing connection, reuse that, otherwise, establish a
|
||||
* new connection.
|
||||
*
|
||||
* If we have to create a new connection, call the auth_fn to get the
|
||||
* info we need, unless the username and password were passed in.
|
||||
*/
|
||||
|
||||
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;
|
||||
struct cli_state *c;
|
||||
struct nmb_name called, calling;
|
||||
const char *server_n = server;
|
||||
struct sockaddr_storage ss;
|
||||
int tried_reverse = 0;
|
||||
int port_try_first;
|
||||
int port_try_next;
|
||||
const char *username_used;
|
||||
NTSTATUS status;
|
||||
|
||||
zero_addr(&ss);
|
||||
ZERO_STRUCT(c);
|
||||
|
||||
if (server[0] == 0) {
|
||||
errno = EPERM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Look for a cached connection */
|
||||
srv = SMBC_find_server(ctx, context, server, share,
|
||||
pp_workgroup, pp_username, pp_password);
|
||||
|
||||
/*
|
||||
* If we found a connection and we're only allowed one share per
|
||||
* server...
|
||||
*/
|
||||
if (srv && *share != '\0' && context->one_share_per_server) {
|
||||
|
||||
/*
|
||||
* ... then if there's no current connection to the share,
|
||||
* connect to it. SMBC_find_server(), or rather the function
|
||||
* pointed to by context->cache.get_cached_srv_fn which
|
||||
* was called by SMBC_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 */
|
||||
SMBC_call_auth_fn(ctx, context, server, share,
|
||||
pp_workgroup, pp_username, pp_password);
|
||||
|
||||
if (!*pp_workgroup || !*pp_username || !*pp_password) {
|
||||
errno = ENOMEM;
|
||||
cli_shutdown(srv->cli);
|
||||
srv->cli = NULL;
|
||||
(context->cache.remove_cached_server_fn)(context,
|
||||
srv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't need to renegotiate encryption
|
||||
* here as the encryption context is not per
|
||||
* tid.
|
||||
*/
|
||||
|
||||
if (!cli_send_tconX(srv->cli, share, "?????",
|
||||
*pp_password,
|
||||
strlen(*pp_password)+1)) {
|
||||
|
||||
errno = SMBC_errno(context, srv->cli);
|
||||
cli_shutdown(srv->cli);
|
||||
srv->cli = NULL;
|
||||
(context->cache.remove_cached_server_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;
|
||||
}
|
||||
|
||||
/* If we're not asked to connect when a connection doesn't exist... */
|
||||
if (! connect_if_not_found) {
|
||||
/* ... then we're done here. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!*pp_workgroup || !*pp_username || !*pp_password) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
|
||||
|
||||
again:
|
||||
|
||||
zero_addr(&ss);
|
||||
|
||||
/* have to open a new connection */
|
||||
if ((c = cli_initialise()) == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (context->use_kerberos) {
|
||||
c->use_kerberos = True;
|
||||
}
|
||||
if (context->fallback_after_kerberos) {
|
||||
c->fallback_after_kerberos = True;
|
||||
}
|
||||
|
||||
c->timeout = context->timeout;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
status = cli_connect(c, server_n, &ss);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
|
||||
/* First connection attempt failed. Try alternate port. */
|
||||
c->port = port_try_next;
|
||||
|
||||
status = cli_connect(c, server_n, &ss);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
cli_shutdown(c);
|
||||
errno = ETIMEDOUT;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cli_session_request(c, &calling, &called)) {
|
||||
cli_shutdown(c);
|
||||
if (strcmp(called.name, "*SMBSERVER")) {
|
||||
make_nmb_name(&called , "*SMBSERVER", 0x20);
|
||||
goto again;
|
||||
} else { /* Try one more time, but ensure we don't loop */
|
||||
|
||||
/* Only try this if server is an IP address ... */
|
||||
|
||||
if (is_ipaddress(server) && !tried_reverse) {
|
||||
fstring remote_name;
|
||||
struct sockaddr_storage rem_ss;
|
||||
|
||||
if (!interpret_string_addr(&rem_ss, server,
|
||||
NI_NUMERICHOST)) {
|
||||
DEBUG(4, ("Could not convert IP address "
|
||||
"%s to struct sockaddr_storage\n",
|
||||
server));
|
||||
errno = ETIMEDOUT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tried_reverse++; /* Yuck */
|
||||
|
||||
if (name_status_find("*", 0, 0, &rem_ss, remote_name)) {
|
||||
make_nmb_name(&called, remote_name, 0x20);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
}
|
||||
errno = ETIMEDOUT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG(4,(" session request ok\n"));
|
||||
|
||||
if (!cli_negprot(c)) {
|
||||
cli_shutdown(c);
|
||||
errno = ETIMEDOUT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
username_used = *pp_username;
|
||||
|
||||
if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used,
|
||||
*pp_password, strlen(*pp_password),
|
||||
*pp_password, strlen(*pp_password),
|
||||
*pp_workgroup))) {
|
||||
|
||||
/* Failed. Try an anonymous login, if allowed by flags. */
|
||||
username_used = "";
|
||||
|
||||
if (context->no_auto_anonymous_login ||
|
||||
!NT_STATUS_IS_OK(cli_session_setup(c, username_used,
|
||||
*pp_password, 1,
|
||||
*pp_password, 0,
|
||||
*pp_workgroup))) {
|
||||
|
||||
cli_shutdown(c);
|
||||
errno = EPERM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(4,(" session setup ok\n"));
|
||||
|
||||
if (!cli_send_tconX(c, share, "?????",
|
||||
*pp_password, strlen(*pp_password)+1)) {
|
||||
errno = SMBC_errno(context, c);
|
||||
cli_shutdown(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG(4,(" tconx ok\n"));
|
||||
|
||||
if (context->smb_encryption_level) {
|
||||
/* Attempt UNIX smb encryption. */
|
||||
if (!NT_STATUS_IS_OK(cli_force_encryption(c,
|
||||
username_used,
|
||||
*pp_password,
|
||||
*pp_workgroup))) {
|
||||
|
||||
/*
|
||||
* context->smb_encryption_level == 1
|
||||
* means don't fail if encryption can't be negotiated,
|
||||
* == 2 means fail if encryption can't be negotiated.
|
||||
*/
|
||||
|
||||
DEBUG(4,(" SMB encrypt failed\n"));
|
||||
|
||||
if (context->smb_encryption_level == 2) {
|
||||
cli_shutdown(c);
|
||||
errno = EPERM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
DEBUG(4,(" SMB encrypt ok\n"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok, we have got a nice connection
|
||||
* Let's allocate a server structure.
|
||||
*/
|
||||
|
||||
srv = SMB_MALLOC_P(SMBCSRV);
|
||||
if (!srv) {
|
||||
errno = ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ZERO_STRUCTP(srv);
|
||||
srv->cli = c;
|
||||
srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
|
||||
srv->no_pathinfo = False;
|
||||
srv->no_pathinfo2 = False;
|
||||
srv->no_nt_session = False;
|
||||
|
||||
/* now add it to the cache (internal or external) */
|
||||
/* Let the cache function set errno if it wants to */
|
||||
errno = 0;
|
||||
if ((context->cache.add_cached_server_fn)(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;
|
||||
}
|
||||
goto failed;
|
||||
}
|
||||
|
||||
DEBUG(2, ("Server connect ok: //%s/%s: %p\n",
|
||||
server, share, srv));
|
||||
|
||||
DLIST_ADD(context->servers, srv);
|
||||
return srv;
|
||||
|
||||
failed:
|
||||
cli_shutdown(c);
|
||||
if (!srv) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SAFE_FREE(srv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect to a server for getting/setting attributes, possibly on an existing
|
||||
* connection. This works similarly to SMBC_server().
|
||||
*/
|
||||
SMBCSRV *
|
||||
SMBC_attr_server(TALLOC_CTX *ctx,
|
||||
SMBCCTX *context,
|
||||
const char *server,
|
||||
const char *share,
|
||||
char **pp_workgroup,
|
||||
char **pp_username,
|
||||
char **pp_password)
|
||||
{
|
||||
int flags;
|
||||
struct sockaddr_storage ss;
|
||||
struct cli_state *ipc_cli;
|
||||
struct rpc_pipe_client *pipe_hnd;
|
||||
NTSTATUS nt_status;
|
||||
SMBCSRV *ipc_srv=NULL;
|
||||
|
||||
/*
|
||||
* 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 = SMBC_find_server(ctx, context, server, "*IPC$",
|
||||
pp_workgroup, pp_username, pp_password);
|
||||
if (!ipc_srv) {
|
||||
|
||||
/* We didn't find a cached connection. Get the password */
|
||||
if (!*pp_password || (*pp_password)[0] == '\0') {
|
||||
/* ... then retrieve it now. */
|
||||
SMBC_call_auth_fn(ctx, context, server, share,
|
||||
pp_workgroup, pp_username, pp_password);
|
||||
if (!*pp_workgroup || !*pp_username || !*pp_password) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
if (context->use_kerberos) {
|
||||
flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
|
||||
}
|
||||
|
||||
zero_addr(&ss);
|
||||
nt_status = cli_full_connection(&ipc_cli,
|
||||
global_myname(), server,
|
||||
&ss, 0, "IPC$", "?????",
|
||||
*pp_username,
|
||||
*pp_workgroup,
|
||||
*pp_password,
|
||||
flags,
|
||||
Undefined, NULL);
|
||||
if (! NT_STATUS_IS_OK(nt_status)) {
|
||||
DEBUG(1,("cli_full_connection failed! (%s)\n",
|
||||
nt_errstr(nt_status)));
|
||||
errno = ENOTSUP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (context->smb_encryption_level) {
|
||||
/* Attempt UNIX smb encryption. */
|
||||
if (!NT_STATUS_IS_OK(cli_force_encryption(ipc_cli,
|
||||
*pp_username,
|
||||
*pp_password,
|
||||
*pp_workgroup))) {
|
||||
|
||||
/*
|
||||
* context->smb_encryption_level ==
|
||||
* 1 means don't fail if encryption can't be
|
||||
* negotiated, == 2 means fail if encryption
|
||||
* can't be negotiated.
|
||||
*/
|
||||
|
||||
DEBUG(4,(" SMB encrypt failed on IPC$\n"));
|
||||
|
||||
if (context->smb_encryption_level == 2) {
|
||||
cli_shutdown(ipc_cli);
|
||||
errno = EPERM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
DEBUG(4,(" SMB encrypt ok on IPC$\n"));
|
||||
}
|
||||
|
||||
ipc_srv = SMB_MALLOC_P(SMBCSRV);
|
||||
if (!ipc_srv) {
|
||||
errno = ENOMEM;
|
||||
cli_shutdown(ipc_cli);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ZERO_STRUCTP(ipc_srv);
|
||||
ipc_srv->cli = ipc_cli;
|
||||
|
||||
pipe_hnd = cli_rpc_pipe_open_noauth(ipc_srv->cli,
|
||||
PI_LSARPC,
|
||||
&nt_status);
|
||||
if (!pipe_hnd) {
|
||||
DEBUG(1, ("cli_nt_session_open fail!\n"));
|
||||
errno = ENOTSUP;
|
||||
cli_shutdown(ipc_srv->cli);
|
||||
free(ipc_srv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some systems don't support
|
||||
* SEC_RIGHTS_MAXIMUM_ALLOWED, but NT sends 0x2000000
|
||||
* so we might as well do it too.
|
||||
*/
|
||||
|
||||
nt_status = rpccli_lsa_open_policy(
|
||||
pipe_hnd,
|
||||
talloc_tos(),
|
||||
True,
|
||||
GENERIC_EXECUTE_ACCESS,
|
||||
&ipc_srv->pol);
|
||||
|
||||
if (!NT_STATUS_IS_OK(nt_status)) {
|
||||
errno = SMBC_errno(context, ipc_srv->cli);
|
||||
cli_shutdown(ipc_srv->cli);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* now add it to the cache (internal or external) */
|
||||
|
||||
errno = 0; /* let cache function set errno if it likes */
|
||||
if ((context->cache.add_cached_server_fn)(context, ipc_srv,
|
||||
server,
|
||||
"*IPC$",
|
||||
*pp_workgroup,
|
||||
*pp_username)) {
|
||||
DEBUG(3, (" Failed to add server to cache\n"));
|
||||
if (errno == 0) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
cli_shutdown(ipc_srv->cli);
|
||||
free(ipc_srv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DLIST_ADD(context->servers, ipc_srv);
|
||||
}
|
||||
|
||||
return ipc_srv;
|
||||
}
|
302
source3/libsmb/libsmb_stat.c
Normal file
302
source3/libsmb/libsmb_stat.c
Normal file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
SMB client library implementation
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
Copyright (C) Richard Sharpe 2000, 2002
|
||||
Copyright (C) John Terpstra 2000
|
||||
Copyright (C) Tom Jansen (Ninja ISD) 2002
|
||||
Copyright (C) Derrell Lipman 2003-2008
|
||||
Copyright (C) Jeremy Allison 2007, 2008
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libsmbclient.h"
|
||||
#include "libsmb_internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Generate an inode number from file name for those things that need it
|
||||
*/
|
||||
|
||||
static ino_t
|
||||
generate_inode(SMBCCTX *context,
|
||||
const char *name)
|
||||
{
|
||||
if (!context || !context->initialized) {
|
||||
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
if (!*name) return 2; /* FIXME, why 2 ??? */
|
||||
return (ino_t)str_checksum(name);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to put basic stat info into a stat structure ... Used by stat and
|
||||
* fstat below.
|
||||
*/
|
||||
|
||||
static int
|
||||
setup_stat(SMBCCTX *context,
|
||||
struct stat *st,
|
||||
char *fname,
|
||||
SMB_OFF_T size,
|
||||
int mode)
|
||||
{
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
st->st_mode = 0;
|
||||
|
||||
if (IS_DOS_DIR(mode)) {
|
||||
st->st_mode = SMBC_DIR_MODE;
|
||||
} else {
|
||||
st->st_mode = SMBC_FILE_MODE;
|
||||
}
|
||||
|
||||
if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR;
|
||||
if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP;
|
||||
if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH;
|
||||
if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR;
|
||||
|
||||
st->st_size = size;
|
||||
#ifdef HAVE_STAT_ST_BLKSIZE
|
||||
st->st_blksize = 512;
|
||||
#endif
|
||||
#ifdef HAVE_STAT_ST_BLOCKS
|
||||
st->st_blocks = (size+511)/512;
|
||||
#endif
|
||||
#ifdef HAVE_STRUCT_STAT_ST_RDEV
|
||||
st->st_rdev = 0;
|
||||
#endif
|
||||
st->st_uid = getuid();
|
||||
st->st_gid = getgid();
|
||||
|
||||
if (IS_DOS_DIR(mode)) {
|
||||
st->st_nlink = 2;
|
||||
} else {
|
||||
st->st_nlink = 1;
|
||||
}
|
||||
|
||||
if (st->st_ino == 0) {
|
||||
st->st_ino = generate_inode(context, fname);
|
||||
}
|
||||
|
||||
TALLOC_FREE(frame);
|
||||
return True; /* FIXME: Is this needed ? */
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to stat a file given a name
|
||||
*/
|
||||
|
||||
int
|
||||
SMBC_stat_ctx(SMBCCTX *context,
|
||||
const char *fname,
|
||||
struct stat *st)
|
||||
{
|
||||
SMBCSRV *srv = NULL;
|
||||
char *server = NULL;
|
||||
char *share = NULL;
|
||||
char *user = NULL;
|
||||
char *password = NULL;
|
||||
char *workgroup = NULL;
|
||||
char *path = NULL;
|
||||
struct timespec write_time_ts;
|
||||
struct timespec access_time_ts;
|
||||
struct timespec change_time_ts;
|
||||
SMB_OFF_T size = 0;
|
||||
uint16 mode = 0;
|
||||
SMB_INO_T ino = 0;
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
if (!context || !context->initialized) {
|
||||
|
||||
errno = EINVAL; /* Best I can think of ... */
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!fname) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG(4, ("smbc_stat(%s)\n", fname));
|
||||
|
||||
if (SMBC_parse_path(frame,
|
||||
context,
|
||||
fname,
|
||||
&workgroup,
|
||||
&server,
|
||||
&share,
|
||||
&path,
|
||||
&user,
|
||||
&password,
|
||||
NULL)) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!user || user[0] == (char)0) {
|
||||
user = talloc_strdup(frame,context->user);
|
||||
if (!user) {
|
||||
errno = ENOMEM;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
srv = SMBC_server(frame, context, True,
|
||||
server, share, &workgroup, &user, &password);
|
||||
|
||||
if (!srv) {
|
||||
TALLOC_FREE(frame);
|
||||
return -1; /* errno set by SMBC_server */
|
||||
}
|
||||
|
||||
if (!SMBC_getatr(context, srv, path, &mode, &size,
|
||||
NULL,
|
||||
&access_time_ts,
|
||||
&write_time_ts,
|
||||
&change_time_ts,
|
||||
&ino)) {
|
||||
errno = SMBC_errno(context, srv->cli);
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
st->st_ino = ino;
|
||||
|
||||
setup_stat(context, st, (char *) fname, size, mode);
|
||||
|
||||
set_atimespec(st, access_time_ts);
|
||||
set_ctimespec(st, change_time_ts);
|
||||
set_mtimespec(st, write_time_ts);
|
||||
st->st_dev = srv->dev;
|
||||
|
||||
TALLOC_FREE(frame);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to stat a file given an fd
|
||||
*/
|
||||
|
||||
int
|
||||
SMBC_fstat_ctx(SMBCCTX *context,
|
||||
SMBCFILE *file,
|
||||
struct stat *st)
|
||||
{
|
||||
struct timespec change_time_ts;
|
||||
struct timespec access_time_ts;
|
||||
struct timespec write_time_ts;
|
||||
SMB_OFF_T size;
|
||||
uint16 mode;
|
||||
char *server = NULL;
|
||||
char *share = NULL;
|
||||
char *user = NULL;
|
||||
char *password = NULL;
|
||||
char *path = NULL;
|
||||
char *targetpath = NULL;
|
||||
struct cli_state *targetcli = NULL;
|
||||
SMB_INO_T ino = 0;
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
if (!context || !context->initialized) {
|
||||
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!file || !SMBC_dlist_contains(context->files, file)) {
|
||||
errno = EBADF;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!file->file) {
|
||||
TALLOC_FREE(frame);
|
||||
return (context->posix_emu.fstatdir_fn)(context, file, st);
|
||||
}
|
||||
|
||||
/*d_printf(">>>fstat: parsing %s\n", file->fname);*/
|
||||
if (SMBC_parse_path(frame,
|
||||
context,
|
||||
file->fname,
|
||||
NULL,
|
||||
&server,
|
||||
&share,
|
||||
&path,
|
||||
&user,
|
||||
&password,
|
||||
NULL)) {
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*d_printf(">>>fstat: resolving %s\n", path);*/
|
||||
if (!cli_resolve_path(frame, "", file->srv->cli, path,
|
||||
&targetcli, &targetpath)) {
|
||||
d_printf("Could not resolve %s\n", path);
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
/*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
|
||||
|
||||
if (!cli_qfileinfo(targetcli, file->cli_fd, &mode, &size,
|
||||
NULL,
|
||||
&access_time_ts,
|
||||
&write_time_ts,
|
||||
&change_time_ts,
|
||||
&ino)) {
|
||||
|
||||
time_t change_time, access_time, write_time;
|
||||
|
||||
if (!cli_getattrE(targetcli, file->cli_fd, &mode, &size,
|
||||
&change_time, &access_time, &write_time)) {
|
||||
|
||||
errno = EINVAL;
|
||||
TALLOC_FREE(frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
change_time_ts = convert_time_t_to_timespec(change_time);
|
||||
access_time_ts = convert_time_t_to_timespec(access_time);
|
||||
write_time_ts = convert_time_t_to_timespec(write_time);
|
||||
}
|
||||
|
||||
st->st_ino = ino;
|
||||
|
||||
setup_stat(context, st, file->fname, size, mode);
|
||||
|
||||
set_atimespec(st, access_time_ts);
|
||||
set_ctimespec(st, change_time_ts);
|
||||
set_mtimespec(st, write_time_ts);
|
||||
st->st_dev = file->srv->dev;
|
||||
|
||||
TALLOC_FREE(frame);
|
||||
return 0;
|
||||
|
||||
}
|
2293
source3/libsmb/libsmb_xattr.c
Normal file
2293
source3/libsmb/libsmb_xattr.c
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user