1 /* 2 * Copyright 2008 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 * 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 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 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 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 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 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 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 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 * 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 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 * 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 * 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 * 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 * 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 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 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 * 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 * 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