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 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