INFO_LEVEL_DIRECTORY
=> 0x1,
INFO_LEVEL_FULLDIRECTORY
=> 0x2,
INFO_LEVEL_BOTHDIRECTORY
=> 0x3,
INFO_LEVEL_NAMES
=> 0xc,
INFO_LEVEL_IDBOTHDIRECTORY
=> 0x25,
INFO_LEVEL_IDFULLDIRECTORY
=> 0x26,
FLAGS_RESCAN
=> 0x1,
FLAGS_SINGLE
=> 0x2,
FLAGS_INDEX
=> 0x4,
FLAGS_REOPEN
=> 0x10,
};
sub
init ($) {
$_
[0]->set(
info_level
=> INFO_LEVEL_IDBOTHDIRECTORY,
flags
=> 0,
file_index
=> 0,
file_pattern
=>
'*'
,
buffer_length
=> 65536,
fid
=> 0,
openfile
=>
undef
,
files
=>
undef
,
)
}
sub
parse ($$) {
my
$self
=
shift
;
my
$parser
=
shift
;
if
(
$self
->is_response) {
my
$offset
=
$parser
->uint16;
my
$length
=
$parser
->uint32;
my
@files
= ();
my
$next_diff
;
do
{
my
$current
=
$parser
->offset;
$next_diff
=
$parser
->uint32;
my
$file_index
=
$parser
->uint32;
my
@values
= ((
map
{
$parser
->uint64 } 1 .. 6),
$parser
->uint32);
my
$length
=
$parser
->uint32;
my
$ea_size
=
$parser
->uint32;
my
$short_length
=
$parser
->uint8;
$parser
->uint8;
my
$short_filename
=
$parser
->utf16(26);
substr
(
$short_filename
,
$short_length
) =
''
if
$short_length
<
length
(
$short_filename
);
my
$id
=
$parser
->uint64;
my
$filename
=
$parser
->utf16(
$length
);
my
$file
= SMB::File->new(
index
=>
$file_index
,
name
=>
$filename
,
short_name
=>
$short_filename
,
id
=>
$id
);
$file
->update(
@values
, 1);
push
@files
,
$file
;
$parser
->skip(
$current
+
$next_diff
-
$parser
->offset)
if
$next_diff
;
}
while
$next_diff
;
$self
->files(\
@files
);
}
else
{
$self
->info_level(
$parser
->uint8);
$self
->flags(
$parser
->uint8);
$self
->file_index(
$parser
->uint32);
$self
->fid(
$parser
->fid2);
my
$offset
=
$parser
->uint16;
my
$length
=
$parser
->uint16;
$self
->buffer_length(
$parser
->uint32);
$self
->file_pattern(
$parser
->utf16(
$length
));
}
return
$self
;
}
sub
pack
($$) {
my
$self
=
shift
;
my
$packer
=
shift
;
if
(
$self
->is_response) {
my
$file_index
=
$self
->file_index || 0;
my
$files
=
$self
->files || [];
return
$self
->abort_pack(
$packer
, SMB::STATUS_NO_MORE_FILES)
unless
@$files
;
$packer
->uint16(72)
->stub(
'buffer-length'
,
'uint32'
)
->mark(
'buffer-start'
)
;
my
$level
=
$self
->info_level;
my
$length
= 0;
my
$i
= 0;
for
my
$file
(
@$files
) {
my
$filename
=
$file
->name;
my
$short_filename
=
$file
->{short_name} ||
''
;
$short_filename
.=
"\0"
x (12 -
length
(
$short_filename
));
substr
(
$short_filename
, 12) =
""
;
$packer
->mark(
'file-info-start'
)
->stub(
'next-diff'
,
'uint32'
)
->uint32(
$file_index
+
$i
)
;
$packer
->uint64(
$file
->creation_time)
->uint64(
$file
->last_access_time)
->uint64(
$file
->last_write_time)
->uint64(
$file
->change_time)
->uint64(
$file
->end_of_file)
->uint64(
$file
->allocation_size)
->uint32(
$file
->attributes)
unless
$level
== INFO_LEVEL_NAMES
;
$packer
->uint32(
length
(
$filename
) * 2)
;
$packer
->uint32(
$file
->{ea_size} || 0)
unless
$level
== INFO_LEVEL_NAMES
;
$packer
->uint8 (
length
(
$short_filename
) * 2)
->uint8 (0)
->utf16(
$short_filename
)
if
$level
== INFO_LEVEL_BOTHDIRECTORY ||
$level
== INFO_LEVEL_IDBOTHDIRECTORY
;
$packer
->zero(
$level
== INFO_LEVEL_IDFULLDIRECTORY ? 4 : 2)
->uint64(
$file
->{id} || 0)
if
$level
== INFO_LEVEL_IDFULLDIRECTORY ||
$level
== INFO_LEVEL_IDBOTHDIRECTORY
;
$packer
->utf16(
$filename
)
->fill(
'next-diff'
, ++
$i
==
@$files
? 0 :
$packer
->diff(
'file-info-start'
))
;
}
$packer
->fill(
'buffer-length'
,
$packer
->diff(
'buffer-start'
));
$self
->openfile->last_index(
$file_index
+
$i
);
}
else
{
$packer
->uint8(
$self
->info_level)
->uint8(
$self
->flags)
->uint32(
$self
->file_index)
->fid2(
$self
->fid ||
die
"No fid set"
)
->uint16(
$packer
->diff(
'smb-header'
) + 8)
->uint16(
length
(
$self
->file_pattern) * 2)
->uint32(
$self
->buffer_length)
->utf16(
$self
->file_pattern)
;
}
}
1;