1/*
2 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/*
7 * BSD 3 Clause License
8 *
9 * Copyright (c) 2007, The Storage Networking Industry Association.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 	- Redistributions of source code must retain the above copyright
15 *	  notice, this list of conditions and the following disclaimer.
16 *
17 * 	- Redistributions in binary form must reproduce the above copyright
18 *	  notice, this list of conditions and the following disclaimer in
19 *	  the documentation and/or other materials provided with the
20 *	  distribution.
21 *
22 *	- Neither the name of The Storage Networking Industry Association (SNIA)
23 *	  nor the names of its contributors may be used to endorse or promote
24 *	  products derived from this software without specific prior written
25 *	  permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <strings.h>
43#include <cstack.h>
44#include <ctype.h>
45#include <tlm.h>
46#include "tlm_proto.h"
47
48/*
49 * Implementation of a list based stack class. The stack only holds
50 * pointers/references to application objects. The objects are not
51 * copied and the stack never attempts to dereference or access the
52 * data objects. Applications should treat cstack_t references as
53 * opaque handles.
54 */
55
56/*
57 * cstack_new
58 *
59 * Allocate and initialize a new stack, which is just an empty cstack_t.
60 * A pointer to the new stack is returned. This should be treated as an
61 * opaque handle by the caller.
62 */
63cstack_t *
64cstack_new(void)
65{
66	cstack_t *stk;
67
68	if ((stk = ndmp_malloc(sizeof (cstack_t))) == NULL)
69		return (NULL);
70
71	return (stk);
72}
73
74
75/*
76 * cstack_delete
77 *
78 * Deallocate the stack. This goes through the list freeing all of the
79 * cstack nodes but not the data because we don't know how the data was
80 * allocated. A stack really should be empty before it is deleted.
81 */
82void
83cstack_delete(cstack_t *stk)
84{
85	cstack_t *tmp;
86
87	if (stk == NULL) {
88		NDMP_LOG(LOG_DEBUG, "cstack_delete: invalid stack");
89		return;
90	}
91
92	while ((tmp = stk->next) != NULL) {
93		stk->next = tmp->next;
94		NDMP_LOG(LOG_DEBUG, "cstack_delete(element): 0x%p", tmp);
95		free(tmp);
96	}
97
98	NDMP_LOG(LOG_DEBUG, "cstack_delete: 0x%p", stk);
99	free(stk);
100}
101
102
103/*
104 * cstack_push
105 *
106 * Push an element onto the stack. Allocate a new node and assign the
107 * data and len values. We don't care what about the real values of
108 * data or len and we never try to access them. The stack head will
109 * point to the new node.
110 *
111 * Returns 0 on success. Otherwise returns -1 to indicate overflow.
112 */
113int
114cstack_push(cstack_t *stk, void *data, int len)
115{
116	cstack_t *stk_node;
117
118	if (stk == NULL) {
119		NDMP_LOG(LOG_DEBUG, "cstack_push: invalid stack");
120		return (-1);
121	}
122
123	if ((stk_node = ndmp_malloc(sizeof (cstack_t))) == NULL)
124		return (-1);
125
126	stk_node->data = data;
127	stk_node->len = len;
128	stk_node->next = stk->next;
129	stk->next = stk_node;
130
131	NDMP_LOG(LOG_DEBUG, "cstack_push(0x%p): 0x%p", stk, stk_node);
132	return (0);
133}
134
135
136/*
137 * cstack_pop
138 *
139 * Pop an element off the stack. Set up the data and len references for
140 * the caller, advance the stack head and free the popped stack node.
141 *
142 * Returns 0 on success. Otherwise returns -1 to indicate underflow.
143 */
144int
145cstack_pop(cstack_t *stk, void **data, int *len)
146{
147	cstack_t *stk_node;
148
149	if (stk == NULL) {
150		NDMP_LOG(LOG_DEBUG, "cstack_pop: invalid stack");
151		return (-1);
152	}
153
154	if ((stk_node = stk->next) == NULL) {
155		NDMP_LOG(LOG_DEBUG, "cstack_pop: underflow");
156		return (-1);
157	}
158
159	if (data)
160		*data = stk_node->data;
161
162	if (len)
163		*len = stk_node->len;
164
165	stk->next = stk_node->next;
166	NDMP_LOG(LOG_DEBUG, "cstack_pop(0x%p): 0x%p", stk, stk_node);
167
168	free(stk_node);
169	return (0);
170}
171
172/*
173 * cstack_top
174 *
175 * Returns the top data element on the stack without removing it.
176 *
177 * Returns 0 on success. Otherwise returns -1 to indicate underflow.
178 */
179int
180cstack_top(cstack_t *stk, void **data, int *len)
181{
182	if (stk == NULL) {
183		NDMP_LOG(LOG_DEBUG, "cstack_pop: invalid stack");
184		return (-1);
185	}
186
187	if (stk->next == NULL) {
188		NDMP_LOG(LOG_DEBUG, "cstack_pop: underflow");
189		return (-1);
190	}
191
192	if (data)
193		*data = stk->next->data;
194
195	if (len)
196		*len = stk->next->len;
197
198	return (0);
199}
200
201/*
202 * match
203 *
204 * Matching rules:
205 *	c	Any non-special character matches itslef
206 *	?	Match any character
207 *	ab	character 'a' followed by character 'b'
208 *	S	Any string of non-special characters
209 *	AB	String 'A' followed by string 'B'
210 *	*	Any String, including the empty string
211 */
212boolean_t
213match(char *patn, char *str)
214{
215	for (; ; ) {
216		switch (*patn) {
217		case 0:
218			return (*str == 0);
219
220		case '?':
221			if (*str != 0) {
222				str++;
223				patn++;
224				continue;
225			} else {
226				return (FALSE);
227			}
228			break;
229
230		case '*':
231			patn++;
232			if (*patn == 0)
233				return (TRUE);
234
235			while (*str) {
236				if (match(patn, str))
237					return (TRUE);
238				str++;
239			}
240			return (FALSE);
241
242		default:
243			if (*str != *patn)
244				return (FALSE);
245			str++;
246			patn++;
247			continue;
248		}
249	}
250}
251
252/*
253 * Match recursive call
254 */
255int
256match_ci(char *patn, char *str)
257{
258	/*
259	 * "<" is a special pattern that matches only those names
260	 * that do NOT have an extension. "." and ".." are ok.
261	 */
262	if (strcmp(patn, "<") == 0) {
263		if ((strcmp(str, ".") == 0) || (strcmp(str, "..") == 0))
264			return (TRUE);
265		if (strchr(str, '.') == 0)
266			return (TRUE);
267		return (FALSE);
268	}
269	for (; ; ) {
270		switch (*patn) {
271		case 0:
272			return (*str == 0);
273
274		case '?':
275			if (*str != 0) {
276				str++;
277				patn++;
278				continue;
279			} else {
280				return (FALSE);
281			}
282			break;
283
284
285		case '*':
286			patn++;
287			if (*patn == 0)
288				return (TRUE);
289
290			while (*str) {
291				if (match_ci(patn, str))
292					return (TRUE);
293				str++;
294			}
295			return (FALSE);
296
297		default:
298			if (*str != *patn) {
299				int	c1 = *str;
300				int	c2 = *patn;
301
302				c1 = tolower(c1);
303				c2 = tolower(c2);
304				if (c1 != c2)
305					return (FALSE);
306			}
307			str++;
308			patn++;
309			continue;
310		}
311	}
312	/* NOT REACHED */
313}
314
315/*
316 * Linear matching against a list utility function
317 */
318static boolean_t
319parse_match(char line, char *seps)
320{
321	char *sep = seps;
322
323	while (*sep != 0) {
324		/* compare this char with the seperator list */
325		if (*sep == line)
326			return (TRUE);
327		sep++;
328	}
329	return (FALSE);
330}
331
332/*
333 * Returns the next entry of the list after
334 * each separator
335 */
336char *
337parse(char **line, char *seps)
338{
339	char *start = *line;
340
341	while (**line != 0) {
342		*line = *line + 1;
343		if (parse_match(**line, seps)) {
344			/* hit a terminator, skip trailing terminators */
345			while (parse_match(**line, seps)) {
346				**line = 0;
347				*line = *line + 1;
348			}
349			break;
350		}
351	}
352	return (start);
353}
354
355/*
356 * oct_atoi
357 *
358 * Convert an octal string to integer
359 */
360int
361oct_atoi(char *p)
362{
363	int v = 0;
364	int c;
365
366	while (*p == ' ')
367		p++;
368
369	while ('0' <= (c = *p++) && c <= '7') {
370		v <<= 3;
371		v += c - '0';
372	}
373
374	return (v);
375}
376
377/*
378 * strupr
379 *
380 * Convert a string to uppercase using the appropriate codepage. The
381 * string is converted in place. A pointer to the string is returned.
382 * There is an assumption here that uppercase and lowercase values
383 * always result encode to the same length.
384 */
385char *
386strupr(char *s)
387{
388	char c;
389	unsigned char *p = (unsigned char *)s;
390
391	while (*p) {
392		c = toupper(*p);
393		*p++ = c;
394	}
395	return (s);
396}
397
398/*
399 * trim_whitespace
400 *
401 * Trim leading and trailing whitespace chars(as defined by isspace)
402 * from a buffer. Example; if the input buffer contained "  text  ",
403 * it will contain "text", when we return. We assume that the buffer
404 * contains a null terminated string. A pointer to the buffer is
405 * returned.
406 */
407char *
408trim_whitespace(char *buf)
409{
410	char *p = buf;
411	char *q = buf;
412
413	if (buf == 0)
414		return (0);
415
416	while (*p && isspace(*p))
417		++p;
418
419	while ((*q = *p++) != 0)
420		++q;
421
422	if (q != buf) {
423		while ((--q, isspace(*q)) != 0)
424			*q = '\0';
425	}
426
427	return (buf);
428}
429
430/*
431 * trim_name
432 *
433 * Trims the slash and dot slash from the beginning of the
434 * path name.
435 */
436char *
437trim_name(char *nm)
438{
439	while (*nm) {
440		if (*nm == '/') {
441			nm++;
442			continue;
443		}
444		if (*nm == '.' && nm[1] == '/' && nm[2]) {
445			nm += 2;
446			continue;
447		}
448		break;
449	}
450	return (nm);
451}
452
453/*
454 * get_volname
455 *
456 * Extract the volume name from the path
457 */
458char *
459get_volname(char *path)
460{
461	char *cp, *save;
462	int sp;
463
464	if (!path)
465		return (NULL);
466
467	if (!(save = strdup(path)))
468		return (NULL);
469
470	sp = strspn(path, "/");
471	if (*(path + sp) == '\0') {
472		free(save);
473		return (NULL);
474	}
475
476	if ((cp = strchr(save + sp, '/')))
477		*cp = '\0';
478
479	return (save);
480}
481
482/*
483 * fs_volexist
484 *
485 * Check if the volume exists
486 */
487boolean_t
488fs_volexist(char *path)
489{
490	struct stat64 st;
491	char *p;
492
493	if ((p = get_volname(path)) == NULL)
494		return (FALSE);
495
496	if (stat64(p, &st) != 0) {
497		free(p);
498		return (FALSE);
499	}
500
501	free(p);
502	return (TRUE);
503}
504
505/*
506 * tlm_tarhdr_size
507 *
508 * Returns the size of the TLM_TAR_HDR structure.
509 */
510int
511tlm_tarhdr_size(void)
512{
513	return (sizeof (tlm_tar_hdr_t));
514}
515
516/*
517 * dup_dir_info
518 *
519 * Make and return a copy of the directory info.
520 */
521struct full_dir_info *
522dup_dir_info(struct full_dir_info *old_dir_info)
523{
524	struct	full_dir_info *new_dir_info;
525	new_dir_info = ndmp_malloc(sizeof (struct full_dir_info));
526
527	if (new_dir_info) {
528		bcopy(old_dir_info, new_dir_info,
529		    sizeof (struct full_dir_info));
530	}
531	return (new_dir_info);
532}
533
534/*
535 * tlm_new_dir_info
536 *
537 * Create a new structure, set fh field to what is specified and the path
538 * to the concatenation of directory and the component
539 */
540struct full_dir_info *
541tlm_new_dir_info(struct  fs_fhandle *fhp, char *dir, char *nm)
542{
543	struct full_dir_info *fdip;
544
545	if (!(fdip = ndmp_malloc(sizeof (struct full_dir_info))))
546		return (NULL);
547
548	(void) memcpy(&fdip->fd_dir_fh, fhp, sizeof (fs_fhandle_t));
549	if (!tlm_cat_path(fdip->fd_dir_name, dir, nm)) {
550		free(fdip);
551		NDMP_LOG(LOG_DEBUG, "TAPE BACKUP Find> path too long [%s][%s]",
552		    dir, nm);
553		return (NULL);
554	}
555	return (fdip);
556}
557
558/*
559 * sysattr_rdonly
560 *
561 * Check if the attribute file is one of the readonly system
562 * attributes.
563 */
564int
565sysattr_rdonly(char *name)
566{
567	return (name && strcmp(name, SYSATTR_RDONLY) == 0);
568}
569
570/*
571 * sysattr_rw
572 *
573 * Check if the attribute file is one of the read/write system
574 * attributes.
575 */
576int
577sysattr_rw(char *name)
578{
579	return (name && strcmp(name, SYSATTR_RW) == 0);
580}
581