'\" t .\" Title: zfile .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 03/02/2024 .\" Manual: CZMQ Manual .\" Source: CZMQ 4.2.1 .\" Language: English .\" .TH "ZFILE" "3" "03/02/2024" "CZMQ 4\&.2\&.1" "CZMQ Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" zfile \- Class for provides methods to work with files in a portable fashion\&. .SH "SYNOPSIS" .sp .nf // This is a stable class, and may not change except for emergencies\&. It // is provided in stable builds\&. // If file exists, populates properties\&. CZMQ supports portable symbolic // links, which are files with the extension "\&.ln"\&. A symbolic link is a // text file containing one line, the filename of a target file\&. Reading // data from the symbolic link actually reads from the target file\&. Path // may be NULL, in which case it is not used\&. CZMQ_EXPORT zfile_t * zfile_new (const char *path, const char *name); // Destroy a file item CZMQ_EXPORT void zfile_destroy (zfile_t **self_p); // Duplicate a file item, returns a newly constructed item\&. If the file // is null, or memory was exhausted, returns null\&. // Caller owns return value and must destroy it when done\&. CZMQ_EXPORT zfile_t * zfile_dup (zfile_t *self); // Return file name, remove path if provided CZMQ_EXPORT const char * zfile_filename (zfile_t *self, const char *path); // Refresh file properties from disk; this is not done automatically // on access methods, otherwise it is not possible to compare directory // snapshots\&. CZMQ_EXPORT void zfile_restat (zfile_t *self); // Return when the file was last modified\&. If you want this to reflect the // current situation, call zfile_restat before checking this property\&. CZMQ_EXPORT time_t zfile_modified (zfile_t *self); // Return the last\-known size of the file\&. If you want this to reflect the // current situation, call zfile_restat before checking this property\&. CZMQ_EXPORT off_t zfile_cursize (zfile_t *self); // Return true if the file is a directory\&. If you want this to reflect // any external changes, call zfile_restat before checking this property\&. CZMQ_EXPORT bool zfile_is_directory (zfile_t *self); // Return true if the file is a regular file\&. If you want this to reflect // any external changes, call zfile_restat before checking this property\&. CZMQ_EXPORT bool zfile_is_regular (zfile_t *self); // Return true if the file is readable by this process\&. If you want this to // reflect any external changes, call zfile_restat before checking this // property\&. CZMQ_EXPORT bool zfile_is_readable (zfile_t *self); // Return true if the file is writeable by this process\&. If you want this // to reflect any external changes, call zfile_restat before checking this // property\&. CZMQ_EXPORT bool zfile_is_writeable (zfile_t *self); // Check if file has stopped changing and can be safely processed\&. // Updates the file statistics from disk at every call\&. CZMQ_EXPORT bool zfile_is_stable (zfile_t *self); // Return true if the file was changed on disk since the zfile_t object // was created, or the last zfile_restat() call made on it\&. CZMQ_EXPORT bool zfile_has_changed (zfile_t *self); // Remove the file from disk CZMQ_EXPORT void zfile_remove (zfile_t *self); // Open file for reading // Returns 0 if OK, \-1 if not found or not accessible CZMQ_EXPORT int zfile_input (zfile_t *self); // Open file for writing, creating directory if needed // File is created if necessary; chunks can be written to file at any // location\&. Returns 0 if OK, \-1 if error\&. CZMQ_EXPORT int zfile_output (zfile_t *self); // Read chunk from file at specified position\&. If this was the last chunk, // sets the eof property\&. Returns a null chunk in case of error\&. // Caller owns return value and must destroy it when done\&. CZMQ_EXPORT zchunk_t * zfile_read (zfile_t *self, size_t bytes, off_t offset); // Returns true if zfile_read() just read the last chunk in the file\&. CZMQ_EXPORT bool zfile_eof (zfile_t *self); // Write chunk to file at specified position // Return 0 if OK, else \-1 CZMQ_EXPORT int zfile_write (zfile_t *self, zchunk_t *chunk, off_t offset); // Read next line of text from file\&. Returns a pointer to the text line, // or NULL if there was nothing more to read from the file\&. CZMQ_EXPORT const char * zfile_readln (zfile_t *self); // Close file, if open CZMQ_EXPORT void zfile_close (zfile_t *self); // Return file handle, if opened CZMQ_EXPORT FILE * zfile_handle (zfile_t *self); // Calculate SHA1 digest for file, using zdigest class\&. CZMQ_EXPORT const char * zfile_digest (zfile_t *self); // Self test of this class\&. CZMQ_EXPORT void zfile_test (bool verbose); #ifdef CZMQ_BUILD_DRAFT_API // *** Draft method, for development use, may change without warning *** // Create new temporary file for writing via tmpfile\&. File is automatically // deleted on destroy CZMQ_EXPORT zfile_t * zfile_tmp (void); #endif // CZMQ_BUILD_DRAFT_API // These methods are deprecated, and now moved to zsys class\&. CZMQ_EXPORT bool zfile_exists (const char *filename); CZMQ_EXPORT ssize_t zfile_size (const char *filename); CZMQ_EXPORT mode_t zfile_mode (const char *filename); CZMQ_EXPORT int zfile_delete (const char *filename); CZMQ_EXPORT bool zfile_stable (const char *filename); CZMQ_EXPORT int zfile_mkdir (const char *pathname); CZMQ_EXPORT int zfile_rmdir (const char *pathname); CZMQ_EXPORT void zfile_mode_private (void); CZMQ_EXPORT void zfile_mode_default (void); Please add \*(Aq@interface\*(Aq section in \*(Aq\&./\&.\&./src/zfile\&.c\*(Aq\&. .fi .SH "DESCRIPTION" .sp The zfile class provides methods to work with disk files\&. A file object provides the modified date, current size, and type of the file\&. You can create a file object for a filename that does not yet exist\&. To read or write data from the file, use the input and output methods, and then read and write chunks\&. The output method lets you both read and write chunks, at any offset\&. Finally, this class provides portable symbolic links\&. If a filename ends in "\&.ln", the first line of text in the file is read, and used as the underlying file for read/write operations\&. This lets you manipulate (e\&.g\&.) copy symbolic links without copying the perhaps very large files they point to\&. .sp This class is a new API, deprecating the old zfile class (which still exists but is implemented in zsys now)\&. .SH "EXAMPLE" .PP \fBFrom zfile_test method\fR. .sp .if n \{\ .RS 4 .\} .nf const char *SELFTEST_DIR_RW = "src/selftest\-rw"; const char *testbasedir = "this"; const char *testsubdir = "is/a/test"; const char *testfile = "bilbo"; const char *testlink = "bilbo\&.ln"; char *basedirpath = NULL; // subdir in a test, under SELFTEST_DIR_RW char *dirpath = NULL; // subdir in a test, under basedirpath char *filepath = NULL; // pathname to testfile in a test, in dirpath char *linkpath = NULL; // pathname to testlink in a test, in dirpath basedirpath = zsys_sprintf ("%s/%s", SELFTEST_DIR_RW, testbasedir); assert (basedirpath); dirpath = zsys_sprintf ("%s/%s", basedirpath, testsubdir); assert (dirpath); filepath = zsys_sprintf ("%s/%s", dirpath, testfile); assert (filepath); linkpath = zsys_sprintf ("%s/%s", dirpath, testlink); assert (linkpath); // This subtest is specifically for NULL as current directory, so // no SELFTEST_DIR_RW here; testfile should have no slashes inside\&. // Normally tests clean up in zfile_destroy(), but if a selftest run // dies e\&.g\&. on assert(), workspace remains dirty\&. Better clean it up\&. if (zfile_exists (testfile) ) { if (verbose) zsys_debug ("zfile_test() has to remove \&./%s that should not have been here", testfile); zfile_delete (testfile); } zfile_t *file = zfile_new (NULL, testfile); assert (file); assert (streq (zfile_filename (file, "\&."), testfile)); assert (zfile_is_readable (file) == false); zfile_destroy (&file); // Create a test file in some random subdirectory if (verbose) zsys_debug ("zfile_test() at timestamp %" PRIi64 ": " "Creating new zfile %s", zclock_time(), filepath ); if (zfile_exists (filepath) ) { if (verbose) zsys_debug ("zfile_test() has to remove %s that should not have been here", filepath); zfile_delete (filepath); } file = zfile_new (dirpath, testfile); assert (file); int rc = zfile_output (file); assert (rc == 0); zchunk_t *chunk = zchunk_new (NULL, 100); assert (chunk); zchunk_fill (chunk, 0, 100); // Write 100 bytes at position 1,000,000 in the file if (verbose) zsys_debug ("zfile_test() at timestamp %" PRIi64 ": " "Writing 100 bytes at position 1,000,000 in the file", zclock_time() ); rc = zfile_write (file, chunk, 1000000); if (verbose) zsys_debug ("zfile_test() at timestamp %" PRIi64 ": " "Wrote 100 bytes at position 1,000,000 in the file, result code %d", zclock_time(), rc ); assert (rc == 0); zchunk_destroy (&chunk); zfile_close (file); assert (zfile_is_readable (file)); assert (zfile_cursize (file) == 1000100); if (verbose) zsys_debug ("zfile_test() at timestamp %" PRIi64 ": " "Testing if file is NOT stable (is younger than 1 sec)", zclock_time() ); assert (!zfile_is_stable (file)); if (verbose) zsys_debug ("zfile_test() at timestamp %" PRIi64 ": " "Passed the lag\-dependent tests", zclock_time() ); assert (zfile_digest (file)); // Now truncate file from outside int handle = open (filepath, O_WRONLY | O_TRUNC | O_BINARY, 0); assert (handle >= 0); rc = write (handle, "Hello, World\en", 13); assert (rc == 13); close (handle); assert (zfile_has_changed (file)); #ifdef CZMQ_BUILD_DRAFT_API zclock_sleep ((int)zsys_file_stable_age_msec() + 50); #else zclock_sleep (5050); #endif assert (zfile_has_changed (file)); assert (!zfile_is_stable (file)); zfile_restat (file); assert (zfile_is_stable (file)); assert (streq (zfile_digest (file), "4AB299C8AD6ED14F31923DD94F8B5F5CB89DFB54")); // Check we can read from file rc = zfile_input (file); assert (rc == 0); chunk = zfile_read (file, 1000100, 0); assert (chunk); assert (zchunk_size (chunk) == 13); zchunk_destroy (&chunk); zfile_close (file); // Check we can read lines from file rc = zfile_input (file); assert (rc == 0); const char *line = zfile_readln (file); assert (streq (line, "Hello, World")); line = zfile_readln (file); assert (line == NULL); zfile_close (file); // Try some fun with symbolic links zfile_t *link = zfile_new (dirpath, testlink); assert (link); rc = zfile_output (link); assert (rc == 0); fprintf (zfile_handle (link), "%s\en", filepath); zfile_destroy (&link); link = zfile_new (dirpath, testlink); assert (link); rc = zfile_input (link); assert (rc == 0); chunk = zfile_read (link, 1000100, 0); assert (chunk); assert (zchunk_size (chunk) == 13); zchunk_destroy (&chunk); zfile_destroy (&link); // Remove file and directory zdir_t *dir = zdir_new (basedirpath, NULL); assert (dir); assert (zdir_cursize (dir) == 26); zdir_remove (dir, true); assert (zdir_cursize (dir) == 0); zdir_destroy (&dir); // Check we can no longer read from file assert (zfile_is_readable (file)); zfile_restat (file); assert (!zfile_is_readable (file)); rc = zfile_input (file); assert (rc == \-1); zfile_destroy (&file); // This set of tests is done, free the strings for reuse zstr_free (&basedirpath); zstr_free (&dirpath); zstr_free (&filepath); zstr_free (&linkpath); const char *eof_checkfile = "eof_checkfile"; filepath = zsys_sprintf ("%s/%s", SELFTEST_DIR_RW, eof_checkfile); assert (filepath); if (zfile_exists (filepath) ) { if (verbose) zsys_debug ("zfile_test() has to remove %s that should not have been here", filepath); zfile_delete (filepath); } zstr_free (&filepath); file = zfile_new (SELFTEST_DIR_RW, eof_checkfile); assert (file); // 1\&. Write something first rc = zfile_output (file); assert (rc == 0); chunk = zchunk_new ("123456789", 9); assert (chunk); rc = zfile_write (file, chunk, 0); assert (rc == 0); zchunk_destroy (&chunk); zfile_close (file); assert (zfile_cursize (file) == 9); // 2\&. Read the written something rc = zfile_input (file); assert (rc != \-1); // try to read more bytes than there is in the file chunk = zfile_read (file, 1000, 0); assert (zfile_eof(file)); assert (zchunk_streq (chunk, "123456789")); zchunk_destroy (&chunk); // reading is ok chunk = zfile_read (file, 5, 0); assert (!zfile_eof(file)); assert (zchunk_streq (chunk, "12345")); zchunk_destroy (&chunk); // read from non zero offset until the end chunk = zfile_read (file, 5, 5); assert (zfile_eof(file)); assert (zchunk_streq (chunk, "6789")); zchunk_destroy (&chunk); zfile_remove (file); zfile_close (file); zfile_destroy (&file); #ifdef CZMQ_BUILD_DRAFT_API zfile_t *tempfile = zfile_tmp (); assert (tempfile); assert (zfile_filename (tempfile, NULL)); assert (zsys_file_exists (zfile_filename (tempfile, NULL))); zchunk_t *tchunk = zchunk_new ("HELLO", 6); assert (zfile_write (tempfile, tchunk, 0) == 0); zchunk_destroy (&tchunk); char *filename = strdup (zfile_filename (tempfile, NULL)); zfile_destroy (&tempfile); assert (!zsys_file_exists (filename)); zstr_free (&filename); #endif // CZMQ_BUILD_DRAFT_API #if defined (__WINDOWS__) zsys_shutdown(); #endif .fi .if n \{\ .RE .\} .sp .SH "AUTHORS" .sp The czmq manual was written by the authors in the AUTHORS file\&. .SH "RESOURCES" .sp Main web site: \m[blue]\fB\%\fR\m[] .sp Report bugs to the email <\m[blue]\fBzeromq\-dev@lists\&.zeromq\&.org\fR\m[]\&\s-2\u[1]\d\s+2> .SH "COPYRIGHT" .sp Copyright (c) the Contributors as noted in the AUTHORS file\&. This file is part of CZMQ, the high\-level C binding for 0MQ: http://czmq\&.zeromq\&.org\&. This Source Code Form is subject to the terms of the Mozilla Public License, v\&. 2\&.0\&. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla\&.org/MPL/2\&.0/\&. LICENSE included with the czmq distribution\&. .SH "NOTES" .IP " 1." 4 zeromq-dev@lists.zeromq.org .RS 4 \%mailto:zeromq-dev@lists.zeromq.org .RE