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 * 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 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 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 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 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 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 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 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 * 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 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 * 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 * 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 * 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 * 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 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 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 * 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 * 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 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 573 sysattr_rw(char *name) 574 { 575 return (name && strcmp(name, SYSATTR_RW) == 0); 576 } 577