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 */
63 cstack_t *
cstack_new(void)64 cstack_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 */
82 void
cstack_delete(cstack_t * stk)83 cstack_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 */
113 int
cstack_push(cstack_t * stk,void * data,int len)114 cstack_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 */
144 int
cstack_pop(cstack_t * stk,void ** data,int * len)145 cstack_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 */
179 int
cstack_top(cstack_t * stk,void ** data,int * len)180 cstack_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 */
212 boolean_t
match(char * patn,char * str)213 match(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 */
255 int
match_ci(char * patn,char * str)256 match_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 */
318 static boolean_t
parse_match(char line,char * seps)319 parse_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 */
336 char *
parse(char ** line,char * seps)337 parse(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 */
360 int
oct_atoi(char * p)361 oct_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 */
385 char *
strupr(char * s)386 strupr(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 */
407 char *
trim_whitespace(char * buf)408 trim_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 */
436 char *
trim_name(char * nm)437 trim_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 */
458 char *
get_volname(char * path)459 get_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 */
487 boolean_t
fs_volexist(char * path)488 fs_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 */
510 int
tlm_tarhdr_size(void)511 tlm_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 */
521 struct full_dir_info *
dup_dir_info(struct full_dir_info * old_dir_info)522 dup_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 */
540 struct full_dir_info *
tlm_new_dir_info(struct fs_fhandle * fhp,char * dir,char * nm)541 tlm_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 */
564 int
sysattr_rdonly(char * name)565 sysattr_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 */
576 int
sysattr_rw(char * name)577 sysattr_rw(char *name)
578 {
579 return (name && strcmp(name, SYSATTR_RW) == 0);
580 }
581