Libs-dev/libio: Difference between revisions

From KolibriOS wiki
Jump to navigation Jump to search
m (C example, POSIX references)
No edit summary
 
(13 intermediate revisions by 5 users not shown)
Line 1: Line 1:
Right now, libio provides API to only work with files, although other communication types (like pipes) are also planned.
Right now, '''libio''' provides <abbr title="Application Programming Interface">API</abbr> to only work with files (although other communication types like pipes were also planned initially)
 
By default, library is compiled to use OEM file names. Support for Unicode file names is also present but requires include file to be changed and library to be recompiled.
By default, library is compiled to use OEM file names. Support for Unicode file names is also present but requires include file to be changed and library to be recompiled.


In most cases, libio follows POSIX function prototypes. POSIX equivalents are specified for each function, where applicable.
In most cases, '''libio''' follows [http://en.wikipedia.org/wiki/POSIX POSIX] function prototypes. POSIX equivalents are specified for each function, where applicable.


=Functions (enumerating files)=
=Functions (enumerating files)=
Line 13: Line 14:


Arguments:
Arguments:
:<tt>_dir</tt>
:<tt>_dir</tt> &rarr; asciiz
::directory path to search in <asciiz>
::directory path to search in
:<tt>_mask</tt>
:<tt>_mask</tt> &rarr; asciiz
::file mask, with use of wildcards <asciiz>
::file mask, with use of wildcards (a.k.a. shell patterns)
:<tt>_attr</tt>
:<tt>_attr</tt> &rarr; dword
::file attributes mask (combination of FA_* constants) <dword>
::file attributes mask (combination of [[#File_attributes|FA_* constants]])


Result:
Result:
:<tt>eax</tt>
:<tt>eax</tt> &rarr; [[#FileInfoA|FileInfo]]*
::0 (error) / matched file data pointer (acts as find descriptor) <[[#FileInfoA|FileInfo]]*>
::0 (error) / matched file data pointer (acts as find descriptor)


==file_find_next==
==file_find_next==
Line 31: Line 32:


Arguments:
Arguments:
:<tt>_findd</tt>
:<tt>_findd</tt> &rarr; [[#FileInfoA|FileInfo]]*
::find descriptor (see [[#file_find_first|file_find_first]]) <[[#FileInfoA|FileInfo]]*>
::find descriptor (see [[#file_find_first|file_find_first]])


Result:
Result:
:<tt>eax</tt>
:<tt>eax</tt> &rarr; [[#FileInfoA|FileInfo]]*
::0 (error) / matched file data pointer (acts as find descriptor) <[[#FileInfoA|FileInfo]]*>
::0 (error) / matched file data pointer (acts as find descriptor)


==file_find_close==
==file_find_close==
Line 45: Line 46:


Arguments:
Arguments:
:<tt>_findd</tt>
:<tt>_findd</tt> &rarr; [[#FileInfoA|FileInfo]]*
::find descriptor (see [[#file_find_first|file_find_first]]) <[[#FileInfoA|FileInfo]]*>
::find descriptor (see [[#file_find_first|file_find_first]])


Result:
Result:
:<tt>eax</tt>
:<tt>eax</tt> &rarr; dword
::result of memory freeing routine
::result of memory freeing routine


Line 61: Line 62:


Arguments:
Arguments:
:<tt>_name</tt>
:<tt>_name</tt> &rarr; asciiz
::path to file (full or relative) <asciiz>
::path to file (full or relative)


Result:
Result:
:<tt>eax</tt>
:<tt>ebx (attention: ebx, not eax)</tt> &rarr; dword
::-1 (error) / file size (in bytes, up to 2G) <dword>
::-1 (error) / file size (in bytes, up to 2G)


Notes:
Notes:
Line 78: Line 79:


Arguments:
Arguments:
:<tt>_name</tt>
:<tt>_name</tt> &rarr; asciiz
::path to file (full or relative) <asciiz>
::path to file (full or relative)
:<tt>_mode</tt>
:<tt>_mode</tt> &rarr; dword
::mode to open file in (combination of [[#File_open_mode|O_* constants]]) <dword>
::mode to open file in (combination of [[#File_open_mode|O_* constants]])


Result:
Result:
:<tt>eax</tt>
:<tt>eax</tt> &rarr; InternalFileInfo*
::0 (error) / file descriptor <InternalFileInfo*>
::0 (error) / file descriptor


Notes:
Notes:
Line 100: Line 101:


Arguments:
Arguments:
:<tt>_filed</tt>
:<tt>_filed</tt> &rarr; InternalFileInfo*
::file descriptor (see [[#file_open|file_open]]) <InternalFileInfo*>
::file descriptor (see [[#file_open|file_open]])
:<tt>_buf</tt>
:<tt>_buf</tt> &rarr; byte*
::buffer to put read data to <byte*>
::buffer to put read data to
:<tt>_buflen</tt>
:<tt>_buflen</tt> &rarr; dword
::buffer size (number of bytes to be read from file) <dword>
::buffer size (number of bytes to be read from file)


Result:
Result:
:<tt>eax</tt>
:<tt>eax</tt> &rarr; dword
::-1 (error) / number of bytes read <dword>
::-1 (error) / number of bytes read


Notes:
Notes:
Line 124: Line 125:


Arguments:
Arguments:
:<tt>_filed</tt>
:<tt>_filed</tt> &rarr; InternalFileInfo*
::file descriptor (see [[#file_open|file_open]]) <InternalFileInfo*>
::file descriptor (see [[#file_open|file_open]])
:<tt>_buf</tt>
:<tt>_buf</tt> &rarr; byte*
::buffer to get write data from <byte*>
::buffer to get write data from
:<tt>_buflen</tt>
:<tt>_buflen</tt> &rarr; dword
::buffer size (number of bytes to be written to file) <dword>
::buffer size (number of bytes to be written to file)


Result:
Result:
:<tt>eax</tt>
:<tt>eax</tt> &rarr; dword
::-1 (error) / number of bytes written <dword>
::-1 (error) / number of bytes written


Notes:
Notes:
Line 148: Line 149:


Arguments:
Arguments:
:<tt>_filed</tt>
:<tt>_filed</tt> &rarr; InternalFileInfo*
::file descriptor (see [[#file_open|file_open]]) <InternalFileInfo*>
::file descriptor (see [[#file_open|file_open]])
:<tt>_where</tt>
:<tt>_where</tt> &rarr; dword
::position in file (in bytes) counted from specified origin <dword>
::position in file (in bytes) counted from specified origin
:<tt>_origin</tt>
:<tt>_origin</tt> &rarr; dword
::origin from where to set the position (one of [[#File_seek_origin|SEEK_* constants]]) <dword>
::origin from where to set the position (one of [[#File_seek_origin|SEEK_* constants]])


Result:
Result:
:<tt>eax</tt>
:<tt>eax</tt> &rarr; dword
::-1 (error) / 0 <dword>
::-1 (error) / 0


Notes:
Notes:
Line 172: Line 173:


Arguments:
Arguments:
:<tt>_filed</tt>
:<tt>_filed</tt> &rarr; InternalFileInfo*
::file descriptor (see [[#file_open|file_open]]) <InternalFileInfo*>
::file descriptor (see [[#file_open|file_open]])


Result:
Result:
:<tt>eax</tt>
:<tt>eax</tt> &rarr; dword
::false / true <dword>
::false / true


Notes:
Notes:
Line 192: Line 193:


Arguments:
Arguments:
:<tt>_filed</tt>
:<tt>_filed</tt> &rarr; InternalFileInfo*
::file descriptor (see [[#file_open|file_open]]) <InternalFileInfo*>
::file descriptor (see [[#file_open|file_open]])


Result:
Result:
:<tt>eax</tt>
:<tt>eax</tt> &rarr; dword
::-1 (error) / 0 <dword>
::-1 (error) / 0


Notes:
Notes:
Line 212: Line 213:


Arguments:
Arguments:
:<tt>_filed</tt>
:<tt>_filed</tt> &rarr; InternalFileInfo*
::file descriptor (see [[#file_open|file_open]]) <InternalFileInfo*>
::file descriptor (see [[#file_open|file_open]])


Result:
Result:
:<tt>eax</tt>
:<tt>eax</tt> &rarr; dword
::-1 (error) / file pointer position <dword>
::-1 (error) / file pointer position


Notes:
Notes:
Line 232: Line 233:


Arguments:
Arguments:
:<tt>_filed</tt>
:<tt>_filed</tt> &rarr; InternalFileInfo*
::file descriptor (see [[#file_open|file_open]]) <InternalFileInfo*>
::file descriptor (see [[#file_open|file_open]])


Result:
Result:
:<tt>eax</tt>
:<tt>eax</tt> &rarr; dword
::-1 (error) / file pointer position <dword>
::-1 (error) / 0


Notes:
Notes:
Line 244: Line 245:
POSIX equivalent:
POSIX equivalent:
:<tt>int result = fclose(_filed);</tt>
:<tt>int result = fclose(_filed);</tt>
==file_err==
Not yet implemented.
It was planned to give an extended information about errors that occur.


=Constants=
=Constants=


==File open mode==
==File open mode==
O_BINARY = 00000000b
<source>
O_READ  = 00000001b
O_BINARY = 00000000b
O_WRITE  = 00000010b
O_READ  = 00000001b
O_CREATE = 00000100b
O_WRITE  = 00000010b
O_SHARE  = 00001000b
O_CREATE = 00000100b
O_TEXT  = 00010000b
O_SHARE  = 00001000b
O_TEXT  = 00010000b
</source>


Detailed description:
Detailed description:
Line 270: Line 277:


==File seek origin==
==File seek origin==
SEEK_SET = 0
<source>
SEEK_CUR = 1
SEEK_SET = 0
SEEK_END = 2
SEEK_CUR = 1
SEEK_END = 2
</source>


Detailed description:
Detailed description:
Line 283: Line 292:


==File attributes==
==File attributes==
FA_READONLY = 00000001b
<source>
FA_HIDDEN  = 00000010b
FA_READONLY = 00000001b
FA_SYSTEM  = 00000100b
FA_HIDDEN  = 00000010b
FA_LABEL    = 00001000b
FA_SYSTEM  = 00000100b
FA_FOLDER  = 00010000b
FA_LABEL    = 00001000b
FA_ARCHIVED = 00100000b
FA_FOLDER  = 00010000b
FA_ANY      = 00111111b
FA_ARCHIVED = 00100000b
FA_ANY      = 00111111b
</source>
 
Detailed description:
:<tt>FA_READONLY</tt>
::file is read-only (write forbidden)
:<tt>FA_HIDDEN</tt>
::file or directory is hidden (should generally not be visible by user)
:<tt>FA_SYSTEM</tt>
::file or directory contains valuable operating system data
:<tt>FA_LABEL</tt>
::not a file, name holds disk label
:<tt>FA_FOLDER</tt>
::not a file, but directory
:<tt>FA_ARCHIVED</tt>
::file is archived (deprecated, system-specific use)
:<tt>FA_ANY</tt>
::any of above attributes (used when specifying mask)


=Structures=
=Structures=
Line 296: Line 323:
Date and time as returned by underlying system calls.
Date and time as returned by underlying system calls.


struct FileDateTime
<source>
  union
struct FileDateTime
    time    dd ?
  union
    struct
    time    dd ?
      sec  db ?
    struct
      min  db ?
      sec  db ?
      hour  db ?
      min  db ?
    ends
      hour  db ?
  ends
    ends
  union
  ends
    date    dd ?
  union
    struct
    date    dd ?
      day  db ?
    struct
      month db ?
      day  db ?
      year  dw ?
      month db ?
    ends
      year  dw ?
  ends
    ends
ends
  ends
ends
</source>


==FileInfoBlock==
==FileInfoBlock==
File information block used by underlying system calls to identify function to be called and its basic arguments. Should generally not be used by programs.
File information block used by underlying system calls to identify function to be called and its basic arguments. Should generally not be used by programs.


struct FileInfoBlock
<source>
  Function  dd ?
struct FileInfoBlock
  Position  dd ?
  Function  dd ?
  Flags      dd ?
  Position  dd ?
  Count      dd ?
  Flags      dd ?
  Buffer    dd ?
  Count      dd ?
              db ?
  Buffer    dd ?
  FileName  dd ?
            db ?
ends
  FileName  dd ?
ends
</source>


==FileInfoHeader==
==FileInfoHeader==
File information header as returned by underlying call to [[SysFn70|70.1]] system function. Should generally not be used by programs.
File information header as returned by underlying call to [[SysFn70|70.1]] system function. Should generally not be used by programs.


struct FileInfoHeader
<source>
  Version    dd ?
struct FileInfoHeader
  FilesRead  dd ?
  Version    dd ?
  FilesCount dd ?
  FilesRead  dd ?
              rd 5
  FilesCount dd ?
ends
            rd 5
ends
</source>


==FileInfoA==
==FileInfoA==
OEM version of FileInfo structure.
OEM version of FileInfo structure.


struct FileInfoA
<source>
  Attributes  dd ?
struct FileInfoA
  Flags        dd ?
  Attributes  dd ?
  DateCreate  [[#FileDateTime|FileDateTime]]
  Flags        dd ?
  DateAccess  [[#FileDateTime|FileDateTime]]
  DateCreate  FileDateTime
  DateModify  [[#FileDateTime|FileDateTime]]
  DateAccess  FileDateTime
  union
  DateModify  FileDateTime
    FileSize  dq ?
  union
    struct
    FileSize  dq ?
      FileSizeLow  dd ?
    struct
      FileSizeHigh dd ?
      FileSizeLow  dd ?
    ends
      FileSizeHigh dd ?
  ends
    ends
  FileName    rb 252
  ends
ends
  FileName    rb 264
ends
</source>


==FileInfoW==
==FileInfoW==
Unicode version of FileInfo structure.
Unicode version of FileInfo structure.


struct FileInfoW
<source>
  Attributes  dd ?
struct FileInfoW
  Flags        dd ?
  Attributes  dd ?
  DateCreate  [[#FileDateTime|FileDateTime]]
  Flags        dd ?
  DateAccess  [[#FileDateTime|FileDateTime]]
  DateCreate  FileDateTime
  DateModify  [[#FileDateTime|FileDateTime]]
  DateAccess  FileDateTime
  union
  DateModify  FileDateTime
    FileSize  dq ?
  union
    struct
    FileSize  dq ?
      FileSizeLow  dd ?
    struct
      FileSizeHigh dd ?
      FileSizeLow  dd ?
    ends
      FileSizeHigh dd ?
  ends
    ends
  FileName    rw 260
  ends
ends
  FileName    rw 260
ends
</source>


=Usage examples=
=Usage examples=
Small piece of code illustrating file opening, reading 256 bytes, seeking to the beginning, writing same data back and closing file descriptor. Note that we could succeessfully read less than 256 bytes, so we remember the exact number.
Small piece of code illustrating file opening, reading 256 bytes, seeking to the beginning, writing same data back and closing file descriptor. Note that we could succeessfully read less than 256 bytes, so we remember the exact number. Note also that we use "invoke" here since the call is indirect.


<source>
<source line>
include 'libio/libio.inc'
include 'libio/libio.inc'


; ...
; ...


         stdcall file_open, filename, O_READ + O_WRITE
         invoke  file_open, filename, O_READ + O_WRITE
         or      eax, eax
         or      eax, eax
         jz      .error
         jz      .error
Line 390: Line 427:
         mov    [fdesc], eax
         mov    [fdesc], eax
   
   
         stdcall file_read, eax, buffer, 256
         invoke  file_read, eax, buffer, 256
         mov    [bytes_read], eax
         mov    [bytes_read], eax
         inc    eax
         inc    eax
         jz      .close
         jz      .close


         stdcall file_seek, [fdesc], 0, SEEK_SET
         invoke  file_seek, [fdesc], 0, SEEK_SET
         inc    eax
         inc    eax
         jz      .close
         jz      .close


         stdcall file_write, [fdesc], buffer, [bytes_read]
         invoke  file_write, [fdesc], buffer, [bytes_read]


   .close:
   .close:
         stdcall file_close, [fdesc]
         invoke  file_close, [fdesc]
   
   
   .error:
   .error:
Line 416: Line 453:
Same code written in C could look like (just for the reference):
Same code written in C could look like (just for the reference):


<source lang="C">
<source lang="c" line>
     FILE *f = file_open("/hd0/1/a.dat", O_READ | O_WRITE);
     FILE *f = file_open("/hd0/1/a.dat", O_READ | O_WRITE);
     if (f)
     if (f)
Line 440: Line 477:


[[Category:Coding]][[Category:Manuals]]
[[Category:Coding]][[Category:Manuals]]
[[Category:Libraries]]

Latest revision as of 17:33, 5 January 2022

Right now, libio provides API to only work with files (although other communication types like pipes were also planned initially)

By default, library is compiled to use OEM file names. Support for Unicode file names is also present but requires include file to be changed and library to be recompiled.

In most cases, libio follows POSIX function prototypes. POSIX equivalents are specified for each function, where applicable.

Functions (enumerating files)

file_find_first

Find first file with matching attributes and mask in specified directory.

Prototype:

proc file.find_first _dir, _mask, _attr

Arguments:

_dir → asciiz
directory path to search in
_mask → asciiz
file mask, with use of wildcards (a.k.a. shell patterns)
_attr → dword
file attributes mask (combination of FA_* constants)

Result:

eaxFileInfo*
0 (error) / matched file data pointer (acts as find descriptor)

file_find_next

Find next file matching criteria.

Prototype:

proc file.find_next _findd

Arguments:

_finddFileInfo*
find descriptor (see file_find_first)

Result:

eaxFileInfo*
0 (error) / matched file data pointer (acts as find descriptor)

file_find_close

Close find descriptor and free memory.

Prototype:

proc file.find_close _findd

Arguments:

_finddFileInfo*
find descriptor (see file_find_first)

Result:

eax → dword
result of memory freeing routine

Functions (working with specific file)

file_size

Get file size.

Prototype:

proc file.size _name

Arguments:

_name → asciiz
path to file (full or relative)

Result:

ebx (attention: ebx, not eax) → dword
-1 (error) / file size (in bytes, up to 2G)

Notes:

call file_err to obtain extended error information

file_open

Open file.

Prototype:

proc file.open _name, _mode

Arguments:

_name → asciiz
path to file (full or relative)
_mode → dword
mode to open file in (combination of O_* constants)

Result:

eax → InternalFileInfo*
0 (error) / file descriptor

Notes:

call file_err to obtain extended error information

POSIX equivalent:

FILE *result = fopen(_name, _mode);

file_read

Read data from file.

Prototype:

proc file.read _filed, _buf, _buflen

Arguments:

_filed → InternalFileInfo*
file descriptor (see file_open)
_buf → byte*
buffer to put read data to
_buflen → dword
buffer size (number of bytes to be read from file)

Result:

eax → dword
-1 (error) / number of bytes read

Notes:

call file_err to obtain extended error information

POSIX equivalent:

size_t result = fread(_buf, _buflen, 1, _filed);

file_write

Write data to file.

Prototype:

proc file.write _filed, _buf, _buflen

Arguments:

_filed → InternalFileInfo*
file descriptor (see file_open)
_buf → byte*
buffer to get write data from
_buflen → dword
buffer size (number of bytes to be written to file)

Result:

eax → dword
-1 (error) / number of bytes written

Notes:

call file_err to obtain extended error information

POSIX equivalent:

size_t result = fwrite(_buf, _buflen, 1, _filed);

file_seek

Set file pointer position.

Prototype:

proc file.seek _filed, _where, _origin

Arguments:

_filed → InternalFileInfo*
file descriptor (see file_open)
_where → dword
position in file (in bytes) counted from specified origin
_origin → dword
origin from where to set the position (one of SEEK_* constants)

Result:

eax → dword
-1 (error) / 0

Notes:

call file_err to obtain extended error information

POSIX equivalent:

int result = fseek(_filed, _where, _origin);

file_iseof

Determine if file pointer is at the end of file.

Prototype:

proc file.eof? _filed

Arguments:

_filed → InternalFileInfo*
file descriptor (see file_open)

Result:

eax → dword
false / true

Notes:

call file_err to obtain extended error information

POSIX equivalent:

int result = feof(_filed);

file_truncate (file_seteof)

Truncate file size to current file pointer position:

Prototype:

proc file.truncate _filed

Arguments:

_filed → InternalFileInfo*
file descriptor (see file_open)

Result:

eax → dword
-1 (error) / 0

Notes:

call file_err to obtain extended error information

POSIX equivalent:

int result = ftruncate(fileno(_filed), ftell(_filed));

file_tell

Get current file pointer position.

Prototype:

proc file.tell _filed

Arguments:

_filed → InternalFileInfo*
file descriptor (see file_open)

Result:

eax → dword
-1 (error) / file pointer position

Notes:

call file_err to obtain extended error information

POSIX equivalent:

long result = ftell(_filed);

file_close

Close file.

Prototype:

proc file.close _filed

Arguments:

_filed → InternalFileInfo*
file descriptor (see file_open)

Result:

eax → dword
-1 (error) / 0

Notes:

call file_err to obtain extended error information

POSIX equivalent:

int result = fclose(_filed);

file_err

Not yet implemented. It was planned to give an extended information about errors that occur.

Constants

File open mode

O_BINARY = 00000000b
O_READ   = 00000001b
O_WRITE  = 00000010b
O_CREATE = 00000100b
O_SHARE  = 00001000b
O_TEXT   = 00010000b

Detailed description:

O_BINARY
don't change read/written data in any way (default)
O_READ
open file for reading
O_WRITE
open file for writing
O_CREATE
create file if it doesn't exist, open otherwise
O_SHARE
allow simultaneous access by using different file descriptors (not implemented)
O_TEXT
replace newline chars with LF (overrides O_BINARY, not implemented)

File seek origin

SEEK_SET = 0
SEEK_CUR = 1
SEEK_END = 2

Detailed description:

SEEK_SET
from beginning of file
SEEK_CUR
from current pointer position
SEEK_END
from end of file

File attributes

FA_READONLY = 00000001b
FA_HIDDEN   = 00000010b
FA_SYSTEM   = 00000100b
FA_LABEL    = 00001000b
FA_FOLDER   = 00010000b
FA_ARCHIVED = 00100000b
FA_ANY      = 00111111b

Detailed description:

FA_READONLY
file is read-only (write forbidden)
FA_HIDDEN
file or directory is hidden (should generally not be visible by user)
FA_SYSTEM
file or directory contains valuable operating system data
FA_LABEL
not a file, name holds disk label
FA_FOLDER
not a file, but directory
FA_ARCHIVED
file is archived (deprecated, system-specific use)
FA_ANY
any of above attributes (used when specifying mask)

Structures

FileDateTime

Date and time as returned by underlying system calls.

struct FileDateTime
  union
    time    dd ?
    struct
      sec   db ?
      min   db ?
      hour  db ?
    ends
  ends
  union
    date    dd ?
    struct
      day   db ?
      month db ?
      year  dw ?
    ends
  ends
ends

FileInfoBlock

File information block used by underlying system calls to identify function to be called and its basic arguments. Should generally not be used by programs.

struct FileInfoBlock
  Function   dd ?
  Position   dd ?
  Flags      dd ?
  Count      dd ?
  Buffer     dd ?
             db ?
  FileName   dd ?
ends

FileInfoHeader

File information header as returned by underlying call to 70.1 system function. Should generally not be used by programs.

struct FileInfoHeader
  Version    dd ?
  FilesRead  dd ?
  FilesCount dd ?
             rd 5
ends

FileInfoA

OEM version of FileInfo structure.

struct FileInfoA
  Attributes   dd ?
  Flags        dd ?
  DateCreate   FileDateTime
  DateAccess   FileDateTime
  DateModify   FileDateTime
  union
    FileSize   dq ?
    struct
      FileSizeLow  dd ?
      FileSizeHigh dd ?
    ends
  ends
  FileName     rb 264
ends

FileInfoW

Unicode version of FileInfo structure.

struct FileInfoW
  Attributes   dd ?
  Flags        dd ?
  DateCreate   FileDateTime
  DateAccess   FileDateTime
  DateModify   FileDateTime
  union
    FileSize   dq ?
    struct
      FileSizeLow  dd ?
      FileSizeHigh dd ?
    ends
  ends
  FileName     rw 260
ends

Usage examples

Small piece of code illustrating file opening, reading 256 bytes, seeking to the beginning, writing same data back and closing file descriptor. Note that we could succeessfully read less than 256 bytes, so we remember the exact number. Note also that we use "invoke" here since the call is indirect.

include 'libio/libio.inc'

; ...

        invoke  file_open, filename, O_READ + O_WRITE
        or      eax, eax
        jz      .error

        mov     [fdesc], eax
 
        invoke  file_read, eax, buffer, 256
        mov     [bytes_read], eax
        inc     eax
        jz      .close

        invoke  file_seek, [fdesc], 0, SEEK_SET
        inc     eax
        jz      .close

        invoke  file_write, [fdesc], buffer, [bytes_read]

  .close:
        invoke  file_close, [fdesc]
 
  .error:

; ...

filename   db '/hd0/1/a.dat', 0
fdesc      dd ?
bytes_read dd ?
buffer     db 256 dup(?)

Same code written in C could look like (just for the reference):

    FILE *f = file_open("/hd0/1/a.dat", O_READ | O_WRITE);
    if (f)
    {
        do
        {
            char buffer[256];
            size_t bytes_read = file_read(f, buffer, sizeof(buffer));
            if (bytes_read == -1)
            {
                break;
            }
            if (file_seek(f, 0, SEEK_SET) == -1)
            {
                break;
            }
            file_write(f, buffer, bytes_read);
        }
        while (0);
        file_close(f);
    }