Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Source for file plugin
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : *
8 : */
9 :
10 : #include "file.h"
11 : #include <fcntl.h>
12 : #include <kdberrors.h>
13 : #include <kdbhelper.h>
14 : #include <stdio.h>
15 : #include <stdlib.h>
16 : #include <string.h>
17 : #include <sys/stat.h>
18 : #include <time.h>
19 :
20 :
21 40 : int elektraFileGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned ELEKTRA_UNUSED, Key * parentKey ELEKTRA_UNUSED)
22 : {
23 40 : if (!elektraStrCmp (keyName (parentKey), "system/elektra/modules/file"))
24 : {
25 31 : KeySet * contract =
26 31 : ksNew (30, keyNew ("system/elektra/modules/file", KEY_VALUE, "file plugin waits for your orders", KEY_END),
27 : keyNew ("system/elektra/modules/file/exports", KEY_END),
28 : keyNew ("system/elektra/modules/file/exports/get", KEY_FUNC, elektraFileGet, KEY_END),
29 : keyNew ("system/elektra/modules/file/exports/set", KEY_FUNC, elektraFileSet, KEY_END),
30 : #include ELEKTRA_README
31 : keyNew ("system/elektra/modules/file/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
32 31 : ksAppend (returned, contract);
33 31 : ksDel (contract);
34 :
35 31 : return 1; // success
36 : }
37 :
38 9 : short binary = 0;
39 9 : short info = 0;
40 9 : KeySet * config = elektraPluginGetConfig (handle);
41 9 : Key * lookup = ksLookupByName (config, "/info", KDB_O_NONE);
42 9 : if (lookup) info = 1;
43 9 : lookup = ksLookupByName (config, "/binary", KDB_O_NONE);
44 9 : if (lookup) binary = 1;
45 :
46 9 : const char * fileName = keyString (parentKey);
47 :
48 : struct stat sb;
49 9 : if (stat (fileName, &sb) == -1)
50 : {
51 0 : ELEKTRA_SET_RESOURCE_ERRORF (parentKey, "Failed to stat file %s, aborting. Reason: %s", fileName, strerror (errno));
52 0 : return -1;
53 : }
54 :
55 9 : long long fileSize = (long long) sb.st_size;
56 :
57 9 : unsigned char * buffer = NULL;
58 9 : if (!binary)
59 9 : buffer = elektraMalloc (fileSize + 1); // fileSize + null terminator
60 : else
61 0 : buffer = elektraMalloc (fileSize);
62 :
63 9 : if (!buffer)
64 : {
65 0 : ELEKTRA_SET_OUT_OF_MEMORY_ERRORF (parentKey, "Failed to allocate buffer of %lld bytes for %s", fileSize, fileName);
66 0 : return -1;
67 : }
68 :
69 9 : FILE * fp = NULL;
70 9 : fp = fopen (fileName, "rb");
71 9 : if (!fp)
72 : {
73 0 : ELEKTRA_SET_RESOURCE_ERRORF (parentKey, "Failed to open file %s. Reason: %s", fileName, strerror (errno));
74 0 : elektraFree (buffer);
75 0 : return -1;
76 : }
77 :
78 :
79 : // loop until until fileSize elements of size sizeof(char) are read
80 : long long bytesRead = 0;
81 18 : while (bytesRead < fileSize)
82 : {
83 9 : size_t bytes = fread (buffer + bytesRead, 1, (size_t) fileSize, fp);
84 9 : if (bytes == 0) break;
85 9 : bytesRead += bytes;
86 : }
87 :
88 9 : if (bytesRead < fileSize)
89 : {
90 0 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERRORF (parentKey, "Failed to read %s completely. Got %lld of %lld bytes", fileName,
91 : bytesRead, fileSize);
92 0 : elektraFree (buffer);
93 0 : fclose (fp);
94 0 : return -1;
95 : }
96 9 : fclose (fp);
97 :
98 9 : Key * key = keyNew (keyName (parentKey), KEY_END);
99 9 : if (binary)
100 : {
101 0 : keySetBinary (key, (const void *) buffer, (size_t) fileSize);
102 : }
103 : else
104 : {
105 9 : buffer[fileSize] = '\0';
106 9 : keySetString (key, (char *) buffer);
107 : }
108 9 : if (info)
109 3 : {
110 3 : unsigned long long maxValue = UINT64_MAX;
111 3 : size_t maxChars = snprintf (NULL, 0, "%llu", maxValue);
112 3 : char tmp[maxChars + 1]; //
113 3 : snprintf (tmp, sizeof (tmp), "%lld", fileSize);
114 3 : keySetMeta (key, "info/size", tmp);
115 3 : keySetMeta (key, "info/ctime", ctime (&sb.st_ctime));
116 3 : keySetMeta (key, "info/atime", ctime (&sb.st_atime));
117 3 : keySetMeta (key, "info/mtime", ctime (&sb.st_mtime));
118 3 : snprintf (tmp, sizeof (tmp), "%ld", (long) sb.st_uid);
119 3 : keySetMeta (key, "info/uid", tmp);
120 3 : snprintf (tmp, sizeof (tmp), "%ld", (long) sb.st_gid);
121 3 : keySetMeta (key, "info/gid", tmp);
122 3 : snprintf (tmp, sizeof (tmp), "%o", (unsigned int) sb.st_mode);
123 3 : keySetMeta (key, "info/mode", tmp);
124 3 : snprintf (tmp, sizeof (tmp), "%ld", (long) sb.st_ino);
125 3 : keySetMeta (key, "info/inode", tmp);
126 : }
127 9 : ksAppendKey (returned, key);
128 :
129 9 : elektraFree (buffer);
130 9 : return 1; // success
131 : }
132 :
133 6 : int elektraFileSet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned ELEKTRA_UNUSED, Key * parentKey ELEKTRA_UNUSED)
134 : {
135 : // set all keys
136 : // this function is optional
137 6 : const Key * key = ksLookup (returned, parentKey, KDB_O_NONE);
138 6 : if (!key) return 0;
139 6 : const char * fileName = keyString (parentKey);
140 :
141 6 : FILE * fp = NULL;
142 6 : fp = fopen (fileName, "wb");
143 6 : if (!fp)
144 : {
145 0 : ELEKTRA_SET_RESOURCE_ERRORF (parentKey, "Failed to open %s for writing. Reason: %s", fileName, strerror (errno));
146 0 : return -1;
147 : }
148 6 : ssize_t svalueSize = keyGetValueSize (key);
149 6 : if (svalueSize <= 0)
150 : {
151 0 : fclose (fp);
152 0 : return 0;
153 : }
154 6 : size_t valueSize = (size_t) svalueSize;
155 6 : unsigned char * value = elektraMalloc (valueSize);
156 6 : if (!value)
157 : {
158 0 : ELEKTRA_MALLOC_ERROR (parentKey, valueSize);
159 0 : fclose (fp);
160 0 : return -1;
161 : }
162 6 : if (!keyIsBinary (key))
163 : {
164 6 : keyGetString (key, (char *) value, valueSize);
165 6 : valueSize -= 1; // don't write the null terminator to the file
166 : }
167 : else
168 : {
169 0 : keyGetBinary (key, value, valueSize);
170 : }
171 6 : size_t bytesWritten = 0;
172 18 : while (bytesWritten < valueSize)
173 : {
174 6 : size_t bytes = fwrite (value, 1, valueSize, fp);
175 6 : if (bytes == 0) break;
176 6 : bytesWritten += bytes;
177 : }
178 6 : fclose (fp);
179 6 : elektraFree (value);
180 :
181 6 : if (bytesWritten < valueSize)
182 : {
183 : return -1;
184 : }
185 :
186 6 : return 1; // success
187 : }
188 :
189 57 : Plugin * ELEKTRA_PLUGIN_EXPORT
190 : {
191 : // clang-format off
192 57 : return elektraPluginExport ("file",
193 : ELEKTRA_PLUGIN_GET, &elektraFileGet,
194 : ELEKTRA_PLUGIN_SET, &elektraFileSet,
195 : ELEKTRA_PLUGIN_END);
196 : }
197 :
|