1ZFILE(3) CZMQ Manual ZFILE(3)
2
3
4
6 zfile - Class for provides methods to work with files in a portable
7 fashion.
8
10 // This is a stable class, and may not change except for emergencies. It
11 // is provided in stable builds.
12 // If file exists, populates properties. CZMQ supports portable symbolic
13 // links, which are files with the extension ".ln". A symbolic link is a
14 // text file containing one line, the filename of a target file. Reading
15 // data from the symbolic link actually reads from the target file. Path
16 // may be NULL, in which case it is not used.
17 CZMQ_EXPORT zfile_t *
18 zfile_new (const char *path, const char *name);
19
20 // Destroy a file item
21 CZMQ_EXPORT void
22 zfile_destroy (zfile_t **self_p);
23
24 // Duplicate a file item, returns a newly constructed item. If the file
25 // is null, or memory was exhausted, returns null.
26 // Caller owns return value and must destroy it when done.
27 CZMQ_EXPORT zfile_t *
28 zfile_dup (zfile_t *self);
29
30 // Return file name, remove path if provided
31 CZMQ_EXPORT const char *
32 zfile_filename (zfile_t *self, const char *path);
33
34 // Refresh file properties from disk; this is not done automatically
35 // on access methods, otherwise it is not possible to compare directory
36 // snapshots.
37 CZMQ_EXPORT void
38 zfile_restat (zfile_t *self);
39
40 // Return when the file was last modified. If you want this to reflect the
41 // current situation, call zfile_restat before checking this property.
42 CZMQ_EXPORT time_t
43 zfile_modified (zfile_t *self);
44
45 // Return the last-known size of the file. If you want this to reflect the
46 // current situation, call zfile_restat before checking this property.
47 CZMQ_EXPORT off_t
48 zfile_cursize (zfile_t *self);
49
50 // Return true if the file is a directory. If you want this to reflect
51 // any external changes, call zfile_restat before checking this property.
52 CZMQ_EXPORT bool
53 zfile_is_directory (zfile_t *self);
54
55 // Return true if the file is a regular file. If you want this to reflect
56 // any external changes, call zfile_restat before checking this property.
57 CZMQ_EXPORT bool
58 zfile_is_regular (zfile_t *self);
59
60 // Return true if the file is readable by this process. If you want this to
61 // reflect any external changes, call zfile_restat before checking this
62 // property.
63 CZMQ_EXPORT bool
64 zfile_is_readable (zfile_t *self);
65
66 // Return true if the file is writeable by this process. If you want this
67 // to reflect any external changes, call zfile_restat before checking this
68 // property.
69 CZMQ_EXPORT bool
70 zfile_is_writeable (zfile_t *self);
71
72 // Check if file has stopped changing and can be safely processed.
73 // Updates the file statistics from disk at every call.
74 CZMQ_EXPORT bool
75 zfile_is_stable (zfile_t *self);
76
77 // Return true if the file was changed on disk since the zfile_t object
78 // was created, or the last zfile_restat() call made on it.
79 CZMQ_EXPORT bool
80 zfile_has_changed (zfile_t *self);
81
82 // Remove the file from disk
83 CZMQ_EXPORT void
84 zfile_remove (zfile_t *self);
85
86 // Open file for reading
87 // Returns 0 if OK, -1 if not found or not accessible
88 CZMQ_EXPORT int
89 zfile_input (zfile_t *self);
90
91 // Open file for writing, creating directory if needed
92 // File is created if necessary; chunks can be written to file at any
93 // location. Returns 0 if OK, -1 if error.
94 CZMQ_EXPORT int
95 zfile_output (zfile_t *self);
96
97 // Read chunk from file at specified position. If this was the last chunk,
98 // sets the eof property. Returns a null chunk in case of error.
99 // Caller owns return value and must destroy it when done.
100 CZMQ_EXPORT zchunk_t *
101 zfile_read (zfile_t *self, size_t bytes, off_t offset);
102
103 // Returns true if zfile_read() just read the last chunk in the file.
104 CZMQ_EXPORT bool
105 zfile_eof (zfile_t *self);
106
107 // Write chunk to file at specified position
108 // Return 0 if OK, else -1
109 CZMQ_EXPORT int
110 zfile_write (zfile_t *self, zchunk_t *chunk, off_t offset);
111
112 // Read next line of text from file. Returns a pointer to the text line,
113 // or NULL if there was nothing more to read from the file.
114 CZMQ_EXPORT const char *
115 zfile_readln (zfile_t *self);
116
117 // Close file, if open
118 CZMQ_EXPORT void
119 zfile_close (zfile_t *self);
120
121 // Return file handle, if opened
122 CZMQ_EXPORT FILE *
123 zfile_handle (zfile_t *self);
124
125 // Calculate SHA1 digest for file, using zdigest class.
126 CZMQ_EXPORT const char *
127 zfile_digest (zfile_t *self);
128
129 // Self test of this class.
130 CZMQ_EXPORT void
131 zfile_test (bool verbose);
132
133 #ifdef CZMQ_BUILD_DRAFT_API
134 // *** Draft method, for development use, may change without warning ***
135 // Create new temporary file for writing via tmpfile. File is automatically
136 // deleted on destroy
137 CZMQ_EXPORT zfile_t *
138 zfile_tmp (void);
139
140 #endif // CZMQ_BUILD_DRAFT_API
141 // These methods are deprecated, and now moved to zsys class.
142 CZMQ_EXPORT bool
143 zfile_exists (const char *filename);
144 CZMQ_EXPORT ssize_t
145 zfile_size (const char *filename);
146 CZMQ_EXPORT mode_t
147 zfile_mode (const char *filename);
148 CZMQ_EXPORT int
149 zfile_delete (const char *filename);
150 CZMQ_EXPORT bool
151 zfile_stable (const char *filename);
152 CZMQ_EXPORT int
153 zfile_mkdir (const char *pathname);
154 CZMQ_EXPORT int
155 zfile_rmdir (const char *pathname);
156 CZMQ_EXPORT void
157 zfile_mode_private (void);
158 CZMQ_EXPORT void
159 zfile_mode_default (void);
160 Please add '@interface' section in './../src/zfile.c'.
161
163 The zfile class provides methods to work with disk files. A file object
164 provides the modified date, current size, and type of the file. You can
165 create a file object for a filename that does not yet exist. To read or
166 write data from the file, use the input and output methods, and then
167 read and write chunks. The output method lets you both read and write
168 chunks, at any offset. Finally, this class provides portable symbolic
169 links. If a filename ends in ".ln", the first line of text in the file
170 is read, and used as the underlying file for read/write operations.
171 This lets you manipulate (e.g.) copy symbolic links without copying the
172 perhaps very large files they point to.
173
174 This class is a new API, deprecating the old zfile class (which still
175 exists but is implemented in zsys now).
176
178 From zfile_test method.
179
180 const char *SELFTEST_DIR_RW = "src/selftest-rw";
181
182 const char *testbasedir = "this";
183 const char *testsubdir = "is/a/test";
184 const char *testfile = "bilbo";
185 const char *testlink = "bilbo.ln";
186 char *basedirpath = NULL; // subdir in a test, under SELFTEST_DIR_RW
187 char *dirpath = NULL; // subdir in a test, under basedirpath
188 char *filepath = NULL; // pathname to testfile in a test, in dirpath
189 char *linkpath = NULL; // pathname to testlink in a test, in dirpath
190
191 basedirpath = zsys_sprintf ("%s/%s", SELFTEST_DIR_RW, testbasedir);
192 assert (basedirpath);
193 dirpath = zsys_sprintf ("%s/%s", basedirpath, testsubdir);
194 assert (dirpath);
195 filepath = zsys_sprintf ("%s/%s", dirpath, testfile);
196 assert (filepath);
197 linkpath = zsys_sprintf ("%s/%s", dirpath, testlink);
198 assert (linkpath);
199
200 // This subtest is specifically for NULL as current directory, so
201 // no SELFTEST_DIR_RW here; testfile should have no slashes inside.
202 // Normally tests clean up in zfile_destroy(), but if a selftest run
203 // dies e.g. on assert(), workspace remains dirty. Better clean it up.
204 if (zfile_exists (testfile) ) {
205 if (verbose)
206 zsys_debug ("zfile_test() has to remove ./%s that should not have been here", testfile);
207 zfile_delete (testfile);
208 }
209 zfile_t *file = zfile_new (NULL, testfile);
210 assert (file);
211 assert (streq (zfile_filename (file, "."), testfile));
212 assert (zfile_is_readable (file) == false);
213 zfile_destroy (&file);
214
215 // Create a test file in some random subdirectory
216 if (verbose)
217 zsys_debug ("zfile_test() at timestamp %" PRIi64 ": "
218 "Creating new zfile %s",
219 zclock_time(), filepath );
220
221 if (zfile_exists (filepath) ) {
222 if (verbose)
223 zsys_debug ("zfile_test() has to remove %s that should not have been here", filepath);
224 zfile_delete (filepath);
225 }
226
227 file = zfile_new (dirpath, testfile);
228 assert (file);
229 int rc = zfile_output (file);
230 assert (rc == 0);
231 zchunk_t *chunk = zchunk_new (NULL, 100);
232 assert (chunk);
233 zchunk_fill (chunk, 0, 100);
234
235 // Write 100 bytes at position 1,000,000 in the file
236 if (verbose)
237 zsys_debug ("zfile_test() at timestamp %" PRIi64 ": "
238 "Writing 100 bytes at position 1,000,000 in the file",
239 zclock_time() );
240 rc = zfile_write (file, chunk, 1000000);
241 if (verbose)
242 zsys_debug ("zfile_test() at timestamp %" PRIi64 ": "
243 "Wrote 100 bytes at position 1,000,000 in the file, result code %d",
244 zclock_time(), rc );
245 assert (rc == 0);
246 zchunk_destroy (&chunk);
247 zfile_close (file);
248 assert (zfile_is_readable (file));
249 assert (zfile_cursize (file) == 1000100);
250 if (verbose)
251 zsys_debug ("zfile_test() at timestamp %" PRIi64 ": "
252 "Testing if file is NOT stable (is younger than 1 sec)",
253 zclock_time() );
254 assert (!zfile_is_stable (file));
255 if (verbose)
256 zsys_debug ("zfile_test() at timestamp %" PRIi64 ": "
257 "Passed the lag-dependent tests",
258 zclock_time() );
259 assert (zfile_digest (file));
260
261 // Now truncate file from outside
262 int handle = open (filepath, O_WRONLY | O_TRUNC | O_BINARY, 0);
263 assert (handle >= 0);
264 rc = write (handle, "Hello, World\n", 13);
265 assert (rc == 13);
266 close (handle);
267 assert (zfile_has_changed (file));
268 #ifdef CZMQ_BUILD_DRAFT_API
269 zclock_sleep ((int)zsys_file_stable_age_msec() + 50);
270 #else
271 zclock_sleep (5050);
272 #endif
273 assert (zfile_has_changed (file));
274
275 assert (!zfile_is_stable (file));
276 zfile_restat (file);
277 assert (zfile_is_stable (file));
278 assert (streq (zfile_digest (file), "4AB299C8AD6ED14F31923DD94F8B5F5CB89DFB54"));
279
280 // Check we can read from file
281 rc = zfile_input (file);
282 assert (rc == 0);
283 chunk = zfile_read (file, 1000100, 0);
284 assert (chunk);
285 assert (zchunk_size (chunk) == 13);
286 zchunk_destroy (&chunk);
287 zfile_close (file);
288
289 // Check we can read lines from file
290 rc = zfile_input (file);
291 assert (rc == 0);
292 const char *line = zfile_readln (file);
293 assert (streq (line, "Hello, World"));
294 line = zfile_readln (file);
295 assert (line == NULL);
296 zfile_close (file);
297
298 // Try some fun with symbolic links
299 zfile_t *link = zfile_new (dirpath, testlink);
300 assert (link);
301 rc = zfile_output (link);
302 assert (rc == 0);
303 fprintf (zfile_handle (link), "%s\n", filepath);
304 zfile_destroy (&link);
305
306 link = zfile_new (dirpath, testlink);
307 assert (link);
308 rc = zfile_input (link);
309 assert (rc == 0);
310 chunk = zfile_read (link, 1000100, 0);
311 assert (chunk);
312 assert (zchunk_size (chunk) == 13);
313 zchunk_destroy (&chunk);
314 zfile_destroy (&link);
315
316 // Remove file and directory
317 zdir_t *dir = zdir_new (basedirpath, NULL);
318 assert (dir);
319 assert (zdir_cursize (dir) == 26);
320 zdir_remove (dir, true);
321 assert (zdir_cursize (dir) == 0);
322 zdir_destroy (&dir);
323
324 // Check we can no longer read from file
325 assert (zfile_is_readable (file));
326 zfile_restat (file);
327 assert (!zfile_is_readable (file));
328 rc = zfile_input (file);
329 assert (rc == -1);
330 zfile_destroy (&file);
331
332 // This set of tests is done, free the strings for reuse
333 zstr_free (&basedirpath);
334 zstr_free (&dirpath);
335 zstr_free (&filepath);
336 zstr_free (&linkpath);
337
338 const char *eof_checkfile = "eof_checkfile";
339 filepath = zsys_sprintf ("%s/%s", SELFTEST_DIR_RW, eof_checkfile);
340 assert (filepath);
341
342 if (zfile_exists (filepath) ) {
343 if (verbose)
344 zsys_debug ("zfile_test() has to remove %s that should not have been here", filepath);
345 zfile_delete (filepath);
346 }
347 zstr_free (&filepath);
348
349 file = zfile_new (SELFTEST_DIR_RW, eof_checkfile);
350 assert (file);
351
352 // 1. Write something first
353 rc = zfile_output (file);
354 assert (rc == 0);
355 chunk = zchunk_new ("123456789", 9);
356 assert (chunk);
357
358 rc = zfile_write (file, chunk, 0);
359 assert (rc == 0);
360 zchunk_destroy (&chunk);
361 zfile_close (file);
362 assert (zfile_cursize (file) == 9);
363
364 // 2. Read the written something
365 rc = zfile_input (file);
366 assert (rc != -1);
367 // try to read more bytes than there is in the file
368 chunk = zfile_read (file, 1000, 0);
369 assert (zfile_eof(file));
370 assert (zchunk_streq (chunk, "123456789"));
371 zchunk_destroy (&chunk);
372
373 // reading is ok
374 chunk = zfile_read (file, 5, 0);
375 assert (!zfile_eof(file));
376 assert (zchunk_streq (chunk, "12345"));
377 zchunk_destroy (&chunk);
378
379 // read from non zero offset until the end
380 chunk = zfile_read (file, 5, 5);
381 assert (zfile_eof(file));
382 assert (zchunk_streq (chunk, "6789"));
383 zchunk_destroy (&chunk);
384 zfile_remove (file);
385 zfile_close (file);
386 zfile_destroy (&file);
387
388 #ifdef CZMQ_BUILD_DRAFT_API
389 zfile_t *tempfile = zfile_tmp ();
390 assert (tempfile);
391 assert (zfile_filename (tempfile, NULL));
392 assert (zsys_file_exists (zfile_filename (tempfile, NULL)));
393 zchunk_t *tchunk = zchunk_new ("HELLO", 6);
394 assert (zfile_write (tempfile, tchunk, 0) == 0);
395 zchunk_destroy (&tchunk);
396
397 char *filename = strdup (zfile_filename (tempfile, NULL));
398 zfile_destroy (&tempfile);
399 assert (!zsys_file_exists (filename));
400 zstr_free (&filename);
401 #endif // CZMQ_BUILD_DRAFT_API
402
403 #if defined (__WINDOWS__)
404 zsys_shutdown();
405 #endif
406
407
409 The czmq manual was written by the authors in the AUTHORS file.
410
412 Main web site:
413
414 Report bugs to the email <zeromq-dev@lists.zeromq.org[1]>
415
417 Copyright (c) the Contributors as noted in the AUTHORS file. This file
418 is part of CZMQ, the high-level C binding for 0MQ:
419 http://czmq.zeromq.org. This Source Code Form is subject to the terms
420 of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
421 distributed with this file, You can obtain one at
422 http://mozilla.org/MPL/2.0/. LICENSE included with the czmq
423 distribution.
424
426 1. zeromq-dev@lists.zeromq.org
427 mailto:zeromq-dev@lists.zeromq.org
428
429
430
431CZMQ 4.2.1 01/19/2023 ZFILE(3)