From ad6387b0242caa2b3c64d62a133752e10546211b Mon Sep 17 00:00:00 2001 From: Scott Lystig Fritchie Date: Thu, 17 Nov 2011 00:47:23 -0600 Subject: Add DTrace support for OS X, Solaris, and Linux (via SystemTap), 4/4 Add probes to (mostly) the efile_drv.c driver and other file I/O-related source files. --- erts/preloaded/src/prim_file.erl | 600 ++++++++++++++++++++++++--------------- 1 file changed, 375 insertions(+), 225 deletions(-) (limited to 'erts/preloaded/src/prim_file.erl') diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 36cbe329e8..5c9cad3a2c 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -25,39 +25,59 @@ %%% Interface towards a single file's contents. Uses ?FD_DRV. %% Generic file contents operations --export([open/2, close/1, datasync/1, sync/1, advise/4, position/2, truncate/1, - write/2, pwrite/2, pwrite/3, read/2, read_line/1, pread/2, pread/3, - copy/3, sendfile/10]). + +-export([ + open/2, open/3, + close/1, close/2, + datasync/1, datasync/2, + sync/1, sync/2, + advise/4, advise/5, + position/2, position/3, + truncate/1, truncate/2, + write/2, write/3, + pwrite/2, pwrite/3, pwrite/4, + read/2, read/3, + read_line/1, read_line/2, + pread/2, pread/3, pread/4, + copy/3, copy/4, + sendfile/10 + ]). %% Specialized file operations --export([open/1, open/3]). --export([read_file/1, read_file/2, write_file/2]). --export([ipread_s32bu_p32bu/3]). +-export([open/1]). +-export([read_file/1, read_file/2, read_file/3, write_file/2, write_file/3]). +-export([ipread_s32bu_p32bu/3, ipread_s32bu_p32bu/4]). %%% Interface towards file system and metadata. Uses ?DRV. %% Takes an optional port (opens a ?DRV port per default) as first argument. --export([get_cwd/0, get_cwd/1, get_cwd/2, - set_cwd/1, set_cwd/2, - delete/1, delete/2, - rename/2, rename/3, - make_dir/1, make_dir/2, - del_dir/1, del_dir/2, - read_file_info/1, read_file_info/2, read_file_info/3, - altname/1, altname/2, - write_file_info/2, write_file_info/3, write_file_info/4, - make_link/2, make_link/3, - make_symlink/2, make_symlink/3, - read_link/1, read_link/2, - read_link_info/1, read_link_info/2, read_link_info/3, - list_dir/1, list_dir/2]). + +-export([ + get_cwd/0, get_cwd/1, get_cwd/3, + set_cwd/1, set_cwd/3, + delete/1, delete/2, delete/3, + rename/2, rename/3, rename/4, + make_dir/1, make_dir/3, + del_dir/1, del_dir/3, + read_file_info/1, read_file_info/2, read_file_info/3, read_file_info/4, + altname/1, altname/3, + write_file_info/2, write_file_info/4, write_file_info/5, + make_link/2, make_link/3, make_link/4, + make_symlink/2, make_symlink/3, make_symlink/4, + read_link/1, read_link/3, + read_link_info/1, read_link_info/2, read_link_info/3, read_link_info/4, + list_dir/1, list_dir/3 + ]). %% How to start and stop the ?DRV port. -export([start/0, stop/1]). %% Debug exports --export([open_int/4, open_mode/1, open_mode/4]). +-export([open_int/4, open_int/5, open_mode/1, open_mode/4]). + +%% For DTrace/Systemtap tracing +-export([get_dtrace_utag/0]). %%%----------------------------------------------------------------- %%% Includes and defines @@ -155,30 +175,21 @@ %%% Supposed to be called by applications through module file. -%% Opens a file using the driver port Port. Returns {error, Reason} -%% | {ok, FileDescriptor} -open(Port, File, ModeList) when is_port(Port), - (is_list(File) orelse is_binary(File)), - is_list(ModeList) -> - case open_mode(ModeList) of - {Mode, _Portopts, _Setopts} -> - open_int(Port, File, Mode, []); - Reason -> - {error, Reason} - end; -open(_,_,_) -> - {error, badarg}. - %% Opens a file. Returns {error, Reason} | {ok, FileDescriptor}. -open(File, ModeList) when (is_list(File) orelse is_binary(File)), - is_list(ModeList) -> +open(File, ModeList) -> + open(File, ModeList, get_dtrace_utag()). + +open(File, ModeList, DTraceUtag) + when (is_list(File) orelse is_binary(File)), + is_list(ModeList), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> case open_mode(ModeList) of {Mode, Portopts, Setopts} -> - open_int({?FD_DRV, Portopts},File, Mode, Setopts); + open_int({?FD_DRV, Portopts}, File, Mode, Setopts, DTraceUtag); Reason -> {error, Reason} end; -open(_, _) -> +open(_, _, _) -> {error, badarg}. %% Opens a port that can be used for open/3 or read_file/2. @@ -193,29 +204,34 @@ open(Portopts) when is_list(Portopts) -> open(_) -> {error, badarg}. -open_int({Driver, Portopts}, File, Mode, Setopts) -> +open_int(Arg, File, Mode, Setopts) -> + open_int(Arg, File, Mode, Setopts, get_dtrace_utag()). + +open_int({Driver, Portopts}, File, Mode, Setopts, DTraceUtag) -> + %% TODO: add DTraceUtag to drv_open()? case drv_open(Driver, Portopts) of {ok, Port} -> - open_int(Port, File, Mode, Setopts); + open_int(Port, File, Mode, Setopts, DTraceUtag); {error, _} = Error -> Error end; -open_int(Port, File, Mode, Setopts) -> +open_int(Port, File, Mode, Setopts, DTraceUtag) -> M = Mode band ?EFILE_MODE_MASK, - case drv_command(Port, [<>, pathname(File)]) of + case drv_command(Port, [<>, + pathname(File), enc_utag(DTraceUtag)]) of {ok, Number} -> - open_int_setopts(Port, Number, Setopts); + open_int_setopts(Port, Number, Setopts, DTraceUtag); Error -> drv_close(Port), Error end. -open_int_setopts(Port, Number, []) -> +open_int_setopts(Port, Number, [], _DTraceUtag) -> {ok, #file_descriptor{module = ?MODULE, data = {Port, Number}}}; -open_int_setopts(Port, Number, [Cmd | Tail]) -> - case drv_command(Port, Cmd) of +open_int_setopts(Port, Number, [Cmd | Tail], DTraceUtag) -> + case drv_command(Port, [Cmd, enc_utag(DTraceUtag)]) of ok -> - open_int_setopts(Port, Number, Tail); + open_int_setopts(Port, Number, Tail, DTraceUtag); Error -> drv_close(Port), Error @@ -225,50 +241,64 @@ open_int_setopts(Port, Number, [Cmd | Tail]) -> %% Returns ok. -close(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> - case drv_command(Port, <>) of +close(Arg) -> + close(Arg, get_dtrace_utag()). + +close(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + case drv_command(Port, [<>, enc_utag(DTraceUtag)]) of ok -> drv_close(Port); Error -> Error end; %% Closes a port opened with open/1. -close(Port) when is_port(Port) -> +close(Port, _DTraceUtag) when is_port(Port) -> drv_close(Port). --define(ADVISE(Offs, Len, Adv), +-define(ADVISE(Offs, Len, Adv, BUtag), <>). + Adv:32/signed, BUtag/binary>>). %% Returns {error, Reason} | ok. +advise(FD, Offset, Length, Advise) -> + advise(FD, Offset, Length, Advise, get_dtrace_utag()). + advise(#file_descriptor{module = ?MODULE, data = {Port, _}}, - Offset, Length, Advise) -> + Offset, Length, Advise, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + BUtag = term_to_binary(enc_utag(DTraceUtag)), case Advise of normal -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NORMAL), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NORMAL, BUtag), drv_command(Port, Cmd); random -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_RANDOM), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_RANDOM, BUtag), drv_command(Port, Cmd); sequential -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_SEQUENTIAL), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_SEQUENTIAL, BUtag), drv_command(Port, Cmd); will_need -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_WILLNEED), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_WILLNEED, BUtag), drv_command(Port, Cmd); dont_need -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_DONTNEED), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_DONTNEED, BUtag), drv_command(Port, Cmd); no_reuse -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NOREUSE), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NOREUSE, BUtag), drv_command(Port, Cmd); _ -> {error, einval} end. %% Returns {error, Reason} | ok. -write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes) -> - case drv_command(Port, [?FILE_WRITE,Bytes]) of +write(Desc, Bytes) -> + write(Desc, Bytes, get_dtrace_utag()). + +write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + %% This is rare case where DTraceUtag is not at end of command list. + case drv_command(Port, [?FILE_WRITE,enc_utag(DTraceUtag),Bytes]) of {ok, _Size} -> ok; Error -> @@ -278,39 +308,40 @@ write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes) -> %% Returns ok | {error, {WrittenCount, Reason}} pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, L) when is_list(L) -> - pwrite_int(Port, L, 0, [], []). + pwrite_int(Port, L, 0, [], [], get_dtrace_utag()). -pwrite_int(_, [], 0, [], []) -> +pwrite_int(_, [], 0, [], [], _DTraceUtag) -> ok; -pwrite_int(Port, [], N, Spec, Data) -> - Header = list_to_binary([<> | reverse(Spec)]), +pwrite_int(Port, [], N, Spec, Data, DTraceUtag) -> + Header = list_to_binary([<>, enc_utag(DTraceUtag), + <>, reverse(Spec)]), case drv_command_raw(Port, [Header | reverse(Data)]) of {ok, _Size} -> ok; Error -> Error end; -pwrite_int(Port, [{Offs, Bytes} | T], N, Spec, Data) +pwrite_int(Port, [{Offs, Bytes} | T], N, Spec, Data, DTraceUtag) when is_integer(Offs) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE -> - pwrite_int(Port, T, N, Spec, Data, Offs, Bytes); + pwrite_int(Port, T, N, Spec, Data, Offs, Bytes, DTraceUtag); true -> {error, einval} end; -pwrite_int(_, [_|_], _N, _Spec, _Data) -> +pwrite_int(_, [_|_], _N, _Spec, _Data, _DTraceUtag) -> {error, badarg}. -pwrite_int(Port, T, N, Spec, Data, Offs, Bin) +pwrite_int(Port, T, N, Spec, Data, Offs, Bin, DTraceUtag) when is_binary(Bin) -> Size = byte_size(Bin), pwrite_int(Port, T, N+1, [<> | Spec], - [Bin | Data]); -pwrite_int(Port, T, N, Spec, Data, Offs, Bytes) -> + [Bin | Data], DTraceUtag); +pwrite_int(Port, T, N, Spec, Data, Offs, Bytes, DTraceUtag) -> try list_to_binary(Bytes) of Bin -> - pwrite_int(Port, T, N, Spec, Data, Offs, Bin) + pwrite_int(Port, T, N, Spec, Data, Offs, Bin, DTraceUtag) catch error:Reason -> {error, Reason} @@ -319,11 +350,28 @@ pwrite_int(Port, T, N, Spec, Data, Offs, Bytes) -> %% Returns {error, Reason} | ok. -pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes) +pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, L, DTraceUtag) + when is_list(L), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + pwrite_int(Port, L, 0, [], [], DTraceUtag); + +pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes) when is_integer(Offs) -> + pwrite_int2(Port, Offs, Bytes, get_dtrace_utag()); +pwrite(#file_descriptor{module = ?MODULE}, _, _) -> + {error, badarg}. + +pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes, DTraceUtag) + when is_integer(Offs), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + pwrite_int2(Port, Offs, Bytes, DTraceUtag); +pwrite(#file_descriptor{module = ?MODULE}, _, _, _DTraceUtag) -> + {error, badarg}. + +pwrite_int2(Port, Offs, Bytes, DTraceUtag) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE -> - case pwrite_int(Port, [], 0, [], [], Offs, Bytes) of + case pwrite_int(Port, [], 0, [], [], Offs, Bytes, DTraceUtag) of {error, {_, Reason}} -> {error, Reason}; Result -> @@ -331,22 +379,30 @@ pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes) end; true -> {error, einval} - end; -pwrite(#file_descriptor{module = ?MODULE}, _, _) -> - {error, badarg}. - + end. %% Returns {error, Reason} | ok. -datasync(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> - drv_command(Port, [?FILE_FDATASYNC]). +datasync(FD) -> + datasync(FD, get_dtrace_utag()). + +datasync(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + drv_command(Port, [?FILE_FDATASYNC, enc_utag(DTraceUtag)]). %% Returns {error, Reason} | ok. -sync(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> - drv_command(Port, [?FILE_FSYNC]). +sync(FD) -> + sync(FD, get_dtrace_utag()). + +sync(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + drv_command(Port, [?FILE_FSYNC, enc_utag(DTraceUtag)]). %% Returns {ok, Data} | eof | {error, Reason}. -read_line(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> - case drv_command(Port, <>) of +read_line(FD) -> + read_line(FD, get_dtrace_utag()). + +read_line(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) -> + case drv_command(Port, [<>, enc_utag(DTraceUtag)]) of {ok, {0, _Data}} -> eof; {ok, {_Size, Data}} -> @@ -366,11 +422,17 @@ read_line(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> end. %% Returns {ok, Data} | eof | {error, Reason}. -read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size) - when is_integer(Size), 0 =< Size -> +read(FD, Size) -> + read(FD, Size, get_dtrace_utag()). + +read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size, DTraceUtag) + when is_integer(Size), + 0 =< Size, + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> if Size < ?LARGEFILESIZE -> - case drv_command(Port, <>) of + case drv_command(Port, [<>, + enc_utag(DTraceUtag)]) of {ok, {0, _Data}} when Size =/= 0 -> eof; {ok, {_Size, Data}} -> @@ -379,7 +441,8 @@ read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size) %% Garbage collecting here might help if %% the current processes have some old binaries left. erlang:garbage_collect(), - case drv_command(Port, <>) of + case drv_command(Port, [<>, + enc_utag(DTraceUtag)]) of {ok, {0, _Data}} when Size =/= 0 -> eof; {ok, {_Size, Data}} -> @@ -397,35 +460,43 @@ read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size) %% Returns {ok, [Data|eof, ...]} | {error, Reason} pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, L) when is_list(L) -> - pread_int(Port, L, 0, []). + pread_int(Port, L, 0, [], get_dtrace_utag()). -pread_int(_, [], 0, []) -> +pread_int(_, [], 0, [], _DTraceUtag) -> {ok, []}; -pread_int(Port, [], N, Spec) -> - drv_command(Port, [<> | reverse(Spec)]); -pread_int(Port, [{Offs, Size} | T], N, Spec) +pread_int(Port, [], N, Spec, DTraceUtag) -> + drv_command(Port, [<>, enc_utag(DTraceUtag), + <<0:32, N:32>>, reverse(Spec)]); +pread_int(Port, [{Offs, Size} | T], N, Spec, DTraceUtag) when is_integer(Offs), is_integer(Size), 0 =< Size -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE, Size < ?LARGEFILESIZE -> - pread_int(Port, T, N+1, [<> | Spec]); + pread_int(Port, T, N+1, [<> | Spec], + DTraceUtag); true -> {error, einval} end; -pread_int(_, [_|_], _N, _Spec) -> +pread_int(_, [_|_], _N, _Spec, _DTraceUtag) -> {error, badarg}. - - %% Returns {ok, Data} | eof | {error, Reason}. -pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size) +pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, L, DTraceUtag) + when is_list(L), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + pread_int(Port, L, 0, [], get_dtrace_utag()); +pread(FD, Offs, Size) when is_integer(Offs), is_integer(Size), 0 =< Size -> + pread(FD, Offs, Size, get_dtrace_utag()). + +pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE, Size < ?LARGEFILESIZE -> case drv_command(Port, - <>) of + [<>, enc_utag(DTraceUtag), + <<0:32, 1:32, Offs:64/signed, Size:64>>]) of {ok, [eof]} -> eof; {ok, [Data]} -> @@ -436,17 +507,22 @@ pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size) true -> {error, einval} end; -pread(#file_descriptor{module = ?MODULE, data = {_, _}}, _, _) -> +pread(_, _, _, _) -> {error, badarg}. %% Returns {ok, Position} | {error, Reason}. -position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At) -> +position(FD, At) -> + position(FD, At, get_dtrace_utag()). + +position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> case lseek_position(At) of {Offs, Whence} when -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE -> - drv_command(Port, <>); + drv_command(Port, [<>, + enc_utag(DTraceUtag)]); {_, _} -> {error, einval}; Reason -> @@ -454,63 +530,89 @@ position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At) -> end. %% Returns {error, Reaseon} | ok. -truncate(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> - drv_command(Port, <>). +truncate(FD) -> + truncate(FD, get_dtrace_utag()). + +truncate(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + drv_command(Port, [<>, enc_utag(DTraceUtag)]). %% Returns {error, Reason} | {ok, BytesCopied} +copy(Source, Dest, Length) -> + copy(Source, Dest, Length, get_dtrace_utag()). + copy(#file_descriptor{module = ?MODULE} = Source, #file_descriptor{module = ?MODULE} = Dest, - Length) + Length, DTraceUtag) when is_integer(Length), Length >= 0; - is_atom(Length) -> + is_atom(Length), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> %% XXX Should be moved down to the driver for optimization. - file:copy_opened(Source, Dest, Length). + file:copy_opened(Source, Dest, Length, DTraceUtag). + +ipread_s32bu_p32bu(FD, Offs, Arg) -> + ipread_s32bu_p32bu(FD, Offs, Arg, get_dtrace_utag()). ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {_, _}} = Handle, Offs, - Infinity) when is_atom(Infinity) -> + Infinity, + DTraceUtag) + when is_atom(Infinity), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> ipread_s32bu_p32bu(Handle, Offs, (1 bsl 31)-1); ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, - MaxSize) - when is_integer(Offs), is_integer(MaxSize) -> + MaxSize, + DTraceUtag) + when is_integer(Offs), + is_integer(MaxSize), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE, 0 =< MaxSize, MaxSize < (1 bsl 31) -> - drv_command(Port, <>); + drv_command(Port, [<>, enc_utag(DTraceUtag)]); true -> {error, einval} end; ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {_, _}}, _Offs, - _MaxSize) -> + _MaxSize, + _DTraceUtag) -> {error, badarg}. %% Returns {ok, Contents} | {error, Reason} read_file(File) when (is_list(File) orelse is_binary(File)) -> + read_file(File, get_dtrace_utag()); +read_file(_) -> + {error, badarg}. + +read_file(File, DTraceUtag) + when (is_list(File) orelse is_binary(File)), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag))-> case drv_open(?FD_DRV, [binary]) of {ok, Port} -> - Result = read_file(Port, File), + Result = read_file(Port, File, DTraceUtag), close(Port), Result; {error, _} = Error -> Error end; -read_file(_) -> +read_file(_, _) -> {error, badarg}. %% Takes a Port opened with open/1. -read_file(Port, File) when is_port(Port), +read_file(Port, File, DTraceUtag) when is_port(Port), (is_list(File) orelse is_binary(File)) -> - Cmd = [?FILE_READ_FILE | pathname(File)], + Cmd = [?FILE_READ_FILE | + list_to_binary([pathname(File), enc_utag(DTraceUtag)])], case drv_command(Port, Cmd) of {error, enomem} -> %% It could possibly help to do a @@ -522,22 +624,30 @@ read_file(Port, File) when is_port(Port), Result -> Result end; -read_file(_,_) -> +read_file(_,_,_) -> {error, badarg}. %% Returns {error, Reason} | ok. -write_file(File, Bin) when (is_list(File) orelse is_binary(File)) -> +write_file(File, Bin) -> + write_file(File, Bin, get_dtrace_utag()). + +write_file(File, Bin, DTraceUtag) + when (is_list(File) orelse is_binary(File)), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + OldUtag = put(dtrace_utag, DTraceUtag), % TODO: API? case open(File, [binary, write]) of {ok, Handle} -> Result = write(Handle, Bin), close(Handle), + put(dtrace_utag, OldUtag), Result; Error -> + put(dtrace_utag, OldUtag), Error end; -write_file(_, _) -> +write_file(_, _, _) -> {error, badarg}. @@ -601,54 +711,56 @@ stop(Port) when is_port(Port) -> -%% get_cwd/{0,1,2} +%% get_cwd/{0,1,3} get_cwd() -> - get_cwd_int(0). + get_cwd_int(0, get_dtrace_utag()). get_cwd(Port) when is_port(Port) -> - get_cwd_int(Port, 0); + get_cwd_int(Port, 0, get_dtrace_utag()); get_cwd([]) -> - get_cwd_int(0); + get_cwd_int(0, get_dtrace_utag()); get_cwd([Letter, $: | _]) when $a =< Letter, Letter =< $z -> - get_cwd_int(Letter - $a + 1); + get_cwd_int(Letter - $a + 1, get_dtrace_utag()); get_cwd([Letter, $: | _]) when $A =< Letter, Letter =< $Z -> - get_cwd_int(Letter - $A + 1); + get_cwd_int(Letter - $A + 1, get_dtrace_utag()); get_cwd([_|_]) -> {error, einval}; get_cwd(_) -> {error, badarg}. -get_cwd(Port, []) when is_port(Port) -> - get_cwd_int(Port, 0); -get_cwd(Port, [Letter, $: | _]) +get_cwd(Port, [], DTraceUtag) when is_port(Port) -> + get_cwd_int(Port, 0, DTraceUtag); +get_cwd(Port, no_drive, DTraceUtag) when is_port(Port) -> + get_cwd_int(Port, 0, DTraceUtag); +get_cwd(Port, [Letter, $: | _], DTraceUtag) when is_port(Port), $a =< Letter, Letter =< $z -> - get_cwd_int(Port, Letter - $a + 1); -get_cwd(Port, [Letter, $: | _]) + get_cwd_int(Port, Letter - $a + 1, DTraceUtag); +get_cwd(Port, [Letter, $: | _], DTraceUtag) when is_port(Port), $A =< Letter, Letter =< $Z -> - get_cwd_int(Port, Letter - $A + 1); -get_cwd(Port, [_|_]) when is_port(Port) -> + get_cwd_int(Port, Letter - $A + 1, DTraceUtag); +get_cwd(Port, [_|_], _DTraceUtag) when is_port(Port) -> {error, einval}; -get_cwd(_, _) -> +get_cwd(_, _, _DTraceUtag) -> {error, badarg}. -get_cwd_int(Drive) -> - get_cwd_int({?DRV, [binary]}, Drive). +get_cwd_int(Drive, DTraceUtag) -> + get_cwd_int({?DRV, [binary]}, Drive, DTraceUtag). -get_cwd_int(Port, Drive) -> - drv_command(Port, <>). +get_cwd_int(Port, Drive, DTraceUtag) -> + drv_command(Port, list_to_binary([?FILE_PWD, Drive, enc_utag(DTraceUtag)])). -%% set_cwd/{1,2} +%% set_cwd/{1,3} set_cwd(Dir) -> - set_cwd_int({?DRV, [binary]}, Dir). + set_cwd_int({?DRV, [binary]}, Dir, get_dtrace_utag()). -set_cwd(Port, Dir) when is_port(Port) -> - set_cwd_int(Port, Dir). +set_cwd(Port, Dir, DTraceUtag) when is_port(Port) -> + set_cwd_int(Port, Dir, DTraceUtag). -set_cwd_int(Port, Dir0) -> +set_cwd_int(Port, Dir0, DTraceUtag) -> Dir = (catch case os:type() of @@ -658,7 +770,7 @@ set_cwd_int(Port, Dir0) -> %% must call get_cwd from here and use %% absname/2, since %% absname/1 uses file:get_cwd ... - case get_cwd_int(Port, 0) of + case get_cwd_int(Port, 0, "") of {ok, AbsPath} -> filename:absname(Dir0, AbsPath); _Badcwd -> @@ -669,78 +781,86 @@ set_cwd_int(Port, Dir0) -> end), %% Dir is now either a string or an EXIT tuple. %% An EXIT tuple will fail in the following catch. - drv_command(Port, [?FILE_CHDIR, pathname(Dir)]). + drv_command(Port, [?FILE_CHDIR, pathname(Dir), enc_utag(DTraceUtag)]). -%% delete/{1,2} +%% delete/{1,2,3} delete(File) -> - delete_int({?DRV, [binary]}, File). + delete_int({?DRV, [binary]}, File, get_dtrace_utag()). delete(Port, File) when is_port(Port) -> - delete_int(Port, File). + delete_int(Port, File, get_dtrace_utag()). + +delete(Port, File, DTraceUtag) when is_port(Port) -> + delete_int(Port, File, DTraceUtag). -delete_int(Port, File) -> - drv_command(Port, [?FILE_DELETE, pathname(File)]). +delete_int(Port, File, DTraceUtag) -> + drv_command(Port, [?FILE_DELETE, pathname(File), enc_utag(DTraceUtag)]). -%% rename/{2,3} +%% rename/{2,3,4} rename(From, To) -> - rename_int({?DRV, [binary]}, From, To). + rename_int({?DRV, [binary]}, From, To, get_dtrace_utag()). rename(Port, From, To) when is_port(Port) -> - rename_int(Port, From, To). + rename_int(Port, From, To, get_dtrace_utag()). + +rename(Port, From, To, DTraceUtag) when is_port(Port) -> + rename_int(Port, From, To, DTraceUtag). -rename_int(Port, From, To) -> - drv_command(Port, [?FILE_RENAME, pathname(From), pathname(To)]). +rename_int(Port, From, To, DTraceUtag) -> + drv_command(Port, [?FILE_RENAME, pathname(From), pathname(To), + enc_utag(DTraceUtag)]). -%% make_dir/{1,2} +%% make_dir/{1,3} make_dir(Dir) -> - make_dir_int({?DRV, [binary]}, Dir). + make_dir_int({?DRV, [binary]}, Dir, get_dtrace_utag()). -make_dir(Port, Dir) when is_port(Port) -> - make_dir_int(Port, Dir). +make_dir(Port, Dir, DTraceUtag) when is_port(Port) -> + make_dir_int(Port, Dir, DTraceUtag). -make_dir_int(Port, Dir) -> - drv_command(Port, [?FILE_MKDIR, pathname(Dir)]). +make_dir_int(Port, Dir, DTraceUtag) -> + drv_command(Port, [?FILE_MKDIR, pathname(Dir), enc_utag(DTraceUtag)]). -%% del_dir/{1,2} +%% del_dir/{1,3} del_dir(Dir) -> - del_dir_int({?DRV, [binary]}, Dir). + del_dir_int({?DRV, [binary]}, Dir, get_dtrace_utag()). -del_dir(Port, Dir) when is_port(Port) -> - del_dir_int(Port, Dir). +del_dir(Port, Dir, DTraceUtag) when is_port(Port) -> + del_dir_int(Port, Dir, DTraceUtag). -del_dir_int(Port, Dir) -> - drv_command(Port, [?FILE_RMDIR, pathname(Dir)]). +del_dir_int(Port, Dir, DTraceUtag) -> + drv_command(Port, [?FILE_RMDIR, pathname(Dir), enc_utag(DTraceUtag)]). - - -%% read_file_info/{1,2,3} +%% read_file_info/{1,2,3,4} read_file_info(File) -> - read_file_info_int({?DRV, [binary]}, File, local). + read_file_info_int({?DRV, [binary]}, File, local, get_dtrace_utag()). read_file_info(Port, File) when is_port(Port) -> - read_file_info_int(Port, File, local); + read_file_info_int(Port, File, local, get_dtrace_utag()); read_file_info(File, Opts) -> - read_file_info_int({?DRV, [binary]}, File, plgv(time, Opts, local)). + read_file_info_int({?DRV, [binary]}, File, plgv(time, Opts, local), get_dtrace_utag()). -read_file_info(Port, File, Opts) when is_port(Port) -> - read_file_info_int(Port, File, plgv(time, Opts, local)). +read_file_info(Port, File, Opts) when is_port(Port), is_list(Opts) -> + read_file_info_int(Port, File, plgv(time, Opts, local), get_dtrace_utag()). -read_file_info_int(Port, File, TimeType) -> +read_file_info(Port, File, Opts, DTraceUtag) when is_port(Port) -> + read_file_info_int(Port, File, plgv(time, Opts, local), DTraceUtag). + +read_file_info_int(Port, File, TimeType, DTraceUtag) -> try - case drv_command(Port, [?FILE_FSTAT, pathname(File)]) of + case drv_command(Port, [?FILE_FSTAT, pathname(File), enc_utag(DTraceUtag)]) of {ok, FI} -> {ok, FI#file_info{ ctime = from_seconds(FI#file_info.ctime, TimeType), mtime = from_seconds(FI#file_info.mtime, TimeType), @@ -752,30 +872,33 @@ read_file_info_int(Port, File, TimeType) -> error:_ -> {error, badarg} end. - -%% altname/{1,2} +%% altname/{1,3} altname(File) -> - altname_int({?DRV, [binary]}, File). + altname_int({?DRV, [binary]}, File, get_dtrace_utag()). -altname(Port, File) when is_port(Port) -> - altname_int(Port, File). +altname(Port, File, DTraceUtag) when is_port(Port) -> + altname_int(Port, File, DTraceUtag). -altname_int(Port, File) -> - drv_command(Port, [?FILE_ALTNAME, pathname(File)]). +altname_int(Port, File, DTraceUtag) -> + drv_command(Port, [?FILE_ALTNAME, pathname(File), enc_utag(DTraceUtag)]). -%% write_file_info/{2,3,4} + +%% write_file_info/{2,3,4,5} write_file_info(File, Info) -> - write_file_info_int({?DRV, [binary]}, File, Info, local). + write_file_info_int({?DRV, [binary]}, File, Info, local, get_dtrace_utag()). write_file_info(Port, File, Info) when is_port(Port) -> - write_file_info_int(Port, File, Info, local); + write_file_info_int(Port, File, Info, local, get_dtrace_utag()); write_file_info(File, Info, Opts) -> - write_file_info_int({?DRV, [binary]}, File, Info, plgv(time, Opts, local)). + write_file_info_int({?DRV, [binary]}, File, Info, plgv(time, Opts, local), get_dtrace_utag()). write_file_info(Port, File, Info, Opts) when is_port(Port) -> - write_file_info_int(Port, File, Info, plgv(time, Opts, local)). + write_file_info_int(Port, File, Info, plgv(time, Opts, local), get_dtrace_utag()). + +write_file_info(Port, File, Info, Opts, DTraceUtag) when is_port(Port) -> + write_file_info_int(Port, File, Info, plgv(time, Opts, local), DTraceUtag). write_file_info_int(Port, File, #file_info{mode=Mode, @@ -784,7 +907,8 @@ write_file_info_int(Port, File, atime=Atime0, mtime=Mtime0, ctime=Ctime0}, - TimeType) -> + TimeType, + DTraceUtag) -> % Atime and/or Mtime might be undefined % - use localtime() for atime, if atime is undefined @@ -803,12 +927,13 @@ write_file_info_int(Port, File, int_to_int64bytes(to_seconds(Atime, TimeType)), int_to_int64bytes(to_seconds(Mtime, TimeType)), int_to_int64bytes(to_seconds(Ctime, TimeType)), - pathname(File)]) + pathname(File), + enc_utag(DTraceUtag) + ]) catch error:_ -> {error, badarg} end. - file_info_validate_atime(Atime, _) when Atime =/= undefined -> Atime; file_info_validate_atime(undefined, local) -> erlang:localtime(); file_info_validate_atime(undefined, universal) -> erlang:universaltime(); @@ -820,63 +945,72 @@ file_info_validate_mtime(Mtime, _) -> Mtime. file_info_validate_ctime(undefined, Mtime) -> Mtime; file_info_validate_ctime(Ctime, _) -> Ctime. -%% make_link/{2,3} +%% make_link/{2,3,4} make_link(Old, New) -> - make_link_int({?DRV, [binary]}, Old, New). + make_link_int({?DRV, [binary]}, Old, New, get_dtrace_utag()). make_link(Port, Old, New) when is_port(Port) -> - make_link_int(Port, Old, New). + make_link_int(Port, Old, New, get_dtrace_utag()). -make_link_int(Port, Old, New) -> - drv_command(Port, [?FILE_LINK, pathname(Old), pathname(New)]). +make_link(Port, Old, New, DTraceUtag) when is_port(Port) -> + make_link_int(Port, Old, New, DTraceUtag). +make_link_int(Port, Old, New, DTraceUtag) -> + drv_command(Port, [?FILE_LINK, pathname(Old), pathname(New), + enc_utag(DTraceUtag)]). -%% make_symlink/{2,3} + +%% make_symlink/{2,3,4} make_symlink(Old, New) -> - make_symlink_int({?DRV, [binary]}, Old, New). + make_symlink_int({?DRV, [binary]}, Old, New, get_dtrace_utag()). make_symlink(Port, Old, New) when is_port(Port) -> - make_symlink_int(Port, Old, New). + make_symlink_int(Port, Old, New, get_dtrace_utag()). + +make_symlink(Port, Old, New, DTraceUtag) when is_port(Port) -> + make_symlink_int(Port, Old, New, DTraceUtag). -make_symlink_int(Port, Old, New) -> - drv_command(Port, [?FILE_SYMLINK, pathname(Old), pathname(New)]). +make_symlink_int(Port, Old, New, DTraceUtag) -> + drv_command(Port, [?FILE_SYMLINK, pathname(Old), pathname(New), + enc_utag(DTraceUtag)]). -%% read_link/{2,3} +%% read_link/{1,3} read_link(Link) -> - read_link_int({?DRV, [binary]}, Link). + read_link_int({?DRV, [binary]}, Link, get_dtrace_utag()). -read_link(Port, Link) when is_port(Port) -> - read_link_int(Port, Link). +read_link(Port, Link, DTraceUtag) when is_port(Port) -> + read_link_int(Port, Link, DTraceUtag). -read_link_int(Port, Link) -> - drv_command(Port, [?FILE_READLINK, pathname(Link)]). +read_link_int(Port, Link, DTraceUtag) -> + drv_command(Port, [?FILE_READLINK, pathname(Link), enc_utag(DTraceUtag)]). -%% read_link_info/{2,3} +%% read_link_info/{1,2,3,4} read_link_info(Link) -> - read_link_info_int({?DRV, [binary]}, Link, local). + read_link_info_int({?DRV, [binary]}, Link, local, get_dtrace_utag()). read_link_info(Port, Link) when is_port(Port) -> - read_link_info_int(Port, Link, local); - + read_link_info_int(Port, Link, local, get_dtrace_utag()); read_link_info(Link, Opts) -> - read_link_info_int({?DRV, [binary]}, Link, plgv(time, Opts, local)). + read_link_info_int({?DRV, [binary]}, Link, plgv(time, Opts, local), get_dtrace_utag()). read_link_info(Port, Link, Opts) when is_port(Port) -> - read_link_info_int(Port, Link, plgv(time, Opts, local)). + read_link_info_int(Port, Link, plgv(time, Opts, local), get_dtrace_utag()). +read_link_info(Port, Link, Opts, DTraceUtag) when is_port(Port) -> + read_link_info_int(Port, Link, plgv(time, Opts, local), DTraceUtag). -read_link_info_int(Port, Link, TimeType) -> +read_link_info_int(Port, Link, TimeType, DTraceUtag) -> try - case drv_command(Port, [?FILE_LSTAT, pathname(Link)]) of + case drv_command(Port, [?FILE_LSTAT, pathname(Link), enc_utag(DTraceUtag)]) of {ok, FI} -> {ok, FI#file_info{ ctime = from_seconds(FI#file_info.ctime, TimeType), mtime = from_seconds(FI#file_info.mtime, TimeType), @@ -888,16 +1022,16 @@ read_link_info_int(Port, Link, TimeType) -> error:_ -> {error, badarg} end. -%% list_dir/{1,2} +%% list_dir/{1,3} list_dir(Dir) -> - list_dir_int({?DRV, [binary]}, Dir). + list_dir_int({?DRV, [binary]}, Dir, get_dtrace_utag()). -list_dir(Port, Dir) when is_port(Port) -> - list_dir_int(Port, Dir). +list_dir(Port, Dir, DTraceUtag) when is_port(Port) -> + list_dir_int(Port, Dir, DTraceUtag). -list_dir_int(Port, Dir) -> - drv_command(Port, [?FILE_READDIR, pathname(Dir)], []). +list_dir_int(Port, Dir, DTraceUtag) -> + drv_command(Port, [?FILE_READDIR, pathname(Dir), enc_utag(DTraceUtag)], []). @@ -1335,7 +1469,6 @@ reverse(L, T) -> lists:reverse(L, T). pathname(File) -> (catch prim_file:internal_name2native(File)). - %% proplist:get_value/3 plgv(K, [{K, V}|_], _) -> V; plgv(K, [_|KVs], D) -> plgv(K, KVs, D); @@ -1359,3 +1492,20 @@ to_seconds({_,_} = Datetime, universal) -> erlang:universaltime_to_posixtime(Datetime); to_seconds({_,_} = Datetime, local) -> erlang:universaltime_to_posixtime(erlang:localtime_to_universaltime(Datetime)). + +%% TODO: Duplicate code! +get_dtrace_utag() -> + case get(dtrace_utag) of + X when is_list(X) -> + X; + _ -> + "" + end. + +%% TODO: Measure if it's worth checking (re:run()?) for NUL byte first? +enc_utag([0|Cs]) -> + enc_utag(Cs); +enc_utag([C|Cs]) -> + [C|enc_utag(Cs)]; +enc_utag([]) -> + [0]. -- cgit v1.2.3