File Coverage

lib/SMB/v2/Command/QueryDirectory.pm
Criterion Covered Total %
statement 12 77 15.5
branch 0 26 0.0
condition 0 16 0.0
subroutine 4 9 44.4
pod 0 5 0.0
total 16 133 12.0


line stmt bran cond sub pod time code
1             # SMB Perl library, Copyright (C) 2014-2018 Mikhael Goikhman, migo@cpan.org
2             #
3             # This program is free software: you can redistribute it and/or modify
4             # it under the terms of the GNU General Public License as published by
5             # the Free Software Foundation, either version 3 of the License, or
6             # (at your option) any later version.
7             #
8             # This program is distributed in the hope that it will be useful,
9             # but WITHOUT ANY WARRANTY; without even the implied warranty of
10             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11             # GNU General Public License for more details.
12             #
13             # You should have received a copy of the GNU General Public License
14             # along with this program. If not, see .
15              
16             package SMB::v2::Command::QueryDirectory;
17              
18 1     1   9 use strict;
  1         3  
  1         36  
19 1     1   8 use warnings;
  1         2  
  1         39  
20              
21 1     1   7 use parent 'SMB::v2::Command';
  1         3  
  1         5  
22              
23             use constant {
24 1         1381 INFO_LEVEL_DIRECTORY => 0x1,
25             INFO_LEVEL_FULLDIRECTORY => 0x2,
26             INFO_LEVEL_BOTHDIRECTORY => 0x3,
27             INFO_LEVEL_NAMES => 0xc,
28             INFO_LEVEL_IDBOTHDIRECTORY => 0x25,
29             INFO_LEVEL_IDFULLDIRECTORY => 0x26,
30              
31             FLAGS_RESCAN => 0x1,
32             FLAGS_SINGLE => 0x2,
33             FLAGS_INDEXS => 0x4,
34             FLAGS_REOPEN => 0x10,
35 1     1   96 };
  1         2  
36              
37             sub init ($) {
38 0     0 0   $_[0]->set(
39             info_level => INFO_LEVEL_IDBOTHDIRECTORY,
40             flags => 0,
41             file_index => 0,
42             file_pattern => '*',
43             buffer_length => 65536,
44             fid => 0,
45             openfile => undef,
46             files => undef,
47             )
48             }
49              
50             sub parse ($$) {
51 0     0 0   my $self = shift;
52 0           my $parser = shift;
53              
54 0 0         if ($self->is_response) {
55 0           my $offset = $parser->uint16;
56 0           my $length = $parser->uint32;
57              
58 0           my @files = ();
59 0           my $next_diff;
60 0           do {
61 0           my $current = $parser->offset;
62 0           $next_diff = $parser->uint32;
63 0           my $file_index = $parser->uint32;
64 0           my @values = ((map { $parser->uint64 } 1 .. 6), $parser->uint32);
  0            
65 0           my $length = $parser->uint32;
66 0           my $ea_size = $parser->uint32; # TODO
67 0           my $short_length = $parser->uint8;
68 0           $parser->uint8;
69 0           my $short_filename = $parser->utf16(26);
70 0 0         substr($short_filename, $short_length) = ''
71             if $short_length < length($short_filename);
72 0           my $id = $parser->uint64;
73 0           my $filename = $parser->utf16($length);
74 0           my $file = SMB::File->new(index => $file_index, name => $filename, short_name => $short_filename, id => $id);
75 0           $file->update(@values, 1);
76 0           push @files, $file;
77 0 0         $parser->skip($current + $next_diff - $parser->offset) if $next_diff;
78             } while $next_diff;
79              
80 0           $self->files(\@files);
81             } else {
82 0           $self->info_level($parser->uint8);
83 0           $self->flags($parser->uint8);
84 0           $self->file_index($parser->uint32);
85 0           $self->fid($parser->fid2);
86 0           my $offset = $parser->uint16;
87 0           my $length = $parser->uint16;
88 0           $self->buffer_length($parser->uint32);
89 0           $self->file_pattern($parser->utf16($length));
90             }
91              
92 0           return $self;
93             }
94              
95             sub pack ($$) {
96 0     0 0   my $self = shift;
97 0           my $packer = shift;
98              
99 0 0         if ($self->is_response) {
100 0   0       my $file_index = $self->file_index || 0;
101 0   0       my $files = $self->files || [];
102              
103 0 0         return $self->abort_pack($packer, SMB::STATUS_NO_MORE_FILES)
104             unless @$files;
105              
106 0           $packer
107             ->uint16(72)
108             ->stub('buffer-length', 'uint32')
109             ->mark('buffer-start')
110             ;
111              
112 0           my $level = $self->info_level;
113 0           my $length = 0;
114 0           my $i = 0;
115 0           for my $file (@$files) {
116 0           my $filename = $file->name;
117 0   0       my $short_filename = $file->{short_name} || '';
118             # pad and cut short name to exactly 12 chars
119 0           $short_filename .= "\0" x (12 - length($short_filename));
120 0           substr($short_filename, 12) = "";
121              
122 0           $packer
123             ->mark('file-info-start')
124             ->stub('next-diff', 'uint32')
125             ->uint32($file_index + $i)
126             ;
127 0 0         $packer
128             ->uint64($file->creation_time)
129             ->uint64($file->last_access_time)
130             ->uint64($file->last_write_time)
131             ->uint64($file->change_time)
132             ->uint64($file->end_of_file)
133             ->uint64($file->allocation_size)
134             ->uint32($file->attributes)
135             unless $level == INFO_LEVEL_NAMES
136             ;
137 0           $packer
138             ->uint32(length($filename) * 2)
139             ;
140             $packer
141 0 0 0       ->uint32($file->{ea_size} || 0) # TODO
142             unless $level == INFO_LEVEL_NAMES
143             ;
144 0 0 0       $packer
145             ->uint8(length($short_filename) * 2)
146             ->uint8(0)
147             ->utf16($short_filename)
148             if $level == INFO_LEVEL_BOTHDIRECTORY || $level == INFO_LEVEL_IDBOTHDIRECTORY
149             ;
150 0 0 0       $packer
    0          
151             ->zero($level == INFO_LEVEL_IDFULLDIRECTORY ? 4 : 2)
152             ->uint64($file->id)
153             if $level == INFO_LEVEL_IDFULLDIRECTORY || $level == INFO_LEVEL_IDBOTHDIRECTORY
154             ;
155 0 0         $packer
156             ->utf16($filename)
157             ->align('file-info-start', 8)
158             ->fill('next-diff', ++$i == @$files ? 0 : $packer->diff('file-info-start'))
159             ;
160             }
161              
162 0           $packer->fill('buffer-length', $packer->diff('buffer-start'));
163 0           $self->openfile->last_index($file_index + $i);
164             } else {
165 0   0       $packer
166             ->uint8($self->info_level)
167             ->uint8($self->flags)
168             ->uint32($self->file_index)
169             ->fid2($self->fid || die "No fid set")
170             ->uint16($packer->diff('smb-header') + 8)
171             ->uint16(length($self->file_pattern) * 2)
172             ->uint32($self->buffer_length)
173             ->utf16($self->file_pattern)
174             ;
175             }
176             }
177              
178             sub is_index_specified ($) {
179 0     0 0   my $self = shift;
180              
181 0 0         return $self->flags & FLAGS_INDEXS ? 1 : 0;
182             }
183              
184             sub is_reopen ($) {
185 0     0 0   my $self = shift;
186              
187 0 0         return $self->flags & FLAGS_REOPEN ? 1 : 0;
188             }
189              
190             1;