1
package Filesys::SmbClient;
3
# module Filesys::SmbClient : provide function to access Samba filesystem
5
# Copyright 2000-2012 A.Barbet alian@cpan.org. All rights reserved.
7
# $Log: SmbClient.pm,v $
8
# Revision 3.2 2012/12/04 14:49:32 alian
10
# release 3.2: implements connection close with smbc_free_context (acca@cpan.org)
12
# release 3.1: fix for rt#12221 rt#18757 rt#13173 and bug in configure
14
# Revision 3.0 2005/03/04 16:15:00 alian
15
# 3.0 2005/03/05 alian
16
# - Update to samba3 API and use SMBCTXX
17
# - Add set_flag method for samba 3.0.11
18
# - Update smb2www-2.cgi to browse workgroup with smb://
19
# - Return 0 not undef at end of file with read/READLINE
20
# (tks to jonathan.segal at genizon.com for report).
21
# - Fix whence bug in seek method (not used before)
22
# - Add some tests for read and seek patched in this version
24
# Revision 1.5 2003/11/09 18:28:01 alian
25
# Add Copyright section
27
# See file CHANGES for others update
30
use constant SMBC_WORKGROUP => 1;
31
use constant SMBC_SERVER => 2;
32
use constant SMBC_FILE_SHARE => 3;
33
use constant SMBC_PRINTER_SHARE => 4;
34
use constant SMBC_COMMS_SHARE => 5;
35
use constant SMBC_IPC_SHARE =>6;
36
use constant SMBC_DIR => 7;
37
use constant SMBC_FILE => 8;
38
use constant SMBC_LINK => 9;
39
use constant MAX_LENGTH_LINE => 4096;
40
use constant SMB_CTX_FLAG_USE_KERBEROS => (1 << 0);
41
use constant SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS => (1 << 1);
42
use constant SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON => (1 << 2);
44
use vars qw($AUTOLOAD $VERSION @ISA @EXPORT);
53
@ISA = qw(Exporter DynaLoader Tie::Handle);
54
@EXPORT = qw(SMBC_DIR SMBC_WORKGROUP SMBC_SERVER SMBC_FILE_SHARE
55
SMBC_PRINTER_SHARE SMBC_COMMS_SHARE SMBC_IPC_SHARE SMBC_FILE
56
SMBC_LINK _write _open _close _read _lseek
57
SMB_CTX_FLAG_USE_KERBEROS SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS
58
SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON);
59
$VERSION = ('$Revision: 3.2 $ ' =~ /(\d+\.\d+)/)[0];
61
bootstrap Filesys::SmbClient $VERSION;
66
"closedir" => \&_closedir,
68
"opendir" => \&_opendir,
69
"print_file" => \&_print_file,
71
"rename" => \&_rename,
73
"unlink" => \&_unlink,
74
"unlink_print_job" => \&_unlink_print_job,
77
#------------------------------------------------------------------------------
79
#------------------------------------------------------------------------------
84
return unless $attr =~ /[^A-Z]/;
85
die "Method undef ->$attr()\n" unless defined($commandes{$attr});
86
return $commandes{$attr}->($self->{context}, @_);
89
#------------------------------------------------------------------------------
91
#------------------------------------------------------------------------------
94
my ($class,$fn,$mode,@args) = @_;
95
$mode = '0666' if (!$mode);
96
my $self = new($class, @args);
97
print "Filesys::SmbClient TIEHANDLE\n" if ($DEBUG);
99
$self->{FD} = _open($self->{context}, $fn, $mode) or return undef; }
103
#------------------------------------------------------------------------------
105
#------------------------------------------------------------------------------
107
my ($class,$fn,$mode) = @_;
108
$mode = '0666' if (!$mode);
109
print "OPEN\n" if ($DEBUG);
110
$class->{FD} = _open($class->{context}, $fn, $mode) or return undef;
114
#------------------------------------------------------------------------------
116
#------------------------------------------------------------------------------
122
#------------------------------------------------------------------------------
124
#------------------------------------------------------------------------------
126
my ($self,$buffer,$length,$offset) = @_;
127
print "Filesys::SmbClient WRITE\n" if ($DEBUG);
128
$buffer = substr($buffer,0,$length) if ($length);
129
SEEK($self,$offset, SEEK_SET) if ($offset);
130
my $lg = _write($self->{context}, $self->{FD}, $buffer, $length);
131
return ($lg == -1) ? undef : $lg;
134
#------------------------------------------------------------------------------
136
#------------------------------------------------------------------------------
138
my ($self,$offset,$whence) = @_;
139
print "Filesys::SmbClient SEEK\n" if ($DEBUG);
140
return _lseek($self->{context}, $self->{FD}, $offset, $whence);
143
#------------------------------------------------------------------------------
145
#------------------------------------------------------------------------------
148
print "Filesys::SmbClient READ\n" if ($DEBUG);
150
my $lg = ($_[1] ? $_[1] : MAX_LENGTH_LINE);
152
defined($$buf = _read($self->{context}, $self->{FD}, $lg)) or return undef;
153
# $$buf = _read($self->{context}, $self->{FD}, $lg) or return undef;
154
return length($$buf);
157
#------------------------------------------------------------------------------
159
#------------------------------------------------------------------------------
162
print "Filesys::SmbClient READLINE\n" if ($DEBUG);
163
# Check if we have \n on old string
164
my $buf = $self->{_BUFFER};
165
if ($buf && $buf=~m!^([^\n]*\n)(.*)$!ms) {
166
print "Gave ->$1<- and take ->$2<-\n" if ($self->{params}->{debug});
168
$self->{_BUFFER} = $2;
169
return wantarray() ? ($p,$self->READLINE) : $p;
171
# Read while we haven't \n or eof
173
READ($self,$part,MAX_LENGTH_LINE);
174
while ($part and $part!~m!\n!ms and $self->{_FD}) {
176
$part = $self->read($self->{_FD}, @_);
178
$buf.= $part if ($part);
180
return (wantarray() ? "" : undef) if (!$buf);
181
# Return first line and save rest in $self->{_BUFFER}
182
if ($buf=~m!^([^\n]*\n)(.*)$!ms) {
183
print "Give ->$1<- and take ->$2<-\n" if ($self->{params}->{debug});
184
$self->{_BUFFER} = $2;
185
return wantarray() ? ($1,$self->READLINE) : $1;
187
undef $self->{_BUFFER};
188
return wantarray() ? ($buf,$self->READLINE) : $buf;
191
#------------------------------------------------------------------------------
193
#------------------------------------------------------------------------------
197
print "Filesys::SmbClient GETC\n" if ($DEBUG);
198
if ($self->{_BUFFER}) {
199
print "Filesys::SmbClient GETC using $self->{_BUFFER}\n"
200
if ($self->{params}->{debug});
201
$c = substr($self->{_BUFFER},0,1);
202
$self->{_BUFFER} = substr($self->{_BUFFER},1);
205
READ($self,$c,1) or return undef;
209
#------------------------------------------------------------------------------
211
#------------------------------------------------------------------------------
214
print "Filesys::SmbClient CLOSE\n" if ($DEBUG);
215
_close($self->{context}, $self->{FD});
218
#------------------------------------------------------------------------------
220
#------------------------------------------------------------------------------
224
print "Filesys::SmbClient UNTIE\n" if ($DEBUG);
226
undef($self->{_BUFFER});
229
#------------------------------------------------------------------------------
231
#------------------------------------------------------------------------------
240
if (!$vars{'workgroup'}) { $vars{'workgroup'}=""; }
241
if (!$vars{'username'}) { $vars{'username'}=""; }
242
if (!$vars{'password'}) { $vars{'password'}=""; }
243
if (!$vars{'debug'}) { $vars{'debug'}=0; }
244
push(@l, $vars{'username'});
245
push(@l, $vars{'password'});
246
push(@l, $vars{'workgroup'});
247
push(@l, $vars{'debug'});
248
print "Filesys::SmbClient new>",join(" ", @l),"\n" if $vars{'debug'};
249
$self->{params}= \%vars;
251
else { @l =("","","",0); }
252
# Here is a temporary hack:
253
# Actually libsmbclient will segfault if it can't find file
254
# $ENV{HOME}/.smb/smb.conf so I will test if it exist,
255
# and create it if no file is found. A empty file is enough ...
256
# In cgi environnement, $ENV{HOME} can be unset because
257
# nobody is not a real user. So I will set $ENV{HOME} to dir /tmp
258
if (!$ENV{HOME}) {$ENV{HOME}="/tmp";}
259
if (!-e "$ENV{HOME}/.smb/smb.conf") {
260
print STDERR "you don't have a $ENV{HOME}/.smb/smb.conf, ",
261
"I will create it (empty file)\n";
262
mkdir "$ENV{HOME}/.smb",0755 unless (-e "$ENV{HOME}/.smb");
263
open(F,">$ENV{HOME}/.smb/smb.conf") ||
264
die "Can't create $ENV{HOME}/.smb/smb.conf : $!\n";
267
# End of temporary hack
269
$self->{context} = _init(@l);
270
$vars{'flags'} && _set_flags($self->{context}, $vars{'flags'});
271
die 'You must have a samba configuration file '.
272
'($HOME/.smb/smb.conf , even if it is empty' unless $self->{context};
276
#------------------------------------------------------------------------------
278
#------------------------------------------------------------------------------
282
_set_flags($self->{context}, $flag);
286
#------------------------------------------------------------------------------
288
#------------------------------------------------------------------------------
293
while (my @l = _readdir($self->{context}, $_[0])) { push(@tab,\@l); }
296
my @l = _readdir($self->{context}, $_[0]);
301
#------------------------------------------------------------------------------
303
#------------------------------------------------------------------------------
308
while (my @l = _readdir($self->{context}, $_[0])) { push(@tab,$l[1]);}
311
my @l =_readdir($self->{context}, $_[0]);
316
#------------------------------------------------------------------------------
318
#------------------------------------------------------------------------------
320
my ($self,$file,$perms)=@_;
321
$perms = '0666' if (!$perms);
322
$self->{_FD} = _open($self->{context}, $file, $perms);
323
print "Filesys::SmbClient open <$self->{_FD}>\n"
324
if ($self->{params}->{debug});
328
#------------------------------------------------------------------------------
330
#------------------------------------------------------------------------------
332
my ($self,$fd,$offset,$whence) = @_;
333
return -1 if ($fd == -1);
334
print "Filesys::SmbClient seek\n" if ($self->{params}->{debug});
335
$whence = SEEK_SET if (!$whence);
336
warn "Whence diff from SEEK_SET not implemented in smb"
337
if ($whence ne SEEK_SET);
338
return _lseek($self->{context}, $fd, $offset, SEEK_SET);
341
#------------------------------------------------------------------------------
343
#------------------------------------------------------------------------------
347
print "Filesys::SmbClient write ".$self.' '.$fd.' '.join(" ",@_)."\n"
348
if ($self->{params}->{debug});
349
my $buffer = join("",@_);
350
return _write($self->{context}, $fd, $buffer, length($buffer));
353
#------------------------------------------------------------------------------
355
#------------------------------------------------------------------------------
357
my ($self,$fd,$lg)=@_;
358
$lg = MAX_LENGTH_LINE if (!$lg);
359
return _read($self->{context}, $fd, $lg);
362
#------------------------------------------------------------------------------
364
#------------------------------------------------------------------------------
366
my ($self,$dir,$mode)=@_;
367
$mode = '0755' if (!$mode);
368
return _mkdir($self->{context}, $dir, $mode);
371
#------------------------------------------------------------------------------
373
#------------------------------------------------------------------------------
377
my $fd = $self->opendir($url) || return undef;
378
my @f = $self->readdir_struct($fd);
379
$self->closedir($fd);
381
next if ($v->[1] eq '.' or $v->[1] eq '..');
382
my $u = $url."/".$v->[1];
383
if ($v->[0] == SMBC_FILE) { $self->unlink($u); }
384
elsif ($v->[0] == SMBC_DIR) { $self->rmdir_recurse($u); }
386
return $self->rmdir($url);
389
#------------------------------------------------------------------------------
391
#------------------------------------------------------------------------------
393
my ($self, $flag)=@_;
394
return _shutdown($self->{context}, $flag);
401
#------------------------------------------------------------------------------
407
Filesys::SmbClient - Interface for access Samba filesystem with libsmclient.so
412
use Filesys::SmbClient;
414
my $smb = new Filesys::SmbClient(username => "alian",
416
workgroup => "alian",
420
my $fd = $smb->open("smb://jupiter/doc/general.css", '0666');
421
while (defined(my $l= $smb->read($fd,50))) {print $l; }
426
See section EXAMPLE for others scripts.
430
Provide interface to access routine defined in libsmbclient.so provided with
433
Since 3.0 release of this package, you need a least samba-3.0.2.
434
For prior release of Samba, use Filesys::SmbClient version 1.x.
436
For old and 2.x release, this library is available on Samba source, but is not
438
Do "make bin/libsmbclient.so" in sources directory of Samba to build
439
this libraries. Then copy source/include/libsmbclient.h to
440
/usr/local/samba/include and source/bin/libsmbclient.so to
441
/usr/local/samba/lib before install this module.
443
If you want to use filehandle with this module, you need Perl 5.6 or later.
445
When a path is used, his scheme is :
447
smb://server/share/rep/doc
460
Hash can have this keys:
486
Return instance of Filesys::SmbClient on succes, die with error else.
490
my $smb = new Filesys::SmbClient(username => "alian",
492
workgroup => "alian",
498
Set flag for smb connection. See _SMBCCTX->flags in libsmclient.h
503
=item SMB_CTX_FLAG_USE_KERBEROS
505
=item SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS
507
=item SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON
513
=head2 Tie Filesys::SmbClient filehandle
515
This didn't work before 5.005_64. Why, I don't know.
516
When you have tied a filehandle with Filesys::SmbClient,
517
you can call classic methods for filehandle:
518
print, printf, seek, syswrite, getc, open, close, read.
519
See perldoc for usage.
524
tie(*FD, 'Filesys::SmbClient');
525
open(FD,"smb://jupiter/doc/test")
526
or print "Can't open file:", $!, "\n";
527
while(<FD>) { print $_; }
533
tie(*FD, 'Filesys::SmbClient');
534
open(FD,">smb://jupiter/doc/test")
535
or print "Can't create file:", $!, "\n";
536
print FD "Samba test","\n";
537
printf FD "%s", "And that work !\n";
545
=item mkdir FILENAME, MODE
547
Create directory $fname with permissions set to $mode.
548
Return 1 on success, else 0 is return and errno and $! is set.
552
$smb->mkdir("smb://jupiter/doc/toto",'0666')
553
or print "Error mkdir: ", $!, "\n";
557
Erase directory $fname. Return 1 on success, else 0 is return
558
and errno and $! is set. ($fname must be empty, else see
563
$smb->rmdir("smb://jupiter/doc/toto")
564
or print "Error rmdir: ", $!, "\n";
566
=item rmdir_recurse FILENAME
568
Erase directory $fname. Return 1 on success, else 0 is return
569
and errno and $! is set. Il $fname is not empty, all files and
574
$smb->rmdir_recurse("smb://jupiter/doc/toto")
575
or print "Error rmdir_recurse: ", $!, "\n";
577
=item opendir FILENAME
579
Open directory $fname. Return file descriptor on succes, else 0 is
580
return and $! is set.
582
=item readdir FILEHANDLE
584
Read a directory. In a list context, return the full content of
585
the directory $fd, else return next element. Each elem is
586
a name of a directory or files.
588
Return undef at end of directory.
592
my $fd = $smb->opendir("smb://jupiter/doc");
593
foreach my $n ($smb->readdir($fd)) {print $n,"\n";}
596
=item readdir_struct FILEHANDLE
598
Read a directory. In a list context, return the full content of
599
the directory FILEHANDLE, else return next element. Each element
600
is a ref to an array with type, name and comment. Type can be :
608
=item SMBC_FILE_SHARE
610
=item SMBC_PRINTER_SHARE
612
=item SMBC_COMMS_SHARE
624
Return undef at end of directory.
628
my $fd = $smb->opendir("smb://jupiter/doc");
629
while (my $f = $smb->readdir_struct($fd)) {
630
if ($f->[0] == SMBC_DIR) {print "Directory ",$f->[1],"\n";}
631
elsif ($f->[0] == SMBC_FILE) {print "File ",$f->[1],"\n";}
636
=item closedir FILEHANDLE
648
Stat a file FILENAME. Return a list with info on success,
649
else an empty list is return and $! is set.
681
device type (if inode device)
689
blocksize for filesystem I/O
693
number of blocks allocated
701
time of last modification
711
my @tab = $smb->stat("smb://jupiter/doc/tata");
712
if ($#tab == 0) { print "Erreur in stat:", $!, "\n"; }
714
for (10..12) {$tab[$_] = localtime($tab[$_]);}
715
print join("\n",@tab);
718
=item fstat FILEHANDLE
720
Like stat, but on a file handle
722
=item rename OLDNAME,NEWNAME
724
Changes the name of a file; an existing file NEWNAME will be clobbered.
725
Returns true for success, false otherwise, with $! set.
729
$smb->rename("smb://jupiter/doc/toto","smb://jupiter/doc/tata")
730
or print "Can't rename file:", $!, "\n";
732
=item unlink FILENAME
734
Unlink FILENAME. Return 1 on success, else 0 is return
735
and errno and $! is set.
739
$smb->unlink("smb://jupiter/doc/test")
740
or print "Can't unlink file:", $!, "\n";
745
=item open FILENAME, MODE
747
Open file $fname with perm $mode. Return file descriptor
748
on success, else 0 is return and $! is set.
752
my $fd = $smb->open("smb://jupiter/doc/test", 0666)
753
or print "Can't read file:", $!, "\n";
755
my $fd = $smb->open(">smb://jupiter/doc/test", 0666)
756
or print "Can't create file:", $!, "\n";
758
my $fd = $smb->open(">>smb://jupiter/doc/test", 0666)
759
or print "Can't append to file:", $!, "\n";
761
=item read FILEHANDLE
763
=item read FILEHANDLE, LENGTH
765
Read $count bytes of data on file descriptor $fd. It lenght is not set,
766
4096 bytes will be read.
768
Return buffer read on success, undef at end of file,
769
-1 is return on error and $! is set.
771
FILEHANDLE must be open with open of this module.
773
=item write FILEHANDLE, $buf
775
=item write FILEHANDLE, @buf
777
Write $buf or @buf on file descriptor $fd.
778
Return number of bytes wrote, else -1 is return and errno and $! is set.
782
my $fd = $smb->open(">smb://jupiter/doc/test", 0666)
783
or print "Can't create file:", $!, "\n";
784
$smb->write($fd, "A test of write call")
788
FILEHANDLE must be open with open of this module.
790
=item seek FILEHANDLE, POS
792
Sets FILEHANDLE's position, just like the "fseek"
793
call of "stdio". FILEHANDLE may be an expression
794
whose value gives the name of the filehandle. The
795
values for WHENCE is always SEEK_SET beacause others
796
didn't work on libsmbclient.so
798
FILEHANDLE must be open with open of this module.
800
=item close FILEHANDLE
802
Close file FILEHANDLE. Return 0 on success, else -1 is return and
809
A wrapper around `libsmbclient's `smbc_free_context'.
811
Close open files, release Samba connection, delete context,
812
aquired during open_* calls.
816
$smb->shutdown(0); # Gracefully close connection
817
$sbm->shutdown(1); # Forcibly close files and connection
820
shutdown(1) may cause complaints about talloc memory
821
leaks, if there are currently no open files.
827
=item unlink_print_job PRINTER_URL, IDJOB
829
Remove job number IDJOB on printer PRINTER_URL
831
=item print_file DOCUMENT_URL, PRINTER_URL
833
Print file DOCUMENT_URL on PRINTER_URL
865
This module come with some scripts:
871
Just for check that this module is ok :-)
875
A CGI interface with these features:
881
browse workgroup ,share, dir
897
unlink file, directory
905
The Filesys-SmbClient module is Copyright (c) 1999-2003 Alain BARBET, France,
906
alian at cpan.org. All rights reserved.
908
You may distribute under the terms of either the GNU General
909
Public License or the Artistic License, as specified
910
in the Perl README file.