1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21-module(ram_file_SUITE).
22
23-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
24	 init_per_group/2,end_per_group/2,
25	 %% init/1, fini/1,
26	 init_per_testcase/2, end_per_testcase/2]).
27-export([open_modes/1, open_old_modes/1, pread_pwrite/1, position/1,
28	 truncate/1, sync/1, get_set_file/1, compress/1, uuencode/1,
29	 large_file_errors/1, large_file_light/1,
30	 large_file_heavy/0, large_file_heavy/1]).
31
32-include_lib("common_test/include/ct.hrl").
33-include_lib("kernel/include/file.hrl").
34
35-define(FILE_MODULE, file).         % Name of module to test
36-define(RAM_FILE_MODULE, ram_file). % Name of module to test
37
38%%--------------------------------------------------------------------------
39
40suite() ->
41    [{ct_hooks,[ts_install_cth]},
42     {timetrap,{minutes,1}}].
43
44all() ->
45    [open_modes, open_old_modes, pread_pwrite, position,
46     truncate, sync, get_set_file, compress, uuencode,
47     large_file_errors, large_file_light, large_file_heavy].
48
49groups() ->
50    [].
51
52init_per_suite(Config) ->
53    Config.
54
55end_per_suite(_Config) ->
56    ok.
57
58init_per_group(_GroupName, Config) ->
59    Config.
60
61end_per_group(_GroupName, Config) ->
62    Config.
63
64
65init_per_testcase(Func, Config) ->
66    Config.
67
68end_per_testcase(_Func, Config) ->
69    Config.
70
71%%--------------------------------------------------------------------------
72%% Test suites
73
74%% Test that the basic read, write and binary options works for open/2.
75open_modes(Config) when is_list(Config) ->
76    Str1 = "The quick brown fox ",
77    Str2 = "jumps over a lazy dog ",
78    Str  = Str1 ++ Str2,
79    Bin1 = list_to_binary(Str1),
80    Bin2 = list_to_binary(Str2),
81    Bin  = list_to_binary(Str),
82    %%
83    open_read_write(?FILE_MODULE, Str1, [ram, read, write], Str2),
84    open_read(?FILE_MODULE, Str, [ram]),
85    open_read_write(?FILE_MODULE, Bin1, [ram, binary, read, write], Bin2),
86    open_read(?FILE_MODULE, Bin, [ram, binary, read]),
87    %%
88    ok.
89
90%% Test that the old style read, write and binary options
91%% works for open/2.
92open_old_modes(Config) when is_list(Config) ->
93    Str1 = "The quick brown fox ",
94    Str2 = "jumps over a lazy dog ",
95    Str  = Str1 ++ Str2,
96    Bin1 = list_to_binary(Str1),
97    Bin2 = list_to_binary(Str2),
98    Bin  = list_to_binary(Str),
99    %%
100    open_read_write(?RAM_FILE_MODULE, Str1, read_write, Str2),
101    open_read(?RAM_FILE_MODULE, Str, read),
102    open_read_write(?RAM_FILE_MODULE, Bin1, {binary, read_write}, Bin2),
103    open_read(?RAM_FILE_MODULE, Bin, {binary, read}),
104    %%
105    ok.
106
107open_read_write(Module, Data1, Options, Data2) ->
108    io:format("~p:open_read_write(~p, ~p, ~p, ~p)~n",
109	      [?MODULE, Module, Data1, Options, Data2]),
110    %%
111    Size1 = sizeof(Data1),
112    Size2 = sizeof(Data2),
113    Data  = append(Data1, Data2),
114    Size  = Size1 + Size2,
115    %%
116    {ok, Fd}    = Module:open(Data1, Options),
117    {ok, Data1} = Module:read(Fd, Size1),
118    eof         = Module:read(Fd, 1),
119    {ok, Zero}  = Module:read(Fd, 0),
120    0           = sizeof(Zero),
121    ok          = Module:write(Fd, Data2),
122    {ok, 0}     = Module:position(Fd, bof),
123    {ok, Data}  = Module:read(Fd, Size),
124    eof         = Module:read(Fd, 1),
125    {ok, Zero}  = Module:read(Fd, 0),
126    ok          = Module:close(Fd),
127    %%
128    ok.
129
130open_read(Module, Data, Options) ->
131    io:format("~p:open_read(~p, ~p, ~p)~n",
132	      [?MODULE, Module, Data, Options]),
133    %%
134    Size = sizeof(Data),
135    %%
136    {ok, Fd}         = Module:open(Data, Options),
137    {ok, Data}       = Module:read(Fd, Size),
138    eof              = Module:read(Fd, 1),
139    {ok, Zero}       = Module:read(Fd, 0),
140    0                = sizeof(Zero),
141    {error, ebadf}   = Module:write(Fd, Data),
142    {ok, 0}          = Module:position(Fd, bof),
143    {ok, Data}       = Module:read(Fd, Size),
144    eof              = Module:read(Fd, 1),
145    {ok, Zero}       = Module:read(Fd, 0),
146    ok               = Module:close(Fd),
147    %%
148    ok.
149
150
151
152%% Test that pread/2,3 and pwrite/2,3 works.
153pread_pwrite(Config) when is_list(Config) ->
154    Str = "Flygande bäckaziner söka hwila på mjuqa tuvor x",
155    Bin = list_to_binary(Str),
156    %%
157    pread_pwrite_test(?FILE_MODULE, Str, [ram, read, write]),
158    pread_pwrite_test(?FILE_MODULE, Bin, [ram, binary, read, write]),
159    pread_pwrite_test(?RAM_FILE_MODULE, Str, [read, write]),
160    pread_pwrite_test(?RAM_FILE_MODULE, Bin, {binary, read_write}),
161    %%
162    ok.
163
164pread_pwrite_test(Module, Data, Options) ->
165    io:format("~p:pread_pwrite_test(~p, ~p, ~p)~n",
166	      [?MODULE, Module, Data, Options]),
167    %%
168    Size = sizeof(Data),
169    %%
170    {ok, Fd}         = Module:open([], Options),
171    ok               = Module:pwrite(Fd, 0, Data),
172    {ok, Data}       = Module:pread(Fd, 0, Size+1),
173    eof              = Module:pread(Fd, Size+1, 1),
174    {ok, Zero}       = Module:pread(Fd, Size+1, 0),
175    0                = sizeof(Zero),
176    ok               = Module:pwrite(Fd, [{0, Data}, {Size+17, Data}]),
177    {ok, [Data,
178	  eof,
179	  Data,
180	  Zero]}     = Module:pread(Fd, [{Size+17, Size+1},
181					 {2*Size+17+1, 1},
182					 {0, Size},
183					 {2*Size+17+1, 0}]),
184    ok               = Module:close(Fd),
185    %%
186    ok.
187
188%% Test that position/2 works.
189position(Config) when is_list(Config) ->
190    Str = "Att vara eller icke vara, det är frågan. ",
191    Bin = list_to_binary(Str),
192    %%
193    position_test(?FILE_MODULE, Str, [ram, read]),
194    position_test(?FILE_MODULE, Bin, [ram, binary]),
195    position_test(?RAM_FILE_MODULE, Str, [read]),
196    position_test(?RAM_FILE_MODULE, Bin, {binary, read}),
197    %%
198    ok.
199
200position_test(Module, Data, Options) ->
201    io:format("~p:position_test(~p, ~p, ~p)~n",
202	      [?MODULE, Module, Data, Options]),
203    %%
204    Size = sizeof(Data),
205    Size_7 = Size+7,
206    %%
207    Slice_0_2 = slice(Data, 0, 2),
208    Slice_0_3 = slice(Data, 0, 3),
209    Slice_2_5 = slice(Data, 2, 5),
210    Slice_3_4 = slice(Data, 3, 4),
211    Slice_5   = slice(Data, 5, Size),
212    %%
213    {ok, Fd}          = Module:open(Data, Options),
214    %%
215    io:format("CUR positions"),
216    {ok, Slice_0_2}   = Module:read(Fd, 2),
217    {ok, 2}           = Module:position(Fd, cur),
218    {ok, Slice_2_5}   = Module:read(Fd, 5),
219    {ok, 3}           = Module:position(Fd, {cur, -4}),
220    {ok, Slice_3_4}   = Module:read(Fd, 4),
221    {ok, 0}           = Module:position(Fd, {cur, -7}),
222    {ok, Slice_0_3}   = Module:read(Fd, 3),
223    {ok, 0}           = Module:position(Fd, {cur, -3}),
224    {error, einval}   = Module:position(Fd, {cur, -1}),
225    {ok, 0}           = Module:position(Fd, 0),
226    {ok, 2}           = Module:position(Fd, {cur, 2}),
227    {ok, Slice_2_5}   = Module:read(Fd, 5),
228    {ok, Size_7}      = Module:position(Fd, {cur, Size}),
229    {ok, Zero}        = Module:read(Fd, 0),
230    0                 = sizeof(Zero),
231    eof               = Module:read(Fd, 1),
232    %%
233    io:format("Absolute and BOF positions"),
234    {ok, Size}        = Module:position(Fd, Size),
235    eof               = Module:read(Fd, 1),
236    {ok, 5}           = Module:position(Fd, 5),
237    {ok, Slice_5}     = Module:read(Fd, Size),
238    {ok, 2}           = Module:position(Fd, {bof, 2}),
239    {ok, Slice_2_5}   = Module:read(Fd, 5),
240    {ok, 3}           = Module:position(Fd, 3),
241    {ok, Slice_3_4}   = Module:read(Fd, 4),
242    {ok, 0}           = Module:position(Fd, bof),
243    {ok, Slice_0_2}   = Module:read(Fd, 2),
244    {ok, Size_7}      = Module:position(Fd, {bof, Size_7}),
245    {ok, Zero}        = Module:read(Fd, 0),
246    %%
247    io:format("EOF positions"),
248    {ok, Size}        = Module:position(Fd, eof),
249    eof               = Module:read(Fd, 1),
250    {ok, 5}           = Module:position(Fd, {eof, -Size+5}),
251    {ok, Slice_5}     = Module:read(Fd, Size),
252    {ok, 2}           = Module:position(Fd, {eof, -Size+2}),
253    {ok, Slice_2_5}   = Module:read(Fd, 5),
254    {ok, 3}           = Module:position(Fd, {eof, -Size+3}),
255    {ok, Slice_3_4}   = Module:read(Fd, 4),
256    {ok, 0}           = Module:position(Fd, {eof, -Size}),
257    {ok, Slice_0_2}   = Module:read(Fd, 2),
258    {ok, Size_7}      = Module:position(Fd, {eof, 7}),
259    {ok, Zero}        = Module:read(Fd, 0),
260    eof               = Module:read(Fd, 1),
261    %%
262    ok.
263
264
265
266%% Test that truncate/1 works.
267truncate(Config) when is_list(Config) ->
268    Str = "Mån ädlare att lida och fördraga "
269	++ "ett bittert ödes stygn av pilar, ",
270    Bin = list_to_binary(Str),
271    %%
272    ok = truncate_test(?FILE_MODULE, Str, [ram, read, write]),
273    ok = truncate_test(?FILE_MODULE, Bin, [ram, binary, read, write]),
274    ok = truncate_test(?RAM_FILE_MODULE, Str, read_write),
275    ok = truncate_test(?RAM_FILE_MODULE, Bin, [binary, read, write]),
276    %%
277    {error, eacces} = truncate_test(?FILE_MODULE, Str, [ram]),
278    {error, eacces} = truncate_test(?FILE_MODULE, Bin, [ram, binary, read]),
279    {error, eacces} = truncate_test(?RAM_FILE_MODULE, Str, read),
280    {error, eacces} = truncate_test(?RAM_FILE_MODULE, Bin, {binary, read}),
281    %%
282    ok.
283
284truncate_test(Module, Data, Options) ->
285    io:format("~p:truncate_test(~p, ~p, ~p)~n",
286	      [?MODULE, Module, Data, Options]),
287    %%
288    Size = sizeof(Data),
289    Size1 = Size-2,
290    Data1 = slice(Data, 0, Size1),
291    %%
292    {ok, Fd}    = Module:open(Data, Options),
293    {ok, Size1} = Module:position(Fd, Size1),
294    case Module:truncate(Fd) of
295	ok ->
296	    {ok, 0}     = Module:position(Fd, 0),
297	    {ok, Data1} = Module:read(Fd, Size),
298	    ok          = Module:close(Fd),
299	    ok;
300	Error ->
301	    ok      = Module:close(Fd),
302	    Error
303    end.
304
305
306
307%% Test that sync/1 at least does not crash.
308sync(Config) when is_list(Config) ->
309    Str = "än att ta till vapen mot ett hav av kval. ",
310    Bin = list_to_binary(Str),
311    %%
312    sync_test(?FILE_MODULE, Str, [ram, read, write]),
313    sync_test(?FILE_MODULE, Bin, [ram, binary, read, write]),
314    sync_test(?RAM_FILE_MODULE, Str, read_write),
315    sync_test(?RAM_FILE_MODULE, Bin, [binary, read, write]),
316    %%
317    sync_test(?FILE_MODULE, Str, [ram]),
318    sync_test(?FILE_MODULE, Bin, [ram, binary, read]),
319    sync_test(?RAM_FILE_MODULE, Str, read),
320    sync_test(?RAM_FILE_MODULE, Bin, {binary, read}),
321    %%
322    ok.
323
324sync_test(Module, Data, Options) ->
325    io:format("~p:sync_test(~p, ~p, ~p)~n",
326	      [?MODULE, Module, Data, Options]),
327    %%
328    Size = sizeof(Data),
329    %%
330    {ok, Fd}    = Module:open(Data, Options),
331    ok          = Module:sync(Fd),
332    {ok, Data}  = Module:read(Fd, Size+1),
333    ok.
334
335
336
337%% Tests get_file/1, set_file/2, get_file_close/1 and get_size/1.
338get_set_file(Config) when is_list(Config) ->
339    %% These two strings should not be of equal length.
340    Str  = "När högan nord blir snöbetäckt, ",
341    Str2 = "får alla harar byta dräkt. ",
342    Bin  = list_to_binary(Str),
343    Bin2 = list_to_binary(Str2),
344    %%
345    ok = get_set_file_test(Str, read_write, Str2),
346    ok = get_set_file_test(Bin, [binary, read, write], Bin2),
347    ok = get_set_file_test(Str, read, Str2),
348    ok = get_set_file_test(Bin, [binary, read], Bin2),
349    %%
350    ok.
351
352get_set_file_test(Data, Options, Data2) ->
353    io:format("~p:get_set_file_test(~p, ~p, ~p)~n",
354	      [?MODULE, Data, Options, Data2]),
355    %%
356    Size  = sizeof(Data),
357    Size2 = sizeof(Data2),
358    %%
359    {ok, Fd}        = ?RAM_FILE_MODULE:open(Data, Options),
360    {ok, Size}      = ?RAM_FILE_MODULE:get_size(Fd),
361    {ok, Data}      = ?RAM_FILE_MODULE:get_file(Fd),
362    {ok, Data}      = ?RAM_FILE_MODULE:get_file_close(Fd),
363    {error, einval} = ?RAM_FILE_MODULE:get_size(Fd),
364    {ok, Fd2}       = ?RAM_FILE_MODULE:open(Data, Options),
365    case ?RAM_FILE_MODULE:set_file(Fd2, Data2) of
366	{ok, Size2} ->
367	    {ok, Size2} = ?RAM_FILE_MODULE:get_size(Fd2),
368	    {ok, Data2} = ?RAM_FILE_MODULE:get_file(Fd2),
369	    {ok, Data2} = ?RAM_FILE_MODULE:get_file_close(Fd2),
370	    ok;
371	{error, _} = Error ->
372	    {ok, Data}  = ?RAM_FILE_MODULE:get_file_close(Fd2),
373	    Error
374    end.
375
376
377
378%% Test that compress/1 and uncompress/1 works.
379compress(Config) when is_list(Config) ->
380    Data   = proplists:get_value(data_dir, Config),
381    Real   = filename:join(Data, "realmen.html"),
382    RealGz = filename:join(Data, "realmen.html.gz"),
383    %%
384    %% Uncompress test
385    %%
386    {ok, FdReal}   = ?FILE_MODULE:open(Real, []),
387    {ok, Fd}       = ?FILE_MODULE:open([], [ram, read, write]),
388    {ok, FdRealGz} = ?FILE_MODULE:open(RealGz, []),
389    %%
390    {ok, SzGz}     = ?FILE_MODULE:copy(FdRealGz, Fd),
391    {ok, Sz}       = ?RAM_FILE_MODULE:uncompress(Fd),
392    {ok, 0}        = ?FILE_MODULE:position(Fd, bof),
393    true           = compare(FdReal, Fd),
394    %%
395    true           = (SzGz =< Sz),
396    %%
397    %% Compress and uncompress test
398    %%
399    {ok, 0}        = ?FILE_MODULE:position(FdReal, bof),
400    {ok, 0}        = ?FILE_MODULE:position(Fd, bof),
401    ok             = ?FILE_MODULE:truncate(Fd),
402    {ok, Sz}       = ?FILE_MODULE:copy(FdReal, Fd),
403    {ok, SzGz}     = ?RAM_FILE_MODULE:compress(Fd),
404    {ok, Sz}       = ?RAM_FILE_MODULE:uncompress(Fd),
405    {ok, 0}        = ?FILE_MODULE:position(Fd, bof),
406    {ok, 0}        = ?FILE_MODULE:position(FdReal, bof),
407    true           = compare(FdReal, Fd),
408    %%
409    ok             = ?FILE_MODULE:close(FdReal),
410    ok             = ?FILE_MODULE:close(Fd),
411    ok             = ?FILE_MODULE:close(FdRealGz),
412
413
414    %% Test uncompressing data that will be expanded many times.
415    Huge = iolist_to_binary(mk_42(18)),
416    HugeSize = byte_size(Huge),
417    HugeGz = zlib:gzip(Huge),
418
419    {ok,HugeFd} = ?FILE_MODULE:open([], [ram,read,write,binary]),
420    ok = ?FILE_MODULE:write(HugeFd, HugeGz),
421    {ok,HugeSize} = ?RAM_FILE_MODULE:uncompress(HugeFd),
422    {ok,0} = ?FILE_MODULE:position(HugeFd, bof),
423    {ok,Huge} = ?FILE_MODULE:read(HugeFd, HugeSize),
424
425    %% Uncompressing again should do nothing.
426    {ok,HugeSize} = ?RAM_FILE_MODULE:uncompress(HugeFd),
427    {ok,0} = ?FILE_MODULE:position(HugeFd, bof),
428    {ok,Huge} = ?FILE_MODULE:read(HugeFd, HugeSize),
429
430    ok = ?FILE_MODULE:close(HugeFd),
431
432    ok.
433
434mk_42(0) ->
435    [42];
436mk_42(N) ->
437    B = mk_42(N-1),
438    [B|B].
439
440%% Test that uuencode/1 and uudecode/1 works.
441uuencode(Config) when is_list(Config) ->
442    Data   = proplists:get_value(data_dir, Config),
443    Real   = filename:join(Data, "realmen.html"),
444    RealUu = filename:join(Data, "realmen.html.uu"),
445    %%
446    %% Uudecode test
447    %%
448    {ok, FdReal}   = ?FILE_MODULE:open(Real, []),
449    {ok, Fd}       = ?FILE_MODULE:open([], [ram, read, write]),
450    {ok, FdRealUu} = ?FILE_MODULE:open(RealUu, []),
451    %%
452    {ok, SzUu}     = ?FILE_MODULE:copy(FdRealUu, Fd),
453    {ok, Sz}       = ?RAM_FILE_MODULE:uudecode(Fd),
454    true           = (Sz =< SzUu),
455    {ok, 0}        = ?FILE_MODULE:position(Fd, bof),
456    true           = compare(FdReal, Fd),
457    %%
458    %% Uuencode and decode test
459    %%
460    F = fun(Offs) ->
461		Size = Sz - Offs,
462		{ok, Offs}     = ?FILE_MODULE:position(FdReal, {bof,Offs}),
463		{ok, 0}        = ?FILE_MODULE:position(Fd, bof),
464		ok             = ?FILE_MODULE:truncate(Fd),
465		{ok, Size}     = ?FILE_MODULE:copy(FdReal, Fd),
466		{ok, SizeUu}   = ?RAM_FILE_MODULE:uuencode(Fd),
467		true           = (Size =< SizeUu),
468		{ok, Size}     = ?RAM_FILE_MODULE:uudecode(Fd),
469		{ok, Offs}     = ?FILE_MODULE:position(FdReal, {bof,Offs}),
470		{ok, 0}        = ?FILE_MODULE:position(Fd, bof),
471		true           = compare(FdReal, Fd)
472	end,
473    lists:foreach(F, lists:seq(0,Sz-1, 43)),
474
475    ok             = ?FILE_MODULE:close(FdReal),
476    ok             = ?FILE_MODULE:close(Fd),
477    ok             = ?FILE_MODULE:close(FdRealUu),
478    %%
479    ok.
480
481
482%% Test error checking of large file offsets.
483large_file_errors(Config) when is_list(Config) ->
484    TwoGig = 1 bsl 31,
485    {ok,Fd}         = ?RAM_FILE_MODULE:open("1234567890", [read,write]),
486    {error, einval} = ?FILE_MODULE:read(Fd, TwoGig),
487    {error, badarg} = ?FILE_MODULE:read(Fd, -1),
488    {error, einval} = ?FILE_MODULE:position(Fd, {bof,TwoGig}),
489    {error, einval} = ?FILE_MODULE:position(Fd, {bof,-TwoGig-1}),
490    {error, einval} = ?FILE_MODULE:position(Fd, {bof,-1}),
491    {error, einval} = ?FILE_MODULE:position(Fd, {cur,TwoGig}),
492    {error, einval} = ?FILE_MODULE:position(Fd, {cur,-TwoGig-1}),
493    {error, einval} = ?FILE_MODULE:position(Fd, {eof,TwoGig}),
494    {error, einval} = ?FILE_MODULE:position(Fd, {eof,-TwoGig-1}),
495    {error, einval} = ?FILE_MODULE:pread(Fd, TwoGig, 1),
496    {error, einval} = ?FILE_MODULE:pread(Fd, -TwoGig-1, 1),
497    {error, einval} = ?FILE_MODULE:pread(Fd, -1, 1),
498    {error, einval} = ?FILE_MODULE:pwrite(Fd, TwoGig, "@"),
499    {error, einval} = ?FILE_MODULE:pwrite(Fd, -TwoGig-1, "@"),
500    {error, einval} = ?FILE_MODULE:pwrite(Fd, -1, "@"),
501    {error, einval} = ?FILE_MODULE:pread(Fd, TwoGig, 0),
502    {error, einval} = ?FILE_MODULE:pread(Fd, -TwoGig-1, 0),
503    {error, einval} = ?FILE_MODULE:pread(Fd, -1, 0),
504    ok              = ?FILE_MODULE:close(Fd),
505    ok.
506
507
508
509%% Test light operations on a \large\ ram_file.
510large_file_light(Config) when is_list(Config) ->
511    PrivDir = proplists:get_value(priv_dir, Config),
512    %% Marker for next test case that is to heavy to run in a suite.
513    ok = ?FILE_MODULE:write_file(
514	    filename:join(PrivDir, "large_file_light"),
515	    <<"TAG">>),
516    %%
517    Data = "abcdefghijklmnopqrstuvwzyz",
518    Size = sizeof(Data),
519    Max = (1 bsl 31) - 1,
520    Max__1 = Max - 1,
521    {ok, Fd}        = ?RAM_FILE_MODULE:open(Data, [read]),
522    {ok, Data}      = ?FILE_MODULE:read(Fd, Size+1),
523    {ok, Max__1}    = ?FILE_MODULE:position(Fd, {eof, Max-Size-1}),
524    eof             = ?FILE_MODULE:read(Fd, 1),
525    {ok, Max}       = ?FILE_MODULE:position(Fd, {bof, Max}),
526    {ok, Zero}      = ?FILE_MODULE:read(Fd, 0),
527    0               = sizeof(Zero),
528    eof             = ?FILE_MODULE:read(Fd, 1),
529    eof             = ?FILE_MODULE:pread(Fd, Max__1, 1),
530    {ok, Zero}      = ?FILE_MODULE:pread(Fd, Max, 0),
531    eof             = ?FILE_MODULE:pread(Fd, Max, 1),
532    ok.
533
534
535
536large_file_heavy() ->
537    [{timetrap,{minutes,5}}].
538
539%% Test operations on a maximum size (2 GByte - 1) ram_file.
540large_file_heavy(Config) when is_list(Config) ->
541    PrivDir = proplists:get_value(priv_dir, Config),
542    %% Check previous test case marker.
543    case ?FILE_MODULE:read_file_info(
544	    filename:join(PrivDir, "large_file_light")) of
545	{ok,_} ->
546	    {skipped,"Too heavy for casual testing!"};
547	_ ->
548	    do_large_file_heavy(Config)
549    end.
550
551do_large_file_heavy(_Config) ->
552    Data = "qwertyuiopasdfghjklzxcvbnm",
553    Size = sizeof(Data),
554    Max = (1 bsl 31) - 1,
555    Max__1 = Max - 1,
556    Max__3 = Max - 3,
557    {ok, Fd}        = ?RAM_FILE_MODULE:open(Data, [read,write]),
558    {ok, Data}      = ?FILE_MODULE:read(Fd, Size+1),
559    {ok, Max}       = ?FILE_MODULE:position(Fd, {eof, Max-Size}),
560    eof             = ?FILE_MODULE:read(Fd, 1),
561    erlang:display({allocating,2,'GByte',please,be,patient,'...'}),
562    ok              = ?FILE_MODULE:write(Fd, ""),
563    erlang:display({allocating,2,'GByte',succeeded}),
564    {ok, Max__1}    = ?FILE_MODULE:position(Fd, {eof, -1}),
565    {ok, [0]}       = ?FILE_MODULE:read(Fd, 1),
566    {ok, []}        = ?FILE_MODULE:read(Fd, 0),
567    eof             = ?FILE_MODULE:read(Fd, 1),
568    ok              = ?FILE_MODULE:pwrite(Fd, Max-3, "TAG"),
569    {ok, Max}       = ?FILE_MODULE:position(Fd, cur),
570    {ok, Max__3}    = ?FILE_MODULE:position(Fd, {eof, -3}),
571    {ok, "TAG"}     = ?FILE_MODULE:read(Fd, 3+1),
572    {ok, Max__3}    = ?FILE_MODULE:position(Fd, {cur, -3}),
573    ok              = ?FILE_MODULE:write(Fd, "tag"),
574    {ok, Max}       = ?FILE_MODULE:position(Fd, cur),
575    {ok, 0}         = ?FILE_MODULE:position(Fd, bof),
576    {ok, "tag"}     = ?FILE_MODULE:pread(Fd, Max__3, 3+1),
577    {ok, 0}         = ?FILE_MODULE:position(Fd, cur),
578    ok              = ?FILE_MODULE:close(Fd),
579    ok.
580
581%%--------------------------------------------------------------------------
582%% Utility functions
583
584compare(FdA, FdB) ->
585    Size = 65536,
586    case {?FILE_MODULE:read(FdA, Size), ?FILE_MODULE:read(FdB, Size)} of
587	{{error, _} = Error, _} ->
588	    Error;
589	{_, {error, _} = Error} ->
590	    Error;
591	{{ok, A}, {ok, B}} ->
592	    case compare_data(A, B) of
593		true ->
594		    compare(FdA, FdB);
595		false ->
596		    false
597	    end;
598	{eof, eof} ->
599	    true;
600	_ ->
601	    false
602    end.
603
604compare_data(A, B) when is_list(A), is_list(B) ->
605    list_to_binary(A) == list_to_binary(B);
606compare_data(A, B) when is_list(A), is_binary(B) ->
607    list_to_binary(A) == B;
608compare_data(A, B) when is_binary(A), is_list(B) ->
609    A == list_to_binary(B);
610compare_data(A, B) when is_binary(A), is_binary(B) ->
611    A == B.
612
613sizeof(Data) when is_list(Data) ->
614    length(Data);
615sizeof(Data) when is_binary(Data) ->
616    byte_size(Data).
617
618append(Data1, Data2) when is_list(Data1), is_list(Data2) ->
619    Data1 ++ Data2;
620append(Data1, Data2) when is_binary(Data1), is_binary(Data2) ->
621    list_to_binary([Data1 | Data2]).
622
623slice(Data, Start, Length) when is_list(Data) ->
624    lists:sublist(Data, Start+1, Length);
625slice(Data, Start, Length) when is_binary(Data) ->
626    {_, Bin} = split_binary(Data, Start),
627    if
628	Length >= byte_size(Bin) ->
629	    Bin;
630	true ->
631	    {B, _} = split_binary(Bin, Length),
632	    B
633    end.
634
635