1 /*
2 OWFS -- One-Wire filesystem
3 OWHTTPD -- One-Wire Web Server
4 Written 2003 Paul H Alfille
5 email: paul.alfille@gmail.com
6 Released under the GPL
7 See the header file: ow.h for full attribution
8 1wire/iButton system from Dallas Semiconductor
9 */
10
11 #include <config.h>
12 #include "owfs_config.h"
13 #include "ow.h"
14 #include "ow_counters.h"
15 #include "ow_connection.h"
16
17 static GOOD_OR_BAD OWQ_allocate_array( struct one_wire_query * owq ) ;
18 static GOOD_OR_BAD OWQ_parsename(const char *path, struct one_wire_query *owq);
19 static GOOD_OR_BAD OWQ_parsename_plus(const char *path, const char * file, struct one_wire_query *owq);
20
21 #define OWQ_DEFAULT_READ_BUFFER_SIZE 1
22
23 /* Create the Parsename structure and create the buffer */
OWQ_create_from_path(const char * path)24 struct one_wire_query * OWQ_create_from_path(const char *path)
25 {
26 int sz = sizeof( struct one_wire_query ) + OWQ_DEFAULT_READ_BUFFER_SIZE;
27 struct one_wire_query * owq = owmalloc( sz );
28
29 LEVEL_DEBUG("%s", path);
30
31 if ( owq == NO_ONE_WIRE_QUERY) {
32 LEVEL_DEBUG("No memory to create object for path %s",path) ;
33 return NO_ONE_WIRE_QUERY ;
34 }
35
36 memset(owq, 0, sz);
37 OWQ_cleanup(owq) = owq_cleanup_owq ;
38
39 if ( GOOD( OWQ_parsename(path,owq) ) ) {
40 if ( GOOD( OWQ_allocate_array(owq)) ) {
41 /* Add a 1 byte buffer by default. This distinguishes from filesystem calls at end of buffer */
42 /* Read bufer is provided by OWQ_assign_read_buffer or OWQ_allocate_read_buffer */
43 OWQ_buffer(owq) = (char *) (& owq[1]) ; // point just beyond the one_wire_query struct
44 OWQ_size(owq) = OWQ_DEFAULT_READ_BUFFER_SIZE ;
45 return owq ;
46 }
47 }
48 OWQ_destroy(owq);
49 return NO_ONE_WIRE_QUERY ;
50 }
51
52 /* Create the Parsename structure and load the relevant fields */
OWQ_create_sibling(const char * sibling,struct one_wire_query * owq_original)53 struct one_wire_query * OWQ_create_sibling(const char *sibling, struct one_wire_query *owq_original)
54 {
55 char path[PATH_MAX] ;
56 struct parsedname * pn_original = PN(owq_original) ;
57 int dirlength = pn_original->dirlength ;
58 struct one_wire_query * owq_sib ;
59
60 strncpy(path, pn_original->path,dirlength) ;
61 strcpy(&path[dirlength],sibling) ;
62
63 if ( pn_original->selected_filetype == NO_FILETYPE ) {
64 if ( pn_original->subdir == NO_SUBDIR ) {
65 // not a filetype or a subdir
66 return NO_ONE_WIRE_QUERY ;
67 }
68 // Add extension only if original property is aggregate
69 } else if ( pn_original->selected_filetype->ag != NON_AGGREGATE ) {
70 // search for sibling in the filetype array
71 struct filetype * sib_filetype = bsearch(sibling, pn_original->selected_device->filetype_array,
72 (size_t) pn_original->selected_device->count_of_filetypes, sizeof(struct filetype), filetype_cmp) ;
73 // see if sibling is also an aggregate property
74 LEVEL_DEBUG("Path %s is an agggregate",SAFESTRING(pn_original->path));
75 if ( sib_filetype != NO_FILETYPE && sib_filetype->ag != NON_AGGREGATE ) {
76 char * aggregate_point = path + strlen(path) ;
77 LEVEL_DEBUG("Sibling is also an aggregate",sibling);
78 if (pn_original->extension == EXTENSION_BYTE ) {
79 strcpy( aggregate_point, ".BYTE" ) ;
80 } else if (pn_original->extension == EXTENSION_ALL ) {
81 strcpy( aggregate_point, ".ALL" ) ;
82 } else if (sib_filetype->ag->letters == ag_letters) {
83 UCLIBCLOCK;
84 snprintf(aggregate_point, OW_FULLNAME_MAX, ".%c", pn_original->extension + 'A');
85 UCLIBCUNLOCK;
86 } else {
87 UCLIBCLOCK;
88 snprintf(aggregate_point, OW_FULLNAME_MAX, ".%d", pn_original->extension );
89 UCLIBCUNLOCK;
90 }
91 }
92 }
93
94 LEVEL_DEBUG("Create sibling %s from %s as %s", sibling, pn_original->path,path);
95
96 owq_sib = OWQ_create_from_path(path) ;
97 if ( owq_sib != NO_ONE_WIRE_QUERY ) {
98 // Sib has no offset
99 OWQ_offset(owq_sib) = 0 ;
100 // Make uncached as restrictive as original
101 // Make unaliased as restrictive as original
102 PN(owq_sib)->state |= (pn_original->state & (ePS_uncached|ePS_unaliased) ) ;
103 return owq_sib ;
104 }
105 return NO_ONE_WIRE_QUERY ;
106 }
107
108 /* Use an aggregate OWQ as a template for a single element */
OWQ_create_separate(int extension,struct one_wire_query * owq_aggregate)109 struct one_wire_query * OWQ_create_separate( int extension, struct one_wire_query * owq_aggregate )
110 {
111 int sz = sizeof( struct one_wire_query ) + OWQ_DEFAULT_READ_BUFFER_SIZE;
112 struct one_wire_query * owq_sep = owmalloc( sz );
113
114 LEVEL_DEBUG("%s with extension %d", PN(owq_aggregate)->path,extension);
115
116 if ( owq_sep== NO_ONE_WIRE_QUERY) {
117 LEVEL_DEBUG("No memory to create object for extension %d",extension) ;
118 return NO_ONE_WIRE_QUERY ;
119 }
120
121 memset(owq_sep, 0, sz);
122 OWQ_cleanup(owq_sep) = owq_cleanup_owq ;
123
124 memcpy( PN(owq_sep), PN(owq_aggregate), sizeof(struct parsedname) ) ;
125 PN(owq_sep)->extension = extension ;
126 OWQ_buffer(owq_sep) = (char *) (& owq_sep[1]) ; // point just beyond the one_wire_query struct
127 OWQ_size(owq_sep) = OWQ_DEFAULT_READ_BUFFER_SIZE ;
128 OWQ_offset(owq_sep) = 0 ;
129 return owq_sep ;
130 }
131
132 /* Use an single OWQ as a template for the aggregate one */
OWQ_create_aggregate(struct one_wire_query * owq_single)133 struct one_wire_query * OWQ_create_aggregate( struct one_wire_query * owq_single )
134 {
135 int sz = sizeof( struct one_wire_query ) + OWQ_DEFAULT_READ_BUFFER_SIZE;
136 struct one_wire_query * owq_all = owmalloc( sz );
137
138 LEVEL_DEBUG("%s with extension ALL", PN(owq_single)->path);
139
140 if ( owq_all == NO_ONE_WIRE_QUERY) {
141 LEVEL_DEBUG("No memory to create object for extension ALL") ;
142 return NO_ONE_WIRE_QUERY ;
143 }
144
145 memset(owq_all, 0, sz);
146 OWQ_cleanup(owq_all) = owq_cleanup_owq ;
147
148 memcpy( PN(owq_all), PN(owq_single), sizeof(struct parsedname) ) ;
149 PN(owq_all)->extension = EXTENSION_ALL ;
150 OWQ_buffer(owq_all) = (char *) (& owq_all[1]) ; // point just beyond the one_wire_query struct
151 OWQ_size(owq_all) = OWQ_DEFAULT_READ_BUFFER_SIZE ;
152 OWQ_offset(owq_all) = 0 ;
153 if ( BAD( OWQ_allocate_array(owq_all)) ) {
154 OWQ_destroy(owq_all);
155 return NO_ONE_WIRE_QUERY ;
156 }
157 return owq_all ;
158 }
159
160 /* Create the Parsename structure and load the relevant fields */
OWQ_create(const char * path,struct one_wire_query * owq)161 GOOD_OR_BAD OWQ_create(const char *path, struct one_wire_query *owq)
162 {
163 LEVEL_DEBUG("%s", path);
164
165 if ( GOOD( OWQ_parsename(path,owq) ) ) {
166 if ( GOOD( OWQ_allocate_array(owq)) ) {
167 return gbGOOD ;
168 }
169 OWQ_destroy(owq);
170 }
171 return gbBAD ;
172 }
173
174 /* Create the Parsename structure (using path and file) and load the relevant fields */
175 /* Starts with a statically allocated owq space */
OWQ_create_plus(const char * path,const char * file,struct one_wire_query * owq)176 GOOD_OR_BAD OWQ_create_plus(const char *path, const char *file, struct one_wire_query *owq)
177 {
178 LEVEL_DEBUG("%s + %s", path, file);
179
180 OWQ_cleanup(owq) = owq_cleanup_none ;
181 if ( GOOD( OWQ_parsename_plus(path,file,owq) ) ) {
182 if ( GOOD( OWQ_allocate_array(owq)) ) {
183 return gbGOOD ;
184 }
185 OWQ_destroy(owq);
186 }
187 return gbBAD ;
188 }
189
190 /* Create the Parsename structure in owq */
OWQ_parsename(const char * path,struct one_wire_query * owq)191 static GOOD_OR_BAD OWQ_parsename(const char *path, struct one_wire_query *owq)
192 {
193 struct parsedname *pn = PN(owq);
194
195 if ( FS_ParsedName(path, pn) != 0 ) {
196 return gbBAD ;
197 }
198 OWQ_cleanup(owq) |= owq_cleanup_pn ;
199 return gbGOOD ;
200 }
201
OWQ_parsename_plus(const char * path,const char * file,struct one_wire_query * owq)202 static GOOD_OR_BAD OWQ_parsename_plus(const char *path, const char * file, struct one_wire_query *owq)
203 {
204 struct parsedname *pn = PN(owq);
205
206 if ( FS_ParsedNamePlus(path, file, pn) != 0 ) {
207 return gbBAD ;
208 }
209 OWQ_cleanup(owq) |= owq_cleanup_pn ;
210 return gbGOOD ;
211 }
212
OWQ_allocate_array(struct one_wire_query * owq)213 static GOOD_OR_BAD OWQ_allocate_array( struct one_wire_query * owq )
214 {
215 struct parsedname * pn = PN(owq) ;
216 if (pn->extension == EXTENSION_ALL && pn->type != ePN_structure) {
217 OWQ_array(owq) = owcalloc((size_t) pn->selected_filetype->ag->elements, sizeof(union value_object));
218 if (OWQ_array(owq) == NO_ONE_WIRE_QUERY) {
219 return gbBAD ;
220 }
221 OWQ_cleanup(owq) |= owq_cleanup_array ;
222 } else {
223 OWQ_I(owq) = 0;
224 }
225 return gbGOOD ;
226 }
227
OWQ_assign_read_buffer(char * buffer,size_t size,off_t offset,struct one_wire_query * owq)228 void OWQ_assign_read_buffer(char *buffer, size_t size, off_t offset, struct one_wire_query *owq)
229 {
230 OWQ_buffer(owq) = buffer;
231 OWQ_size(owq) = size;
232 OWQ_offset(owq) = offset;
233 }
234
OWQ_assign_write_buffer(const char * buffer,size_t size,off_t offset,struct one_wire_query * owq)235 void OWQ_assign_write_buffer(const char *buffer, size_t size, off_t offset, struct one_wire_query *owq)
236 {
237 // OWQ_buffer used for both read (non-const) and write (const)
238 #if ( __GNUC__ > 4 ) || (__GNUC__ == 4 && __GNUC_MINOR__ > 4 )
239 #pragma GCC diagnostic push
240 #pragma GCC diagnostic ignored "-Wcast-qual"
241 OWQ_buffer(owq) = (char *) buffer;
242 #pragma GCC diagnostic pop
243 #else
244 OWQ_buffer(owq) = (char *) buffer;
245 #endif
246 OWQ_size(owq) = size;
247 OWQ_offset(owq) = offset;
248 }
249
250 // create the buffer of size filesize
OWQ_allocate_read_buffer(struct one_wire_query * owq)251 GOOD_OR_BAD OWQ_allocate_read_buffer(struct one_wire_query * owq )
252 {
253 struct parsedname * pn = PN(owq) ;
254 size_t size = FullFileLength(pn);
255
256 if ( size > 0 ) {
257 char * buffer = owmalloc(size+1) ;
258 if ( buffer == NULL ) {
259 return gbBAD ;
260 }
261 memset(buffer,0,size+1) ;
262 OWQ_buffer(owq) = buffer ;
263 OWQ_size(owq) = size ;
264 OWQ_offset(owq) = 0 ;
265 OWQ_cleanup(owq) |= owq_cleanup_buffer ;
266 }
267 return gbGOOD;
268 }
269
OWQ_allocate_write_buffer(const char * write_buffer,size_t buffer_length,off_t offset,struct one_wire_query * owq)270 GOOD_OR_BAD OWQ_allocate_write_buffer( const char * write_buffer, size_t buffer_length, off_t offset, struct one_wire_query * owq )
271 {
272 char * buffer_copy ;
273
274 if ( buffer_length == 0 ) {
275 // Buffer size is zero. Allowed, but make it NULL and no cleanup needed.
276 OWQ_size(owq) = 0 ;
277 OWQ_offset(owq) = 0 ;
278 return gbGOOD ;
279 }
280
281 buffer_copy = owmalloc( buffer_length+1) ;
282 if ( buffer_copy == NULL) {
283 // cannot allocate space for buffer
284 LEVEL_DEBUG("Cannot allocate %ld bytes for buffer", buffer_length) ;
285 OWQ_size(owq) = 0 ;
286 OWQ_offset(owq) = 0 ;
287 return gbBAD ;
288 }
289
290 memcpy( buffer_copy, write_buffer, buffer_length) ;
291 buffer_copy[buffer_length] = '\0' ; // make sure it's zero-ended
292 OWQ_buffer(owq) = buffer_copy ;
293 OWQ_size(owq) = buffer_length ;
294 OWQ_length(owq) = buffer_length ;
295 OWQ_offset(owq) = offset ;
296 OWQ_cleanup(owq) |= owq_cleanup_buffer ; // buffer needs cleanup
297 return gbGOOD ;
298 }
299
OWQ_destroy(struct one_wire_query * owq)300 void OWQ_destroy(struct one_wire_query *owq)
301 {
302 if ( owq == NO_ONE_WIRE_QUERY) {
303 return ;
304 }
305
306 if ( OWQ_cleanup(owq) & owq_cleanup_buffer ) {
307 owfree(OWQ_buffer(owq)) ;
308 }
309
310 if ( OWQ_cleanup(owq) & owq_cleanup_rbuffer ) {
311 //owfree(OWQ_read_buffer(owq)) ;
312 }
313
314 if ( OWQ_cleanup(owq) & owq_cleanup_array ) {
315 owfree(OWQ_array(owq)) ;
316 }
317
318 if ( OWQ_cleanup(owq) & owq_cleanup_pn ) {
319 FS_ParsedName_destroy(PN(owq)) ;
320 }
321
322 if ( OWQ_cleanup(owq) & owq_cleanup_owq ) {
323 owfree(owq) ;
324 } else {
325 OWQ_cleanup(owq) = owq_cleanup_none ;
326 }
327 }
328