Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed bug with many files in folder on Samba. Changed the recv.buffer…

… size for trans2-next messages.
  • Loading branch information...
commit 17656a8fc5b710249b8eee316bd9df5a00238b37 1 parent 2efea4b
etnt authored
View
10 lib/esmb/src/esmb.app.src
@@ -1,14 +1,8 @@
{application,esmb,
- [{description,"Erlang SMB Library"},
+ [{description,"esmb handling"},
{vsn,"%VSN%"},
{modules,[%MODULES%]},
{registered,[]},
{env, []},
{mod, {esmb_app, []}},
- {applications,[kernel,stdlib,sasl]},
- {dependencies,
- [{kernel, "2.9.6"},
- {stdlib, "1.12.7"},
- {fd_server, "2.3.0"},
- {sasl,"1.10.1"}]}]}.
-
+ {applications,[kernel,stdlib,sasl]}]}.
View
115 lib/esmb/src/esmb.erl
@@ -111,9 +111,12 @@
-include("esmb_rpc.hrl").
-
+-ifdef(debug).
+-define(sdbg(S,A), ?elog(S,A)).
+-else.
-define(sdbg(S,A), true).
-%%-define(sdbg(S,A), ?elog(S,A)).
+-endif.
+
%%% ==============================================
%%% ====== T Y P E D E C L A R A T I O N S ======
@@ -909,8 +912,7 @@ connect(Host, SockOpts) -> connect(Host, SockOpts, ?PORT).
%%% @end
%%%
connect(Host, SockOpts, Port) ->
- Opts = [binary, {packet, 0}|SockOpts],
- case gen_tcp:connect(Host, Port, Opts) of
+ case esmb_netbios:connect(Host, Port, SockOpts) of
{ok,S} ->
case nbss_session_request(S, "*SMBSERVER", caller()) of
{ok,_} ->
@@ -929,7 +931,7 @@ connect(Host, SockOpts, Port) ->
%%% @end
%%%
close(S) ->
- gen_tcp:close(S),
+ esmb_netbios:close(S),
ok.
@@ -1195,6 +1197,7 @@ c_delete_file(S, InReq, Path) ->
%%% @end
%%%
list_dir(S, InReq, Path) ->
+ ?sdbg("Enter list_dir/3~n", []),
catch c_list_dir(S, InReq, Path).
c_list_dir(S, InReq, Path) ->
@@ -1203,7 +1206,7 @@ c_list_dir(S, InReq, Path) ->
{Req2, X} when X#find_result.eos == true ->
Req2#smbpdu{finfo = X#find_result.finfo};
{Req2, X} ->
- list_dir_cont(S, Req2, Path, X#find_result.sid, X#find_result.finfo)
+ list_dir_cont(S, Req2, <<>>, X#find_result.sid, X#find_result.finfo)
end.
list_dir_cont(S, InReq, Path, Sid, Finfo) ->
@@ -1291,7 +1294,11 @@ negotiate(S) ->
c_negotiate(S) ->
{Req, Pdu} = smb_negotiate_pdu(),
- decode_smb_response(Req, nbss_session_service(S, Pdu)).
+ Neg = decode_smb_response(Req, nbss_session_service(S, Pdu)),
+ %% Sigh...we want to get hold of the socket in case
+ %% we need to retrieve more data, e.g far down in the
+ %% dec_trans2_xxxxx code.
+ Neg#smb_negotiate_res{sock = S}.
%%%
@@ -1631,6 +1638,7 @@ dec_transaction_req(Req, Pdu) ->
_/binary>> = Buffer
end).
+
dec_trans2_find_x2(Req, Pdu, SubCmd) ->
Res = safe_dec_smb(Req, Pdu), % NB: may throw(Pdu)
<<TotParamCount:16/little,
@@ -1655,12 +1663,95 @@ dec_trans2_find_x2(Req, Pdu, SubCmd) ->
LastNameOffset,
Res#smbpdu.bf),
<<_:DataOffset/binary, Data/binary>> = Pdu,
+ x2_more(Res, Sid, Data, SearchCount, EndOfSearch,
+ TotDataCount, DataCount + DataDisplacement).
+
+
+
+%%% We have got all the data
+x2_more(Res, Sid, Data, SearchCount, EoS, TotDataCount, TotDataCount) ->
+ ?sdbg("x2_more - Yes, we got all data~n", []),
+ Finfo = dec_find_file_both_dir_info(Res, Data, SearchCount),
+ {Res, #find_result{sid = Sid,
+ eos = to_bool(EoS),
+ finfo = Finfo}};
+%%% We need more data
+x2_more(Res, Sid, Data, SearchCount, EoS, TotDataCount, DataCount)
+ when TotDataCount > DataCount ->
+ ?sdbg("x2_more - We need more data (~w)~n", [TotDataCount - DataCount]),
+ X = x2_get_more(Res, Data),
+ Finfo = dec_find_file_both_dir_info(Res, X#smbpdu.data, SearchCount),
+ {Res, #find_result{sid = Sid,
+ eos = to_bool(EoS),
+ finfo = Finfo}};
+%%% Bad case, log error, and handle it gracefully !!
+x2_more(Res, Sid, Data, SearchCount, EoS, TotDataCount, DataCount) ->
+ ?elog("+++ x2_more got error: TotDataCount=~p , DataCount=~p~n",
+ [TotDataCount, DataCount]),
Finfo = dec_find_file_both_dir_info(Res, Data, SearchCount),
%%print_fd_info(Finfo),
{Res, #find_result{sid = Sid,
- eos = to_bool(EndOfSearch),
+ eos = to_bool(EoS),
finfo = Finfo}}.
+x2_get_more(Req, Data) ->
+ S = (Req#smbpdu.neg)#smb_negotiate_res.sock,
+ {ok, _, Pdu} = esmb_netbios:recv(S),
+ Res = safe_dec_smb(Req, Pdu), % NB: may throw(Pdu)
+ <<TotParamCount:16/little,
+ TotDataCount:16/little,
+ _:16/little, % reserved
+ ParamCount:16/little,
+ ParamOffset:16/little,
+ ParamDisplacement:16/little,
+ DataCount:16/little,
+ DataOffset:16/little,
+ DataDisplacement:16/little,
+ SetupCount,
+ _/binary>> = Res#smbpdu.wp,
+ Bf = Res#smbpdu.bf,
+ {SetupWords, B1} =
+ if (SetupCount > 0) ->
+ <<Xsw:SetupCount/binary,Xb1/binary>> = Bf,
+ {Xsw, Xb1};
+ true ->
+ {<<>>, Bf}
+ end,
+ %% We may have some pad bytes here between the
+ %% ByteCount parameter and the actual data.
+ %% Strip it off by computing how many bytes
+ %% we have upto and including the ByteCount param,
+ %% and subtract that from the DataOffset param.
+ %% Whatever is left is the number of pad-bytes.
+ Pad = DataOffset -
+ (?SMB_HEADER_LEN +
+ 1 + % WordCount == 1 byte
+ ((Res#smbpdu.wc + SetupCount) * 2) +
+ 2), % ByteCount == 2 bytes
+ NewData = if (Pad > 0) ->
+ <<SS:Pad/binary,Xdata/binary>> = B1,
+ Xdata;
+ true ->
+ B1
+ end,
+ if
+ (TotDataCount == (DataCount + DataDisplacement)) ->
+ ?sdbg("x2_get_more - Yes, got it all~n", []),
+ Res#smbpdu{data = concat_binary([Data,NewData])};
+ (TotDataCount > (DataCount + DataDisplacement)) ->
+ ?sdbg("x2_get_more - Need more ~n", [TotDataCount - (DataCount + DataDisplacement)]),
+ x2_get_more(Res, concat_binary([Data,NewData]));
+ true ->
+ %% Bad case, see comment above.
+ ?elog("x2_get_more: ERROR TotDataCount=~p , DataCount=~p~n",
+ [TotDataCount, DataCount]),
+ Res#smbpdu{data = concat_binary([Data,NewData])}
+ end.
+
+
+
+
+
%%% ---
@@ -1696,8 +1787,10 @@ dec_find_file_both_dir_info(<<Offset:32/little, % Offset to next struct
dec_find_file_both_dir_info(Rest, Ucode, Max, I) when I > Max ->
[];
dec_find_file_both_dir_info(Rest, Ucode, Max, I) ->
- ?elog("dec_find_file_both_dir_info: <ERROR> Missing file info I=~p~n",[I]),
- %%hexprint(b2l(Rest)),
+ {backtrace, BT} = process_info(self(), backtrace),
+ ?elog("dec_find_file_both_dir_info: <ERROR> Missing file info I=~p Max=~p~nBacktrace=~s~n",
+ [I,Max,binary_to_list(BT)]),
+ hexprint(b2l(Rest)),
[].
@@ -2193,7 +2286,7 @@ wp_trans2_find_x2(SubCmd, PathLen, NullLen) ->
<<ParamCount:16/little, % Total parameter bytes sent
0:16/little, % Total data bytes sent
10:16/little, % Max parameter bytes to return
- 4096:16/little, % Max data bytes to return
+ ?MAX_BUFFER_SIZE:16/little,% Max data bytes to return
0, % Max setup words to return
0, % reserved
0:16/little, % Flags
View
5 lib/esmb/src/esmb_client.erl
@@ -227,7 +227,7 @@ ls(S, Neg, {Pdu0, Cwd} = State) ->
Cset = get(charset),
WinPath = mk_winpath(Neg, Cwd, Cset),
Udir = to_ucs2(Neg, add_wildcard(Neg, Cset, WinPath), Cset),
- Pdu = esmb:list_dir(S, Pdu0, Udir),
+ Pdu = (catch esmb:list_dir(S, Pdu0, Udir)),
print_file_info(Neg, Pdu#smbpdu.finfo),
{Pdu, Cwd}.
@@ -239,7 +239,8 @@ print_file_info(Neg, L) ->
X#file_info.size,
check_attr(X#file_info.attr)])
end,
- lists:foreach(F, L).
+ lists:foreach(F, L),
+ io:format("Number of entries are ~w~n", [string:len(L)]).
dt(X) ->
{Y,M,D} = X#dt.last_access_date,
View
5 lib/esmb/src/esmb_lib.hrl
@@ -220,7 +220,6 @@
-define(HEADER_SIZE, 100). % max_data_sent = max_buffer_size - header_size
-%-define(MAX_BUFFER_SIZE, 8192).
-define(MAX_BUFFER_SIZE, 16644).
%%% This record hold the negotiation result.
@@ -234,7 +233,9 @@
samba2=false,
samba2_cset=?CSET_ASCII,
netware=false,
- flags2 % copy of the flags2 field from the neg. PDU
+ flags2, % copy of the flags2 field from the neg. PDU
+ %% --- Own, additional info
+ sock % The Socket fd used for this session
}).
%%% SecurityMode flags when LANMAN is negotiated
View
105 lib/esmb/src/esmb_netbios.erl
@@ -10,7 +10,7 @@
nbss_session_service/2, nbss_datagram_service/2,
nbss_src_name/1, nbss_dst_name/1, nb_dec_name/1,
tt_ename/1, tt_dname/1, dec_nbns/2, positive_query_response_pdu/2,
- dec_nbss_datagram/1]).
+ dec_nbss_datagram/1, recv/1, connect/3, close/1]).
-import(esmb, [b2l/1, ip2bin/1, bin2ip/1, ip2str/1, lcase/1, sizeof/1]).
@@ -30,7 +30,7 @@ nbss_session_service(S, SMB_pdu) ->
nbss_datagram_service(Dgm, Pdu) ->
Res = gen_udp:send(Dgm#netbios_dgm.sock,
- "192.168.128.255",
+ "192.168.128.255", %% FIXME
?NETBIOS_DGM_PORT,
nbss_datagram_pdu(Dgm, Pdu)),
Res.
@@ -62,27 +62,28 @@ dec_nbns(Bin, _Ns) ->
Bin. % NYI !!
-dec_msg(<<?POSITIVE_SESSION_RESPONSE,Flags,Length:16>>) ->
+dec_msg(_, <<?POSITIVE_SESSION_RESPONSE,Flags,Length:16>>) ->
{ok, ?POSITIVE_SESSION_RESPONSE};
-dec_msg(<<?SESSION_SERVICE, _, Length:16, SMB_pdu/binary>>) ->
- {ok, ?SESSION_SERVICE, get_more(Length, sizeof(SMB_pdu), [SMB_pdu])};
-dec_msg(<<?SESSION_KEEP_ALIVE, _/binary>>) ->
+dec_msg(S, <<?SESSION_SERVICE, _, Length:16, SMB_pdu/binary>>) ->
+ {ok, ?SESSION_SERVICE, get_more(S, Length, sizeof(SMB_pdu), [SMB_pdu])};
+dec_msg(_, <<?SESSION_KEEP_ALIVE, _/binary>>) ->
{ok, ?SESSION_KEEP_ALIVE};
-dec_msg(<<?NEGATIVE_SESSION_RESPONSE,Flags,Length:16,Ecode>>) ->
+dec_msg(_, <<?NEGATIVE_SESSION_RESPONSE,Flags,Length:16,Ecode>>) ->
Emsg = neg_sess_resp(Ecode),
{error, neg_sess_resp(Ecode)};
-dec_msg(Bin) ->
+dec_msg(_, Bin) ->
?elog("dec_msg got: ~p~n",[Bin]),
{error, Bin}.
-get_more(Expected, Got, Bins) when Got < Expected ->
- receive
- {tcp,_,Bin} ->
- get_more(Expected, Got + size(Bin), [Bin | Bins])
+get_more(S, Expected, Got, Bins) when Got < Expected ->
+ case recv(S, Expected - Got) of
+ {ok, Bin} ->
+ get_more(S, Expected, Got + size(Bin), [Bin | Bins])
end;
-get_more(_, _, Bins) ->
+get_more(_, Expected, _Got, Bins) ->
concat_binary(lists:reverse(Bins)).
+
neg_sess_resp(16#80) -> "Not listening on called name";
neg_sess_resp(16#81) -> "Not listening for calling name";
neg_sess_resp(16#82) -> "Called name not present";
@@ -274,35 +275,63 @@ lcase_host(T) when tuple(T) -> T;
lcase_host(L) when list(L) -> lcase(L).
+%%%
+%%% We want to make sure we connect in passive mode so
+%%% that we can control exactly how many bytes to be read.
+%%%
+connect(Host, Port, SockOpts) ->
+ Opts = [binary, {packet,0}, {active,false} | SockOpts],
+ gen_tcp:connect(Host, Port, Opts).
+
+close(Sock) ->
+ gen_tcp:close(Sock).
+
+
send_recv(S, Packet) ->
gen_tcp:send(S, [Packet]),
recv(S).
recv(S) ->
- receive
- {tcp,S,Bin} ->
- case dec_msg(Bin) of
- {ok, ?SESSION_KEEP_ALIVE} ->
- recv(S);
- Else ->
- Else
- end;
-
- {tcp,_,Bin} ->
- %%?elog("recv: ignoring stale tcp msg~n",[]),
- recv(S);
-
- {tcp_closed,S} ->
- %%?elog("recv: port closed~n",[]),
- exit(closed);
-
- {tcp_closed,_} ->
- %%?elog("recv: ignoring stale port closed msg~n",[]),
- recv(S);
-
- Else ->
- %%?elog("recv: got unexpected msg: ~p~n",[Else]),
- gen_tcp:close(S),
- exit(Else)
+ case recv_4(S) of
+ {ok, Bin} ->
+ dec_msg(S, Bin);
+ {error, Reason} ->
+ ?elog("recv/1: got error, Reason=~p~n", [Reason]),
+ {error, Reason}
end.
+recv_4(S) ->
+ recv(S, 4).
+
+recv(S, Length) ->
+ gen_tcp:recv(S, Length).
+
+
+%%%old_recv(S) ->
+%%% receive
+%%% {tcp,S,Bin} ->
+%%% case dec_msg(Bin) of
+%%% {ok, ?SESSION_KEEP_ALIVE} ->
+%%% recv(S);
+%%% Else ->
+%%% Else
+%%% end;
+%%%
+%%% {tcp,_,Bin} ->
+%%% %%?elog("recv: ignoring stale tcp msg~n",[]),
+%%% recv(S);
+%%%
+%%% {tcp_closed,S} ->
+%%% %%?elog("recv: port closed~n",[]),
+%%% exit(closed);
+%%%
+%%% {tcp_closed,_} ->
+%%% %%?elog("recv: ignoring stale port closed msg~n",[]),
+%%% recv(S);
+%%%
+%%% Else ->
+%%% %%?elog("recv: got unexpected msg: ~p~n",[Else]),
+%%% gen_tcp:close(S),
+%%% exit(Else)
+%%% end.
+
Please sign in to comment.
Something went wrong with that request. Please try again.