net-smb 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Makefile +18 -0
- data/Rakefile +10 -2
- data/Rakefile.local.example +7 -0
- data/ext/net/smb/dlinklist.h +181 -0
- data/ext/net/smb/rb_smb.h +100 -0
- data/ext/net/smb/smb.c +254 -51
- data/ext/net/smb/smbdir.c +236 -0
- data/ext/net/smb/smbfile.c +354 -0
- data/lib/net/smb/version.rb +1 -1
- data/net-smb.gemspec +2 -2
- data/test/bin/smbd.wrapper +26 -0
- data/test/etc/smb.conf +32 -0
- data/test/test_net_smb.rb +310 -5
- metadata +15 -5
data/Makefile
ADDED
data/Rakefile
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
begin
|
2
|
+
load 'Rakefile.local'
|
3
|
+
rescue LoadError => e
|
4
|
+
end
|
5
|
+
|
1
6
|
begin
|
2
7
|
require 'bundler/gem_tasks'
|
3
8
|
rescue LoadError => e
|
4
|
-
p e
|
5
9
|
end
|
10
|
+
|
6
11
|
require 'rake/clean'
|
7
12
|
require 'rake/testtask'
|
8
13
|
|
@@ -10,7 +15,10 @@ Rake::TestTask.new
|
|
10
15
|
|
11
16
|
CLEAN.include('ext/**/*.{log,o,so}')
|
12
17
|
CLEAN.include('ext/**/Makefile')
|
13
|
-
|
18
|
+
CLEAN.include('lib/**/*.so')
|
19
|
+
CLOBBER.include('pkg/*')
|
20
|
+
CLOBBER.include('test/log')
|
21
|
+
CLOBBER.include('test/log.[0-9]')
|
14
22
|
|
15
23
|
EXT_PATH = 'net/smb'
|
16
24
|
|
@@ -0,0 +1,7 @@
|
|
1
|
+
ENV['CFLAGS'] = '-I/usr/local/samba/include'
|
2
|
+
ENV['LDFLAGS'] = '-L/usr/local/samba/lib -Wl,-rpath,/usr/local/samba/lib'
|
3
|
+
|
4
|
+
ENV['TEST_SMBD'] = '/usr/local/samba/sbin/smbd'
|
5
|
+
ENV['TEST_PDBEDIT'] = '/usr/local/samba/bin/pdbedit'
|
6
|
+
#ENV['TEST_SMBD_STRACE'] = 'strace'
|
7
|
+
#ENV['TEST_SMBD_STRACE_OPTIONS'] = '-ffttTxs9999'
|
@@ -0,0 +1,181 @@
|
|
1
|
+
/*
|
2
|
+
Unix SMB/CIFS implementation.
|
3
|
+
some simple double linked list macros
|
4
|
+
|
5
|
+
Copyright (C) Andrew Tridgell 1998-2010
|
6
|
+
|
7
|
+
This program is free software; you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU General Public License as published by
|
9
|
+
the Free Software Foundation; either version 3 of the License, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
This program is distributed in the hope that it will be useful,
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
GNU General Public License for more details.
|
16
|
+
|
17
|
+
You should have received a copy of the GNU General Public License
|
18
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
*/
|
20
|
+
|
21
|
+
/* To use these macros you must have a structure containing a next and
|
22
|
+
prev pointer */
|
23
|
+
|
24
|
+
#ifndef _DLINKLIST_H
|
25
|
+
#define _DLINKLIST_H
|
26
|
+
|
27
|
+
/*
|
28
|
+
February 2010 - changed list format to have a prev pointer from the
|
29
|
+
list head. This makes DLIST_ADD_END() O(1) even though we only have
|
30
|
+
one list pointer.
|
31
|
+
|
32
|
+
The scheme is as follows:
|
33
|
+
|
34
|
+
1) with no entries in the list:
|
35
|
+
list_head == NULL
|
36
|
+
|
37
|
+
2) with 1 entry in the list:
|
38
|
+
list_head->next == NULL
|
39
|
+
list_head->prev == list_head
|
40
|
+
|
41
|
+
3) with 2 entries in the list:
|
42
|
+
list_head->next == element2
|
43
|
+
list_head->prev == element2
|
44
|
+
element2->prev == list_head
|
45
|
+
element2->next == NULL
|
46
|
+
|
47
|
+
4) with N entries in the list:
|
48
|
+
list_head->next == element2
|
49
|
+
list_head->prev == elementN
|
50
|
+
elementN->prev == element{N-1}
|
51
|
+
elementN->next == NULL
|
52
|
+
|
53
|
+
This allows us to find the tail of the list by using
|
54
|
+
list_head->prev, which means we can add to the end of the list in
|
55
|
+
O(1) time
|
56
|
+
|
57
|
+
|
58
|
+
Note that the 'type' arguments below are no longer needed, but
|
59
|
+
are kept for now to prevent an incompatible argument change
|
60
|
+
*/
|
61
|
+
|
62
|
+
|
63
|
+
/*
|
64
|
+
add an element at the front of a list
|
65
|
+
*/
|
66
|
+
#define DLIST_ADD(list, p) \
|
67
|
+
do { \
|
68
|
+
if (!(list)) { \
|
69
|
+
(p)->prev = (list) = (p); \
|
70
|
+
(p)->next = NULL; \
|
71
|
+
} else { \
|
72
|
+
(p)->prev = (list)->prev; \
|
73
|
+
(list)->prev = (p); \
|
74
|
+
(p)->next = (list); \
|
75
|
+
(list) = (p); \
|
76
|
+
} \
|
77
|
+
} while (0)
|
78
|
+
|
79
|
+
/*
|
80
|
+
remove an element from a list
|
81
|
+
Note that the element doesn't have to be in the list. If it
|
82
|
+
isn't then this is a no-op
|
83
|
+
*/
|
84
|
+
#define DLIST_REMOVE(list, p) \
|
85
|
+
do { \
|
86
|
+
if ((p) == (list)) { \
|
87
|
+
if ((p)->next) (p)->next->prev = (p)->prev; \
|
88
|
+
(list) = (p)->next; \
|
89
|
+
} else if ((list) && (p) == (list)->prev) { \
|
90
|
+
(p)->prev->next = NULL; \
|
91
|
+
(list)->prev = (p)->prev; \
|
92
|
+
} else { \
|
93
|
+
if ((p)->prev) (p)->prev->next = (p)->next; \
|
94
|
+
if ((p)->next) (p)->next->prev = (p)->prev; \
|
95
|
+
} \
|
96
|
+
if ((p) != (list)) (p)->next = (p)->prev = NULL; \
|
97
|
+
} while (0)
|
98
|
+
|
99
|
+
/*
|
100
|
+
find the head of the list given any element in it.
|
101
|
+
Note that this costs O(N), so you should avoid this macro
|
102
|
+
if at all possible!
|
103
|
+
*/
|
104
|
+
#define DLIST_HEAD(p, result_head) \
|
105
|
+
do { \
|
106
|
+
(result_head) = (p); \
|
107
|
+
while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
|
108
|
+
} while(0)
|
109
|
+
|
110
|
+
/* return the last element in the list */
|
111
|
+
#define DLIST_TAIL(list) ((list)?(list)->prev:NULL)
|
112
|
+
|
113
|
+
/* return the previous element in the list. */
|
114
|
+
#define DLIST_PREV(p) (((p)->prev && (p)->prev->next != NULL)?(p)->prev:NULL)
|
115
|
+
|
116
|
+
/* insert 'p' after the given element 'el' in a list. If el is NULL then
|
117
|
+
this is the same as a DLIST_ADD() */
|
118
|
+
#define DLIST_ADD_AFTER(list, p, el) \
|
119
|
+
do { \
|
120
|
+
if (!(list) || !(el)) { \
|
121
|
+
DLIST_ADD(list, p); \
|
122
|
+
} else { \
|
123
|
+
(p)->prev = (el); \
|
124
|
+
(p)->next = (el)->next; \
|
125
|
+
(el)->next = (p); \
|
126
|
+
if ((p)->next) (p)->next->prev = (p); \
|
127
|
+
if ((list)->prev == (el)) (list)->prev = (p); \
|
128
|
+
}\
|
129
|
+
} while (0)
|
130
|
+
|
131
|
+
|
132
|
+
/*
|
133
|
+
add to the end of a list.
|
134
|
+
Note that 'type' is ignored
|
135
|
+
*/
|
136
|
+
#define DLIST_ADD_END(list, p, type) \
|
137
|
+
do { \
|
138
|
+
if (!(list)) { \
|
139
|
+
DLIST_ADD(list, p); \
|
140
|
+
} else { \
|
141
|
+
DLIST_ADD_AFTER(list, p, (list)->prev); \
|
142
|
+
} \
|
143
|
+
} while (0)
|
144
|
+
|
145
|
+
/* promote an element to the from of a list */
|
146
|
+
#define DLIST_PROMOTE(list, p) \
|
147
|
+
do { \
|
148
|
+
DLIST_REMOVE(list, p); \
|
149
|
+
DLIST_ADD(list, p); \
|
150
|
+
} while (0)
|
151
|
+
|
152
|
+
/*
|
153
|
+
demote an element to the end of a list.
|
154
|
+
Note that 'type' is ignored
|
155
|
+
*/
|
156
|
+
#define DLIST_DEMOTE(list, p, type) \
|
157
|
+
do { \
|
158
|
+
DLIST_REMOVE(list, p); \
|
159
|
+
DLIST_ADD_END(list, p, NULL); \
|
160
|
+
} while (0)
|
161
|
+
|
162
|
+
/*
|
163
|
+
concatenate two lists - putting all elements of the 2nd list at the
|
164
|
+
end of the first list.
|
165
|
+
Note that 'type' is ignored
|
166
|
+
*/
|
167
|
+
#define DLIST_CONCATENATE(list1, list2, type) \
|
168
|
+
do { \
|
169
|
+
if (!(list1)) { \
|
170
|
+
(list1) = (list2); \
|
171
|
+
} else { \
|
172
|
+
(list1)->prev->next = (list2); \
|
173
|
+
if (list2) { \
|
174
|
+
void *_tmplist = (void *)(list1)->prev; \
|
175
|
+
(list1)->prev = (list2)->prev; \
|
176
|
+
(list2)->prev = _tmplist; \
|
177
|
+
} \
|
178
|
+
} \
|
179
|
+
} while (0)
|
180
|
+
|
181
|
+
#endif /* _DLINKLIST_H */
|
@@ -0,0 +1,100 @@
|
|
1
|
+
/*
|
2
|
+
* Ruby/Net::SMB - SMB/CIFS client (Samba libsmbclient binding) for Ruby
|
3
|
+
* Common header for Net::SMB
|
4
|
+
* Copyright (C) 2012 SATOH Fumiyas @ OSS Technology Corp., Japan
|
5
|
+
*
|
6
|
+
* This program is free software; you can redistribute it and/or modify
|
7
|
+
* it under the terms of the GNU General Public License as published by
|
8
|
+
* the Free Software Foundation; either version 3 of the License, or
|
9
|
+
* (at your option) any later version.
|
10
|
+
*
|
11
|
+
* This program is distributed in the hope that it will be useful,
|
12
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
* GNU General Public License for more details.
|
15
|
+
*
|
16
|
+
* You should have received a copy of the GNU General Public License
|
17
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
*/
|
19
|
+
|
20
|
+
#ifndef _RB_SMB_H_
|
21
|
+
|
22
|
+
#include <ruby.h>
|
23
|
+
#include <ruby/encoding.h>
|
24
|
+
#include <libsmbclient.h>
|
25
|
+
|
26
|
+
#ifdef RB_SMB_DEBUG
|
27
|
+
# undef RB_SMB_DEBUG
|
28
|
+
# define RB_SMB_DEBUG(fmt, ...) \
|
29
|
+
do { \
|
30
|
+
fprintf(stdout, "%s:%s:%d ", __FILE__, __func__, __LINE__); \
|
31
|
+
fprintf(stdout, fmt, __VA_ARGS__); \
|
32
|
+
fflush(stdout); \
|
33
|
+
} while (0)
|
34
|
+
#else
|
35
|
+
# define RB_SMB_DEBUG(fmt, ...)
|
36
|
+
#endif
|
37
|
+
|
38
|
+
#define SMBC_TRUE ((smbc_bool)1)
|
39
|
+
#define SMBC_FALSE ((smbc_bool)0)
|
40
|
+
|
41
|
+
#define TRUE_P(value) ((value) == Qtrue)
|
42
|
+
#define FALSE_P(value) (NIL_P(value) || (value) == Qfalse)
|
43
|
+
|
44
|
+
#define SMBC2RB_BOOL(b) ((b) ? Qtrue : Qfalse)
|
45
|
+
#define RB2SMBC_BOOL(v) (TRUE_P(v) ? SMBC_TRUE : SMBC_FALSE)
|
46
|
+
|
47
|
+
#define RB_SMB_NAME "Net::SMB"
|
48
|
+
#define RB_SMBDIR_NAME "Net::SMB::Dir"
|
49
|
+
#define RB_SMBFILE_NAME "Net::SMB::File"
|
50
|
+
|
51
|
+
#define RB_SMBFILE_BUFFER_SIZE 8192
|
52
|
+
|
53
|
+
typedef struct rb_smb_data RB_SMB_DATA;
|
54
|
+
typedef struct rb_smbfile_data RB_SMBFILE_DATA;
|
55
|
+
|
56
|
+
struct rb_smbfile_data {
|
57
|
+
rb_encoding *enc;
|
58
|
+
VALUE smb_obj; /* Net::SMB object */
|
59
|
+
RB_SMB_DATA *smb_data;
|
60
|
+
SMBCCTX *smbcctx;
|
61
|
+
SMBCFILE *smbcfile;
|
62
|
+
char *url;
|
63
|
+
int fmode;
|
64
|
+
int oflags;
|
65
|
+
int eof;
|
66
|
+
off_t pos;
|
67
|
+
char *buffer;
|
68
|
+
size_t buffer_size;
|
69
|
+
size_t buffer_used_size;
|
70
|
+
size_t buffer_pos;
|
71
|
+
RB_SMBFILE_DATA *next, *prev;
|
72
|
+
};
|
73
|
+
|
74
|
+
struct rb_smb_data {
|
75
|
+
rb_encoding *enc;
|
76
|
+
SMBCCTX *smbcctx;
|
77
|
+
VALUE auth_callback;
|
78
|
+
RB_SMBFILE_DATA *smbfile_data_list;
|
79
|
+
};
|
80
|
+
|
81
|
+
#define RB_SMB_DATA_FROM_OBJ(obj, data) \
|
82
|
+
RB_SMB_DATA *data; \
|
83
|
+
Data_Get_Struct(obj, RB_SMB_DATA, data);
|
84
|
+
|
85
|
+
#define RB_SMBFILE_DATA_FROM_OBJ(obj, data) \
|
86
|
+
RB_SMBFILE_DATA *data; \
|
87
|
+
Data_Get_Struct(obj, RB_SMBFILE_DATA, data);
|
88
|
+
|
89
|
+
extern VALUE rb_cSMB;
|
90
|
+
extern VALUE rb_eSMBError;
|
91
|
+
extern VALUE rb_cSMBDir;
|
92
|
+
extern VALUE rb_cSMBFile;
|
93
|
+
|
94
|
+
void Init_smbdir(void);
|
95
|
+
void Init_smbfile(void);
|
96
|
+
|
97
|
+
#define _RB_SMB_H_
|
98
|
+
|
99
|
+
#endif /* _RB_SMB_H_ */
|
100
|
+
|
data/ext/net/smb/smb.c
CHANGED
@@ -1,107 +1,310 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
/*
|
2
|
+
* Ruby/Net::SMB - SMB/CIFS client (Samba libsmbclient binding) for Ruby
|
3
|
+
* Net::SMB class
|
4
|
+
* Copyright (C) 2012 SATOH Fumiyas @ OSS Technology Corp., Japan
|
5
|
+
*
|
6
|
+
* This program is free software; you can redistribute it and/or modify
|
7
|
+
* it under the terms of the GNU General Public License as published by
|
8
|
+
* the Free Software Foundation; either version 3 of the License, or
|
9
|
+
* (at your option) any later version.
|
10
|
+
*
|
11
|
+
* This program is distributed in the hope that it will be useful,
|
12
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
* GNU General Public License for more details.
|
15
|
+
*
|
16
|
+
* You should have received a copy of the GNU General Public License
|
17
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
*/
|
3
19
|
|
4
|
-
|
5
|
-
|
6
|
-
VALUE auth_callback;
|
7
|
-
};
|
20
|
+
#include "rb_smb.h"
|
21
|
+
#include "dlinklist.h"
|
8
22
|
|
9
|
-
|
10
|
-
|
23
|
+
VALUE rb_cSMB;
|
24
|
+
VALUE rb_eSMBError;
|
11
25
|
|
12
|
-
|
13
|
-
#define value2bool(v) ((b) ? Qtrue : Qfalse)
|
26
|
+
/* ====================================================================== */
|
14
27
|
|
15
|
-
|
16
|
-
|
17
|
-
|
28
|
+
static void smbcctx_auth_fn(SMBCCTX *smbcctx,
|
29
|
+
const char *server, const char *share,
|
30
|
+
char *workgroup, int wgmaxlen,
|
31
|
+
char *username, int unmaxlen,
|
32
|
+
char *password, int pwmaxlen)
|
33
|
+
{
|
34
|
+
VALUE self = (VALUE)smbc_getOptionUserData(smbcctx);
|
35
|
+
VALUE cred_obj;
|
36
|
+
VALUE workgroup_obj;
|
37
|
+
VALUE username_obj;
|
38
|
+
VALUE password_obj;
|
39
|
+
RB_SMB_DATA_FROM_OBJ(self, data);
|
18
40
|
|
19
|
-
|
41
|
+
if (NIL_P(data->auth_callback)) {
|
42
|
+
return;
|
43
|
+
}
|
20
44
|
|
21
|
-
|
45
|
+
cred_obj = rb_funcall(data->auth_callback,
|
46
|
+
rb_intern("call"), 2,
|
47
|
+
rb_str_new2(server),
|
48
|
+
rb_str_new2(share));
|
49
|
+
|
50
|
+
if (TYPE(cred_obj) != T_ARRAY) {
|
51
|
+
rb_raise(rb_eTypeError,
|
52
|
+
RB_SMB_NAME
|
53
|
+
"#on_auth proc must return an array of username, passsword, and optional workgroup name");
|
54
|
+
}
|
55
|
+
if (RARRAY_LEN(cred_obj) < 2 || RARRAY_LEN(cred_obj) > 3) {
|
56
|
+
rb_raise(rb_eArgError,
|
57
|
+
RB_SMB_NAME
|
58
|
+
"#on_auth proc must return an array of username, passsword, and optional workgroup name");
|
59
|
+
}
|
22
60
|
|
23
|
-
|
61
|
+
username_obj = RARRAY_PTR(cred_obj)[0];
|
62
|
+
password_obj = RARRAY_PTR(cred_obj)[1];
|
63
|
+
workgroup_obj = (RARRAY_LEN(cred_obj) >= 3) ? RARRAY_PTR(cred_obj)[2] : Qnil;
|
64
|
+
|
65
|
+
if (!NIL_P(workgroup_obj)) {
|
66
|
+
SafeStringValue(workgroup_obj);
|
67
|
+
if (RSTRING_LEN(workgroup_obj) > wgmaxlen - 1) {
|
68
|
+
rb_raise(rb_eArgError, "Workgroup name too long");
|
69
|
+
}
|
70
|
+
strcpy(workgroup, RSTRING_PTR(workgroup_obj));
|
71
|
+
}
|
72
|
+
else {
|
73
|
+
workgroup[0] = '\0';
|
74
|
+
}
|
75
|
+
if (!NIL_P(username_obj)) {
|
76
|
+
SafeStringValue(username_obj);
|
77
|
+
if (RSTRING_LEN(username_obj) > unmaxlen - 1) {
|
78
|
+
rb_raise(rb_eArgError, "Username too long");
|
79
|
+
}
|
80
|
+
strcpy(username, RSTRING_PTR(username_obj));
|
81
|
+
}
|
82
|
+
else {
|
83
|
+
username[0] = '\0';
|
84
|
+
}
|
85
|
+
if (!NIL_P(password_obj)) {
|
86
|
+
SafeStringValue(password_obj);
|
87
|
+
if (RSTRING_LEN(password_obj) > pwmaxlen - 1) {
|
88
|
+
rb_raise(rb_eArgError, "Password too long");
|
89
|
+
}
|
90
|
+
strcpy(password, RSTRING_PTR(password_obj));
|
91
|
+
}
|
92
|
+
else {
|
93
|
+
password[0] = '\0';
|
94
|
+
}
|
95
|
+
|
96
|
+
RB_SMB_DEBUG("\\%s\%s %s\%s|%s\n", server, share, workgroup, username, password);
|
97
|
+
}
|
98
|
+
|
99
|
+
static void rb_smb_data_gc_mark(RB_SMB_DATA *data)
|
24
100
|
{
|
25
|
-
rb_gc_mark(
|
101
|
+
rb_gc_mark(data->auth_callback);
|
26
102
|
}
|
27
103
|
|
28
|
-
static void
|
104
|
+
static void rb_smb_data_free(RB_SMB_DATA *data)
|
29
105
|
{
|
30
|
-
|
106
|
+
RB_SMBFILE_DATA *smbfile_data;
|
107
|
+
|
108
|
+
for (smbfile_data = data->smbfile_data_list; smbfile_data != NULL;
|
109
|
+
smbfile_data = smbfile_data->next) {
|
110
|
+
smbfile_data->smb_obj = Qnil;
|
111
|
+
smbfile_data->smb_data = NULL;
|
112
|
+
smbfile_data->smbcctx = NULL;
|
113
|
+
smbfile_data->smbcfile = NULL;
|
114
|
+
}
|
115
|
+
smbc_free_context(data->smbcctx, 1);
|
116
|
+
|
117
|
+
ruby_xfree(data);
|
31
118
|
}
|
32
119
|
|
33
|
-
static VALUE
|
120
|
+
static VALUE rb_smb_data_alloc(VALUE klass)
|
34
121
|
{
|
35
|
-
|
122
|
+
VALUE data_obj;
|
123
|
+
RB_SMB_DATA *data = ALLOC(RB_SMB_DATA);
|
124
|
+
const char *home_backup = getenv("HOME");
|
125
|
+
|
126
|
+
memset(data, 0, sizeof(*data));
|
36
127
|
|
37
|
-
|
128
|
+
data_obj = Data_Wrap_Struct(klass, rb_smb_data_gc_mark, rb_smb_data_free, data);
|
38
129
|
|
39
|
-
/*
|
40
|
-
|
41
|
-
|
42
|
-
|
130
|
+
/* Unset $HOME to ignore $HOME/.smb/smb.conf */
|
131
|
+
if (home_backup) {
|
132
|
+
unsetenv("HOME");
|
133
|
+
}
|
134
|
+
data->smbcctx = smbc_new_context();
|
135
|
+
if (home_backup) {
|
136
|
+
setenv("HOME", home_backup, 1);
|
137
|
+
}
|
138
|
+
if (data->smbcctx == NULL) {
|
139
|
+
rb_sys_fail("smbc_new_context() failed");
|
43
140
|
}
|
44
141
|
|
45
|
-
|
142
|
+
data->auth_callback = Qnil;
|
46
143
|
|
47
|
-
return
|
144
|
+
return data_obj;
|
48
145
|
}
|
49
146
|
|
50
|
-
static VALUE
|
147
|
+
static VALUE rb_smb_initialize(VALUE self)
|
51
148
|
{
|
52
|
-
|
149
|
+
RB_SMB_DATA_FROM_OBJ(self, data);
|
150
|
+
|
151
|
+
/* FIXME: Take encoding from argument */
|
152
|
+
/* FIXME: Read unix charset (?) from smb.conf for default encoding */
|
153
|
+
data->enc = rb_enc_find("UTF-8");
|
53
154
|
|
54
|
-
smbc_setDebug(smbcctx
|
55
|
-
|
155
|
+
smbc_setDebug(data->smbcctx, 0);
|
156
|
+
smbc_setOptionUserData(data->smbcctx, (void *)self);
|
157
|
+
smbc_setOptionDebugToStderr(data->smbcctx, SMBC_TRUE);
|
158
|
+
smbc_setOptionNoAutoAnonymousLogin(data->smbcctx, SMBC_TRUE);
|
159
|
+
smbc_setFunctionAuthDataWithContext(data->smbcctx, smbcctx_auth_fn);
|
160
|
+
|
161
|
+
if (smbc_init_context(data->smbcctx) == NULL) {
|
162
|
+
rb_sys_fail("smbc_init_context() failed");
|
163
|
+
}
|
56
164
|
|
57
165
|
return self;
|
58
166
|
}
|
59
167
|
|
60
|
-
static VALUE
|
168
|
+
static VALUE rb_smb_debug_get(VALUE self)
|
61
169
|
{
|
62
|
-
|
170
|
+
RB_SMB_DATA_FROM_OBJ(self, data);
|
63
171
|
|
64
|
-
return INT2NUM(smbc_getDebug(smbcctx
|
172
|
+
return INT2NUM(smbc_getDebug(data->smbcctx));
|
65
173
|
}
|
66
174
|
|
67
|
-
static VALUE
|
175
|
+
static VALUE rb_smb_debug_set(VALUE self, VALUE debug)
|
68
176
|
{
|
69
|
-
|
177
|
+
RB_SMB_DATA_FROM_OBJ(self, data);
|
70
178
|
|
71
|
-
smbc_setDebug(smbcctx
|
179
|
+
smbc_setDebug(data->smbcctx, NUM2INT(debug));
|
72
180
|
|
73
181
|
return debug;
|
74
182
|
}
|
75
183
|
|
76
|
-
static VALUE
|
184
|
+
static VALUE rb_smb_use_kerberos_get(VALUE self)
|
77
185
|
{
|
78
|
-
|
186
|
+
RB_SMB_DATA_FROM_OBJ(self, data);
|
79
187
|
|
80
|
-
return smbc_getOptionUseKerberos(smbcctx
|
188
|
+
return SMBC2RB_BOOL(smbc_getOptionUseKerberos(data->smbcctx));
|
81
189
|
}
|
82
190
|
|
83
|
-
static VALUE
|
191
|
+
static VALUE rb_smb_use_kerberos_set(VALUE self, VALUE flag)
|
84
192
|
{
|
85
|
-
|
193
|
+
RB_SMB_DATA_FROM_OBJ(self, data);
|
86
194
|
|
87
|
-
smbc_setOptionUseKerberos(smbcctx
|
195
|
+
smbc_setOptionUseKerberos(data->smbcctx, RB2SMBC_BOOL(flag));
|
88
196
|
|
89
197
|
return flag;
|
90
198
|
}
|
91
199
|
|
200
|
+
static VALUE rb_smb_on_auth(int argc, VALUE* argv, VALUE self)
|
201
|
+
{
|
202
|
+
RB_SMB_DATA_FROM_OBJ(self, data);
|
203
|
+
|
204
|
+
VALUE proc;
|
205
|
+
VALUE block;
|
206
|
+
|
207
|
+
if (argc == 0 && !rb_block_given_p()) {
|
208
|
+
rb_raise(rb_eArgError, "No block or proc given");
|
209
|
+
}
|
210
|
+
else if (argc > 0 && rb_block_given_p()) {
|
211
|
+
rb_raise(rb_eArgError, "Cannot use both block and proc");
|
212
|
+
}
|
213
|
+
|
214
|
+
rb_scan_args(argc, argv, "01&", &proc, &block);
|
215
|
+
if (argc == 1) {
|
216
|
+
data->auth_callback = proc;
|
217
|
+
}
|
218
|
+
else {
|
219
|
+
data->auth_callback = block;
|
220
|
+
}
|
221
|
+
|
222
|
+
return Qnil;
|
223
|
+
}
|
224
|
+
|
225
|
+
static VALUE rb_smb_opendir(VALUE self, VALUE url_obj)
|
226
|
+
{
|
227
|
+
RB_SMB_DATA_FROM_OBJ(self, data);
|
228
|
+
VALUE args[2];
|
229
|
+
VALUE smbdir;
|
230
|
+
|
231
|
+
args[0] = self;
|
232
|
+
args[1] = url_obj;
|
233
|
+
smbdir = rb_class_new_instance(2, args, rb_cSMBDir);
|
234
|
+
|
235
|
+
RB_SMBFILE_DATA_FROM_OBJ(smbdir, smbfile_data);
|
236
|
+
DLIST_ADD(data->smbfile_data_list, smbfile_data);
|
237
|
+
|
238
|
+
return smbdir;
|
239
|
+
}
|
240
|
+
|
241
|
+
static VALUE rb_smb_open(int argc, VALUE *argv, VALUE self)
|
242
|
+
{
|
243
|
+
RB_SMB_DATA_FROM_OBJ(self, data);
|
244
|
+
VALUE argv_new[argc+1];
|
245
|
+
VALUE smbfile;
|
246
|
+
|
247
|
+
argv_new[0] = self;
|
248
|
+
memcpy(argv_new + 1, argv, sizeof(*argv) * argc);
|
249
|
+
smbfile = rb_class_new_instance(argc+1, argv_new, rb_cSMBFile);
|
250
|
+
|
251
|
+
RB_SMBFILE_DATA_FROM_OBJ(smbfile, smbfile_data);
|
252
|
+
DLIST_ADD(data->smbfile_data_list, smbfile_data);
|
253
|
+
|
254
|
+
return smbfile;
|
255
|
+
}
|
256
|
+
|
257
|
+
|
92
258
|
/* ====================================================================== */
|
93
259
|
|
94
260
|
void Init_smb(void)
|
95
261
|
{
|
96
262
|
VALUE rb_mNet = rb_define_module("Net");
|
97
|
-
VALUE rb_mSMB = rb_define_module_under(rb_mNet, "SMB");
|
98
|
-
VALUE rb_cSMBCCTX = rb_define_class_under(rb_mNet, "SMBCCTX", rb_cObject);
|
99
263
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
rb_define_method(
|
264
|
+
/* Net::SMB */
|
265
|
+
rb_cSMB = rb_define_class_under(rb_mNet, "SMB", rb_cObject);
|
266
|
+
rb_define_alloc_func(rb_cSMB, rb_smb_data_alloc);
|
267
|
+
rb_define_method(rb_cSMB, "initialize", rb_smb_initialize, 0);
|
268
|
+
rb_define_method(rb_cSMB, "debug", rb_smb_debug_get, 0);
|
269
|
+
rb_define_method(rb_cSMB, "debug=", rb_smb_debug_set, 1);
|
270
|
+
rb_define_method(rb_cSMB, "use_kerberos", rb_smb_use_kerberos_get, 0);
|
271
|
+
rb_define_method(rb_cSMB, "use_kerberos=", rb_smb_use_kerberos_set, 1);
|
272
|
+
rb_define_method(rb_cSMB, "on_auth", rb_smb_on_auth, -1);
|
273
|
+
rb_define_alias(rb_cSMB, "on_authentication", "on_auth");
|
274
|
+
rb_define_method(rb_cSMB, "opendir", rb_smb_opendir, 1);
|
275
|
+
rb_define_method(rb_cSMB, "open", rb_smb_open, -1);
|
276
|
+
|
277
|
+
/* Net::SMB::Error */
|
278
|
+
rb_eSMBError = rb_define_class_under(rb_cSMB, "Error", rb_eStandardError);
|
279
|
+
|
280
|
+
const char *smbc_ver = smbc_version();
|
281
|
+
int smbc_ver_major = atoi(smbc_ver);
|
282
|
+
int smbc_ver_minor = (smbc_ver = strchr(smbc_ver, '.')) ? atoi(++smbc_ver) : 0;
|
283
|
+
int smbc_ver_release = (smbc_ver = strchr(smbc_ver, '.')) ? atoi(++smbc_ver) : 0;
|
284
|
+
long smbc_ver_number =
|
285
|
+
(smbc_ver_major << 16) +
|
286
|
+
(smbc_ver_minor << 8) +
|
287
|
+
smbc_ver_release;
|
288
|
+
|
289
|
+
if (smbc_ver_number <= 0x030606L) {
|
290
|
+
/*
|
291
|
+
* Hack to avoid Samba Bug 9038 - libsmbclient: SMBC_module_init()
|
292
|
+
* does not init global parameters if $HOME is not set
|
293
|
+
* https://bugzilla.samba.org/show_bug.cgi?id=9038
|
294
|
+
*/
|
295
|
+
const char *home_backup = getenv("HOME");
|
296
|
+
/* Unset $HOME to ignore $HOME/.smb/smb.conf */
|
297
|
+
if (home_backup) {
|
298
|
+
unsetenv("HOME");
|
299
|
+
}
|
300
|
+
SMBCCTX *smbcctx = smbc_new_context();
|
301
|
+
if (home_backup) {
|
302
|
+
setenv("HOME", home_backup, 1);
|
303
|
+
}
|
304
|
+
smbc_init_context(smbcctx);
|
305
|
+
}
|
104
306
|
|
105
|
-
|
307
|
+
Init_smbdir();
|
308
|
+
Init_smbfile();
|
106
309
|
}
|
107
310
|
|