| 1 | /* |
|---|
| 2 | * (C) 2001 Clemson University and The University of Chicago |
|---|
| 3 | * |
|---|
| 4 | * See COPYING in top-level directory. |
|---|
| 5 | */ |
|---|
| 6 | |
|---|
| 7 | #include <stdio.h> |
|---|
| 8 | #include <stdlib.h> |
|---|
| 9 | #include <string.h> |
|---|
| 10 | #include <errno.h> |
|---|
| 11 | #include <ctype.h> |
|---|
| 12 | #include <assert.h> |
|---|
| 13 | |
|---|
| 14 | #include "str-utils.h" |
|---|
| 15 | |
|---|
| 16 | /* PINT_string_count_segments() |
|---|
| 17 | * |
|---|
| 18 | * Count number of segments in a path. |
|---|
| 19 | * |
|---|
| 20 | * Parameters: |
|---|
| 21 | * pathname - pointer to string |
|---|
| 22 | * |
|---|
| 23 | * Returns number of segments in pathname; -1 if |
|---|
| 24 | * pathname is invalid or has no components |
|---|
| 25 | * |
|---|
| 26 | * Example inputs and return values: |
|---|
| 27 | * |
|---|
| 28 | * NULL - returns -1 |
|---|
| 29 | * / - returns -1 |
|---|
| 30 | * filename - returns 1 |
|---|
| 31 | * /filename - returns 1 |
|---|
| 32 | * /filename/ - returns 1 |
|---|
| 33 | * /filename// - returns 1 |
|---|
| 34 | * /dirname/filename - returns 2 |
|---|
| 35 | * dirname/filename |
|---|
| 36 | * |
|---|
| 37 | */ |
|---|
| 38 | int PINT_string_count_segments(char *pathname) |
|---|
| 39 | { |
|---|
| 40 | int count = 0; |
|---|
| 41 | char *segp = (char *)0; |
|---|
| 42 | void *segstate; |
|---|
| 43 | |
|---|
| 44 | while(!PINT_string_next_segment(pathname,&segp,&segstate)) |
|---|
| 45 | { |
|---|
| 46 | count++; |
|---|
| 47 | } |
|---|
| 48 | return count; |
|---|
| 49 | } |
|---|
| 50 | |
|---|
| 51 | /* PINT_get_base_dir() |
|---|
| 52 | * |
|---|
| 53 | * Get base (parent) dir of a absolute path |
|---|
| 54 | * |
|---|
| 55 | * Parameters: |
|---|
| 56 | * pathname - pointer to directory string |
|---|
| 57 | * out_base_dir - pointer to out base dir string |
|---|
| 58 | * max_out_len - max length of out_base_dir buffer |
|---|
| 59 | * |
|---|
| 60 | * All incoming arguments must be valid and non-zero |
|---|
| 61 | * |
|---|
| 62 | * Returns 0 on success; -1 if args are invalid |
|---|
| 63 | * |
|---|
| 64 | * Example inputs and outputs/return values: |
|---|
| 65 | * |
|---|
| 66 | * pathname: /tmp - out_base_dir: / - returns 0 |
|---|
| 67 | * pathname: /tmp/foo - out_base_dir: /tmp - returns 0 |
|---|
| 68 | * pathname: /tmp/foo/bar - out_base_dir: /tmp/foo - returns 0 |
|---|
| 69 | * |
|---|
| 70 | * |
|---|
| 71 | * invalid pathname input examples: |
|---|
| 72 | * pathname: / - out_base_dir: undefined - returns -1 |
|---|
| 73 | * pathname: NULL - out_base_dir: undefined - returns -1 |
|---|
| 74 | * pathname: foo - out_base_dir: undefined - returns -1 |
|---|
| 75 | * |
|---|
| 76 | */ |
|---|
| 77 | int PINT_get_base_dir(char *pathname, char *out_base_dir, int out_max_len) |
|---|
| 78 | { |
|---|
| 79 | int ret = -1, len = 0; |
|---|
| 80 | char *start, *end; |
|---|
| 81 | |
|---|
| 82 | if (pathname && out_base_dir && out_max_len) |
|---|
| 83 | { |
|---|
| 84 | if ((strcmp(pathname,"/") == 0) || (pathname[0] != '/')) |
|---|
| 85 | { |
|---|
| 86 | return ret; |
|---|
| 87 | } |
|---|
| 88 | |
|---|
| 89 | start = pathname; |
|---|
| 90 | end = (char *)(pathname + strlen(pathname)); |
|---|
| 91 | |
|---|
| 92 | while(end && (end > start) && (*(--end) != '/')); |
|---|
| 93 | |
|---|
| 94 | /* |
|---|
| 95 | get rid of trailing slash unless we're handling |
|---|
| 96 | the case where parent is the root directory |
|---|
| 97 | (in root dir case, len == 1) |
|---|
| 98 | */ |
|---|
| 99 | len = ++end - start; |
|---|
| 100 | if (len != 1) |
|---|
| 101 | { |
|---|
| 102 | len--; |
|---|
| 103 | } |
|---|
| 104 | if (len < out_max_len) |
|---|
| 105 | { |
|---|
| 106 | memcpy(out_base_dir,start,len); |
|---|
| 107 | out_base_dir[len] = '\0'; |
|---|
| 108 | ret = 0; |
|---|
| 109 | } |
|---|
| 110 | } |
|---|
| 111 | return ret; |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | /* PINT_string_next_segment() |
|---|
| 115 | * |
|---|
| 116 | * Parameters: |
|---|
| 117 | * pathname - pointer to string |
|---|
| 118 | * inout_segp - address of pointer; NULL to get first segment, |
|---|
| 119 | * pointer to last segment to get next segment |
|---|
| 120 | * opaquep - address of void *, used to maintain state outside |
|---|
| 121 | * the function |
|---|
| 122 | * |
|---|
| 123 | * Returns 0 if segment is available, -1 on end of string. |
|---|
| 124 | * |
|---|
| 125 | * This approach is nice because it keeps all the necessary state |
|---|
| 126 | * outside the function and concisely stores it in two pointers. |
|---|
| 127 | * |
|---|
| 128 | * Internals: |
|---|
| 129 | * We're using opaquep to store the location of where we placed a |
|---|
| 130 | * '\0' separator to get a segment. The value is undefined when |
|---|
| 131 | * called with *inout_segp == NULL. Afterwards, if we place a '\0', |
|---|
| 132 | * *opaquep will point to where we placed it. If we do not, then we |
|---|
| 133 | * know that we've hit the end of the path string before we even |
|---|
| 134 | * start processing. |
|---|
| 135 | * |
|---|
| 136 | * Note that it is possible that *opaquep != NULL and still there are |
|---|
| 137 | * no more segments; a trailing '/' could cause this, for example. |
|---|
| 138 | */ |
|---|
| 139 | int PINT_string_next_segment(char *pathname, |
|---|
| 140 | char **inout_segp, |
|---|
| 141 | void **opaquep) |
|---|
| 142 | { |
|---|
| 143 | char *ptr = (char *)0; |
|---|
| 144 | |
|---|
| 145 | /* initialize our starting position */ |
|---|
| 146 | if (*inout_segp == NULL) |
|---|
| 147 | { |
|---|
| 148 | ptr = pathname; |
|---|
| 149 | } |
|---|
| 150 | else if (*opaquep != NULL) |
|---|
| 151 | { |
|---|
| 152 | /* replace the '/', point just past it */ |
|---|
| 153 | ptr = (char *) *opaquep; |
|---|
| 154 | *ptr = '/'; |
|---|
| 155 | ptr++; |
|---|
| 156 | } |
|---|
| 157 | else |
|---|
| 158 | return -1; /* NULL *opaquep indicates last segment returned last time */ |
|---|
| 159 | |
|---|
| 160 | /* at this point, the string is back in its original state */ |
|---|
| 161 | |
|---|
| 162 | /* jump past separators */ |
|---|
| 163 | while ((*ptr != '\0') && (*ptr == '/')) |
|---|
| 164 | ptr++; |
|---|
| 165 | if (*ptr == '\0') |
|---|
| 166 | return -1; /* all that was left was trailing '/'s */ |
|---|
| 167 | |
|---|
| 168 | *inout_segp = ptr; |
|---|
| 169 | |
|---|
| 170 | /* find next separator */ |
|---|
| 171 | while ((*ptr != '\0') && (*ptr != '/')) |
|---|
| 172 | ptr++; |
|---|
| 173 | if (*ptr == '\0') |
|---|
| 174 | *opaquep = NULL; /* indicate last segment */ |
|---|
| 175 | else |
|---|
| 176 | { |
|---|
| 177 | /* terminate segment and save position of terminator */ |
|---|
| 178 | *ptr = '\0'; |
|---|
| 179 | *opaquep = ptr; |
|---|
| 180 | } |
|---|
| 181 | return 0; |
|---|
| 182 | } |
|---|
| 183 | |
|---|
| 184 | |
|---|
| 185 | /* |
|---|
| 186 | * PINT_parse_handle_ranges: the first time this is called, set 'status' to |
|---|
| 187 | * zero. get back the first range in the string in the out_extent |
|---|
| 188 | * variable. keep calling PINT_parse_handle_ranges until it returns zero |
|---|
| 189 | * |
|---|
| 190 | * range : string representing our ranges |
|---|
| 191 | * out_extent->first: (output) beginning of range |
|---|
| 192 | * out_extent->last : (output) end of range |
|---|
| 193 | * status : (opaque) how far we are in the range string |
|---|
| 194 | * |
|---|
| 195 | * returns: |
|---|
| 196 | * 0: no more ranges |
|---|
| 197 | * 1: found a range. look at 'first' and 'last' for the values |
|---|
| 198 | * -1: something bad happened, possibly invalid arguments |
|---|
| 199 | */ |
|---|
| 200 | int PINT_parse_handle_ranges( |
|---|
| 201 | char *range, |
|---|
| 202 | PVFS_handle_extent *out_extent, |
|---|
| 203 | int *status) |
|---|
| 204 | { |
|---|
| 205 | char *p = NULL, *endchar = NULL; |
|---|
| 206 | |
|---|
| 207 | if (!out_extent || !status) |
|---|
| 208 | { |
|---|
| 209 | return -1; |
|---|
| 210 | } |
|---|
| 211 | |
|---|
| 212 | p = range + *status; |
|---|
| 213 | |
|---|
| 214 | /* from strtol(3): |
|---|
| 215 | If endptr is not NULL, strtoul() stores the address of the |
|---|
| 216 | first invalid character in *endptr. If there were no dig |
|---|
| 217 | its at all, strtoul() stores the original value of nptr in |
|---|
| 218 | *endptr (and returns 0). In particular, if *nptr is not |
|---|
| 219 | `\0' but **endptr is `\0' on return, the entire string is |
|---|
| 220 | valid. */ |
|---|
| 221 | out_extent->first = out_extent->last = |
|---|
| 222 | #ifdef HAVE_STRTOULL |
|---|
| 223 | (PVFS_handle)strtoull(p, &endchar, 0); |
|---|
| 224 | #else |
|---|
| 225 | (PVFS_handle)strtoul(p, &endchar, 0); |
|---|
| 226 | #endif |
|---|
| 227 | if ( p == endchar ) /* all done */ |
|---|
| 228 | return 0; |
|---|
| 229 | /* strtoul eats leading space, but not trailing space. take care of ws |
|---|
| 230 | * between number and delimiter (- or ,) */ |
|---|
| 231 | while (isspace(*endchar)) endchar++; |
|---|
| 232 | |
|---|
| 233 | p = endchar+1; /* skip over the ',' or '-'*/ |
|---|
| 234 | |
|---|
| 235 | switch (*endchar) { |
|---|
| 236 | case '-': /* we got the first half of the range. grab 2nd half */ |
|---|
| 237 | #ifdef HAVE_STRTOULL |
|---|
| 238 | out_extent->last = (PVFS_handle)strtoull(p, &endchar, 0); |
|---|
| 239 | #else |
|---|
| 240 | out_extent->last = (PVFS_handle)strtoul(p, &endchar, 0); |
|---|
| 241 | #endif |
|---|
| 242 | /* again, skip trailing space ...*/ |
|---|
| 243 | while (isspace(*endchar)) endchar++; |
|---|
| 244 | /* ... and the delimiter */ |
|---|
| 245 | if (*endchar == ',') endchar ++; |
|---|
| 246 | /* 'status' tells us how far we are in the string */ |
|---|
| 247 | *status = ( endchar - range); |
|---|
| 248 | break; |
|---|
| 249 | case ',': /* end of a range */ |
|---|
| 250 | case '\0': /* end of the whole string */ |
|---|
| 251 | *status = ( p - range ); |
|---|
| 252 | break; |
|---|
| 253 | default: |
|---|
| 254 | return -1; |
|---|
| 255 | } |
|---|
| 256 | return 1; |
|---|
| 257 | } |
|---|
| 258 | |
|---|
| 259 | /* |
|---|
| 260 | * PINT_get_path_element: gets the specified segment in the |
|---|
| 261 | * provided path. |
|---|
| 262 | * |
|---|
| 263 | * pathname : string containing a valid pathname |
|---|
| 264 | * segment_num: the desired segment number in the path |
|---|
| 265 | * out_segment: where the segment will be stored on success |
|---|
| 266 | * out_max_len: max num bytes to store in out_segment |
|---|
| 267 | * |
|---|
| 268 | * returns: |
|---|
| 269 | * 0 : if the segment was found and copied |
|---|
| 270 | * -1: if an invalid segment was specified |
|---|
| 271 | * |
|---|
| 272 | * Example inputs and outputs/return values: |
|---|
| 273 | * |
|---|
| 274 | * pathname: /mnt/pvfs2/foo, segment_num: 0 |
|---|
| 275 | * out_segment: mnt, returns 0 |
|---|
| 276 | * pathname: /mnt/pvfs2/foo, segment_num: 2 |
|---|
| 277 | * out_segment: foo, returns 0 |
|---|
| 278 | * pathname: /mnt/pvfs2/foo, segment_num: 5 |
|---|
| 279 | * out_segment: undefined, returns -1 |
|---|
| 280 | */ |
|---|
| 281 | int PINT_get_path_element( |
|---|
| 282 | char *pathname, |
|---|
| 283 | int segment_num, |
|---|
| 284 | char *out_segment, |
|---|
| 285 | int out_max_len) |
|---|
| 286 | { |
|---|
| 287 | int count = -1; |
|---|
| 288 | char *segp = (char *)0; |
|---|
| 289 | void *segstate = NULL; |
|---|
| 290 | char local_pathname[PVFS_NAME_MAX] = {0}; |
|---|
| 291 | |
|---|
| 292 | strncpy(local_pathname,pathname,PVFS_NAME_MAX); |
|---|
| 293 | |
|---|
| 294 | while(!PINT_string_next_segment(local_pathname,&segp,&segstate)) |
|---|
| 295 | { |
|---|
| 296 | if (++count == segment_num) |
|---|
| 297 | { |
|---|
| 298 | strncpy(out_segment,segp,(size_t)out_max_len); |
|---|
| 299 | break; |
|---|
| 300 | } |
|---|
| 301 | } |
|---|
| 302 | return ((count == segment_num) ? 0 : -1); |
|---|
| 303 | } |
|---|
| 304 | |
|---|
| 305 | /* PINT_get_next_path |
|---|
| 306 | * |
|---|
| 307 | * gets remaining path given number of path segments to skip |
|---|
| 308 | * |
|---|
| 309 | * returns 0 on success, -errno on failure |
|---|
| 310 | */ |
|---|
| 311 | int PINT_get_next_path(char *path, char **newpath, int skip) |
|---|
| 312 | { |
|---|
| 313 | int pathlen=0, i=0, num_slashes_seen=0; |
|---|
| 314 | int delimiter1=0; |
|---|
| 315 | |
|---|
| 316 | pathlen = strlen(path) + 1; |
|---|
| 317 | |
|---|
| 318 | /* find our starting point in the old path, it could be past multiple |
|---|
| 319 | * segments*/ |
|---|
| 320 | for(i =0; i < pathlen; i++) |
|---|
| 321 | { |
|---|
| 322 | if (path[i] == '/') |
|---|
| 323 | { |
|---|
| 324 | num_slashes_seen++; |
|---|
| 325 | if (num_slashes_seen > skip) |
|---|
| 326 | { |
|---|
| 327 | break; |
|---|
| 328 | } |
|---|
| 329 | } |
|---|
| 330 | } |
|---|
| 331 | |
|---|
| 332 | delimiter1 = i; |
|---|
| 333 | if (pathlen - delimiter1 < 1) |
|---|
| 334 | { |
|---|
| 335 | return (-PVFS_EINVAL); |
|---|
| 336 | } |
|---|
| 337 | |
|---|
| 338 | *newpath = malloc(pathlen - delimiter1); |
|---|
| 339 | if (*newpath == NULL) |
|---|
| 340 | { |
|---|
| 341 | return (-PVFS_ENOMEM); |
|---|
| 342 | } |
|---|
| 343 | memcpy(*newpath, &path[delimiter1], pathlen - delimiter1 ); |
|---|
| 344 | /* *newpath[pathlen - delimiter1 -1 ] = '\0';*/ |
|---|
| 345 | return(0); |
|---|
| 346 | } |
|---|
| 347 | |
|---|
| 348 | /* |
|---|
| 349 | * PINT_split_string_list() |
|---|
| 350 | * |
|---|
| 351 | * separates a comma delimited list of items into an array of strings |
|---|
| 352 | * |
|---|
| 353 | * returns the number of strings successfully parsed |
|---|
| 354 | */ |
|---|
| 355 | int PINT_split_string_list(char ***tokens, const char *comma_list) |
|---|
| 356 | { |
|---|
| 357 | |
|---|
| 358 | const char *holder = NULL; |
|---|
| 359 | const char *holder2 = NULL; |
|---|
| 360 | const char *end = NULL; |
|---|
| 361 | int tokencount = 1, retval; |
|---|
| 362 | int i = -1; |
|---|
| 363 | |
|---|
| 364 | if (!comma_list || !tokens) |
|---|
| 365 | { |
|---|
| 366 | return (0); |
|---|
| 367 | } |
|---|
| 368 | |
|---|
| 369 | /* count how many commas we have first */ |
|---|
| 370 | holder = comma_list; |
|---|
| 371 | while ((holder = index(holder, ','))) |
|---|
| 372 | { |
|---|
| 373 | tokencount++; |
|---|
| 374 | holder++; |
|---|
| 375 | } |
|---|
| 376 | |
|---|
| 377 | /* if we don't find any commas, just set the entire string to the first |
|---|
| 378 | * token and return |
|---|
| 379 | */ |
|---|
| 380 | if(0 == tokencount) |
|---|
| 381 | { |
|---|
| 382 | tokencount = 1; |
|---|
| 383 | } |
|---|
| 384 | |
|---|
| 385 | retval = tokencount; |
|---|
| 386 | /* allocate pointers for each */ |
|---|
| 387 | *tokens = (char **) malloc(sizeof(char *) * tokencount); |
|---|
| 388 | if (!(*tokens)) |
|---|
| 389 | { |
|---|
| 390 | return 0; |
|---|
| 391 | } |
|---|
| 392 | |
|---|
| 393 | if(1 == tokencount) |
|---|
| 394 | { |
|---|
| 395 | (*tokens)[0] = strdup(comma_list); |
|---|
| 396 | if(!(*tokens)[0]) |
|---|
| 397 | { |
|---|
| 398 | tokencount = 0; |
|---|
| 399 | goto failure; |
|---|
| 400 | } |
|---|
| 401 | return tokencount; |
|---|
| 402 | } |
|---|
| 403 | |
|---|
| 404 | /* copy out all of the tokenized strings */ |
|---|
| 405 | holder = comma_list; |
|---|
| 406 | end = comma_list + strlen(comma_list); |
|---|
| 407 | for (i = 0; i < tokencount && holder; i++) |
|---|
| 408 | { |
|---|
| 409 | holder2 = index(holder, ','); |
|---|
| 410 | if (!holder2) |
|---|
| 411 | { |
|---|
| 412 | holder2 = end; |
|---|
| 413 | } |
|---|
| 414 | if (holder2 - holder == 0) { |
|---|
| 415 | retval--; |
|---|
| 416 | return (retval); |
|---|
| 417 | } |
|---|
| 418 | (*tokens)[i] = (char *) malloc((holder2 - holder) + 1); |
|---|
| 419 | if (!(*tokens)[i]) |
|---|
| 420 | { |
|---|
| 421 | goto failure; |
|---|
| 422 | } |
|---|
| 423 | strncpy((*tokens)[i], holder, (holder2 - holder)); |
|---|
| 424 | (*tokens)[i][(holder2 - holder)] = '\0'; |
|---|
| 425 | assert(strlen((*tokens)[i]) != 0); |
|---|
| 426 | holder = holder2 + 1; |
|---|
| 427 | } |
|---|
| 428 | |
|---|
| 429 | return (retval); |
|---|
| 430 | |
|---|
| 431 | failure: |
|---|
| 432 | |
|---|
| 433 | /* free up any memory we allocated if we failed */ |
|---|
| 434 | if (*tokens) |
|---|
| 435 | { |
|---|
| 436 | for (i = 0; i < tokencount; i++) |
|---|
| 437 | { |
|---|
| 438 | if ((*tokens)[i]) |
|---|
| 439 | { |
|---|
| 440 | free((*tokens)[i]); |
|---|
| 441 | } |
|---|
| 442 | } |
|---|
| 443 | free(*tokens); |
|---|
| 444 | } |
|---|
| 445 | return (0); |
|---|
| 446 | } |
|---|
| 447 | |
|---|
| 448 | /* PINT_free_string_list() |
|---|
| 449 | * |
|---|
| 450 | * Free the string list allocated by PINT_split_string_list() |
|---|
| 451 | */ |
|---|
| 452 | void PINT_free_string_list(char ** list, int len) |
|---|
| 453 | { |
|---|
| 454 | int i = 0; |
|---|
| 455 | |
|---|
| 456 | if(list) |
|---|
| 457 | { |
|---|
| 458 | for(; i < len; ++i) |
|---|
| 459 | { |
|---|
| 460 | if(list[i]) |
|---|
| 461 | { |
|---|
| 462 | free(list[i]); |
|---|
| 463 | } |
|---|
| 464 | } |
|---|
| 465 | free(list); |
|---|
| 466 | } |
|---|
| 467 | } |
|---|
| 468 | |
|---|
| 469 | /* PINT_remove_base_dir() |
|---|
| 470 | * |
|---|
| 471 | * Get absolute path minus the base dir |
|---|
| 472 | * |
|---|
| 473 | * Parameters: |
|---|
| 474 | * pathname - pointer to directory string |
|---|
| 475 | * out_base_dir - pointer to out dir string |
|---|
| 476 | * max_out_len - max length of out_base_dir buffer |
|---|
| 477 | * |
|---|
| 478 | * All incoming arguments must be valid and non-zero |
|---|
| 479 | * |
|---|
| 480 | * Returns 0 on success; -1 if args are invalid |
|---|
| 481 | * |
|---|
| 482 | * Example inputs and outputs/return values: |
|---|
| 483 | * |
|---|
| 484 | * pathname: /tmp/foo - out_base_dir: foo - returns 0 |
|---|
| 485 | * pathname: /tmp/foo/bar - out_base_dir: bar - returns 0 |
|---|
| 486 | * |
|---|
| 487 | * |
|---|
| 488 | * invalid pathname input examples: |
|---|
| 489 | * pathname: / - out_base_dir: undefined - returns -1 |
|---|
| 490 | * pathname: NULL - out_base_dir: undefined - returns -1 |
|---|
| 491 | * pathname: foo - out_base_dir: undefined - returns -1 |
|---|
| 492 | * |
|---|
| 493 | */ |
|---|
| 494 | int PINT_remove_base_dir( |
|---|
| 495 | const char *pathname, |
|---|
| 496 | char *out_dir, |
|---|
| 497 | int out_max_len) |
|---|
| 498 | { |
|---|
| 499 | int ret = -1, len = 0; |
|---|
| 500 | const char *start, *end, *end_ref; |
|---|
| 501 | |
|---|
| 502 | if (pathname && out_dir && out_max_len) |
|---|
| 503 | { |
|---|
| 504 | if ((strcmp(pathname, "/") == 0) || (pathname[0] != '/')) |
|---|
| 505 | { |
|---|
| 506 | return -PVFS_ENOTDIR; |
|---|
| 507 | } |
|---|
| 508 | |
|---|
| 509 | start = pathname; |
|---|
| 510 | end = pathname + strlen(pathname); |
|---|
| 511 | end_ref = end; |
|---|
| 512 | |
|---|
| 513 | while (end && (end > start) && (*(--end) != '/')); |
|---|
| 514 | |
|---|
| 515 | len = end_ref - ++end; |
|---|
| 516 | if (len < out_max_len) |
|---|
| 517 | { |
|---|
| 518 | memcpy(out_dir, end, len); |
|---|
| 519 | out_dir[len] = '\0'; |
|---|
| 520 | ret = 0; |
|---|
| 521 | } |
|---|
| 522 | } |
|---|
| 523 | return ret; |
|---|
| 524 | } |
|---|
| 525 | |
|---|
| 526 | /* PINT_remove_dir_prefix() |
|---|
| 527 | * |
|---|
| 528 | * Strips prefix directory out of the path, output includes beginning |
|---|
| 529 | * slash |
|---|
| 530 | * |
|---|
| 531 | * Parameters: |
|---|
| 532 | * pathname - pointer to directory string (absolute) |
|---|
| 533 | * prefix - pointer to prefix dir string (absolute) |
|---|
| 534 | * out_path - pointer to output dir string |
|---|
| 535 | * max_out_len - max length of out_base_dir buffer |
|---|
| 536 | * |
|---|
| 537 | * All incoming arguments must be valid and non-zero |
|---|
| 538 | * |
|---|
| 539 | * Returns 0 on success; -errno on failure |
|---|
| 540 | * |
|---|
| 541 | * Example inputs and outputs/return values: |
|---|
| 542 | * |
|---|
| 543 | * pathname: /mnt/pvfs2/foo, prefix: /mnt/pvfs2 |
|---|
| 544 | * out_path: /foo, returns 0 |
|---|
| 545 | * pathname: /mnt/pvfs2/foo, prefix: /mnt/pvfs2/ |
|---|
| 546 | * out_path: /foo, returns 0 |
|---|
| 547 | * pathname: /mnt/pvfs2/foo/bar, prefix: /mnt/pvfs2 |
|---|
| 548 | * out_path: /foo/bar, returns 0 |
|---|
| 549 | * pathname: /mnt/pvfs2/foo/bar, prefix: / |
|---|
| 550 | * out_path: /mnt/pvfs2/foo/bar, returns 0 |
|---|
| 551 | * |
|---|
| 552 | * invalid pathname input examples: |
|---|
| 553 | * pathname: /mnt/foo/bar, prefix: /mnt/pvfs2 |
|---|
| 554 | * out_path: undefined, returns -PVFS_ENOENT |
|---|
| 555 | * pathname: /mnt/pvfs2fake/foo/bar, prefix: /mnt/pvfs2 |
|---|
| 556 | * out_path: undefined, returns -PVFS_ENOENT |
|---|
| 557 | * pathname: /mnt/foo/bar, prefix: mnt/pvfs2 |
|---|
| 558 | * out_path: undefined, returns -PVFS_EINVAL |
|---|
| 559 | * pathname: mnt/foo/bar, prefix: /mnt/pvfs2 |
|---|
| 560 | * out_path: undefined, returns -PVFS_EINVAL |
|---|
| 561 | * out_max_len not large enough for buffer, returns -PVFS_ENAMETOOLONG |
|---|
| 562 | */ |
|---|
| 563 | int PINT_remove_dir_prefix( |
|---|
| 564 | const char *pathname, |
|---|
| 565 | const char *prefix, |
|---|
| 566 | char *out_path, |
|---|
| 567 | int out_max_len) |
|---|
| 568 | { |
|---|
| 569 | int ret = -PVFS_EINVAL; |
|---|
| 570 | int prefix_len, pathname_len; |
|---|
| 571 | int cut_index; |
|---|
| 572 | |
|---|
| 573 | if (!pathname || !prefix || !out_path || !out_max_len) |
|---|
| 574 | { |
|---|
| 575 | return ret; |
|---|
| 576 | } |
|---|
| 577 | |
|---|
| 578 | /* make sure we are given absolute paths */ |
|---|
| 579 | if ((pathname[0] != '/') || (prefix[0] != '/')) |
|---|
| 580 | { |
|---|
| 581 | return ret; |
|---|
| 582 | } |
|---|
| 583 | |
|---|
| 584 | while (pathname[1] == '/') |
|---|
| 585 | pathname++; |
|---|
| 586 | |
|---|
| 587 | prefix_len = strlen(prefix); |
|---|
| 588 | pathname_len = strlen(pathname); |
|---|
| 589 | |
|---|
| 590 | /* account for trailing slashes on prefix */ |
|---|
| 591 | while (prefix[prefix_len - 1] == '/') |
|---|
| 592 | { |
|---|
| 593 | prefix_len--; |
|---|
| 594 | } |
|---|
| 595 | |
|---|
| 596 | /* if prefix_len is now zero, then prefix must have been root |
|---|
| 597 | * directory; return copy of entire pathname |
|---|
| 598 | */ |
|---|
| 599 | if (prefix_len == 0) |
|---|
| 600 | { |
|---|
| 601 | cut_index = 0; |
|---|
| 602 | } |
|---|
| 603 | else |
|---|
| 604 | { |
|---|
| 605 | |
|---|
| 606 | /* make sure prefix would fit in pathname */ |
|---|
| 607 | if (prefix_len > (pathname_len + 1)) |
|---|
| 608 | return (-PVFS_ENOENT); |
|---|
| 609 | |
|---|
| 610 | /* see if we can find prefix at beginning of path */ |
|---|
| 611 | if (strncmp(prefix, pathname, prefix_len) == 0) |
|---|
| 612 | { |
|---|
| 613 | /* apparent match; see if next element is a slash */ |
|---|
| 614 | if ((pathname[prefix_len] != '/') && |
|---|
| 615 | (pathname[prefix_len] != '\0')) |
|---|
| 616 | return (-PVFS_ENOENT); |
|---|
| 617 | |
|---|
| 618 | /* this was indeed a match */ |
|---|
| 619 | /* in the case of no trailing slash cut_index will point to the end |
|---|
| 620 | * of "prefix" (NULL). */ |
|---|
| 621 | cut_index = prefix_len; |
|---|
| 622 | } |
|---|
| 623 | else |
|---|
| 624 | { |
|---|
| 625 | return (-PVFS_ENOENT); |
|---|
| 626 | } |
|---|
| 627 | } |
|---|
| 628 | |
|---|
| 629 | /* if we hit this point, then we were successful */ |
|---|
| 630 | |
|---|
| 631 | /* is the buffer large enough? */ |
|---|
| 632 | if ((1 + strlen(&(pathname[cut_index]))) > out_max_len) |
|---|
| 633 | return (-PVFS_ENAMETOOLONG); |
|---|
| 634 | |
|---|
| 635 | /* try to handle the case of no trailing slash */ |
|---|
| 636 | if (pathname[cut_index] == '\0') |
|---|
| 637 | { |
|---|
| 638 | out_path[0] = '/'; |
|---|
| 639 | out_path[1] = '\0'; |
|---|
| 640 | } |
|---|
| 641 | else |
|---|
| 642 | /* copy out appropriate part of pathname */ |
|---|
| 643 | strcpy(out_path, &(pathname[cut_index])); |
|---|
| 644 | |
|---|
| 645 | return (0); |
|---|
| 646 | } |
|---|
| 647 | |
|---|
| 648 | char *PINT_merge_handle_range_strs(char *range1, char *range2) |
|---|
| 649 | { |
|---|
| 650 | char *merged_range = NULL; |
|---|
| 651 | |
|---|
| 652 | if (range1 && range2) |
|---|
| 653 | { |
|---|
| 654 | int rlen1 = strlen(range1) * sizeof(char) + 1; |
|---|
| 655 | int rlen2 = strlen(range2) * sizeof(char) + 1; |
|---|
| 656 | /* |
|---|
| 657 | 2 bytes bigger since we need a tz null and space for the |
|---|
| 658 | additionally inserted comma |
|---|
| 659 | */ |
|---|
| 660 | merged_range = (char *)malloc(rlen1 + rlen2); |
|---|
| 661 | snprintf(merged_range, rlen1 + rlen2, "%s,%s", |
|---|
| 662 | range1,range2); |
|---|
| 663 | } |
|---|
| 664 | return merged_range; |
|---|
| 665 | } |
|---|
| 666 | |
|---|
| 667 | #ifndef HAVE_STRNLEN |
|---|
| 668 | /* a naive implementation of strnlen for systems w/o glibc */ |
|---|
| 669 | size_t strnlen(const char *s, size_t limit) |
|---|
| 670 | { |
|---|
| 671 | size_t len = 0; |
|---|
| 672 | while ((len < limit) && (*s++)) |
|---|
| 673 | len++; |
|---|
| 674 | return len; |
|---|
| 675 | } |
|---|
| 676 | #endif |
|---|
| 677 | |
|---|
| 678 | #ifndef HAVE_STRSTR |
|---|
| 679 | /* a custom implementation of strstr for systems w/o it */ |
|---|
| 680 | char *strstr(const char *haystack, const char *needle) |
|---|
| 681 | { |
|---|
| 682 | char *ptr = NULL; |
|---|
| 683 | int needle_len = 0; |
|---|
| 684 | int remaining_len = 0; |
|---|
| 685 | |
|---|
| 686 | ptr = (char *)haystack; |
|---|
| 687 | if (haystack && needle) |
|---|
| 688 | { |
|---|
| 689 | needle_len = strlen(needle); |
|---|
| 690 | remaining_len = strlen(haystack); |
|---|
| 691 | |
|---|
| 692 | while(ptr) |
|---|
| 693 | { |
|---|
| 694 | if (*ptr == *needle) |
|---|
| 695 | { |
|---|
| 696 | if (memcmp(ptr, needle, needle_len) == 0) |
|---|
| 697 | { |
|---|
| 698 | break; |
|---|
| 699 | } |
|---|
| 700 | } |
|---|
| 701 | ptr++; |
|---|
| 702 | remaining_len--; |
|---|
| 703 | |
|---|
| 704 | if ((remaining_len < needle_len) || (*ptr == '\0')) |
|---|
| 705 | { |
|---|
| 706 | ptr = NULL; |
|---|
| 707 | break; |
|---|
| 708 | } |
|---|
| 709 | } |
|---|
| 710 | } |
|---|
| 711 | return ptr; |
|---|
| 712 | } |
|---|
| 713 | #endif |
|---|
| 714 | |
|---|
| 715 | /* |
|---|
| 716 | * PINT_split_keyvals() |
|---|
| 717 | * |
|---|
| 718 | * Splits a given string into a number of key:val strings. |
|---|
| 719 | * |
|---|
| 720 | * Parameters: |
|---|
| 721 | * The given string must be comma separated, and each |
|---|
| 722 | * segment within the comma regions must be of of |
|---|
| 723 | * the form key:val. |
|---|
| 724 | * Return the number of such keyval pairs and a |
|---|
| 725 | * pointer to a double dimensional array of keys and values. |
|---|
| 726 | * In case of errors, a -ve PVFS error is returned. |
|---|
| 727 | * |
|---|
| 728 | * Example inputs and return values: |
|---|
| 729 | * |
|---|
| 730 | * NULL - return -PVFS_EINVAL |
|---|
| 731 | * ab:23 - return nkey as 1, pkey <"ab">, pval <"23"> |
|---|
| 732 | * ab:23,bc:34 - returns nkey as 2, pkey <"ab", "bc">, pval<"23", "34"> |
|---|
| 733 | * |
|---|
| 734 | */ |
|---|
| 735 | int PINT_split_keyvals(char *string, int *nkey, |
|---|
| 736 | char ***pkey, char ***pval) |
|---|
| 737 | { |
|---|
| 738 | char **key, **val, *ptr, *params; |
|---|
| 739 | int nparams = 0, i; |
|---|
| 740 | |
|---|
| 741 | if (string == NULL || nkey == NULL |
|---|
| 742 | || pkey == NULL || pval == NULL) |
|---|
| 743 | { |
|---|
| 744 | return -PVFS_EINVAL; |
|---|
| 745 | } |
|---|
| 746 | params = strdup(string); |
|---|
| 747 | if (params == NULL) |
|---|
| 748 | { |
|---|
| 749 | return -PVFS_ENOMEM; |
|---|
| 750 | } |
|---|
| 751 | ptr = params; |
|---|
| 752 | while (ptr) |
|---|
| 753 | { |
|---|
| 754 | if (*ptr != ',' || *ptr != '\0') |
|---|
| 755 | nparams++; |
|---|
| 756 | ptr++; |
|---|
| 757 | ptr = strchr(ptr, ','); |
|---|
| 758 | } |
|---|
| 759 | if (nparams == 0) |
|---|
| 760 | { |
|---|
| 761 | free(params); |
|---|
| 762 | return -PVFS_EINVAL; |
|---|
| 763 | } |
|---|
| 764 | ptr = params; |
|---|
| 765 | key = (char **) calloc(nparams, sizeof(char *)); |
|---|
| 766 | val = (char **) calloc(nparams, sizeof(char *)); |
|---|
| 767 | if (key == NULL || val == NULL) |
|---|
| 768 | { |
|---|
| 769 | free(key); |
|---|
| 770 | free(val); |
|---|
| 771 | free(params); |
|---|
| 772 | return -PVFS_ENOMEM; |
|---|
| 773 | } |
|---|
| 774 | for (i = 0; i < nparams; i++) |
|---|
| 775 | { |
|---|
| 776 | char *ptr2; |
|---|
| 777 | if (i > 0 && ptr) |
|---|
| 778 | { |
|---|
| 779 | *ptr = '\0'; |
|---|
| 780 | ptr++; |
|---|
| 781 | } |
|---|
| 782 | else if (ptr == NULL) |
|---|
| 783 | { |
|---|
| 784 | break; |
|---|
| 785 | } |
|---|
| 786 | ptr2 = strchr(ptr, ':'); |
|---|
| 787 | if (ptr2 == NULL) |
|---|
| 788 | { |
|---|
| 789 | break; |
|---|
| 790 | } |
|---|
| 791 | key[i] = ptr; |
|---|
| 792 | ptr = strchr(ptr, ','); |
|---|
| 793 | if (ptr != NULL && ptr < ptr2) |
|---|
| 794 | { |
|---|
| 795 | break; |
|---|
| 796 | } |
|---|
| 797 | *ptr2 = '\0'; |
|---|
| 798 | val[i] = ptr2 + 1; |
|---|
| 799 | } |
|---|
| 800 | if (i != nparams) |
|---|
| 801 | { |
|---|
| 802 | free(key); |
|---|
| 803 | free(val); |
|---|
| 804 | free(params); |
|---|
| 805 | return -PVFS_EINVAL; |
|---|
| 806 | } |
|---|
| 807 | else |
|---|
| 808 | { |
|---|
| 809 | for (i = 0; i < nparams; i++) |
|---|
| 810 | { |
|---|
| 811 | char *ptr1, *ptr2; |
|---|
| 812 | ptr1 = strdup(key[i]); |
|---|
| 813 | ptr2 = strdup(val[i]); |
|---|
| 814 | if (ptr1 == NULL || ptr2 == NULL) |
|---|
| 815 | break; |
|---|
| 816 | if (strchr(ptr1, ':') || strchr(ptr2, ':')) |
|---|
| 817 | break; |
|---|
| 818 | key[i] = ptr1; |
|---|
| 819 | val[i] = ptr2; |
|---|
| 820 | } |
|---|
| 821 | if (i != nparams) |
|---|
| 822 | { |
|---|
| 823 | int j; |
|---|
| 824 | for (j = 0; j < i; j++) |
|---|
| 825 | { |
|---|
| 826 | if (key[j]) free(key[j]); |
|---|
| 827 | if (val[j]) free(val[j]); |
|---|
| 828 | } |
|---|
| 829 | free(key); |
|---|
| 830 | free(val); |
|---|
| 831 | free(params); |
|---|
| 832 | return -PVFS_EINVAL; |
|---|
| 833 | } |
|---|
| 834 | free(params); |
|---|
| 835 | *nkey = nparams; |
|---|
| 836 | *pkey = key; |
|---|
| 837 | *pval = val; |
|---|
| 838 | return 0; |
|---|
| 839 | } |
|---|
| 840 | } |
|---|
| 841 | |
|---|
| 842 | |
|---|
| 843 | /* |
|---|
| 844 | * Local variables: |
|---|
| 845 | * c-indent-level: 4 |
|---|
| 846 | * c-basic-offset: 4 |
|---|
| 847 | * End: |
|---|
| 848 | * |
|---|
| 849 | * vim: ts=8 sts=4 sw=4 expandtab |
|---|
| 850 | */ |
|---|
| 851 | |
|---|
| 852 | |
|---|