static void print_stack_trace(pid_t pid, int * count) { void * pinfo = NULL; unw_addr_space_t aspace = NULL; unw_cursor_t cursor; unw_word_t ip, sp; char nbuf[256]; unw_word_t off; int ret; if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) { fprintf(stderr, "Failed to attach to process %llu: %s\n", (unsigned long long)pid, strerror(errno)); return; } /* Wait until the attach is complete. */ waitpid(pid, NULL, 0); if (((pinfo = _UPT_create(pid)) == NULL) || ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) { /* Probably out of memory. */ fprintf(stderr, "Unable to initialize stack unwind for process %llu\n", (unsigned long long)pid); goto cleanup; } if ((ret = unw_init_remote(&cursor, aspace, pinfo))) { fprintf(stderr, "Unable to unwind stack for process %llu: %s\n", (unsigned long long)pid, unw_strerror(ret)); goto cleanup; } if (*count > 0) { printf("\n"); } if (procname(pid, nbuf, sizeof(nbuf))) { printf("Stack trace for process %llu (%s):\n", (unsigned long long)pid, nbuf); } else { printf("Stack trace for process %llu:\n", (unsigned long long)pid); } while (unw_step(&cursor) > 0) { ip = sp = off = 0; unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off); if (ret != 0 && ret != -UNW_ENOMEM) { snprintf(nbuf, sizeof(nbuf), "<unknown symbol>"); } printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n", nbuf, (long long)off, (long long)ip, (long long)sp); } (*count)++; cleanup: if (aspace) { unw_destroy_addr_space(aspace); } if (pinfo) { _UPT_destroy(pinfo); } ptrace(PTRACE_DETACH, pid, NULL, NULL); }
char *format_c() { return procname(); }
/** * @brief Method to determine the rank and size on the local node * * If the program is running on multiple nodes, it can be useful to know the * rank and size of the part of the program running on the local node, e.g. to * write output files per node. * * MPI does not provide standard functions to do this, so we have to do it * ourselves. The method below is based on a suggestion by Markus Wittmann on * his blog * (https://blogs.fau.de/wittmann/2013/02/mpi-node-local-rank-determination/). * * We use MPI_Comm_split to create a new communicator based on a color which is * derived from the processor name, obtained from MPI_Get_processor_name. The * local rank and size are then obtained by calling MPI_Comm_rank and * MPI_Comm_size on this new communicator. * * Because it is impossible to define a completely unique hash function to * convert node names to integer colors, we do a collective gather on the * newly created communicator for the node names. We then check if the names * are really different. If not, we do a second communicator split, where this * time we use the index of the own node name in the node name list as a color. * Since this second collective operation is done on a much smaller * communicator (which should be the local node for most cases), it is much * faster than using the same method at the start. * * @param rank Variable to store the local rank of this process in * @param size Variable to store the local size of the node in * @param noderank Rank of the node in the space of all nodes * @param nodesize Size of the space of all nodes * @param nodecomm Variable to store the local node communicator in */ inline void MyMPI_Comm_local_vars(int* rank, int* size, int* noderank, int* nodesize, MPI_Comm* nodecomm) { MPIGlobal::commtimer.start(); char* name = new char[MPI_MAX_PROCESSOR_NAME]; int namesize; int status = MyMPI_Get_processor_name(name, &namesize); if(status != MPI_SUCCESS) { std::cerr << "Error while obtaining MPI processor name!" << std::endl; my_exit(); } name[namesize] = '\0'; std::string procname(name); int color = MyMPI_hash(procname); MPI_Comm local_world = MPI_COMM_NULL; status = MPI_Comm_split(MPI_COMM_WORLD, color, MPIGlobal::rank, &local_world); if(status != MPI_SUCCESS) { std::cerr << "Error while splitting MPI communicator in local MPI " "communicators!" << std::endl; my_exit(); } status = MPI_Comm_rank(local_world, rank); if(status != MPI_SUCCESS) { std::cerr << "Error while obtaining local MPI rank!" << std::endl; my_exit(); } status = MPI_Comm_size(local_world, size); if(status != MPI_SUCCESS) { std::cerr << "Error while obtaining local MPI size!" << std::endl; my_exit(); } // check if the processes in local_world are really on a single node char* allnames = new char[(*size) * MPI_MAX_PROCESSOR_NAME]; status = MPI_Allgather(name, MPI_MAX_PROCESSOR_NAME, MPI_CHAR, allnames, MPI_MAX_PROCESSOR_NAME, MPI_CHAR, local_world); if(status != MPI_SUCCESS) { std::cerr << "Error while gathering processor names on the presumably " "local communicator!" << std::endl; my_exit(); } int owni = 0; bool is_single = true; for(int i = 0; i < (*size); i++) { std::string othername(&allnames[i * MPI_MAX_PROCESSOR_NAME]); if(othername != procname) { is_single = false; } else { owni = i; } } if(!is_single) { MPI_Comm real_local_world = MPI_COMM_NULL; status = MPI_Comm_split(local_world, owni, (*rank), &real_local_world); if(status != MPI_SUCCESS) { std::cerr << "Error while splitting the local communicator in the " "real node communicators!" << std::endl; my_exit(); } status = MPI_Comm_rank(real_local_world, rank); if(status != MPI_SUCCESS) { std::cerr << "Error while obtaining real local MPI rank!" << std::endl; my_exit(); } status = MPI_Comm_size(real_local_world, size); if(status != MPI_SUCCESS) { std::cerr << "Error while obtaining real local MPI size!" << std::endl; my_exit(); } status = MPI_Comm_free(&real_local_world); if(status != MPI_SUCCESS) { std::cerr << "Error while freeing real local MPI communicator!" << std::endl; my_exit(); } status = MPI_Comm_dup(real_local_world, nodecomm); if(status != MPI_SUCCESS) { std::cerr << "Error while duplicating local MPI communicator!" << std::endl; my_exit(); } } else { status = MPI_Comm_dup(local_world, nodecomm); if(status != MPI_SUCCESS) { std::cerr << "Error while duplicating local MPI communicator!" << std::endl; my_exit(); } } status = MPI_Comm_free(&local_world); if(status != MPI_SUCCESS) { std::cerr << "Error while freeing local MPI communicator!" << std::endl; my_exit(); } delete[] name; // obtain noderank and nodesize MPI_Comm nodeworld; int nodemaster = (*rank == 0); status = MPI_Comm_split(MPI_COMM_WORLD, nodemaster, MPIGlobal::rank, &nodeworld); if(status != MPI_SUCCESS) { std::cerr << "Error while obtaining node world!" << std::endl; my_exit(); } if(*rank == 0) { status = MPI_Comm_rank(nodeworld, noderank); if(status != MPI_SUCCESS) { std::cerr << "Error while obtaining noderank!" << std::endl; my_exit(); } status = MPI_Comm_size(nodeworld, nodesize); if(status != MPI_SUCCESS) { std::cerr << "Error while obtaining nodesize!" << std::endl; my_exit(); } } status = MPI_Comm_free(&nodeworld); if(status != MPI_SUCCESS) { std::cerr << "Error while freeing nodeworld!" << std::endl; my_exit(); } status = MPI_Bcast(noderank, 1, MPI_INT, 0, *nodecomm); if(status != MPI_SUCCESS) { std::cerr << "Error while broadcasting noderank!" << std::endl; my_exit(); } status = MPI_Bcast(nodesize, 1, MPI_INT, 0, *nodecomm); if(status != MPI_SUCCESS) { std::cerr << "Error while broadcasting nodesize!" << std::endl; my_exit(); } MPIGlobal::commtimer.stop(); }
/* =========================================================================== * Process a name or wildcard expression to operate on (or exclude). * We will only arrive here if we do a Freshen or Delete. * Return an error code in the ZEN_ class. * ZEN_OK, ZEN_ABORT, ZEN_MISS03, ZEN_MISS04, ZEN_MISS05, ZEN_MEM22, ZEN_MEM23 *ArgName :: Name to process. */ int procname( char *ArgName, bool RecurseDir, struct Globals *pG ) { char *a; /* path and name for recursion */ zDIR *d; /* directory stream from opendir() */ char *e; /* pointer to name from readd() */ int m; /* matched flag */ char *p; /* path for recursion */ int pnError; /* ProcName error */ struct stat StatRes; /* result of stat() */ struct zlist *z; /* steps through zfiles list */ // sprintf( ewemsg, "in procname name=>%s<= recurse=%d", ArgName, RecurseDir ); // diag( ewemsg ); m = 1; /* set dflt for success indicator (0=success) */ if ( pG->global_abort_sw ) return ZEN_ABORT; /* RCV changed was ZEN_MISS? */ if ( *ArgName == '\0' ) return ZEN_MISS03; /* LSSTAT returns 0 if it's arg is any kind of file (even a dir). */ /* IsShExp returns true if a wildcard symbol is found, or * NULL if none were found -- IsShExp is in util.c */ if ( LSSTAT( GetFullPath( pG, ArgName ), &StatRes ) || (IsShExp( ArgName ) != NULL) ) { // diag( "not a file or dir - 'ArgName' must be a wildcard fspec" ); // Upon finding a wildcard fspec, we need to mark entries in // the "zfiles" list that are included by the wildcard. /* convert the "external" (native) filename to an internal * ZIP-archive-compatible filename. */ p = ex2in( ArgName, (int *)NULL, pG ); /* shouldn't affect matching chars */ /* does any file already in the archive match this spec? */ /* Note that we need the pathname and filename together for this */ for ( z = pG->zfiles; z; z = z->nxt ) { if ( dosmatch( p, z->zname, pG ) ) { /* name is in archive - mark it for updating */ z->mark = pG->pcount ? filter( z->zname, pG ) : 1; FREE( z->name ); // RCV added + next 8 lines needed for FRESHEN mode. if ( (z->name = MALLOC( lstrlen( z->zname ) + 4 )) == NULL ) return ZEN_MEM34; z->name[0] = '\0'; //v1.55 if ( isalpha( ArgName[0] ) && ArgName[1] == ':' && ArgName[2] == '\\') { z->name[0] = ArgName[0]; z->name[1] = ArgName[1]; z->name[2] = ArgName[2]; z->name[3] = '\0'; } lstrcat( z->name, z->zname ); if ( pG->verbose ) printf( "%scluding %s\n", z->mark ? "in" : "ex", z->name ); m = 0; /* we had at least one file in the archive that we marked */ } } FREE( p ); /* returns 1 if no "zfiles" entries were marked, * 0 if at least one entry was marked */ if ( m ) { // diag( "returning ZEN_MISS04 from procname" ); return ZEN_MISS04; } // diag( "returning ZEN_OK from procname" ); return ZEN_OK; } /* end of "if (LSSTAT..." */ /* Existing and good filename or directory-- add the name if it's a file, recurse if directory */ // diag( "good entry to add, or a dir to go into" ); /* check the status returned by LSSTAT earlier to see if 'ArgName' is a dir */ pnError = ZEN_OK; if ( !(StatRes.st_mode & S_IFDIR) ) { /* it's not a directory - add file to found list */ sprintf( pG->ewemsg, "spot 1: Add file %s to found list", ArgName ); diag( pG->ewemsg, pG ); /* newname (fileio.c) adds to found list. If error m!=0 on return */ if ( (m = newname( ArgName, StatRes.st_size, pG )) != ZEN_OK ) { sprintf( pG->ewemsg, "returning %d from procname after newname call", m ); diag( pG->ewemsg, pG ); return m; } } else { /* It is a directory - Add trailing / to the directory name */ // diag( "Spot 2, directory found" ); if ( (p = MALLOC( lstrlen( ArgName )+ 2) ) == NULL ) return ZEN_MEM22; if ( !strcmp( ArgName, "." ) || !strcmp( ArgName, "\\." ) ) { // SLASH *p = '\0'; /* avoid "./" prefix and do not create zip entry */ } else { // diag( "spot 3" ); lstrcpy( p, ArgName ); a = p + lstrlen( p ); if ( a[-1] != '\\' ) lstrcpy( a, "\\" ); // SLASH /* newname (fileio.c) adds to found list. If error m != 0 on return */ if ( pG->dirnames && (m = newname( p, 0, pG )) != ZEN_OK ) { FREE( p ); sprintf( pG->ewemsg, "returning %d from procname after 2nd newname call", m ); diag( pG->ewemsg, pG ); return m; } } /* recurse into directory */ // diag( "spot 4: optional recurse into dir" ); if ( RecurseDir && ((d = Opendir( ArgName, pG )) != NULL) ) { /* Open new dir (like chdir) */ // diag( "good open of dir" ); while ( (e = readd( d, pG )) != NULL ) { if ( pG->global_abort_sw ) { // RCV changed error handling pnError = ZEN_ABORT; break; } /* e is pointing to the new filename we just read from dir */ /* ignore dir entries of . and .. */ if ( strcmp( e, "." ) && strcmp( e, ".." ) ) { /* get a new tmp buffer for the path and fname */ if ( (a = MALLOC( lstrlen( p ) + lstrlen( e ) + 1 )) == NULL ) { pnError = ZEN_MEM23; /* RCV error handling changed */ break; } /* form the new dir's pathname followed by the fname just read */ /* (we need to send in the dir and fname, or it won't be * detected as a valid file by LSSTAT) */ lstrcat( lstrcpy( a, p ), e ); // diag( "DOING RECURSIVE CALL TO PROCNAME FROM PROCNAME" ); if ( (m = procname( a, RecurseDir, pG )) != ZEN_OK ) { /* recursive call failed; return code not ZEN_OK */ if ( m != ZEN_OK && m != ZEN_MISS05 ) { /* unknown error; RCV error handling changed */ pnError = m; FREE( a ); break; } else if ( (int)(char)(m & 0xFF) == ZEN_MISS ) zipwarn( "name not matched: ", a ); } FREE( a ); } } /* end while */ Closedir( d ); } /* end if (spot 4) */ FREE( p ); } /* (StatRes.st_mode & S_IFDIR) == 0) */ // diag( "returning ZEN_ class from procname" ); return pnError; }
/* =========================================================================== * If not in exclude mode, expand the pattern based on the contents * of the file system. * This function is used while gathering filenames to be added or updated *w :: Path/pattern to match. Possible return values: ZEN_MISS, ZEN_OK, ZEN_ABORT, ZEN_MEM or ZEN_PARMS. */ int Wild( char *w, struct Globals *pG ) { zDIR *d; /* Stream for reading directory */ char *e; /* File or directory name found. */ char *n; /* Constructed name from directory */ int WError; /* Result of Wild() */ char *p, *a; /* path originale and fixed. */ char *q; /* Filename / pattern. */ int r; /* Result / temp var. */ char v[5]; /* space for device current directory.*/ bool StopRecurs = false; /* No recursion if filespec is file. */ // sprintf( pG->ewemsg, "in Wild of win32zip.c, pattern=%s recurse=%d", w, pG->recurse ); // diag( pG->ewemsg, pG ); // "zip -$ foo a:" can be used to force a drive name once. // v1.6017 if ( pG->volume_label == 1 ) { pG->volume_label = 2; pG->label = getVolumeLabel( pG, (w != NULL && w[ 1 ] == ':') ? to_up( w[ 0 ] ) : '\0', &pG->label_time, &pG->label_mode, &pG->label_utim ); if ( pG->label != NULL ) (void)newname( pG->label, 0, pG ); if ( w == NULL || (w[1] == ':' && w[2] == '\0') ) return ZEN_OK; } /* Allocate and copy pattern */ if ( (p = a = MALLOC( lstrlen( w ) + 1) ) == NULL ) return ZEN_MEM19; lstrcpy( p, w ); /* Separate path and name into p and q */ // We have '\' or '\name' or 'path1\path2\name2' or 'C:\path\name' but NOT 'C:\name' if ( (q = strrchr( p, '\\' )) != NULL && (q == p || q[-1] != ':') ) { // SLASH *q++ = '\0'; if ( *p == '\0' ) p = lstrcpy( v, "\\." ); /* if path is just '\' SLASH */ } else if ( (q = strrchr( p, ':' )) != NULL ) { /* We have 'C:' or 'C:\' or 'C:\name' */ *q++ = '\0'; p = lstrcat( lstrcpy( v, p ), ":" ); /* copy device as path eg. 'C:' */ if ( *q == '\\' ) { /* -> device:/., name eg. 'C:\.' SLASH */ lstrcat( p, "\\" ); // SLASH q++; /* name or nothing. */ } lstrcat( p, "." ); /* eg. 'C:.' or 'C:\.' */ } else if ( pG->recurse && (!strcmp( p, "." ) || !strcmp( p, ".." )) ) { /* current or parent directory */ /* Get "zip -r foo ." to work. Allow the dubious "zip -r foo .." but * reject "zip -r -m foo ..". "dispose" means wipe out source path. */ if ( pG->dispose && !strcmp( p, ".." ) ) ziperr( ZEN_PARMS15, pG ); q = (char *)pG->wild_match_all; } else { /* no path or device */ q = p; p = lstrcpy( v, "." ); } if ( pG->recurse && *q == '\0' ) q = (char *)pG->wild_match_all; /* take out a possibly redundant dir name of "." */ if ( (r = lstrlen( p )) > 1 && (strcmp( p + r - 2, ":." ) == 0 || strcmp( p + r - 2, "\\." ) == 0) ) // SLASH *(p + r - 1) = '\0'; /* Only filename (not the path) can have special matching characters */ if ( IsShExp( p ) ) { diag( "path has illegal chars", pG ); FREE( a ); return ZEN_PARMS16; } // sprintf( ewemsg, "at break up place in Wild: path=%s name=%s", p, q ); // diag( ewemsg ); if ( !IsShExp( q ) ) { // Speed up checking if file exits in case there are no wildcards struct stat s; // and no recursion and no archiving v1.6016 if ( !pG->recurse && !pG->ArchiveFiles ) { if ( !LSSTAT( GetFullPath( pG, w ), &s ) ) /* file exists ? */ return procname( w, false, pG ); return ZEN_MISS02; /* woops, no wildcards where is the file! */ } if ( pG->norecursefiles ) StopRecurs = true; } /* Now that we have a dir spec, along with an fspec, we'll step * in the dir specified to see if there's any matches against the fspec. */ WError = ZEN_MISS02; if ( (d = Opendir( p, pG )) != NULL ) { while ( (e = readd( d, pG )) != NULL ) { if ( pG->global_abort_sw ) { WError = ZEN_ABORT; break; } // sprintf( ewemsg, "Found %s: %s", d->d_attr & FILE_ATTRIBUTE_DIRECTORY ? "directory" : "file", e ); // diag( ewemsg ); /* if e is NOT '.' or '..', and is a dir or match fspec. */ if ( strcmp( e, "." ) && strcmp( e, ".." ) && (d->d_attr & FILE_ATTRIBUTE_DIRECTORY || dosmatch( q, e, pG )) ) { // diag( "Matched" ); /* we matched fspec or it's a dir and entry is not '.' or '..' */ if ( d->d_attr & FILE_ATTRIBUTE_DIRECTORY ) { // We do not save dirs or go into dirs if norecursefiles==1 and we a file without * or ? specs. if ( !StopRecurs && (pG->dirnames || pG->recurse) ) { if ( (n = MALLOC( lstrlen( p ) + lstrlen( e ) + lstrlen( q ) + 3 )) == NULL ) { WError = ZEN_MEM20; break; } *n = '\0'; if ( *p != '.' ) AddSlash( lstrcpy( n, p ) ); // No ./ as first dir. lstrcat( n, e ); if ( pG->dirnames ) { // Save directory names also. r = procname( n, false, pG ); if ( (int)(char)(r & 0xFF) > ZEN_OK || !pG->recurse ) FREE( n ); if ( (int)(char)(r & 0xFF) > (int)(char)(WError & 0xFF) ) WError = r; if ( (int)(char)(r & 0xFF) > ZEN_OK ) break; } if ( pG->recurse ) { // Recursively go into dir and check for other pattern matches. r = Wild( lstrcat( AddSlash( n ), q ), pG ); // Add the original pattern. FREE( n ); // We keep a ZEN_OK even when ZEN_MISS occurs. if ( (int)(char)(r & 0xFF) > (int)(char)(WError & 0xFF) ) WError = r; if ( (int)(char)(r & 0xFF) > ZEN_OK ) break; // An error, stop processing. } } } else { if ( (n = MALLOC( lstrlen( p ) + lstrlen( e ) + 2 )) == NULL ) { WError = ZEN_MEM21; break; } if ( !strcmp( p, "." ) ) r = procname( e, false, pG ); else r = procname( lstrcat( AddSlash( lstrcpy( n, p ) ), e ), false, pG ); FREE( n ); if ( (int)(char)(r & 0xFF) > (int)(char)(WError & 0xFF) ) WError = r; if ( (int)(char)(r & 0xFF) > ZEN_OK ) break; } } /* end "if (strcmp..." */ } /* end while */ Closedir( d ); } else diag( "can't open dir", pG ); FREE( a ); // sprintf( ewemsg, "Wild returned: %d", WError ); // diag( ewemsg ); return WError; }
/* =========================================================================== select files to be processed */ int ZipSelect(struct Globals *pG, const ZCL2 *C) { int i; // arg counter, root directory flag int k; // next argument type, marked counter, const char *p; // steps through option arguments int r; // temporary variable long g_before; // 1.74 global 'before' int argno, arg1; if ((p = getenv("TZ")) == NULL || *p == '\0') pG->extra_fields = 0; // disable storing "Unix" time stamps SetExclFilters(pG); // Process arguments diag("ready to read zip file", pG); // the read will be done in file: zipfile.c if ((r = readzipfile(pG)) != ZEN_OK) { diag("err returned from \"readzipfile\"", pG); return (ziperr(r, pG)); } if (pG->action == UPDATE || pG->action == FRESHEN) pG->doall = 1; r = 0; arg1 = - 1; g_before = pG->before; for (argno = 0; !r && argno < C->fTotFileSpecs; argno++) { char *fspec; FileData *fileArg = &C->fFDS[argno]; if (!fileArg) continue; fspec = fileArg->fFileSpec; if (!fspec || *fspec == '>') continue; pG->FileArg = fileArg; pG->key = 0; //pG->user_key; // set globals pG->recurse = fileArg->fRecurse; r = C->fLevel; r = r < 0 ? 0 : (r > 9 ? 9 : r); if (r != pG->level) { pG->level = r; pG->method = r ? DEFLATE : STORE; if (pG->verbose) Inform(pG, 0, IDIAG, "setting compression level to %d", r); } // Set the new RootDir if needed; DLL v1.608, Component v1.60L if (fileArg->fRootDir) { // We can't use SetCurrentDirectory() because there is only one cd // in each process // when a user uses threads it went wrong. FREE(pG->OrigCurrentDir); // DLL v1.6017 pG->OCDlength = lstrlen(fileArg->fRootDir); if ((pG->OrigCurrentDir = (char*)MALLOC(pG->OCDlength + 2)) == NULL) { // RP allow space for '\' Inform(pG, ZEN_MEM36, 0, "CurrentDir allocation error"); return ziperr(ZEN_MEM36, pG); } lstrcpy(pG->OrigCurrentDir, fileArg->fRootDir); if (pG->verbose) Inform(pG, 0, IERROR, "Root dir now %s", pG->OrigCurrentDir); } if (C->fVersion > 178) { if (fileArg->fLevel) { r = fileArg->fLevel; r = r < 0 ? 0 : (r > 9 ? 9 : r); if (r != pG->level) { pG->level = r; pG->method = r ? DEFLATE : STORE; if (pG->verbose) Inform(pG, 0, IDIAG, "setting compression level to %d", r); } } if (fileArg->fFromDate) pG->before = fileArg->fFromDate == (unsigned) - 1 ? 0 : fileArg ->fFromDate; else pG->before = g_before; } #ifdef USE_STRM_INPUT if (arg1 < 0) { arg1 = argno; if (pG->UseInStream) { // Here we fill in the FoundList from the input stream data // newname (fileio.c) adds to found list. If error m!=0 on return if ((r = newname(fspec, pG->InStreamSize, pG)) != ZEN_OK) { if (pG->verbose) Inform(pG, 0, IDIAG, "Stream filename could not be added in newname call"); if (pG->zcount) FREE(pG->zsort); return r; } break; } } #endif #ifdef CRYPT if (fileArg->fEncrypt) { pG->key = fileArg->fPassword; if (!pG->key || !*(pG->key)) { // use global if ((r = GetUserPW(pG)) != ZEN_OK) break; pG->key = pG->user_key; } // pG->doesEncrypt = 1; // 1.73 } #endif pG->doall = 0; // do selected if ((pG->action == ADD) || (pG->action == UPDATE)) { if (pG->verbose) Inform(pG, 0, IDIAG, "collecting %s %s", fspec, pG->recurse ? "recurse" : " "); r = Wild(fspec, pG); } else // Freshen or Delete - must be internal file { if (pG->verbose) Inform(pG, 0, IDIAG, "collecting %s %s", fspec, pG->recurse ? "recurse" : " "); r = procname(fspec, pG->recurse, pG); } if (r != ZEN_OK) { if ((int)(char)(r &0xFF) == ZEN_MISS) { /* this occurs if new file wasn't found */ Inform(pG, r, IERROR, "File specification \"%s\" skipped", fspec); r = 0; } } if (r) return ziperr(r, pG); } return 0; }