@@ -8,10 +8,11 @@ defmodule File.Stream do
8
8
* `modes` - the file modes
9
9
* `raw` - a boolean indicating if bin functions should be used
10
10
* `line_or_bytes` - if reading should read lines or a given number of bytes
11
+ * `node` - the node the file belongs to
11
12
12
13
"""
13
14
14
- defstruct path: nil , modes: [ ] , line_or_bytes: :line , raw: true
15
+ defstruct path: nil , modes: [ ] , line_or_bytes: :line , raw: true , node: nil
15
16
16
17
@ type t :: % __MODULE__ { }
17
18
@@ -32,19 +33,29 @@ defmodule File.Stream do
32
33
modes
33
34
end
34
35
35
- % File.Stream { path: path , modes: modes , raw: raw , line_or_bytes: line_or_bytes }
36
+ % File.Stream { path: path , modes: modes , raw: raw , line_or_bytes: line_or_bytes , node: node ( ) }
37
+ end
38
+
39
+ @ doc false
40
+ def __open__ ( % File.Stream { path: path , node: node } , modes ) when node == node ( ) do
41
+ :file . open ( path , modes )
42
+ end
43
+
44
+ @ doc false
45
+ def __open__ ( % File.Stream { path: path , node: node } , modes ) do
46
+ :erpc . call ( node , :file_io_server , :start , [ self ( ) , path , List . delete ( modes , :raw ) ] )
36
47
end
37
48
38
49
defimpl Collectable do
39
- def into ( % { path: path , modes: modes , raw: raw } = stream ) do
50
+ def into ( % { modes: modes , raw: raw } = stream ) do
40
51
modes = for mode <- modes , mode not in [ :read ] , do: mode
41
52
42
- case :file . open ( path , [ :write | modes ] ) do
53
+ case File.Stream . __open__ ( stream , [ :write | modes ] ) do
43
54
{ :ok , device } ->
44
55
{ :ok , into ( device , stream , raw ) }
45
56
46
57
{ :error , reason } ->
47
- raise File.Error , reason: reason , action: "stream" , path: path
58
+ raise File.Error , reason: reason , action: "stream" , path: stream . path
48
59
end
49
60
end
50
61
@@ -73,14 +84,14 @@ defmodule File.Stream do
73
84
defimpl Enumerable do
74
85
@ read_ahead_size 64 * 1024
75
86
76
- def reduce ( % { path: path , modes: modes , line_or_bytes: line_or_bytes , raw: raw } , acc , fun ) do
87
+ def reduce ( % { modes: modes , line_or_bytes: line_or_bytes , raw: raw } = stream , acc , fun ) do
77
88
start_fun = fn ->
78
- case :file . open ( path , read_modes ( modes ) ) do
89
+ case File.Stream . __open__ ( stream , read_modes ( modes ) ) do
79
90
{ :ok , device } ->
80
91
if :trim_bom in modes , do: trim_bom ( device , raw ) |> elem ( 0 ) , else: device
81
92
82
93
{ :error , reason } ->
83
- raise File.Error , reason: reason , action: "stream" , path: path
94
+ raise File.Error , reason: reason , action: "stream" , path: stream . path
84
95
end
85
96
end
86
97
@@ -93,27 +104,20 @@ defmodule File.Stream do
93
104
Stream . resource ( start_fun , next_fun , & :file . close / 1 ) . ( acc , fun )
94
105
end
95
106
96
- def count ( % { path: path , modes: modes , line_or_bytes: :line } = stream ) do
107
+ def count ( % { modes: modes , line_or_bytes: :line , path: path } = stream ) do
97
108
pattern = :binary . compile_pattern ( "\n " )
98
109
counter = & count_lines ( & 1 , path , pattern , read_function ( stream ) , 0 )
99
-
100
- case File . open ( path , read_modes ( modes ) , counter ) do
101
- { :ok , count } ->
102
- { :ok , count }
103
-
104
- { :error , reason } ->
105
- raise File.Error , reason: reason , action: "stream" , path: path
106
- end
110
+ { :ok , open! ( stream , modes , counter ) }
107
111
end
108
112
109
- def count ( % { path: path , line_or_bytes: bytes , raw: true , modes: modes } ) do
110
- case File . stat ( path ) do
113
+ def count ( % { path: path , line_or_bytes: bytes , raw: true , modes: modes , node: node } = stream ) do
114
+ case :erpc . call ( node , File , :stat , [ path ] ) do
111
115
{ :ok , % { size: 0 } } ->
112
116
{ :error , __MODULE__ }
113
117
114
118
{ :ok , % { size: size } } ->
115
119
remainder = if rem ( size , bytes ) == 0 , do: 0 , else: 1
116
- { :ok , div ( size , bytes ) + remainder - count_raw_bom ( path , modes ) }
120
+ { :ok , div ( size , bytes ) + remainder - count_raw_bom ( stream , modes ) }
117
121
118
122
{ :error , reason } ->
119
123
raise File.Error , reason: reason , action: "stream" , path: path
@@ -132,9 +136,23 @@ defmodule File.Stream do
132
136
{ :error , __MODULE__ }
133
137
end
134
138
135
- defp count_raw_bom ( path , modes ) do
139
+ defp open! ( stream , modes , fun ) do
140
+ case File.Stream . __open__ ( stream , read_modes ( modes ) ) do
141
+ { :ok , device } ->
142
+ try do
143
+ fun . ( device )
144
+ after
145
+ :file . close ( device )
146
+ end
147
+
148
+ { :error , reason } ->
149
+ raise File.Error , reason: reason , action: "stream" , path: stream . path
150
+ end
151
+ end
152
+
153
+ defp count_raw_bom ( stream , modes ) do
136
154
if :trim_bom in modes do
137
- File . open! ( path , read_modes ( modes ) , & ( & 1 |> trim_bom ( true ) |> elem ( 1 ) ) )
155
+ open! ( stream , read_modes ( modes ) , & ( & 1 |> trim_bom ( true ) |> elem ( 1 ) ) )
138
156
else
139
157
0
140
158
end
0 commit comments