1 /*  =========================================================================
2     zdir_patch - work with directory patches
3     A patch is a change to the directory (create/delete).
4 
5     Copyright (c) the Contributors as noted in the AUTHORS file.
6     This file is part of CZMQ, the high-level C binding for 0MQ:
7     http://czmq.zeromq.org.
8 
9     This Source Code Form is subject to the terms of the Mozilla Public
10     License, v. 2.0. If a copy of the MPL was not distributed with this
11     file, You can obtain one at http://mozilla.org/MPL/2.0/.
12     =========================================================================
13 */
14 
15 /*
16 @header
17     The zdir_patch class works with one patch, which says "create this
18     file" or "delete this file" (referring to a zfile item each time).
19 @discuss
20 @end
21 */
22 
23 #include "czmq_classes.h"
24 
25 //  Structure of our class
26 //  If you modify this beware to also change _dup
27 
28 struct _zdir_patch_t {
29     char *path;                 //  Directory path
30     char *vpath;                //  Virtual file path
31     zfile_t *file;              //  File we refer to
32     int op;                     //  Operation
33     char *digest;               //  File SHA-1 digest
34 };
35 
36 
37 //  --------------------------------------------------------------------------
38 //  Constructor
39 //  Create new patch, create virtual path from alias
40 
41 zdir_patch_t *
zdir_patch_new(const char * path,zfile_t * file,int op,const char * alias)42 zdir_patch_new (const char *path, zfile_t *file, int op, const char *alias)
43 {
44     zdir_patch_t *self = (zdir_patch_t *) zmalloc (sizeof (zdir_patch_t));
45     assert (self);
46     self->path = strdup (path);
47     assert (self->path);
48     self->file = zfile_dup (file);
49     assert (self->file);
50     self->op = op;
51 
52     //  Calculate virtual path for patch (remove path, prefix alias)
53     const char *filename = zfile_filename (file, path);
54     assert (filename);
55     assert (*filename != '/');
56 
57     self->vpath = (char *) zmalloc (strlen (alias) + strlen (filename) + 2);
58     assert (self->vpath);
59 
60     if (strlen (alias) && alias [strlen (alias) - 1] == '/')
61         sprintf (self->vpath, "%s%s", alias, filename);
62     else
63         sprintf (self->vpath, "%s/%s", alias, filename);
64     return self;
65 }
66 
67 
68 //  --------------------------------------------------------------------------
69 //  Destroy a patch
70 
71 void
zdir_patch_destroy(zdir_patch_t ** self_p)72 zdir_patch_destroy (zdir_patch_t **self_p)
73 {
74     assert (self_p);
75     if (*self_p) {
76         zdir_patch_t *self = *self_p;
77         freen (self->path);
78         freen (self->vpath);
79         freen (self->digest);
80         zfile_destroy (&self->file);
81         freen (self);
82         *self_p = NULL;
83     }
84 }
85 
86 
87 //  --------------------------------------------------------------------------
88 //  Create copy of a patch. If the patch is null, or memory was exhausted,
89 //  returns null.
90 
91 zdir_patch_t *
zdir_patch_dup(zdir_patch_t * self)92 zdir_patch_dup (zdir_patch_t *self)
93 {
94     if (self) {
95         zdir_patch_t *copy = (zdir_patch_t *) zmalloc (sizeof (zdir_patch_t));
96         if (copy) {
97             copy->op = self->op;
98             copy->path = strdup (self->path);
99             if (copy->path)
100                 copy->file = zfile_dup (self->file);
101             if (copy->file)
102                 copy->vpath = strdup (self->vpath);
103             if (copy->vpath)
104                 //  Don't recalculate hash when we duplicate patch
105                 copy->digest = self->digest? strdup (self->digest): NULL;
106 
107             if (copy->digest == NULL && copy->op != patch_delete)
108                 zdir_patch_destroy (&copy);
109         }
110         return copy;
111     }
112     else
113         return NULL;
114 }
115 
116 
117 //  --------------------------------------------------------------------------
118 //  Return patch file directory path
119 
120 const char *
zdir_patch_path(zdir_patch_t * self)121 zdir_patch_path (zdir_patch_t *self)
122 {
123     assert (self);
124     return self->path;
125 }
126 
127 
128 //  --------------------------------------------------------------------------
129 //  Return patch file item
130 
131 zfile_t *
zdir_patch_file(zdir_patch_t * self)132 zdir_patch_file (zdir_patch_t *self)
133 {
134     assert (self);
135     return self->file;
136 }
137 
138 
139 //  --------------------------------------------------------------------------
140 //  Return operation
141 
142 int
zdir_patch_op(zdir_patch_t * self)143 zdir_patch_op (zdir_patch_t *self)
144 {
145     assert (self);
146     return self->op;
147 }
148 
149 
150 //  --------------------------------------------------------------------------
151 //  Return patch virtual file path
152 
153 const char *
zdir_patch_vpath(zdir_patch_t * self)154 zdir_patch_vpath (zdir_patch_t *self)
155 {
156     assert (self);
157     return self->vpath;
158 }
159 
160 
161 //  --------------------------------------------------------------------------
162 //  Calculate hash digest for file (create only)
163 
164 void
zdir_patch_digest_set(zdir_patch_t * self)165 zdir_patch_digest_set (zdir_patch_t *self)
166 {
167     if (self->op == patch_create
168     &&  self->digest == NULL) {
169         self->digest = strdup (zfile_digest (self->file));
170         assert (self->digest);
171     }
172 
173 }
174 
175 
176 //  --------------------------------------------------------------------------
177 //  Return hash digest for patch file (create only)
178 
179 const char *
zdir_patch_digest(zdir_patch_t * self)180 zdir_patch_digest (zdir_patch_t *self)
181 {
182     assert (self);
183     return self->digest;
184 }
185 
186 
187 //  --------------------------------------------------------------------------
188 //  Self test of this class
189 
190 void
zdir_patch_test(bool verbose)191 zdir_patch_test (bool verbose)
192 {
193     printf (" * zdir_patch: ");
194 
195     //  @selftest
196 
197     const char *SELFTEST_DIR_RW = "src/selftest-rw";
198 
199     const char *testfile = "bilbo";
200     const char *prefix   = "/";
201     char *prefixed_testfile = zsys_sprintf ("%s%s", prefix, testfile);
202     assert (prefixed_testfile);
203 
204     // Make sure old aborted tests do not hinder us
205     zsys_file_delete (prefixed_testfile);
206 
207     zfile_t *file = zfile_new (SELFTEST_DIR_RW, testfile);
208     assert (file);
209     zdir_patch_t *patch = zdir_patch_new (SELFTEST_DIR_RW, file, patch_create, prefix);
210     assert (patch);
211     zfile_destroy (&file);
212 
213     file = zdir_patch_file (patch);
214     assert (file);
215     assert (streq (zfile_filename (file, SELFTEST_DIR_RW), testfile));
216     assert (streq (zdir_patch_vpath (patch), prefixed_testfile));
217     zdir_patch_destroy (&patch);
218 
219     zstr_free (&prefixed_testfile);
220 
221 #if defined (__WINDOWS__)
222     zsys_shutdown();
223 #endif
224     //  @end
225 
226     printf ("OK\n");
227 }
228