aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/nifs/common/prim_file_nif.h
blob: 28c1ea9d0021fa915a0083d0f56628142fbd71d9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/*
 * %CopyrightBegin%
 *
 * Copyright Ericsson 2017-2018. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * %CopyrightEnd%
 */

typedef int posix_errno_t;

enum efile_modes_t {
    EFILE_MODE_READ = (1 << 0),
    EFILE_MODE_WRITE = (1 << 1), /* Implies truncating file when used alone. */
    EFILE_MODE_APPEND = (1 << 2),
    EFILE_MODE_EXCLUSIVE = (1 << 3),
    EFILE_MODE_SYNC = (1 << 4),

    EFILE_MODE_SKIP_TYPE_CHECK = (1 << 5), /* Special for device files on Unix. */
    EFILE_MODE_NO_TRUNCATE = (1 << 6), /* Special for reopening on VxWorks. */

    EFILE_MODE_DIRECTORY = (1 << 7),

    EFILE_MODE_READ_WRITE = EFILE_MODE_READ | EFILE_MODE_WRITE
};

enum efile_access_t {
    EFILE_ACCESS_NONE = 0,
    EFILE_ACCESS_READ = 1,
    EFILE_ACCESS_WRITE = 2,
    EFILE_ACCESS_READ_WRITE = EFILE_ACCESS_READ | EFILE_ACCESS_WRITE
};

enum efile_seek_t {
    EFILE_SEEK_BOF,
    EFILE_SEEK_CUR,
    EFILE_SEEK_EOF
};

enum efile_filetype_t {
    EFILE_FILETYPE_DEVICE,
    EFILE_FILETYPE_DIRECTORY,
    EFILE_FILETYPE_REGULAR,
    EFILE_FILETYPE_SYMLINK,
    EFILE_FILETYPE_OTHER
};

enum efile_advise_t {
    EFILE_ADVISE_NORMAL,
    EFILE_ADVISE_RANDOM,
    EFILE_ADVISE_SEQUENTIAL,
    EFILE_ADVISE_WILL_NEED,
    EFILE_ADVISE_DONT_NEED,
    EFILE_ADVISE_NO_REUSE
};

enum efile_state_t {
    EFILE_STATE_IDLE = 0,
    EFILE_STATE_BUSY = 1,
    EFILE_STATE_CLOSE_PENDING = 2,
    EFILE_STATE_CLOSED = 3
};

typedef struct {
    Sint64 size;            /* Size of file */
    Uint32 type;            /* Type of file -- one of EFILE_FILETYPE_*. */
    Uint32 access;          /* Access to file -- one of EFILE_ACCESS_*. */
    Uint32 mode;            /* Access permissions -- bit field. */
    Uint32 links;           /* Number of links to file. */
    Uint32 major_device;    /* Major device or file system. */
    Uint32 minor_device;    /* Minor device (for devices). */
    Uint32 inode;           /* Inode number. */
    Uint32 uid;             /* User id of owner. */
    Uint32 gid;             /* Group id of owner. */
    Sint64 a_time;          /* Last time the file was accessed. */
    Sint64 m_time;          /* Last time the file was modified. */
    Sint64 c_time;          /* Windows: creation time, Unix: last inode
                             * change. */
} efile_fileinfo_t;

/* The smallest value that can be converted freely between universal, local,
 * and POSIX time, as required by read_file_info/2. Corresponds to
 * {{1902,1,1},{0,0,0}} */
#define EFILE_MIN_FILETIME -2145916800

/* Initializes an efile_data_t; must be used in efile_open on success. */
#define EFILE_INIT_RESOURCE(__d, __modes) do { \
        erts_atomic32_init_acqb(&(__d)->state, EFILE_STATE_IDLE); \
        (__d)->posix_errno = 0; \
        (__d)->modes = __modes; \
    } while(0)

typedef struct {
    erts_atomic32_t state;

    posix_errno_t posix_errno;
    enum efile_modes_t modes;

    ErlNifMonitor monitor;
} efile_data_t;

typedef ErlNifBinary efile_path_t;

/* @brief Translates the given "raw name" into the format expected by the APIs
 * used by the underlying implementation. The result is transient and does not
 * need to be released.
 *
 * This may change the structure of the path and its results should never be
 * passed on to the user. Refer to the OS-specific implementation for details.
 *
 * @param path The term to translate; it must have been encoded with
 * prim_file:internal_native2name for compatibility reasons. */
posix_errno_t efile_marshal_path(ErlNifEnv *env, ERL_NIF_TERM path, efile_path_t *result);

/* @brief Returns the underlying handle as an implementation-defined term.
 *
 * This is an internal function intended to support tests and tricky
 * operations like sendfile(2). */
ERL_NIF_TERM efile_get_handle(ErlNifEnv *env, efile_data_t *d);

/* @brief Read until EOF or the given iovec has been filled.
 *
 * @return -1 on failure, or the number of bytes read on success. The return
 * value will be 0 if no bytes could be read before EOF or the end of the
 * iovec. */
Sint64 efile_readv(efile_data_t *d, SysIOVec *iov, int iovlen);

/* @brief Write the entirety of the given iovec.
 *
 * @return -1 on failure, or the number of bytes written on success. "Partial"
 * failures will be reported with -1 and not the number of bytes we managed to
 * write to disk before the failure. */
Sint64 efile_writev(efile_data_t *d, SysIOVec *iov, int iovlen);

/* @brief As \c efile_readv, but starting from a file offset. */
Sint64 efile_preadv(efile_data_t *d, Sint64 offset, SysIOVec *iov, int iovlen);

/* @brief As \c efile_writev, but starting from a file offset. */
Sint64 efile_pwritev(efile_data_t *d, Sint64 offset, SysIOVec *iov, int iovlen);

int efile_seek(efile_data_t *d, enum efile_seek_t seek, Sint64 offset, Sint64 *new_position);

int efile_sync(efile_data_t *d, int data_only);

int efile_advise(efile_data_t *d, Sint64 offset, Sint64 length, enum efile_advise_t advise);
int efile_allocate(efile_data_t *d, Sint64 offset, Sint64 length);
int efile_truncate(efile_data_t *d);

posix_errno_t efile_open(const efile_path_t *path, enum efile_modes_t modes,
        ErlNifResourceType *nif_type, efile_data_t **d);

/** @brief Closes a file. The file must have entered the CLOSED state prior to
 * calling this to prevent double close.
 *
 * Note that the file is completely invalid after this point, so the error code
 * is provided in \c error rather than d->posix_errno. */
int efile_close(efile_data_t *d, posix_errno_t *error);

/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */

posix_errno_t efile_read_info(const efile_path_t *path, int follow_link, efile_fileinfo_t *result);
posix_errno_t efile_read_handle_info(efile_data_t *d, efile_fileinfo_t *result);

/** @brief Sets the file times to the given values. Refer to efile_fileinfo_t
 * for a description of each. */
posix_errno_t efile_set_time(const efile_path_t *path, Sint64 a_time, Sint64 m_time, Sint64 c_time);

/** @brief On Unix, this sets the file permissions according to the docs for
 * file:write_file_info/2. On Windows it uses the "owner write permission" flag
 * to toggle whether the file is read-only or not. */
posix_errno_t efile_set_permissions(const efile_path_t *path, Uint32 permissions);

/** @brief On Unix, this will set the owner/group to the given values. It will
 * do nothing on other platforms. */
posix_errno_t efile_set_owner(const efile_path_t *path, Sint32 owner, Sint32 group);

/** @brief Resolves the final path of the given link. */
posix_errno_t efile_read_link(ErlNifEnv *env, const efile_path_t *path, ERL_NIF_TERM *result);

/** @brief Lists the contents of the given directory.
 * @param result [out] A list of all the directory/file names contained in the
 * given directory. */
posix_errno_t efile_list_dir(ErlNifEnv *env, const efile_path_t *path, ERL_NIF_TERM *result);

/** @brief Changes the name of an existing file or directory, from old_path
 * to new_path.
 *
 * If old_path and new_path refer to the same file or directory, it does
 * nothing and returns success. Otherwise if new_path already exists, it will
 * be deleted and replaced by src subject to the following conditions:
 *
 *     If old_path is a directory, new_path may be an empty directory.
 *     If old_path is a file, new_path may be a file.
 *
 * Neither of these are guaranteed to be atomic. In any other situation where
 * new_path already exists, the rename will fail.
 *
 * Some possible error codes:
 *
 * - EACCES:     Either paths or one of their parent directories can't be read
 *               and/or written.
 * - EEXIST:     new_path is a non-empty directory.
 * - EINVAL:     old_path is a root directory or new_path is a subdirectory
 *               of new_path.
 * - EISDIR:     new_path is a directory, but old_path is not.
 * - ENOTDIR:    old_path is a directory, but new_path is not.
 * - ENOENT:     old_path doesn't exist, or either path is "".
 * - EXDEV:      The paths are on different filesystems.
 *
 * The implementation of rename may allow cross-filesystem renames,
 * but the caller should be prepared to emulate it with copy and
 * delete if errno is EXDEV. */
posix_errno_t efile_rename(const efile_path_t *old_path, const efile_path_t *new_path);

posix_errno_t efile_make_hard_link(const efile_path_t *existing_path, const efile_path_t *new_path);
posix_errno_t efile_make_soft_link(const efile_path_t *existing_path, const efile_path_t *new_path);
posix_errno_t efile_make_dir(const efile_path_t *path);

posix_errno_t efile_del_file(const efile_path_t *path);
posix_errno_t efile_del_dir(const efile_path_t *path);

posix_errno_t efile_get_cwd(ErlNifEnv *env, ERL_NIF_TERM *result);
posix_errno_t efile_set_cwd(const efile_path_t *path);

/** @brief A Windows-specific function for returning the working directory of a
 * given device.
 *
 * @param device_index The drive index; 1 for A, 2 for B, etc.
 * @param result [out] The working directory of the given device
 */
posix_errno_t efile_get_device_cwd(ErlNifEnv *env, int device_index, ERL_NIF_TERM *result);

/** @brief A Windows-specific function for returning the 8.3-name of a given
 * file or directory. */
posix_errno_t efile_altname(ErlNifEnv *env, const efile_path_t *path, ERL_NIF_TERM *result);