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