net-smb 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Makefile ADDED
@@ -0,0 +1,18 @@
1
+ default: build
2
+
3
+ build: gem
4
+
5
+ gem:
6
+ rm pkg/*.gem
7
+ rake build
8
+
9
+ upload:
10
+ $(MAKE) gem
11
+ gem push pkg/*.gem
12
+
13
+ clean:
14
+ rake clean
15
+
16
+ distclean:
17
+ rake clobber
18
+
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
- CLOBBER.include('lib/**/*.so')
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
- #include <ruby.h>
2
- #include <libsmbclient.h>
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
- struct smbcctx {
5
- SMBCCTX *ctx;
6
- VALUE auth_callback;
7
- };
20
+ #include "rb_smb.h"
21
+ #include "dlinklist.h"
8
22
 
9
- #define FALSE_P(value) (NIL_P(value) || (value) == Qfalse)
10
- #define TRUE_P(value) !FALSE_P(value)
23
+ VALUE rb_cSMB;
24
+ VALUE rb_eSMBError;
11
25
 
12
- #define bool2value(b) ((b) ? Qtrue : Qfalse)
13
- #define value2bool(v) ((b) ? Qtrue : Qfalse)
26
+ /* ====================================================================== */
14
27
 
15
- #define get_smbcctx(self) \
16
- struct smbcctx *smbcctx; \
17
- Data_Get_Struct((self), struct smbcctx, smbcctx);
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
- static VALUE eRuntimeError;
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
- static void smbcctx_gc_mark(struct smbcctx *smbcctx)
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(smbcctx->auth_callback);
101
+ rb_gc_mark(data->auth_callback);
26
102
  }
27
103
 
28
- static void smbcctx_free(struct smbcctx *smbcctx)
104
+ static void rb_smb_data_free(RB_SMB_DATA *data)
29
105
  {
30
- smbc_free_context(smbcctx->ctx, 1);
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 rb_smbcctx_alloc(VALUE klass)
120
+ static VALUE rb_smb_data_alloc(VALUE klass)
34
121
  {
35
- struct smbcctx *smbcctx = ALLOC(struct smbcctx);
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
- memset(smbcctx, 0, sizeof(struct smbcctx));
128
+ data_obj = Data_Wrap_Struct(klass, rb_smb_data_gc_mark, rb_smb_data_free, data);
38
129
 
39
- /* FIXME: Unset $HOME to ignore $HOME/.smb/smb.conf */
40
- smbcctx->ctx = smbc_new_context();
41
- if (smbcctx->ctx == NULL) {
42
- rb_sys_fail("Cannot create SMBCCTX");
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
- smbcctx->auth_callback = Qnil;
142
+ data->auth_callback = Qnil;
46
143
 
47
- return Data_Wrap_Struct(klass, smbcctx_gc_mark, smbcctx_free, smbcctx);
144
+ return data_obj;
48
145
  }
49
146
 
50
- static VALUE rb_smbcctx_initialize(VALUE self)
147
+ static VALUE rb_smb_initialize(VALUE self)
51
148
  {
52
- get_smbcctx(self);
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->ctx, 0);
55
- smbc_setOptionDebugToStderr(smbcctx->ctx, (smbc_bool)1);
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 rb_smbcctx_debug_get(VALUE self)
168
+ static VALUE rb_smb_debug_get(VALUE self)
61
169
  {
62
- get_smbcctx(self);
170
+ RB_SMB_DATA_FROM_OBJ(self, data);
63
171
 
64
- return INT2NUM(smbc_getDebug(smbcctx->ctx));
172
+ return INT2NUM(smbc_getDebug(data->smbcctx));
65
173
  }
66
174
 
67
- static VALUE rb_smbcctx_debug_set(VALUE self, VALUE debug)
175
+ static VALUE rb_smb_debug_set(VALUE self, VALUE debug)
68
176
  {
69
- get_smbcctx(self);
177
+ RB_SMB_DATA_FROM_OBJ(self, data);
70
178
 
71
- smbc_setDebug(smbcctx->ctx, NUM2INT(debug));
179
+ smbc_setDebug(data->smbcctx, NUM2INT(debug));
72
180
 
73
181
  return debug;
74
182
  }
75
183
 
76
- static VALUE rb_smbcctx_use_kerberos_get(VALUE self)
184
+ static VALUE rb_smb_use_kerberos_get(VALUE self)
77
185
  {
78
- get_smbcctx(self);
186
+ RB_SMB_DATA_FROM_OBJ(self, data);
79
187
 
80
- return smbc_getOptionUseKerberos(smbcctx->ctx) ? Qtrue : Qfalse;
188
+ return SMBC2RB_BOOL(smbc_getOptionUseKerberos(data->smbcctx));
81
189
  }
82
190
 
83
- static VALUE rb_smbcctx_use_kerberos_set(VALUE self, VALUE flag)
191
+ static VALUE rb_smb_use_kerberos_set(VALUE self, VALUE flag)
84
192
  {
85
- get_smbcctx(self);
193
+ RB_SMB_DATA_FROM_OBJ(self, data);
86
194
 
87
- smbc_setOptionUseKerberos(smbcctx->ctx, (smbc_bool)(TRUE_P(flag) ? 1 : 0));
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
- rb_define_alloc_func(rb_cSMBCCTX, rb_smbcctx_alloc);
101
- rb_define_method(rb_cSMBCCTX, "initialize", rb_smbcctx_initialize, 0);
102
- rb_define_method(rb_cSMBCCTX, "debug", rb_smbcctx_debug_get, 0);
103
- rb_define_method(rb_cSMBCCTX, "debug=", rb_smbcctx_debug_set, 1);
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
- //eRuntimeError = rb_define_class_under(mSMB, "Net::SMB::RuntimeError", rb_eRuntimeError);
307
+ Init_smbdir();
308
+ Init_smbfile();
106
309
  }
107
310