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