~ubuntu-branches/debian/squeeze/erlang/squeeze

« back to all changes in this revision

Viewing changes to lib/kernel/src/prim_file.erl

  • Committer: Bazaar Package Importer
  • Author(s): Sergei Golovan
  • Date: 2009-05-07 15:07:37 UTC
  • mfrom: (1.2.1 upstream) (5.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20090507150737-i4yb5elwinm7r0hc
Tags: 1:13.b-dfsg1-1
* Removed another bunch of non-free RFCs from original tarball
  (closes: #527053).
* Fixed build-dependencies list by adding missing comma. This requires
  libsctp-dev again. Also, added libsctp1 dependency to erlang-base and
  erlang-base-hipe packages because the shared library is loaded via
  dlopen now and cannot be added using dh_slibdeps (closes: #526682).
* Weakened dependency of erlang-webtool on erlang-observer to recommends
  to avoid circular dependencies (closes: #526627).
* Added solaris-i386 to HiPE enabled architectures.
* Made script sources in /usr/lib/erlang/erts-*/bin directory executable,
  which is more convenient if a user wants to create a target Erlang system.
* Shortened extended description line for erlang-dev package to make it
  fit 80x25 terminals.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
%% ``The contents of this file are subject to the Erlang Public License,
2
 
%% Version 1.1, (the "License"); you may not use this file except in
3
 
%% compliance with the License. You should have received a copy of the
4
 
%% Erlang Public License along with this software. If not, it can be
5
 
%% retrieved via the world wide web at http://www.erlang.org/.
6
 
%% 
7
 
%% Software distributed under the License is distributed on an "AS IS"
8
 
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
 
%% the License for the specific language governing rights and limitations
10
 
%% under the License.
11
 
%% 
12
 
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
13
 
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
14
 
%% AB. All Rights Reserved.''
15
 
%% 
16
 
%%     $Id$
17
 
%%
18
 
-module(prim_file).
19
 
 
20
 
%% Interface module to the file driver.
21
 
 
22
 
 
23
 
 
24
 
%%% Interface towards a single file's contents. Uses ?FD_DRV.
25
 
 
26
 
%% Generic file contents operations
27
 
-export([open/2, close/1, sync/1, position/2, truncate/1,
28
 
         write/2, pwrite/2, pwrite/3, read/2, pread/2, pread/3, copy/3]).
29
 
 
30
 
%% Specialized file operations
31
 
-export([open/1, open/3]).
32
 
-export([read_file/1, read_file/2, write_file/2]).
33
 
-export([ipread_s32bu_p32bu/3]).
34
 
 
35
 
 
36
 
 
37
 
%%% Interface towards file system and metadata. Uses ?DRV.
38
 
 
39
 
%% Takes an optional port (opens a ?DRV port per default) as first argument.
40
 
-export([get_cwd/0, get_cwd/1, get_cwd/2, 
41
 
         set_cwd/1, set_cwd/2,
42
 
         delete/1, delete/2, 
43
 
         rename/2, rename/3, 
44
 
         make_dir/1, make_dir/2,
45
 
         del_dir/1, del_dir/2,
46
 
         read_file_info/1, read_file_info/2,
47
 
         altname/1, altname/2,
48
 
         write_file_info/2, write_file_info/3,
49
 
         make_link/2, make_link/3,
50
 
         make_symlink/2, make_symlink/3,
51
 
         read_link/1, read_link/2,
52
 
         read_link_info/1, read_link_info/2,
53
 
         list_dir/1, list_dir/2]).
54
 
%% How to start and stop the ?DRV port.
55
 
-export([start/0, stop/1]).
56
 
 
57
 
%% Debug exports
58
 
-export([open_int/4, open_mode/1, open_mode/4]).
59
 
 
60
 
%%%-----------------------------------------------------------------
61
 
%%% Includes and defines
62
 
 
63
 
-include("file.hrl").
64
 
 
65
 
-define(DRV,    efile).
66
 
-define(FD_DRV, efile).
67
 
 
68
 
-define(LARGEFILESIZE, (1 bsl 63)).
69
 
 
70
 
%% Driver commands
71
 
-define(FILE_OPEN,             1).
72
 
-define(FILE_READ,             2).
73
 
-define(FILE_LSEEK,            3).
74
 
-define(FILE_WRITE,            4).
75
 
-define(FILE_FSTAT,            5).
76
 
-define(FILE_PWD,              6).
77
 
-define(FILE_READDIR,          7).
78
 
-define(FILE_CHDIR,            8).
79
 
-define(FILE_FSYNC,            9).
80
 
-define(FILE_MKDIR,            10).
81
 
-define(FILE_DELETE,           11).
82
 
-define(FILE_RENAME,           12).
83
 
-define(FILE_RMDIR,            13).
84
 
-define(FILE_TRUNCATE,         14).
85
 
-define(FILE_READ_FILE,        15).
86
 
-define(FILE_WRITE_INFO,       16).
87
 
-define(FILE_LSTAT,            19).
88
 
-define(FILE_READLINK,         20).
89
 
-define(FILE_LINK,             21).
90
 
-define(FILE_SYMLINK,          22).
91
 
-define(FILE_CLOSE,            23).
92
 
-define(FILE_PWRITEV,          24).
93
 
-define(FILE_PREADV,           25).
94
 
-define(FILE_SETOPT,           26).
95
 
-define(FILE_IPREAD,           27).
96
 
-define(FILE_ALTNAME,          28).
97
 
 
98
 
%% Driver responses
99
 
-define(FILE_RESP_OK,          0).
100
 
-define(FILE_RESP_ERROR,       1).
101
 
-define(FILE_RESP_DATA,        2).
102
 
-define(FILE_RESP_NUMBER,      3).
103
 
-define(FILE_RESP_INFO,        4).
104
 
-define(FILE_RESP_NUMERR,      5).
105
 
-define(FILE_RESP_LDATA,       6).
106
 
-define(FILE_RESP_N2DATA,      7).
107
 
-define(FILE_RESP_EOF,         8).
108
 
 
109
 
%% Open modes for the driver's open function.
110
 
-define(EFILE_MODE_READ,       1).
111
 
-define(EFILE_MODE_WRITE,      2).
112
 
-define(EFILE_MODE_READ_WRITE, 3).  
113
 
-define(EFILE_MODE_APPEND,     4).
114
 
-define(EFILE_COMPRESSED,      8).
115
 
 
116
 
%% Use this mask to get just the mode bits to be passed to the driver.
117
 
-define(EFILE_MODE_MASK, 15).
118
 
 
119
 
%% Seek modes for the driver's seek function.
120
 
-define(EFILE_SEEK_SET, 0).
121
 
-define(EFILE_SEEK_CUR, 1).
122
 
-define(EFILE_SEEK_END, 2).
123
 
 
124
 
%% Options
125
 
-define(FILE_OPT_DELAYED_WRITE, 0).
126
 
-define(FILE_OPT_READ_AHEAD,    1).
127
 
 
128
 
%% IPREAD variants
129
 
-define(IPREAD_S32BU_P32BU, 0).
130
 
 
131
 
 
132
 
 
133
 
%%%-----------------------------------------------------------------
134
 
%%% Functions operating on a file through a handle. ?FD_DRV.
135
 
%%%
136
 
%%% Generic file contents operations.
137
 
%%%
138
 
%%% Supposed to be called by applications through module file.
139
 
 
140
 
 
141
 
%% Opens a file using the driver port Port. Returns {error, Reason}
142
 
%% | {ok, FileDescriptor}
143
 
open(Port, File, ModeList) when is_port(Port), 
144
 
                                is_list(File), 
145
 
                                is_list(ModeList) ->
146
 
    case open_mode(ModeList) of
147
 
        {Mode, _Portopts, _Setopts} ->
148
 
            open_int(Port, File, Mode, []);
149
 
        Reason ->
150
 
            {error, Reason}
151
 
    end;
152
 
open(_,_,_) ->
153
 
    {error, badarg}.
154
 
 
155
 
%% Opens a file. Returns {error, Reason} | {ok, FileDescriptor}.
156
 
open(File, ModeList) when is_list(File), is_list(ModeList) ->
157
 
    case open_mode(ModeList) of
158
 
        {Mode, Portopts, Setopts} ->
159
 
            open_int({?FD_DRV, Portopts}, File, Mode, Setopts);
160
 
        Reason ->
161
 
            {error, Reason}
162
 
    end;
163
 
open(_, _) ->
164
 
    {error, badarg}.
165
 
 
166
 
%% Opens a port that can be used for open/3 or read_file/2.
167
 
%% Returns {ok, Port} | {error, Reason}.
168
 
open(Portopts) when is_list(Portopts) ->
169
 
%     drv_open(?FD_DRV, Portopts).
170
 
    case drv_open(?FD_DRV, Portopts) of
171
 
        {error, _} = Error ->
172
 
            Error;
173
 
        Other ->
174
 
            Other
175
 
    end;
176
 
open(_) ->
177
 
    {error, badarg}.
178
 
 
179
 
open_int({Driver, Portopts}, File, Mode, Setopts) ->
180
 
    case drv_open(Driver, Portopts) of
181
 
        {ok, Port} ->
182
 
            open_int(Port, File, Mode, Setopts);
183
 
        {error, _} = Error ->
184
 
            Error
185
 
    end;
186
 
open_int(Port, File, Mode, Setopts) ->
187
 
    M = Mode band ?EFILE_MODE_MASK,
188
 
    case drv_command(Port, [<<?FILE_OPEN, M:32>>, File, 0]) of
189
 
        {ok, Number} ->
190
 
            open_int_setopts(Port, Number, Setopts);
191
 
        Error ->
192
 
            drv_close(Port),
193
 
            Error
194
 
    end.
195
 
 
196
 
open_int_setopts(Port, Number, []) ->
197
 
    {ok, #file_descriptor{module = ?MODULE, data = {Port, Number}}};    
198
 
open_int_setopts(Port, Number, [Cmd | Tail]) ->
199
 
    case drv_command(Port, Cmd) of
200
 
        ok ->
201
 
            open_int_setopts(Port, Number, Tail);
202
 
        Error ->
203
 
            drv_close(Port),
204
 
            Error
205
 
    end.
206
 
 
207
 
 
208
 
 
209
 
%% Returns ok.
210
 
 
211
 
close(#file_descriptor{module = ?MODULE, data = {Port, _}}) ->
212
 
    case drv_command(Port, <<?FILE_CLOSE>>) of
213
 
        ok ->
214
 
            drv_close(Port);
215
 
        Error ->
216
 
            Error
217
 
    end;
218
 
%% Closes a port opened with open/1.
219
 
close(Port) when is_port(Port) ->
220
 
    drv_close(Port).
221
 
 
222
 
 
223
 
 
224
 
%% Returns {error, Reason} | ok.
225
 
write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes) ->
226
 
    case drv_command(Port, [?FILE_WRITE,Bytes]) of
227
 
        {ok, _Size} ->
228
 
            ok;
229
 
        Error ->
230
 
            Error
231
 
    end.
232
 
 
233
 
%% Returns ok | {error, {WrittenCount, Reason}}
234
 
pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, L)
235
 
  when is_list(L) ->
236
 
    pwrite_int(Port, L, 0, [], []).
237
 
 
238
 
pwrite_int(_, [], 0, [], []) ->
239
 
    ok;
240
 
pwrite_int(Port, [], N, Spec, Data) ->
241
 
    Header = list_to_binary([<<?FILE_PWRITEV, N:32>> | reverse(Spec)]),
242
 
    case drv_command_raw(Port, [Header | reverse(Data)]) of
243
 
        {ok, _Size} ->
244
 
            ok;
245
 
        Error ->
246
 
            Error
247
 
    end;
248
 
pwrite_int(Port, [{Offs, Bytes} | T], N, Spec, Data)
249
 
  when is_integer(Offs) ->
250
 
    if
251
 
        -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE ->
252
 
            pwrite_int(Port, T, N, Spec, Data, Offs, Bytes);
253
 
        true ->
254
 
            {error, einval}
255
 
    end;
256
 
pwrite_int(_, [_|_], _N, _Spec, _Data) ->
257
 
    {error, badarg}.
258
 
 
259
 
pwrite_int(Port, T, N, Spec, Data, Offs, Bin)
260
 
  when is_binary(Bin) ->
261
 
    Size = byte_size(Bin),
262
 
    pwrite_int(Port, T, N+1, 
263
 
               [<<Offs:64/signed, Size:64>> | Spec], 
264
 
               [Bin | Data]);
265
 
pwrite_int(Port, T, N, Spec, Data, Offs, Bytes) ->
266
 
    try list_to_binary(Bytes) of
267
 
        Bin ->
268
 
            pwrite_int(Port, T, N, Spec, Data, Offs, Bin)
269
 
    catch
270
 
        error:Reason ->
271
 
            {error, Reason}
272
 
    end.
273
 
 
274
 
 
275
 
 
276
 
%% Returns {error, Reason} | ok.
277
 
pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes) 
278
 
  when is_integer(Offs) ->
279
 
    if
280
 
        -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE ->
281
 
            case pwrite_int(Port, [], 0, [], [], Offs, Bytes) of
282
 
                {error, {_, Reason}} ->
283
 
                    {error, Reason};
284
 
                Result ->
285
 
                    Result
286
 
            end;
287
 
        true ->
288
 
            {error, einval}
289
 
    end;
290
 
pwrite(#file_descriptor{module = ?MODULE}, _, _) ->
291
 
    {error, badarg}.
292
 
 
293
 
 
294
 
 
295
 
%% Returns {error, Reason} | ok.
296
 
sync(#file_descriptor{module = ?MODULE, data = {Port, _}}) ->
297
 
    drv_command(Port, [?FILE_FSYNC]).
298
 
 
299
 
%% Returns {ok, Data} | eof | {error, Reason}.
300
 
read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size)
301
 
  when is_integer(Size), 0 =< Size ->
302
 
    if
303
 
        Size < ?LARGEFILESIZE ->
304
 
            case drv_command(Port, <<?FILE_READ, Size:64>>) of
305
 
                {ok, {0, _Data}} when Size =/= 0 ->
306
 
                    eof;
307
 
                {ok, {_Size, Data}} ->
308
 
                    {ok, Data};
309
 
                {error, enomem} ->
310
 
                    %% Garbage collecting here might help if
311
 
                    %% the current processes has some old binaries left.
312
 
                    erlang:garbage_collect(),
313
 
                    case drv_command(Port, <<?FILE_READ, Size:64>>) of
314
 
                        {ok, {0, _Data}} when Size =/= 0 ->
315
 
                            eof;
316
 
                        {ok, {_Size, Data}} ->
317
 
                            {ok, Data};
318
 
                        Other ->
319
 
                            Other
320
 
                    end;
321
 
                Error ->
322
 
                    Error
323
 
            end;
324
 
        true ->
325
 
            {error, einval}
326
 
    end.
327
 
 
328
 
%% Returns {ok, [Data|eof, ...]} | {error, Reason}
329
 
pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, L)
330
 
  when is_list(L) ->
331
 
    pread_int(Port, L, 0, []).
332
 
 
333
 
pread_int(_, [], 0, []) ->
334
 
    {ok, []};
335
 
pread_int(Port, [], N, Spec) ->
336
 
    drv_command(Port, [<<?FILE_PREADV, 0:32, N:32>> | reverse(Spec)]);
337
 
pread_int(Port, [{Offs, Size} | T], N, Spec)
338
 
  when is_integer(Offs), is_integer(Size), 0 =< Size ->
339
 
    if
340
 
        -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE,
341
 
        Size < ?LARGEFILESIZE ->
342
 
            pread_int(Port, T, N+1, [<<Offs:64/signed, Size:64>> | Spec]);
343
 
        true ->
344
 
            {error, einval}
345
 
    end;
346
 
pread_int(_, [_|_], _N, _Spec) ->
347
 
    {error, badarg}.
348
 
 
349
 
 
350
 
 
351
 
%% Returns {ok, Data} | eof | {error, Reason}.
352
 
pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size) 
353
 
  when is_integer(Offs), is_integer(Size), 0 =< Size ->
354
 
    if
355
 
        -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE,
356
 
        Size < ?LARGEFILESIZE ->
357
 
            case drv_command(Port, 
358
 
                             <<?FILE_PREADV, 0:32, 1:32,
359
 
                              Offs:64/signed, Size:64>>) of
360
 
                {ok, [eof]} ->
361
 
                    eof;
362
 
                {ok, [Data]} ->
363
 
                    {ok, Data};
364
 
                Error ->
365
 
                    Error
366
 
            end;
367
 
        true ->
368
 
            {error, einval}
369
 
    end;
370
 
pread(#file_descriptor{module = ?MODULE, data = {_, _}}, _, _) ->
371
 
    {error, badarg}.
372
 
 
373
 
 
374
 
 
375
 
%% Returns {ok, Position} | {error, Reason}.
376
 
position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At) ->
377
 
    case lseek_position(At) of
378
 
        {Offs, Whence}
379
 
        when -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE ->
380
 
            drv_command(Port, <<?FILE_LSEEK, Offs:64/signed, Whence:32>>);
381
 
        {_, _} ->
382
 
            {error, einval};
383
 
        Reason ->
384
 
            {error, Reason}
385
 
    end.
386
 
 
387
 
%% Returns {error, Reaseon} | ok.
388
 
truncate(#file_descriptor{module = ?MODULE, data = {Port, _}}) ->
389
 
    drv_command(Port, <<?FILE_TRUNCATE>>).
390
 
 
391
 
 
392
 
 
393
 
%% Returns {error, Reason} | {ok, BytesCopied}
394
 
copy(#file_descriptor{module = ?MODULE} = Source,
395
 
     #file_descriptor{module = ?MODULE} = Dest,
396
 
     Length)
397
 
  when is_integer(Length), Length >= 0;
398
 
       is_atom(Length) ->
399
 
    %% XXX Should be moved down to the driver for optimization.
400
 
    file:copy_opened(Source, Dest, Length).
401
 
 
402
 
 
403
 
 
404
 
ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE,
405
 
                                    data = {_, _}} = Handle,
406
 
                   Offs,
407
 
                   Infinity) when is_atom(Infinity) ->
408
 
    ipread_s32bu_p32bu(Handle, Offs, (1 bsl 31)-1);
409
 
ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {Port, _}},
410
 
                   Offs,
411
 
                   MaxSize)
412
 
  when is_integer(Offs), is_integer(MaxSize) ->
413
 
    if
414
 
        -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE,
415
 
        0 =< MaxSize, MaxSize < (1 bsl 31) ->
416
 
            drv_command(Port, <<?FILE_IPREAD, ?IPREAD_S32BU_P32BU,
417
 
                               Offs:64, MaxSize:32>>);
418
 
        true ->
419
 
            {error, einval}
420
 
    end;
421
 
ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {_, _}},
422
 
                   _Offs,
423
 
                   _MaxSize) ->
424
 
    {error, badarg}.
425
 
 
426
 
 
427
 
 
428
 
%% Returns {ok, Contents} | {error, Reason}
429
 
read_file(File) ->
430
 
    case drv_open(?FD_DRV, [binary]) of
431
 
        {ok, Port} ->
432
 
            Result = read_file(Port, File),
433
 
            close(Port),
434
 
            Result;
435
 
        {error, _} = Error ->
436
 
            Error
437
 
    end.
438
 
 
439
 
%% Takes a Port opened with open/1.
440
 
read_file(Port, File) when is_port(Port) ->
441
 
    Cmd = [?FILE_READ_FILE | File],
442
 
    case drv_command(Port, Cmd) of
443
 
        {error, enomem} ->
444
 
            %% It could possibly help to do a 
445
 
            %% garbage collection here, 
446
 
            %% if the file server has some references
447
 
            %% to binaries read earlier.
448
 
            erlang:garbage_collect(),
449
 
            drv_command(Port, Cmd);
450
 
        Result ->
451
 
            Result
452
 
    end.
453
 
 
454
 
    
455
 
 
456
 
%% Returns {error, Reason} | ok.
457
 
write_file(File, Bin) ->
458
 
    case open(File, [binary, write]) of
459
 
        {ok, Handle} ->
460
 
            Result = write(Handle, Bin),
461
 
            close(Handle),
462
 
            Result;
463
 
        Error ->
464
 
            Error
465
 
    end.
466
 
 
467
 
 
468
 
 
469
 
%%%-----------------------------------------------------------------
470
 
%%% Functions operating on files without handle to the file. ?DRV.
471
 
%%%
472
 
%%% Supposed to be called by applications through module file.
473
 
 
474
 
 
475
 
 
476
 
%% Returns {ok, Port}, the Port should be used as first argument in all
477
 
%% the following functions. Returns {error, Reason} upon failure.
478
 
start() ->
479
 
    try erlang:open_port({spawn, ?DRV}, []) of
480
 
        Port ->
481
 
            {ok, Port}
482
 
    catch
483
 
        error:Reason ->
484
 
            {error, Reason}
485
 
    end.
486
 
 
487
 
stop(Port) when is_port(Port) ->
488
 
    try erlang:port_close(Port) of
489
 
        _ ->
490
 
            ok
491
 
    catch
492
 
        _:_ ->
493
 
            ok
494
 
    end.
495
 
 
496
 
 
497
 
 
498
 
%%% The following functions take an optional Port as first argument.
499
 
%%% If the port is not supplied, a temporary one is opened and then
500
 
%%% closed after the request has been performed.
501
 
 
502
 
 
503
 
 
504
 
%% get_cwd/{0,1,2}
505
 
 
506
 
get_cwd() ->
507
 
    get_cwd_int(0).
508
 
 
509
 
get_cwd(Port) when is_port(Port) ->
510
 
    get_cwd_int(Port, 0);
511
 
get_cwd([]) ->
512
 
    get_cwd_int(0);
513
 
get_cwd([Letter, $: | _]) when $a =< Letter, Letter =< $z ->
514
 
    get_cwd_int(Letter - $a + 1);
515
 
get_cwd([Letter, $: | _]) when $A =< Letter, Letter =< $Z ->
516
 
    get_cwd_int(Letter - $A + 1);
517
 
get_cwd([_|_]) ->
518
 
    {error, einval};
519
 
get_cwd(_) ->
520
 
    {error, badarg}.
521
 
 
522
 
get_cwd(Port, []) when is_port(Port) ->
523
 
    get_cwd_int(Port, 0);
524
 
get_cwd(Port, [Letter, $: | _])
525
 
  when is_port(Port), $a =< Letter, Letter =< $z ->
526
 
    get_cwd_int(Port, Letter - $a + 1);
527
 
get_cwd(Port, [Letter, $: | _])
528
 
  when is_port(Port), $A =< Letter, Letter =< $Z ->
529
 
    get_cwd_int(Port, Letter - $A + 1);
530
 
get_cwd(Port, [_|_]) when is_port(Port) ->
531
 
    {error, einval};
532
 
get_cwd(_, _) ->
533
 
    {error, badarg}.
534
 
 
535
 
get_cwd_int(Drive) ->
536
 
    get_cwd_int({?DRV, []}, Drive).
537
 
 
538
 
get_cwd_int(Port, Drive) ->
539
 
    drv_command(Port, <<?FILE_PWD, Drive>>).
540
 
 
541
 
 
542
 
 
543
 
%% set_cwd/{1,2}
544
 
 
545
 
set_cwd(Dir) ->
546
 
    set_cwd_int({?DRV, []}, Dir).
547
 
 
548
 
set_cwd(Port, Dir) when is_port(Port) ->
549
 
    set_cwd_int(Port, Dir).
550
 
 
551
 
set_cwd_int(Port, Dir0) ->
552
 
    Dir = 
553
 
        (catch
554
 
         case os:type() of
555
 
             vxworks -> 
556
 
                 %% chdir on vxworks doesn't support
557
 
                 %% relative paths
558
 
                 %% must call get_cwd from here and use
559
 
                 %% absname/2, since
560
 
                 %% absname/1 uses file:get_cwd ...
561
 
                 case get_cwd_int(Port, 0) of
562
 
                     {ok, AbsPath} ->
563
 
                         filename:absname(Dir0, AbsPath);
564
 
                     _Badcwd ->
565
 
                         Dir0
566
 
                 end;
567
 
             _Else ->
568
 
                 Dir0
569
 
         end),
570
 
    %% Dir is now either a string or an EXIT tuple.
571
 
    %% An EXIT tuple will fail in the following catch.
572
 
    drv_command(Port, [?FILE_CHDIR, Dir, 0]).
573
 
 
574
 
 
575
 
 
576
 
%% delete/{1,2}
577
 
 
578
 
delete(File) ->
579
 
    delete_int({?DRV, []}, File).
580
 
 
581
 
delete(Port, File) when is_port(Port) ->
582
 
    delete_int(Port, File).
583
 
 
584
 
delete_int(Port, File) ->
585
 
    drv_command(Port, [?FILE_DELETE, File, 0]).
586
 
 
587
 
 
588
 
 
589
 
%% rename/{2,3}
590
 
 
591
 
rename(From, To) ->
592
 
    rename_int({?DRV, []}, From, To).
593
 
 
594
 
rename(Port, From, To) when is_port(Port) ->
595
 
    rename_int(Port, From, To).
596
 
 
597
 
rename_int(Port, From, To) ->
598
 
    drv_command(Port, [?FILE_RENAME, From, 0, To, 0]).
599
 
 
600
 
 
601
 
 
602
 
%% make_dir/{1,2}
603
 
 
604
 
make_dir(Dir) ->
605
 
    make_dir_int({?DRV, []}, Dir).
606
 
 
607
 
make_dir(Port, Dir) when is_port(Port) ->
608
 
    make_dir_int(Port, Dir).
609
 
 
610
 
make_dir_int(Port, Dir) ->
611
 
    drv_command(Port, [?FILE_MKDIR, Dir, 0]).
612
 
 
613
 
 
614
 
 
615
 
%% del_dir/{1,2}
616
 
 
617
 
del_dir(Dir) ->
618
 
    del_dir_int({?DRV, []}, Dir).
619
 
 
620
 
del_dir(Port, Dir) when is_port(Port) ->
621
 
    del_dir_int(Port, Dir).
622
 
 
623
 
del_dir_int(Port, Dir) ->
624
 
    drv_command(Port, [?FILE_RMDIR, Dir, 0]).
625
 
 
626
 
 
627
 
 
628
 
%% read_file_info/{1,2}
629
 
 
630
 
read_file_info(File) ->
631
 
    read_file_info_int({?DRV, []}, File).
632
 
 
633
 
read_file_info(Port, File) when is_port(Port) ->
634
 
    read_file_info_int(Port, File).
635
 
 
636
 
read_file_info_int(Port, File) ->
637
 
    drv_command(Port, [?FILE_FSTAT, File, 0]).
638
 
 
639
 
%% altname/{1,2}
640
 
 
641
 
altname(File) ->
642
 
    altname_int({?DRV, []}, File).
643
 
 
644
 
altname(Port, File) when is_port(Port) ->
645
 
    altname_int(Port, File).
646
 
 
647
 
altname_int(Port, File) ->
648
 
    drv_command(Port, [?FILE_ALTNAME, File, 0]).
649
 
 
650
 
 
651
 
%% write_file_info/{2,3}
652
 
 
653
 
write_file_info(File, Info) ->
654
 
    write_file_info_int({?DRV, []}, File, Info).
655
 
 
656
 
write_file_info(Port, File, Info) when is_port(Port) ->
657
 
    write_file_info_int(Port, File, Info).
658
 
 
659
 
write_file_info_int(Port, 
660
 
                    File, 
661
 
                    #file_info{mode=Mode, 
662
 
                               uid=Uid, 
663
 
                               gid=Gid,
664
 
                               atime=Atime0, 
665
 
                               mtime=Mtime0, 
666
 
                               ctime=Ctime}) ->
667
 
    {Atime, Mtime} =
668
 
        case {Atime0, Mtime0} of
669
 
            {undefined, Mtime0} -> {erlang:localtime(), Mtime0};
670
 
            {Atime0, undefined} -> {Atime0, Atime0};
671
 
            Complete -> Complete
672
 
        end,
673
 
    drv_command(Port, [?FILE_WRITE_INFO, 
674
 
                        int_to_bytes(Mode), 
675
 
                        int_to_bytes(Uid), 
676
 
                        int_to_bytes(Gid),
677
 
                        date_to_bytes(Atime), 
678
 
                        date_to_bytes(Mtime), 
679
 
                        date_to_bytes(Ctime),
680
 
                        File, 0]).
681
 
 
682
 
 
683
 
 
684
 
%% make_link/{2,3}
685
 
 
686
 
make_link(Old, New) ->
687
 
    make_link_int({?DRV, []}, Old, New).
688
 
 
689
 
make_link(Port, Old, New) when is_port(Port) ->
690
 
    make_link_int(Port, Old, New).
691
 
 
692
 
make_link_int(Port, Old, New) ->
693
 
    drv_command(Port, [?FILE_LINK, Old, 0, New, 0]).
694
 
 
695
 
 
696
 
 
697
 
%% make_symlink/{2,3}
698
 
 
699
 
make_symlink(Old, New) ->
700
 
    make_symlink_int({?DRV, []}, Old, New).
701
 
 
702
 
make_symlink(Port, Old, New) when is_port(Port) ->
703
 
    make_symlink_int(Port, Old, New).
704
 
 
705
 
make_symlink_int(Port, Old, New) ->
706
 
    drv_command(Port, [?FILE_SYMLINK, Old, 0, New, 0]).
707
 
 
708
 
 
709
 
 
710
 
%% read_link/{2,3}
711
 
 
712
 
read_link(Link) ->
713
 
    read_link_int({?DRV, []}, Link).
714
 
 
715
 
read_link(Port, Link) when is_port(Port) ->
716
 
    read_link_int(Port, Link).
717
 
 
718
 
read_link_int(Port, Link) ->
719
 
    drv_command(Port, [?FILE_READLINK, Link, 0]).
720
 
 
721
 
 
722
 
 
723
 
%% read_link_info/{2,3}
724
 
 
725
 
read_link_info(Link) ->
726
 
    read_link_info_int({?DRV, []}, Link).
727
 
 
728
 
read_link_info(Port, Link) when is_port(Port) ->
729
 
    read_link_info_int(Port, Link).
730
 
 
731
 
read_link_info_int(Port, Link) ->
732
 
    drv_command(Port, [?FILE_LSTAT, Link, 0]).
733
 
 
734
 
 
735
 
 
736
 
%% list_dir/{1,2}
737
 
 
738
 
list_dir(Dir) ->
739
 
    list_dir_int({?DRV, []}, Dir).
740
 
 
741
 
list_dir(Port, Dir) when is_port(Port) ->
742
 
    list_dir_int(Port, Dir).
743
 
 
744
 
list_dir_int(Port, Dir) ->
745
 
    drv_command(Port, [?FILE_READDIR, Dir, 0], []).
746
 
 
747
 
 
748
 
 
749
 
%%%-----------------------------------------------------------------
750
 
%%% Functions to communicate with the driver
751
 
 
752
 
 
753
 
 
754
 
%% Opens a driver port and converts any problems into {error, emfile}.
755
 
%% Returns {ok, Port} when succesful.
756
 
 
757
 
drv_open(Driver, Portopts) ->
758
 
    try erlang:open_port({spawn, Driver}, Portopts) of
759
 
        Port ->
760
 
            {ok, Port}
761
 
    catch
762
 
        error:Reason ->
763
 
            {error,Reason}
764
 
    end.
765
 
 
766
 
 
767
 
 
768
 
%% Closes a port in a safe way. Returns ok.
769
 
 
770
 
drv_close(Port) ->
771
 
    try erlang:port_close(Port) catch error:_ -> ok end,
772
 
    receive %% Ugly workaround in case the caller==owner traps exits
773
 
        {'EXIT', Port, _Reason} -> 
774
 
            ok
775
 
    after 0 -> 
776
 
            ok
777
 
    end.
778
 
 
779
 
 
780
 
 
781
 
%% Issues a command to a port and gets the response.
782
 
%% If Port is {Driver, Portopts} a port is first opened and 
783
 
%% then closed after the result has been received.
784
 
%% Returns {ok, Result} or {error, Reason}.
785
 
 
786
 
drv_command_raw(Port, Command) ->
787
 
    drv_command(Port, Command, false, undefined).
788
 
 
789
 
drv_command(Port, Command) ->
790
 
    drv_command(Port, Command, undefined).
791
 
 
792
 
drv_command(Port, Command, R) when is_binary(Command) ->
793
 
    drv_command(Port, Command, true, R);
794
 
drv_command(Port, Command, R) ->
795
 
    try erlang:iolist_to_binary(Command) of
796
 
        Bin ->
797
 
            drv_command(Port, Bin, true, R)
798
 
    catch
799
 
        error:Reason ->
800
 
            {error, Reason}
801
 
    end.
802
 
 
803
 
drv_command(Port, Command, Validated, R) when is_port(Port) ->
804
 
    try erlang:port_command(Port, Command) of
805
 
        true ->
806
 
            drv_get_response(Port, R)
807
 
    catch
808
 
        %% If the Command is valid, knowing that the port is a port,
809
 
        %% a badarg error must mean it is a dead port, that is:
810
 
        %% a currently invalid filehandle, -> einval, not badarg.
811
 
        error:badarg when Validated ->
812
 
            {error, einval};
813
 
        error:badarg ->
814
 
            try erlang:iolist_size(Command) of
815
 
                _ -> % Valid
816
 
                    {error, einval}
817
 
            catch
818
 
                error:_ ->
819
 
                    {error, badarg}
820
 
            end;
821
 
        error:Reason ->
822
 
            {error, Reason}
823
 
    end;
824
 
drv_command({Driver, Portopts}, Command, Validated, R) ->
825
 
    case drv_open(Driver, Portopts) of
826
 
        {ok, Port} ->
827
 
            Result = drv_command(Port, Command, Validated, R),
828
 
            drv_close(Port),
829
 
            Result;
830
 
        Error ->
831
 
            Error
832
 
    end.
833
 
 
834
 
 
835
 
    
836
 
%% Receives the response from a driver port.
837
 
%% Returns: {ok, ListOrBinary}|{error, Reason}
838
 
 
839
 
drv_get_response(Port, R) when is_list(R) ->
840
 
    case drv_get_response(Port) of
841
 
        ok ->
842
 
            {ok, R};
843
 
        {ok, Name} ->
844
 
            drv_get_response(Port, [Name|R]);
845
 
        Error ->
846
 
            Error
847
 
    end;
848
 
drv_get_response(Port, _) ->
849
 
    drv_get_response(Port).
850
 
 
851
 
drv_get_response(Port) ->
852
 
    erlang:bump_reductions(100),
853
 
    receive
854
 
        {Port, {data, [Response|Rest] = Data}} ->
855
 
            try translate_response(Response, Rest)
856
 
            catch
857
 
                error:Reason ->
858
 
                    {error, {bad_response_from_port, Data, 
859
 
                             {Reason, erlang:get_stacktrace()}}}
860
 
            end;
861
 
        {'EXIT', Port, Reason} ->
862
 
            {error, {port_died, Reason}}
863
 
    end.
864
 
 
865
 
 
866
 
%%%-----------------------------------------------------------------
867
 
%%% Utility functions.
868
 
 
869
 
 
870
 
 
871
 
%% Converts a list of mode atoms into an mode word for the driver.
872
 
%% Returns {Mode, Portopts, Setopts} where Portopts is a list of 
873
 
%% options for erlang:open_port/2 and Setopts is a list of 
874
 
%% setopt commands to send to the port, or error Reason upon failure.
875
 
 
876
 
open_mode(List) when is_list(List) ->
877
 
    case open_mode(List, 0, [], []) of
878
 
        {Mode, Portopts, Setopts} when Mode band 
879
 
                          (?EFILE_MODE_READ bor ?EFILE_MODE_WRITE) 
880
 
                          =:= 0 ->
881
 
            {Mode bor ?EFILE_MODE_READ, Portopts, Setopts};
882
 
        Other ->
883
 
            Other
884
 
    end.
885
 
 
886
 
open_mode([raw|Rest], Mode, Portopts, Setopts) ->
887
 
    open_mode(Rest, Mode, Portopts, Setopts);
888
 
open_mode([read|Rest], Mode, Portopts, Setopts) ->
889
 
    open_mode(Rest, Mode bor ?EFILE_MODE_READ, Portopts, Setopts);
890
 
open_mode([write|Rest], Mode, Portopts, Setopts) ->
891
 
    open_mode(Rest, Mode bor ?EFILE_MODE_WRITE, Portopts, Setopts);
892
 
open_mode([binary|Rest], Mode, Portopts, Setopts) ->
893
 
    open_mode(Rest, Mode, [binary | Portopts], Setopts);
894
 
open_mode([compressed|Rest], Mode, Portopts, Setopts) ->
895
 
    open_mode(Rest, Mode bor ?EFILE_COMPRESSED, Portopts, Setopts);
896
 
open_mode([append|Rest], Mode, Portopts, Setopts) ->
897
 
    open_mode(Rest, Mode bor ?EFILE_MODE_APPEND bor ?EFILE_MODE_WRITE, 
898
 
              Portopts, Setopts);
899
 
open_mode([delayed_write|Rest], Mode, Portopts, Setopts) ->
900
 
    open_mode([{delayed_write, 64*1024, 2000}|Rest], Mode,
901
 
              Portopts, Setopts);
902
 
open_mode([{delayed_write, Size, Delay}|Rest], Mode, Portopts, Setopts) 
903
 
  when is_integer(Size), 0 =< Size, is_integer(Delay), 0 =< Delay ->
904
 
    if
905
 
        Size < ?LARGEFILESIZE, Delay < 1 bsl 64 ->
906
 
            open_mode(Rest, Mode, Portopts, 
907
 
                      [<<?FILE_SETOPT, ?FILE_OPT_DELAYED_WRITE,
908
 
                        Size:64, Delay:64>> 
909
 
                       | Setopts]);
910
 
        true ->
911
 
            einval
912
 
    end;
913
 
open_mode([read_ahead|Rest], Mode, Portopts, Setopts) ->
914
 
    open_mode([{read_ahead, 64*1024}|Rest], Mode, Portopts, Setopts);
915
 
open_mode([{read_ahead, Size}|Rest], Mode, Portopts, Setopts)
916
 
  when is_integer(Size), 0 =< Size ->
917
 
    if
918
 
        Size < ?LARGEFILESIZE ->
919
 
            open_mode(Rest, Mode, Portopts,
920
 
                      [<<?FILE_SETOPT, ?FILE_OPT_READ_AHEAD,
921
 
                        Size:64>> | Setopts]);
922
 
        true ->
923
 
            einval
924
 
    end;
925
 
open_mode([], Mode, Portopts, Setopts) ->
926
 
    {Mode, reverse(Portopts), reverse(Setopts)};
927
 
open_mode(_, _Mode, _Portopts, _Setopts) ->
928
 
    badarg.
929
 
 
930
 
 
931
 
 
932
 
%% Converts a position tuple {bof, X} | {cur, X} | {eof, X} into
933
 
%% {Offset, OriginCode} for the driver.
934
 
%% Returns badarg upon failure.
935
 
 
936
 
lseek_position(Pos)
937
 
  when is_integer(Pos) ->
938
 
    lseek_position({bof, Pos});
939
 
lseek_position(bof) ->
940
 
    lseek_position({bof, 0});
941
 
lseek_position(cur) ->
942
 
    lseek_position({cur, 0});
943
 
lseek_position(eof) ->
944
 
    lseek_position({eof, 0});
945
 
lseek_position({bof, Offset})
946
 
  when is_integer(Offset) ->
947
 
    {Offset, ?EFILE_SEEK_SET};
948
 
lseek_position({cur, Offset})
949
 
  when is_integer(Offset) ->
950
 
    {Offset, ?EFILE_SEEK_CUR};
951
 
lseek_position({eof, Offset})
952
 
  when is_integer(Offset) ->
953
 
    {Offset, ?EFILE_SEEK_END};
954
 
lseek_position(_) ->
955
 
    badarg.
956
 
 
957
 
 
958
 
 
959
 
%% Translates the response from the driver into 
960
 
%% {ok, Result} or {error, Reason}.
961
 
 
962
 
translate_response(?FILE_RESP_OK, []) ->
963
 
    ok;
964
 
translate_response(?FILE_RESP_OK, Data) ->
965
 
    {ok, Data};
966
 
translate_response(?FILE_RESP_ERROR, List) when is_list(List) ->
967
 
    {error, list_to_atom(List)};
968
 
translate_response(?FILE_RESP_NUMBER, List) ->
969
 
    {N, []} = get_uint64(List),
970
 
    {ok, N};
971
 
translate_response(?FILE_RESP_DATA, List) ->
972
 
    {N, Data} = get_uint64(List),
973
 
    {ok, {N, Data}};
974
 
translate_response(?FILE_RESP_INFO, List) when is_list(List) ->
975
 
    {ok, transform_info_ints(get_uint32s(List))};
976
 
translate_response(?FILE_RESP_NUMERR, L0) ->
977
 
    {N, L1} = get_uint64(L0),
978
 
    {error, {N, list_to_atom(L1)}};
979
 
translate_response(?FILE_RESP_LDATA, List) ->
980
 
    {ok, transform_ldata(List)};
981
 
translate_response(?FILE_RESP_N2DATA, 
982
 
                   <<Offset:64, 0:64, Size:64>>) ->
983
 
    {ok, {Size, Offset, eof}};
984
 
translate_response(?FILE_RESP_N2DATA, 
985
 
                   [<<Offset:64, 0:64, Size:64>> | <<>>]) ->
986
 
    {ok, {Size, Offset, eof}};
987
 
translate_response(?FILE_RESP_N2DATA = X, 
988
 
                   [<<_:64, 0:64, _:64>> | _] = Data) ->
989
 
    {error, {bad_response_from_port, [X | Data]}};
990
 
translate_response(?FILE_RESP_N2DATA = X, 
991
 
                   [<<_:64, _:64, _:64>> | <<>>] = Data) ->
992
 
    {error, {bad_response_from_port, [X | Data]}};
993
 
translate_response(?FILE_RESP_N2DATA, 
994
 
                   [<<Offset:64, _ReadSize:64, Size:64>> | D]) ->
995
 
    {ok, {Size, Offset, D}};
996
 
translate_response(?FILE_RESP_N2DATA = X, L0) when is_list(L0) ->
997
 
    {Offset, L1}    = get_uint64(L0),
998
 
    {ReadSize, L2} = get_uint64(L1),
999
 
    {Size, L3}      = get_uint64(L2),
1000
 
    case {ReadSize, L3} of
1001
 
        {0, []} ->
1002
 
            {ok, {Size, Offset, eof}};
1003
 
        {0, _} ->
1004
 
            {error, {bad_response_from_port, [X | L0]}};
1005
 
        {_, []} ->
1006
 
            {error, {bad_response_from_port, [X | L0]}};
1007
 
        _ ->
1008
 
            {ok, {Size, Offset, L3}}
1009
 
    end;
1010
 
translate_response(?FILE_RESP_EOF, []) ->
1011
 
    eof;
1012
 
translate_response(X, Data) ->
1013
 
    {error, {bad_response_from_port, [X | Data]}}.
1014
 
 
1015
 
transform_info_ints(Ints) ->
1016
 
    [HighSize, LowSize, Type|Tail0] = Ints,
1017
 
    Size = HighSize * 16#100000000 + LowSize,
1018
 
    [Ay, Am, Ad, Ah, Ami, As|Tail1]  = Tail0,
1019
 
    [My, Mm, Md, Mh, Mmi, Ms|Tail2] = Tail1,
1020
 
    [Cy, Cm, Cd, Ch, Cmi, Cs|Tail3] = Tail2,
1021
 
    [Mode, Links, Major, Minor, Inode, Uid, Gid, Access] = Tail3,
1022
 
    #file_info {
1023
 
                size = Size,
1024
 
                type = file_type(Type),
1025
 
                access = file_access(Access),
1026
 
                atime = {{Ay, Am, Ad}, {Ah, Ami, As}},
1027
 
                mtime = {{My, Mm, Md}, {Mh, Mmi, Ms}},
1028
 
                ctime = {{Cy, Cm, Cd}, {Ch, Cmi, Cs}},
1029
 
                mode = Mode,
1030
 
                links = Links,
1031
 
                major_device = Major,
1032
 
                minor_device = Minor,
1033
 
                inode = Inode,
1034
 
                uid = Uid,
1035
 
                gid = Gid}.
1036
 
    
1037
 
file_type(1) -> device;
1038
 
file_type(2) -> directory;
1039
 
file_type(3) -> regular;
1040
 
file_type(4) -> symlink;
1041
 
file_type(_) -> other.
1042
 
 
1043
 
file_access(0) -> none;   
1044
 
file_access(1) -> write;
1045
 
file_access(2) -> read;
1046
 
file_access(3) -> read_write.
1047
 
 
1048
 
int_to_bytes(Int) when is_integer(Int) ->
1049
 
    <<Int:32>>;
1050
 
int_to_bytes(undefined) ->
1051
 
    <<-1:32>>.
1052
 
 
1053
 
date_to_bytes(undefined) ->
1054
 
    <<-1:32, -1:32, -1:32, -1:32, -1:32, -1:32>>;
1055
 
date_to_bytes({{Y, Mon, D}, {H, Min, S}}) ->
1056
 
    <<Y:32, Mon:32, D:32, H:32, Min:32, S:32>>.
1057
 
 
1058
 
% uint64([[X1, X2, X3, X4] = Y1 | [X5, X6, X7, X8] = Y2]) ->
1059
 
%     (uint32(Y1) bsl 32) bor uint32(Y2).
1060
 
 
1061
 
% uint64(X1, X2, X3, X4, X5, X6, X7, X8) ->
1062
 
%     (uint32(X1, X2, X3, X4) bsl 32) bor uint32(X5, X6, X7, X8).
1063
 
 
1064
 
% uint32([X1,X2,X3,X4]) ->
1065
 
%     (X1 bsl 24) bor (X2 bsl 16) bor (X3 bsl 8) bor X4.
1066
 
 
1067
 
uint32(X1,X2,X3,X4) ->
1068
 
    (X1 bsl 24) bor (X2 bsl 16) bor (X3 bsl 8) bor X4.
1069
 
 
1070
 
get_uint64(L0) ->
1071
 
    {X1, L1} = get_uint32(L0),
1072
 
    {X2, L2} = get_uint32(L1),
1073
 
    {(X1 bsl 32) bor X2, L2}.
1074
 
 
1075
 
get_uint32([X1,X2,X3,X4|List]) ->
1076
 
    {(((((X1 bsl 8) bor X2) bsl 8) bor X3) bsl 8) bor X4, List}.
1077
 
 
1078
 
get_uint32s([X1,X2,X3,X4|Tail]) ->
1079
 
    [uint32(X1,X2,X3,X4) | get_uint32s(Tail)];
1080
 
get_uint32s([]) -> [].
1081
 
 
1082
 
 
1083
 
 
1084
 
%% Binary mode
1085
 
transform_ldata(<<0:32, 0:32>>) ->
1086
 
    [];
1087
 
transform_ldata([<<0:32, N:32, Sizes/binary>> | Datas]) ->
1088
 
    transform_ldata(N, Sizes, Datas, []);
1089
 
%% List mode
1090
 
transform_ldata([_,_,_,_,_,_,_,_|_] = L0) ->
1091
 
    {0, L1} = get_uint32(L0),
1092
 
    {N, L2} = get_uint32(L1),
1093
 
    transform_ldata(N, L2, []).
1094
 
 
1095
 
%% List mode
1096
 
transform_ldata(0, List, Sizes) ->
1097
 
    transform_ldata(0, List, reverse(Sizes), []);
1098
 
transform_ldata(N, L0, Sizes) ->
1099
 
    {Size, L1} = get_uint64(L0),
1100
 
    transform_ldata(N-1, L1, [Size | Sizes]).
1101
 
 
1102
 
%% Binary mode
1103
 
transform_ldata(1, <<0:64>>, <<>>, R) ->
1104
 
    reverse(R, [eof]);
1105
 
transform_ldata(1, <<Size:64>>, Data, R) 
1106
 
  when byte_size(Data) =:= Size ->
1107
 
    reverse(R, [Data]);
1108
 
transform_ldata(N, <<0:64, Sizes/binary>>, [<<>> | Datas], R) ->
1109
 
    transform_ldata(N-1, Sizes, Datas, [eof | R]);
1110
 
transform_ldata(N, <<Size:64, Sizes/binary>>, [Data | Datas], R) 
1111
 
  when byte_size(Data) =:= Size ->
1112
 
    transform_ldata(N-1, Sizes, Datas, [Data | R]);
1113
 
%% List mode
1114
 
transform_ldata(0, [], [], R) ->
1115
 
    reverse(R);
1116
 
transform_ldata(0, List, [0 | Sizes], R) ->
1117
 
    transform_ldata(0, List, Sizes, [eof | R]);
1118
 
transform_ldata(0, List, [Size | Sizes], R) ->
1119
 
    {Front, Rear} = lists_split(List, Size),
1120
 
    transform_ldata(0, Rear, Sizes, [Front | R]).
1121
 
 
1122
 
 
1123
 
 
1124
 
lists_split(List, 0) when is_list(List) ->
1125
 
    {[], List};
1126
 
lists_split(List, N) when is_list(List), is_integer(N), N < 0 ->
1127
 
    erlang:error(badarg, [List, N]);
1128
 
lists_split(List, N) when is_list(List), is_integer(N) ->
1129
 
    case lists_split(List, N, []) of
1130
 
        premature_end_of_list ->
1131
 
            erlang:error(badarg, [List, N]);
1132
 
        Result ->
1133
 
            Result
1134
 
    end.
1135
 
 
1136
 
lists_split(List, 0, Rev) ->
1137
 
    {reverse(Rev), List};
1138
 
lists_split([], _, _) ->
1139
 
    premature_end_of_list;
1140
 
lists_split([Hd | Tl], N, Rev) ->
1141
 
    lists_split(Tl, N-1, [Hd | Rev]).
1142
 
 
1143
 
%% We KNOW that lists:reverse/2 is a BIF.
1144
 
 
1145
 
reverse(X) -> lists:reverse(X, []).
1146
 
reverse(L, T) -> lists:reverse(L, T).