int xchdir(char *path, t_sllist **myenv) { clear_path(path); if (chdir(path) == -1) { fprintf(stderr, "%s%s", path, ERR_ISNOTFOLD); return (EXIT_FAILURE); } else { my_setenv("OLDPWD", my_getenv("PWD", *myenv), myenv); my_setenv("PWD", path, myenv); } return (EXIT_SUCCESS); }
static void setup_torque_env() { char *ptr; if ((ptr = getenv("PBS_HOME"))) { torque_home() = ptr; }else if ((ptr = getenv("PBS_SERVER_HOME"))) { torque_home() = ptr; } else if ((ptr = getenv("PBS_NODEFILE"))) { torque_home() = torque_home_nodefile(ptr); } if( torque_home().size() ){ clear_path(torque_home()); rem_trailing_slash(torque_home()); } }
boolean linedup(xchar ax, xchar ay, xchar bx, xchar by) { tbx = ax - bx; /* These two values are set for use */ tby = ay - by; /* after successful return. */ /* sometimes displacement makes a monster think that you're at its own location; prevent it from throwing and zapping in that case */ if (!tbx && !tby) return FALSE; if ((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */ && distmin(tbx, tby, 0, 0) < BOLT_LIM) { if (clear_path(ax, ay, bx, by, viz_array)) return TRUE; } return FALSE; }
char *cd_init(int fd, FILE *fp, char *param, char **pwds) { char *ret; if (!pwds || !strcmp(param, "-")) { if (!pwds || !pwds[OLD]) return (my_rerror(EBADSEQ, fd, fp)); ret = pwds[OLD]; pwds[OLD] = NULL; return (ret); } if (!strncmp(param, "..", 2)) return (clear_path(fd, fp, param, pwds)); ret = strdup(param); if (!ret) return (alloc_err(fd, fp, 0)); return (ret); }
int check_path(int *maze, int rows, int columns, int x1, int y1, int x2, int y2, int *visited) { if (x1 == x2 && y1 == y2) { *((visited + x1*columns) + y1) = 1; return 1; } if (clear_path(maze, rows, columns, x1, y1) == 1) { *((visited + x1*columns) + y1) = 1; if (*((visited + (x1 + 1)*columns) + y1) == 0) { if (check_path(maze, rows, columns, x1 + 1, y1, x2, y2, visited) == 1) { return 1; } } if (*((visited + x1*columns) + (y1 + 1)) == 0) { if (check_path(maze, rows, columns, x1, y1 + 1, x2, y2, visited) == 1) { return 1; } } if (*((visited + (x1 - 1)*columns) + y1) == 0) { if (check_path(maze, rows, columns, x1 - 1, y1, x2, y2, visited) == 1) { return 1; } } if (*((visited + x1*columns) + (y1 - 1)) == 0) { if (check_path(maze, rows, columns, x1, y1 - 1, x2, y2, visited) == 1) { return 1; } } *((visited + x1*columns) + y1) = 0; return 0; } return 0; }
std::vector<tripoint> map::route( const tripoint &f, const tripoint &t, const int bash, const int maxdist ) const { /* TODO: If the origin or destination is out of bound, figure out the closest * in-bounds point and go to that, then to the real origin/destination. */ int linet1 = 0, linet2 = 0; if( !inbounds( f ) || !inbounds( t ) ) { // Note: The creature needs to understand not-moving upwards // or else the plans can cause it to do so. if( sees( f, t, -1, linet1, linet2 ) ) { return line_to( f, t, linet1, linet2 ); } else { std::vector<tripoint> empty; return empty; } } // First, check for a simple straight line on flat ground // Except when the player is on the line - we need to do regular pathing then const tripoint &pl_pos = g->u.pos(); if( f.z == t.z && clear_path( f, t, -1, 2, 2, linet1, linet2 ) ) { const auto line_path = line_to( f, t, linet1, linet2 ); if( pl_pos.z != f.z ) { // Player on different z-level, certainly not on the line return line_path; } if( std::find( line_path.begin(), line_path.end(), pl_pos ) == line_path.end() ) { return line_path; } } const int pad = 8; // Should be much bigger - low value makes pathfinders dumb! int minx = std::min( f.x, t.x ) - pad; int miny = std::min( f.y, t.y ) - pad; int minz = std::min( f.z, t.z ); // TODO: Make this way bigger int maxx = std::max( f.x, t.x ) + pad; int maxy = std::max( f.y, t.y ) + pad; int maxz = std::max( f.z, t.z ); // Same TODO as above clip_to_bounds( minx, miny, minz ); clip_to_bounds( maxx, maxy, maxz ); pathfinder pf( minx, miny, maxx, maxy ); pf.add_point( 0, 0, f, f ); // Make NPCs not want to path through player // But don't make player pathing stop working if( f != pl_pos && t != pl_pos ) { pf.close_point( pl_pos ); } bool done = false; do { auto cur = pf.get_next(); const int parent_index = flat_index( cur.x, cur.y ); auto &layer = pf.get_layer( cur.z ); auto &cur_state = layer.state[parent_index]; if( cur_state == ASL_CLOSED ) { continue; } if( layer.gscore[parent_index] > maxdist ) { // Shortest path would be too long, return empty vector return std::vector<tripoint>(); } if( cur == t ) { done = true; break; } cur_state = ASL_CLOSED; std::vector<tripoint> neighbors = closest_tripoints_first( 1, cur ); for( const auto &p : neighbors ) { const int index = flat_index( p.x, p.y ); // TODO: Remove this and instead have sentinels at the edges if( p.x < minx || p.x >= maxx || p.y < miny || p.y >= maxy ) { continue; } if( layer.state[index] == ASL_CLOSED ) { continue; } int part = -1; const maptile &tile = maptile_at_internal( p ); const auto &terrain = tile.get_ter_t(); const auto &furniture = tile.get_furn_t(); const vehicle *veh = veh_at_internal( p, part ); const int cost = move_cost_internal( furniture, terrain, veh, part ); // Don't calculate bash rating unless we intend to actually use it const int rating = ( bash == 0 || cost != 0 ) ? -1 : bash_rating_internal( bash, furniture, terrain, false, veh, part ); if( cost == 0 && rating <= 0 && terrain.open.empty() ) { layer.state[index] = ASL_CLOSED; // Close it so that next time we won't try to calc costs continue; } int newg = layer.gscore[parent_index] + cost + ( (cur.x != p.x && cur.y != p.y ) ? 1 : 0); if( cost == 0 ) { // Handle all kinds of doors // Only try to open INSIDE doors from the inside if( !terrain.open.empty() && ( !terrain.has_flag( "OPENCLOSE_INSIDE" ) || !is_outside( cur ) ) ) { newg += 4; // To open and then move onto the tile } else if( veh != nullptr ) { part = veh->obstacle_at_part( part ); int dummy = -1; if( !veh->part_flag( part, "OPENCLOSE_INSIDE" ) || veh_at_internal( cur, dummy ) == veh ) { // Handle car doors, but don't try to path through curtains newg += 10; // One turn to open, 4 to move there } else { // Car obstacle that isn't a door newg += veh->parts[part].hp / bash + 8 + 4; } } else if( rating > 1 ) { // Expected number of turns to bash it down, 1 turn to move there // and 2 turns of penalty not to trash everything just because we can newg += ( 20 / rating ) + 2 + 4; } else if( rating == 1 ) { // Desperate measures, avoid whenever possible newg += 500; } else { continue; // Unbashable and unopenable from here } } // If not visited, add as open // If visited, add it only if we can do so with better score if( layer.state[index] == ASL_NONE || newg < layer.gscore[index] ) { pf.add_point( newg, newg + 2 * rl_dist( p, t ), cur, p ); } } if( !has_zlevels() ) { // The part below is only for z-level pathing continue; } const maptile &parent_tile = maptile_at_internal( cur ); const auto &parent_terrain = parent_tile.get_ter_t(); if( cur.z > minz && parent_terrain.has_flag( TFLAG_GOES_DOWN ) ) { tripoint dest( cur.x, cur.y, cur.z - 1 ); dest = vertical_move_destination<TFLAG_GOES_UP>( *this, dest ); if( inbounds( dest ) ) { auto &layer = pf.get_layer( dest.z ); pf.add_point( layer.gscore[parent_index] + 2, layer.score[parent_index] + 2 * rl_dist( dest, t ), cur, dest ); } } if( cur.z < maxz && parent_terrain.has_flag( TFLAG_GOES_UP ) ) { tripoint dest( cur.x, cur.y, cur.z + 1 ); dest = vertical_move_destination<TFLAG_GOES_DOWN>( *this, dest ); if( inbounds( dest ) ) { auto &layer = pf.get_layer( dest.z ); pf.add_point( layer.gscore[parent_index] + 2, layer.score[parent_index] + 2 * rl_dist( dest, t ), cur, dest ); } } } while( !done && !pf.empty() ); std::vector<tripoint> ret; ret.reserve( rl_dist( f, t ) * 2 ); if( done ) { tripoint cur = t; // Just to limit max distance, in case something weird happens for( int fdist = maxdist; fdist != 0; fdist-- ) { const int cur_index = flat_index( cur.x, cur.y ); const auto &layer = pf.get_layer( cur.z ); const tripoint &par = layer.parent[cur_index]; if( cur == f ) { break; } ret.push_back( cur ); // Jumps are acceptable on 1 z-level changes // This is because stairs teleport the player too if( rl_dist( cur, par ) > 1 && abs( cur.z - par.z ) != 1 ) { debugmsg( "Jump in our route! %d:%d:%d->%d:%d:%d", cur.x, cur.y, cur.z, par.x, par.y, par.z ); return ret; } cur = par; } std::reverse( ret.begin(), ret.end() ); } return ret; }
/** * Move all files from temp to destination directory if at end of group */ void move_files(struct group_list_t *group) { char temppath[MAXPATHNAME], destpath[MAXPATHNAME]; char *filelist[10000]; // TODO: no magic number int len, filecount, i; if (!strcmp(tempdir, "") || (group->file_id != 0)) { return; } if (move_individual) { len = snprintf(temppath, sizeof(temppath), "%s%c_group_%08X", tempdir, PATH_SEP, group->group_id); if ((len >= sizeof(temppath)) || (len == -1)) { glog0(group, "Max pathname length exceeded: %s%c_group_%08X", tempdir, PATH_SEP, group->group_id); } else { move_files_individual(group, temppath, destdir[0]); } return; } { #ifdef WINDOWS intptr_t ffhandle; struct _finddatai64_t finfo; char dirglob[MAXPATHNAME]; snprintf(dirglob, sizeof(dirglob), "%s%c_group_%08X%c*", tempdir, PATH_SEP, group->group_id, PATH_SEP); if ((ffhandle = _findfirsti64(dirglob, &finfo)) == -1) { gsyserror(group, "Failed to open directory %s", dirglob); return; } filecount = 0; do { len = snprintf(temppath, sizeof(temppath), "%s%c_group_%08X%c%s", tempdir, PATH_SEP, group->group_id, PATH_SEP, finfo.name); if ((len >= sizeof(temppath)) || (len == -1)) { glog0(group,"Max pathname length exceeded: %s%c_group_%08X%c%s", tempdir, PATH_SEP, group->group_id, PATH_SEP, finfo.name); continue; } len = snprintf(destpath, sizeof(destpath), "%s%c%s", destdir[0], PATH_SEP, finfo.name); if ((len >= sizeof(destpath)) || (len == -1)) { glog0(group, "Max pathname length exceeded: %s%c%s", destdir[0], PATH_SEP, finfo.name); continue; } // do the move if (strcmp(finfo.name, ".") && strcmp(finfo.name, "..")) { clear_path(destpath, group); if (!MoveFile(temppath, destpath)) { char errbuf[300]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, errbuf, sizeof(errbuf), NULL); glog0(group, "error (%d): %s", GetLastError(), errbuf); } filelist[filecount] = strdup(destpath); if (filelist[filecount] == NULL) { gsyserror(group, "strdup failed!"); exit(ERR_ALLOC); } filecount++; } } while (_findnexti64(ffhandle, &finfo) == 0); _findclose(ffhandle); #else DIR *dir; struct dirent *de; char dirname[MAXPATHNAME]; snprintf(dirname, sizeof(dirname), "%s%c_group_%08X", tempdir, PATH_SEP, group->group_id); if ((dir = opendir(dirname)) == NULL) { gsyserror(group, "Failed to open directory %s", dirname); return; } filecount = 0; // errno needs to be set to 0 before calling readdir, otherwise // we'll report a false error when we exhaust the directory while ((errno = 0, de = readdir(dir)) != NULL) { len = snprintf(temppath, sizeof(temppath), "%s%c%s", dirname, PATH_SEP, de->d_name); if ((len >= sizeof(temppath)) || (len == -1)) { glog0(group, "Max pathname length exceeded: %s%c%s", dirname, PATH_SEP, de->d_name); continue; } len = snprintf(destpath, sizeof(destpath), "%s%c%s", destdir[0], PATH_SEP, de->d_name); if ((len >= sizeof(destpath)) || (len == -1)) { glog0(group, "Max pathname length exceeded: %s%c%s", destdir[0], PATH_SEP, de->d_name); continue; } if (strcmp(de->d_name, ".") && strcmp(de->d_name, "..")) { clear_path(destpath, group); if (rename(temppath, destpath) == -1) { gsyserror(group, "Couldn't move file"); } filelist[filecount] = strdup(destpath); if (filelist[filecount] == NULL) { gsyserror(group, "strdup failed!"); exit(ERR_ALLOC); } filecount++; } } if (errno && (errno != ENOENT)) { gsyserror(group, "Failed to read directory %s", dirname); } closedir(dir); #endif } run_postreceive_multi(group, filelist, filecount); for (i = 0; i < filecount; i++) { free(filelist[i]); } snprintf(temppath, sizeof(temppath), "%s%c_group_%08X", tempdir, PATH_SEP, group->group_id); if (rmdir(temppath) == -1) { gsyserror(group, "Failed remove temp directory %s", temppath); } }
/* Mark locations that are temporarily lit via mobile light sources. */ void do_light_sources(char **cs_rows) { int x, y, min_x, max_x, max_y, offset; const char *limits; short at_hero_range = 0; light_source *ls; char *row; for (ls = level->lev_lights; ls; ls = ls->next) { ls->flags &= ~LSF_SHOW; /* * Check for moved light sources. It may be possible to * save some effort if an object has not moved, but not in * the current setup -- we need to recalculate for every * vision recalc. */ if (ls->type == LS_OBJECT) { if (get_obj_location((struct obj *) ls->id, &ls->x, &ls->y, 0)) ls->flags |= LSF_SHOW; } else if (ls->type == LS_MONSTER) { if (get_mon_location((struct monst *) ls->id, &ls->x, &ls->y, 0)) ls->flags |= LSF_SHOW; } /* minor optimization: don't bother with duplicate light sources */ /* at hero */ if (ls->x == u.ux && ls->y == u.uy) { if (at_hero_range >= ls->range) ls->flags &= ~LSF_SHOW; else at_hero_range = ls->range; } if (ls->flags & LSF_SHOW) { /* * Walk the points in the circle and see if they are * visible from the center. If so, mark'em. * * Kevin's tests indicated that doing this brute-force * method is faster for radius <= 3 (or so). */ limits = circle_ptr(ls->range); if ((max_y = (ls->y + ls->range)) >= ROWNO) max_y = ROWNO-1; if ((y = (ls->y - ls->range)) < 0) y = 0; for (; y <= max_y; y++) { row = cs_rows[y]; offset = limits[abs(y - ls->y)]; if ((min_x = (ls->x - offset)) < 0) min_x = 0; if ((max_x = (ls->x + offset)) >= COLNO) max_x = COLNO-1; if (ls->x == u.ux && ls->y == u.uy) { /* * If the light source is located at the hero, then * we can use the COULD_SEE bits already calcualted * by the vision system. More importantly than * this optimization, is that it allows the vision * system to correct problems with clear_path(). * The function clear_path() is a simple LOS * path checker that doesn't go out of its way * make things look "correct". The vision system * does this. */ for (x = min_x; x <= max_x; x++) if (row[x] & COULD_SEE) row[x] |= TEMP_LIT; } else { for (x = min_x; x <= max_x; x++) if ((ls->x == x && ls->y == y) || clear_path((int)ls->x, (int) ls->y, x, y)) row[x] |= TEMP_LIT; } } } } }
/* return TRUE if successful, FALSE if not */ boolean rloc(struct monst *mtmp, /* mx==COLNO implies migrating monster arrival */ boolean suppress_impossible) { int x, y, trycount; int relaxed_goodpos; if (mtmp == u.usteed) { tele(); return TRUE; } if (mtmp->iswiz && mtmp->mx != COLNO) { /* Wizard, not just arriving */ if (!In_W_tower(u.ux, u.uy, &u.uz)) x = level->upstair.sx, y = level->upstair.sy; else if (!isok(level->dnladder.sx, level->dnladder.sy)) x = level->upladder.sx, y = level->upladder.sy;/* bottom of tower */ else x = level->dnladder.sx, y = level->dnladder.sy; /* if the wiz teleports away to heal, try the up staircase, to block the player's escaping before he's healed (deliberately use `goodpos' rather than `rloc_pos_ok' here) */ if (goodpos(level, x, y, mtmp, 0)) goto found_xy; } for (relaxed_goodpos = -1; relaxed_goodpos < 2; relaxed_goodpos++) { /* If this is a monster that blinks, try to do that first. */ if (relaxed_goodpos < 0) { if ((isok(mtmp->mx, mtmp->my)) && mtmp->data->mflags3 & M3_BLINKAWAY) { /* We're going to do a polar-to-rectangular conversion here, because it's a convenient way to select positions at the correct distance from where we're starting. We'll try with the maximum radius then back it off. */ int maxradius = 2 * mtmp->data->mlevel; int minradius = 2; int theta[24] = { 0, 15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240, 255, 270, 285, 300, 315, 330, 345 }; int angle, fineangle, swi, sw; coord rectcoord; if (maxradius < minradius + 3) maxradius = minradius + 3; /* Shuffle the order of the angles so we don't always get the same one tried first. */ for (angle = 0; angle < 24; angle++) { swi = rn2(24); sw = theta[swi]; theta[swi] = theta[angle]; theta[angle] = sw; } for (trycount = maxradius; trycount >= minradius; trycount--) { for (angle = 0; angle < 24; angle++) for (fineangle = 0; fineangle < 15; fineangle += 3) { /* theta is shuffled so that the angle isn't the same all the time, but it isn't necessary to shuffle over a hundred different angles; we use fineangle to allow positions that don't line up to the 15-degree increments, but the randomness of the blink direction doesn't need that much precision. */ rectcoord = polartorect(trycount, theta[angle] + fineangle); x = mtmp->mx + rectcoord.x; y = mtmp->my + rectcoord.y; if (isok(x,y) && !m_at(level,x,y) && /* TODO: evaluate whether goodpos() should be * used here */ (level->locations[x][y].typ >= CORR) && /* Blinking only works with line-of-sight, but for now I am not requiring the monster to actually _see_ the tile, so e.g. blinking into the dark works ok. */ clear_path(mtmp->mx, mtmp->my, x, y, viz_array) ) { goto found_xy; } } } } continue; } /* first try sensible terrain; if none exists, ignore water, doors and boulders */ int gpflags = relaxed_goodpos ? MM_IGNOREWATER | MM_IGNOREDOORS : 0; /* try several pairs of positions; try the more restrictive rloc_pos_ok before we use the less restrictive goodpos */ trycount = 0; do { x = rn2(COLNO); y = rn2(ROWNO); if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp) : goodpos(level, x, y, mtmp, gpflags)) goto found_xy; } while (++trycount < 1000); /* try every square on the level as a fallback */ for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (goodpos(level, x, y, mtmp, gpflags)) goto found_xy; } /* level either full of monsters or somehow faulty */ if (!suppress_impossible) impossible("rloc(): couldn't relocate monster"); return FALSE; found_xy: rloc_to(mtmp, x, y); return TRUE; }
/** * For the current file in a group, move the existing file to * the appropriate backup directory, if it exists. * In the event of a failure, delete the original file */ void move_to_backup(int listidx) { stat_struct statbuf; char backup_file[MAXBACKUPPATHNAME], *trim_name; int len; if (lstat_func(group_list[listidx].fileinfo.filepath, &statbuf) == -1) { return; } if (backupcnt == 0) { clear_path(group_list[listidx].fileinfo.filepath, listidx); return; } #ifdef WINDOWS if ((group_list[listidx].fileinfo.filepath[1] == ':') && (group_list[listidx].fileinfo.filepath[2] == '\\')) { trim_name = &group_list[listidx].fileinfo.filepath[3]; } else { trim_name = group_list[listidx].fileinfo.filepath; } #else trim_name = group_list[listidx].fileinfo.filepath; #endif len = snprintf(backup_file, sizeof(backup_file), "%s%c%s%c%s%c%s", backupdir[group_list[listidx].fileinfo.destdiridx], PATH_SEP, group_list[listidx].start_date, PATH_SEP, group_list[listidx].start_time, PATH_SEP, trim_name); if (len >= sizeof(backup_file)) { log0(group_list[listidx].group_id, group_list[listidx].file_id, "Max pathname length exceeded for backup file, deleting", group_list[listidx].fileinfo.filepath); clear_path(group_list[listidx].fileinfo.filepath, listidx); return; } clear_path(backup_file, listidx); if (!create_path_to_file(listidx, backup_file)) { log0(group_list[listidx].group_id, group_list[listidx].file_id, "Error creating path to backup file"); clear_path(group_list[listidx].fileinfo.filepath, listidx); } #ifdef WINDOWS if (!MoveFile(group_list[listidx].fileinfo.filepath, backup_file)) { char errbuf[300]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, errbuf, sizeof(errbuf), NULL); log0(group_list[listidx].group_id, group_list[listidx].file_id, "Couldn't rename from %s to %s, deleting: (%d): %s", group_list[listidx].fileinfo.filepath, backup_file, GetLastError(), errbuf); clear_path(group_list[listidx].fileinfo.filepath, listidx); } else { log1(group_list[listidx].group_id, group_list[listidx].file_id, "Backed up existing file to %s", backup_file); } #else if (rename(group_list[listidx].fileinfo.filepath, backup_file) == -1) { syserror(group_list[listidx].group_id, group_list[listidx].file_id, "Couldn't rename from %s to %s, deleting", group_list[listidx].fileinfo.filepath, backup_file); clear_path(group_list[listidx].fileinfo.filepath, listidx); } else { log1(group_list[listidx].group_id, group_list[listidx].file_id, "Backed up existing file to %s", backup_file); } #endif }
/* Returns the bitwise OR of all MSENSE_ values that explain how "viewer" can see "viewee". &youmonst is accepted as either argument. If both arguments are the same, this tests if/how a monster/player can detect itself. */ unsigned msensem(const struct monst *viewer, const struct monst *viewee) { unsigned sensemethod = 0; /* sanity checks, so the caller doesn't have to */ if (viewer != &youmonst) if (!onmap(viewer) || DEADMONSTER(viewer)) return 0; if (viewee != &youmonst) if (!onmap(viewee) || DEADMONSTER(viewee)) return 0; if (!level) { impossible("vision calculations during level creation"); return 0; } /* TODO: once levels rewrite is done, this code can be simplified (and won't work in its present form). */ d_level *sz = m_mz(viewer), *tz = m_mz(viewee); if (sz->dnum != tz->dnum || sz->dlevel != tz->dlevel) return 0; struct level *lev = level; if (viewer != &youmonst) lev = viewer->dlevel; int sx = m_mx(viewer), sy = m_my(viewer), tx = m_mx(viewee), ty = m_my(viewee); int distance = dist2(sx, sy, tx, ty); /* Special case: if either endpoint is an engulfing monster, then we want LOE to the square specifically, ignoring players on that square (because the edge of an engulfing monster blocks LOE to the player). */ char **msensem_vizarray = (Engulfed && (viewer == u.ustuck || viewee == u.ustuck)) ? NULL : viz_array; /* Line of effect. clear_path is like couldsee(), but doesn't require the player to be at either endpoint. (If the player happens to be at one of the endpoints, it just calls couldsee() directly.) */ boolean loe = clear_path(sx, sy, tx, ty, msensem_vizarray); /* A special case for many vision methods: water or the ground blocking vision. A hiding target is also included in these, because hiding is often a case of using an object, part of the floor, a cranny in the ceiling, etc., to block vision (and even when it isn't, it should block vision in the same cases). */ boolean vertical_loe = !(m_mburied(viewer) || m_mburied(viewee) || ((!!m_underwater(viewee)) ^ (!!m_underwater(viewer))) || m_mundetected(viewee)); boolean invisible = !!m_has_property(viewee, INVIS, ANY_PROPERTY, 0); /* For normal vision, one necessary condition is that the target must be adjacent or on a lit square (we assume there's just enough light in the dungeon that even in dark areas, adjacent squares are visible to normal vision). We test "lit" by testing that the square is either temporarily lit, or permanently lit. (We can't use the normal cansee() check because that doesn't work for squares outside the player's LOE, and it's possible that neither the viewer nor the viewee is the player.) TODO: templit off-level. That's very hard to implement because we don't run lighting calculations off-level. */ boolean target_lit = distance <= 2 || (lev == level && templit(tx, ty)) || lev->locations[tx][ty].lit; /* TODO: Maybe infravision (and perhaps even infravisibility) should be properties? */ boolean infravision_ok = infravision(viewer->data) && infravisible(viewee->data); boolean blinded = !!m_has_property(viewer, BLINDED, ANY_PROPERTY, 0); boolean see_invisible = !!m_has_property(viewer, SEE_INVIS, ANY_PROPERTY, 0); if (loe && vertical_loe && !blinded) { if (!invisible && target_lit) sensemethod |= MSENSE_VISION; if (!invisible && infravision_ok) sensemethod |= MSENSE_INFRAVISION; if (invisible && (target_lit || infravision_ok) && see_invisible) sensemethod |= MSENSE_SEEINVIS | MSENSEF_KNOWNINVIS; } /* Telepathy. The viewee needs a mind; the viewer needs either to be blind, or for the telepathy to be extrinsic and the viewer within BOLT_LIM. */ if (!mindless(viewee->data) && !m_helpless(viewer, hm_unconscious)) { unsigned telepathy_reason = m_has_property(viewer, TELEPAT, ANY_PROPERTY, 0); if ((telepathy_reason && blinded) || (telepathy_reason & (W_EQUIP | W_ARTIFACT) && distance <= BOLT_LIM * BOLT_LIM)) sensemethod |= MSENSE_TELEPATHY; } /* Astral vision. Like regular vision, but has a distance check rather than an LOE check. It's unclear whether this pierces blindness, because the only item that gives astral vision also gives blindness immunity; this code assumes not. */ boolean xray = m_has_property(viewer, XRAY_VISION, ANY_PROPERTY, 0) && (!invisible || see_invisible); if (vertical_loe && distance <= XRAY_RANGE * XRAY_RANGE && xray && (target_lit || infravision_ok)) { sensemethod |= MSENSE_XRAY; if (invisible && see_invisible) sensemethod |= MSENSEF_KNOWNINVIS; } /* Ideally scent should work around corners, but not through walls. That's awkward to write, though, because it'd require pathfinding. */ if (vertical_loe && loe && distance <= 5 && has_scent(viewer->data)) sensemethod |= MSENSE_SCENT; /* Monster detection. All that is needed (apart from same-level, which was checked earlier) is the property itself. */ if (m_has_property(viewer, DETECT_MONSTERS, ANY_PROPERTY, 0)) sensemethod |= MSENSE_MONDETECT; /* Warning versus monster class. (Actually implemented as monster /race/.) */ if (mworn_warntype(viewer) & viewee->data->mflags2) sensemethod |= MSENSE_WARNOFMON; /* Covetous sense. Note that the player can benefit from this too, e.g. a player in master lich form will be able to detect the Wizard of Yendor holding the Book of the Dead. */ if (covetous_sense(viewer, viewee)) sensemethod |= MSENSE_COVETOUS; /* Smell of gold, approximating 3.4.3 behaviour (which was previously in set_apparxy in monmove.c). Xorns can sense any monster with gold in their inventory. */ if (viewer->data == &mons[PM_XORN] && money_cnt(m_minvent(viewee))) sensemethod |= MSENSE_GOLDSMELL; /* Warning. This partial-senses monsters that are hostile to the viewer, and have a level of 4 or greater, and a distance of 100 or less. */ if (distance <= 100 && m_mlev(viewee) >= 4 && m_has_property(viewer, WARNING, ANY_PROPERTY, 0) && mm_aggression(viewee, viewer) & ALLOW_M) sensemethod |= MSENSE_WARNING; /* Deducing the existence of a long worm via seeing a segment. Based on the code that was formerly worm_known in worm.c, but expanded to handle monster viewing. Note: assumes that normal vision, possibly modified by astral vision and see invisible, is the only way to see a long worm tail. Infravision doesn't work (they're cold-blooded), and currently no other types of vision are implemented. Detection would find the head. */ if (viewee->wormno && (!invisible || see_invisible) && vertical_loe && !blinded) { struct wseg *curr = viewee->dlevel->wtails[viewee->wormno]; while (curr) { boolean seg_dist = dist2(sx, sy, curr->wx, curr->wy); boolean seg_loe = clear_path(sx, sy, curr->wx, curr->wy, msensem_vizarray) || (xray && seg_dist <= XRAY_RANGE * XRAY_RANGE); boolean seg_lit = seg_dist <= 2 || (lev == level && templit(curr->wx, curr->wy)) || lev->locations[curr->wx][curr->wy].lit; if (seg_loe && seg_lit) sensemethod |= MSENSE_WORM; curr = curr->nseg; } } /* Calculate known invisibility, because we have all the information to hand, and it's a complex calculation without it. We need to be able to see the monster's location with normal vision, but not the monster itself. Also don't include warning in this (because then, we can't match the monster to the message). */ if (loe && vertical_loe && !blinded && sensemethod && target_lit && !(sensemethod & (MSENSE_ANYVISION | MSENSE_WARNING))) sensemethod |= MSENSEF_KNOWNINVIS; /* If the target is in item form, it's not being seen properly. Any vision-style detection of the target is going to not see it as a monster. */ if (m_helpless(viewee, 1 << hr_mimicking) && (lev != level || !Protection_from_shape_changers) && (sensemethod & MSENSE_ANYVISION)) { sensemethod &= ~MSENSE_ANYVISION; sensemethod |= MSENSE_ITEMMIMIC; } return sensemethod; }
std::vector<tripoint> map::route( const tripoint &f, const tripoint &t, const int bash, const int maxdist, const std::set<tripoint> &pre_closed ) const { /* TODO: If the origin or destination is out of bound, figure out the closest * in-bounds point and go to that, then to the real origin/destination. */ std::vector<tripoint> ret; if( !inbounds( f ) ) { return ret; } if( !inbounds( t ) ) { tripoint clipped = t; clip_to_bounds( clipped ); return route( f, clipped, bash, maxdist ); } // First, check for a simple straight line on flat ground // Except when the line contains a pre-closed tile - we need to do regular pathing then if( f.z == t.z && clear_path( f, t, -1, 2, 2 ) ) { const auto line_path = line_to( f, t ); const std::set<tripoint> sorted_line( line_path.begin(), line_path.end() ); if( is_disjoint( sorted_line, pre_closed ) ) { return line_path; } } const int pad = 16; // Should be much bigger - low value makes pathfinders dumb! int minx = std::min( f.x, t.x ) - pad; int miny = std::min( f.y, t.y ) - pad; int minz = std::min( f.z, t.z ); // TODO: Make this way bigger int maxx = std::max( f.x, t.x ) + pad; int maxy = std::max( f.y, t.y ) + pad; int maxz = std::max( f.z, t.z ); // Same TODO as above clip_to_bounds( minx, miny, minz ); clip_to_bounds( maxx, maxy, maxz ); pathfinder pf( minx, miny, maxx, maxy ); // Make NPCs not want to path through player // But don't make player pathing stop working for( const auto &p : pre_closed ) { if( p.x >= minx && p.x < maxx && p.y >= miny && p.y < maxy ) { pf.close_point( p ); } } // Start and end must not be closed pf.unclose_point( f ); pf.unclose_point( t ); pf.add_point( 0, 0, f, f ); bool done = false; do { auto cur = pf.get_next(); const int parent_index = flat_index( cur.x, cur.y ); auto &layer = pf.get_layer( cur.z ); auto &cur_state = layer.state[parent_index]; if( cur_state == ASL_CLOSED ) { continue; } if( layer.gscore[parent_index] > maxdist ) { // Shortest path would be too long, return empty vector return std::vector<tripoint>(); } if( cur == t ) { done = true; break; } cur_state = ASL_CLOSED; const auto &pf_cache = get_pathfinding_cache_ref( cur.z ); const auto cur_special = pf_cache.special[cur.x][cur.y]; // 7 3 5 // 1 . 2 // 6 4 8 constexpr std::array<int, 8> x_offset{{ -1, 1, 0, 0, 1, -1, -1, 1 }}; constexpr std::array<int, 8> y_offset{{ 0, 0, -1, 1, -1, 1, -1, 1 }}; for( size_t i = 0; i < 8; i++ ) { const tripoint p( cur.x + x_offset[i], cur.y + y_offset[i], cur.z ); const int index = flat_index( p.x, p.y ); // @todo Remove this and instead have sentinels at the edges if( p.x < minx || p.x >= maxx || p.y < miny || p.y >= maxy ) { continue; } if( layer.state[index] == ASL_CLOSED ) { continue; } // Penalize for diagonals or the path will look "unnatural" int newg = layer.gscore[parent_index] + ( ( cur.x != p.x && cur.y != p.y ) ? 1 : 0 ); const auto p_special = pf_cache.special[p.x][p.y]; constexpr auto non_normal = PF_SLOW | PF_WALL | PF_VEHICLE | PF_TRAP; // @todo De-uglify, de-huge-n if( !( p_special & non_normal ) ) { // Boring flat dirt - the most common case above the ground newg += 2; } else { int part = -1; const maptile &tile = maptile_at_internal( p ); const auto &terrain = tile.get_ter_t(); const auto &furniture = tile.get_furn_t(); const vehicle *veh = veh_at_internal( p, part ); const int cost = move_cost_internal( furniture, terrain, veh, part ); // Don't calculate bash rating unless we intend to actually use it const int rating = ( bash == 0 || cost != 0 ) ? -1 : bash_rating_internal( bash, furniture, terrain, false, veh, part ); if( cost == 0 && rating <= 0 && !terrain.open && veh == nullptr ) { layer.state[index] = ASL_CLOSED; // Close it so that next time we won't try to calc costs continue; } newg += cost; if( cost == 0 ) { // Handle all kinds of doors // Only try to open INSIDE doors from the inside if( terrain.open && ( !terrain.has_flag( "OPENCLOSE_INSIDE" ) || !is_outside( cur ) ) ) { newg += 4; // To open and then move onto the tile } else if( veh != nullptr ) { part = veh->obstacle_at_part( part ); int dummy = -1; if( veh->part_flag( part, VPFLAG_OPENABLE ) && ( !veh->part_flag( part, "OPENCLOSE_INSIDE" ) || veh_at_internal( cur, dummy ) == veh ) ) { // Handle car doors, but don't try to path through curtains newg += 10; // One turn to open, 4 to move there } else if( part != -1 && bash > 0 ) { // Car obstacle that isn't a door // Or there is no car obstacle, but the car is wedged into an obstacle, // in which case part == -1 newg += 2 * veh->parts[part].hp / bash + 8 + 4; } else { if( !veh->part_flag( part, VPFLAG_OPENABLE ) ) { // Won't be openable, don't try from other sides layer.state[index] = ASL_CLOSED; } continue; } } else if( rating > 1 ) { // Expected number of turns to bash it down, 1 turn to move there // and 5 turns of penalty not to trash everything just because we can newg += ( 20 / rating ) + 2 + 10; } else if( rating == 1 ) { // Desperate measures, avoid whenever possible newg += 500; } else { continue; // Unbashable and unopenable from here } } if( p_special & PF_TRAP ) { const auto &ter_trp = terrain.trap.obj(); const auto &trp = ter_trp.is_benign() ? tile.get_trap_t() : ter_trp; if( !trp.is_benign() ) { // For now make them detect all traps if( has_zlevels() && terrain.has_flag( TFLAG_NO_FLOOR ) ) { // Special case - ledge in z-levels // Warning: really expensive, needs a cache if( valid_move( p, tripoint( p.x, p.y, p.z - 1 ), false, true ) ) { tripoint below( p.x, p.y, p.z - 1 ); if( !has_flag( TFLAG_NO_FLOOR, below ) ) { // Otherwise this would have been a huge fall auto &layer = pf.get_layer( p.z - 1 ); // From cur, not p, because we won't be walking on air pf.add_point( layer.gscore[parent_index] + 10, layer.score[parent_index] + 10 + 2 * rl_dist( below, t ), cur, below ); } // Close p, because we won't be walking on it layer.state[index] = ASL_CLOSED; continue; } } else { // Otherwise it's walkable newg += 500; } } } } // If not visited, add as open // If visited, add it only if we can do so with better score if( layer.state[index] == ASL_NONE || newg < layer.gscore[index] ) { pf.add_point( newg, newg + 2 * rl_dist( p, t ), cur, p ); } } if( !has_zlevels() || !( cur_special & PF_UPDOWN ) ) { // The part below is only for z-level pathing continue; } const maptile &parent_tile = maptile_at_internal( cur ); const auto &parent_terrain = parent_tile.get_ter_t(); if( cur.z > minz && parent_terrain.has_flag( TFLAG_GOES_DOWN ) ) { tripoint dest( cur.x, cur.y, cur.z - 1 ); dest = vertical_move_destination<TFLAG_GOES_UP>( *this, dest ); if( inbounds( dest ) ) { auto &layer = pf.get_layer( dest.z ); pf.add_point( layer.gscore[parent_index] + 2, layer.score[parent_index] + 2 * rl_dist( dest, t ), cur, dest ); } } if( cur.z < maxz && parent_terrain.has_flag( TFLAG_GOES_UP ) ) { tripoint dest( cur.x, cur.y, cur.z + 1 ); dest = vertical_move_destination<TFLAG_GOES_DOWN>( *this, dest ); if( inbounds( dest ) ) { auto &layer = pf.get_layer( dest.z ); pf.add_point( layer.gscore[parent_index] + 2, layer.score[parent_index] + 2 * rl_dist( dest, t ), cur, dest ); } } if( cur.z < maxz && parent_terrain.has_flag( TFLAG_RAMP ) && valid_move( cur, tripoint( cur.x, cur.y, cur.z + 1 ), false, true ) ) { auto &layer = pf.get_layer( cur.z + 1 ); for( size_t it = 0; it < 8; it++ ) { const tripoint above( cur.x + x_offset[it], cur.y + y_offset[it], cur.z + 1 ); pf.add_point( layer.gscore[parent_index] + 4, layer.score[parent_index] + 4 + 2 * rl_dist( above, t ), cur, above ); } } } while( !done && !pf.empty() ); ret.reserve( rl_dist( f, t ) * 2 ); if( done ) { tripoint cur = t; // Just to limit max distance, in case something weird happens for( int fdist = maxdist; fdist != 0; fdist-- ) { const int cur_index = flat_index( cur.x, cur.y ); const auto &layer = pf.get_layer( cur.z ); const tripoint &par = layer.parent[cur_index]; if( cur == f ) { break; } ret.push_back( cur ); // Jumps are acceptable on 1 z-level changes // This is because stairs teleport the player too if( rl_dist( cur, par ) > 1 && abs( cur.z - par.z ) != 1 ) { debugmsg( "Jump in our route! %d:%d:%d->%d:%d:%d", cur.x, cur.y, cur.z, par.x, par.y, par.z ); return ret; } cur = par; } std::reverse( ret.begin(), ret.end() ); } return ret; }
void pgfgd_path_clear(pgfgd_Edge* e) { clear_path (e->path); }
/* Mark locations that are temporarily lit via mobile light sources. */ void do_light_sources(char **cs_rows) { int x, y, min_x, max_x, max_y, offset; const char *limits; short at_hero_range = 0; light_source *ls; char *row; for (ls = level->lev_lights; ls; ls = ls->next) { ls->flags &= ~LSF_SHOW; /* * Check for moved light sources. It may be possible to * save some effort if an object has not moved, but not in * the current setup -- we need to recalculate for every * vision recalc. */ if (ls->type == LS_OBJECT) { if (get_obj_location((struct obj *)ls->id, &ls->x, &ls->y, 0)) ls->flags |= LSF_SHOW; } else if (ls->type == LS_MONSTER) { if (get_mon_location((struct monst *)ls->id, &ls->x, &ls->y, 0)) ls->flags |= LSF_SHOW; } /* minor optimization: don't bother with duplicate light sources at hero */ if (ls->x == u.ux && ls->y == u.uy) { if (at_hero_range >= ls->range) ls->flags &= ~LSF_SHOW; else at_hero_range = ls->range; } if (ls->flags & LSF_SHOW) { /* * Walk the points in the circle and see if they are * visible from the center. If so, mark'em. * * Kevin's tests indicated that doing this brute-force * method is faster for radius <= 3 (or so). */ limits = circle_ptr(ls->range); if ((max_y = (ls->y + ls->range)) >= ROWNO) max_y = ROWNO - 1; if ((y = (ls->y - ls->range)) < 0) y = 0; for (; y <= max_y; y++) { row = cs_rows[y]; offset = limits[abs(y - ls->y)]; if ((min_x = (ls->x - offset)) < 0) min_x = 0; if ((max_x = (ls->x + offset)) >= COLNO) max_x = COLNO - 1; for (x = min_x; x <= max_x; x++) if (clear_path((int)ls->x, (int)ls->y, x, y, cs_rows)) row[x] |= TEMP_LIT; } } } }
void process_cmd(struct cmd_frame_t *cmd) { int res; reply.status = ACK; // change to NACK as necessary reply.cmd = cmd->cmd; switch (cmd->cmd) { case CMD_ECHO: reply.data[0] = cmd->echo.length; memcpy(&reply.data[1], cmd->echo.data, cmd->echo.length); send_reply(&reply, cmd->echo.length+3); break; case CMD_RESET: if (cmd->reset_magic == RESET_MAGIC) { usb_peripheral_reset(); CREG_M4MEMMAP = 0x10400000; scb_reset_system(); } else { send_nack(); } break; case CMD_GET_EVENT_COUNTERS: { struct event_counters counters = get_last_event_counters(); memcpy(reply.data, &counters, sizeof(struct event_counters)); send_reply(&reply, 2+sizeof(struct event_counters)); break; } case CMD_GET_STAGE_GAINS: memcpy(reply.data, stage_fb_gains, sizeof(stage_fb_gains)); send_reply(&reply, 2+sizeof(stage_fb_gains)); break; case CMD_SET_STAGE_GAINS: memcpy(stage_fb_gains, cmd->set_stage_gains, sizeof(stage_fb_gains)); send_ack(); break; case CMD_GET_STAGE_SETPOINT: memcpy(reply.data, stage_fb_setpoint, sizeof(stage_fb_setpoint)); send_reply(&reply, 2+sizeof(stage_fb_setpoint)); break; case CMD_SET_STAGE_SETPOINT: memcpy(stage_fb_setpoint, cmd->set_stage_setpoint, sizeof(stage_fb_setpoint)); send_ack(); break; case CMD_GET_PSD_GAINS: memcpy(reply.data, psd_fb_gains, sizeof(psd_fb_gains)); send_reply(&reply, 2+sizeof(psd_fb_gains)); break; case CMD_SET_PSD_GAINS: memcpy(psd_fb_gains, cmd->set_psd_gains, sizeof(psd_fb_gains)); send_ack(); break; case CMD_GET_PSD_SETPOINT: memcpy(reply.data, psd_fb_setpoint, sizeof(psd_fb_setpoint)); send_reply(&reply, 2+sizeof(psd_fb_setpoint)); break; case CMD_SET_PSD_SETPOINT: memcpy(psd_fb_setpoint, cmd->set_psd_setpoint, sizeof(psd_fb_setpoint)); send_ack(); break; case CMD_GET_MAX_ERROR: memcpy(reply.data, &max_error, sizeof(max_error)); send_reply(&reply, 2+sizeof(max_error)); break; case CMD_SET_MAX_ERROR: max_error = cmd->set_max_error; send_ack(); break; case CMD_GET_OUTPUT_GAINS: { fixed16_t* tmp = (fixed16_t*) reply.data; for (unsigned int i=0; i<STAGE_OUTPUTS; i++) { *tmp = stage_outputs[i].p_gain; tmp++; *tmp = stage_outputs[i].i_gain; tmp++; } send_reply(&reply, 2+2*STAGE_OUTPUTS*sizeof(fixed16_t)); break; } case CMD_SET_OUTPUT_GAINS: { for (unsigned int i=0; i<STAGE_OUTPUTS; i++) { stage_outputs[i].p_gain = cmd->set_output_gains[i][0]; stage_outputs[i].i_gain = cmd->set_output_gains[i][1]; } send_ack(); break; } case CMD_GET_OUTPUT_TAUS: { for (unsigned int i=0; i<STAGE_OUTPUTS; i++) { reply.data[i] = pi_get_tau(&stage_outputs[i]); } send_reply(&reply, 2+3); break; } case CMD_SET_OUTPUT_TAUS: { for (unsigned int i=0; i<STAGE_OUTPUTS; i++) { pi_set_tau(&stage_outputs[i], cmd->set_output_taus[i]); } send_ack(); break; } case CMD_GET_ADC_FREQ: reply.data32[0] = 0; //TODO adc_get_trigger_freq(); send_reply(&reply, 2+4); break; case CMD_SET_ADC_FREQ: adc_set_trigger_freq(cmd->set_adc_freq); send_ack(); break; case CMD_GET_ADC_TRIGGER_MODE: reply.data[0] = adc_get_trigger_mode(); send_reply(&reply, 2+1); break; case CMD_SET_ADC_TRIGGER_MODE: adc_set_trigger_mode(cmd->set_adc_trigger_mode); send_ack(); break; case CMD_START_ADC_STREAM: adc_streaming = true; send_ack(); break; case CMD_STOP_ADC_STREAM: adc_streaming = false; adc_flush(); send_ack(); break; case CMD_FLUSH_ADC_STREAM: if (adc_flush() == 0) { send_ack(); } else { send_nack(); } break; case CMD_GET_ADC_DECIMATION: { reply.data32[0] = adc_get_decimation(); send_reply(&reply, 2+4); break; } case CMD_SET_ADC_DECIMATION: if (adc_set_decimation(cmd->set_adc_decimation) == 0) { send_ack(); } else { send_nack(); } break; case CMD_GET_FEEDBACK_FREQ: { unsigned int freq = feedback_get_loop_freq(); reply.data32[0] = freq; send_reply(&reply, 2+4); break; } case CMD_SET_FEEDBACK_FREQ: feedback_set_loop_freq(cmd->set_feedback_freq); send_ack(); break; case CMD_GET_FEEDBACK_MODE: reply.data[0] = feedback_get_mode(); send_reply(&reply, 3); break; case CMD_SET_FEEDBACK_MODE: feedback_set_mode(cmd->set_feedback_mode); send_ack(); break; case CMD_SET_RAW_POS: if (feedback_set_position(cmd->set_raw_pos) == 0) { send_ack(); } else { send_nack(); } break; case CMD_CLEAR_PATH: clear_path(); send_ack(); break; case CMD_ENQUEUE_POINTS: res = 0; if (cmd->enqueue_points.npts > 0) res = enqueue_points((uint16_t*) &cmd->enqueue_points.points, cmd->enqueue_points.npts); if (res == -1 || res == 0) { reply.data[0] = res != -1; // were the points added? reply.data[1] = is_path_running(); send_reply(&reply, 4); } else { send_nack(); } break; case CMD_START_PATH: if (start_path(cmd->start_path.freq, cmd->start_path.synchronous_adc) == 0) { send_ack(); } else { send_nack(); } break; case CMD_SET_EXCITATION: { struct set_excitation* const se = &cmd->set_excitation; struct excitation_buffer* const exc = &excitations[se->channel]; if ((se->length + se->offset > MAX_EXCITATION_LENGTH) || (se->channel >= 3)) { send_nack(); break; } exc->length = 0; exc->offset = 0; if (se->length != 0) { memcpy(&exc->samples[se->offset], &se->samples, sizeof(uint16_t) * se->length); } exc->length = se->total_length; send_ack(); break; } case CMD_GET_SEARCH_STEP: memcpy(reply.data, search_fb_step, sizeof(search_fb_step)); send_reply(&reply, 2+sizeof(search_fb_step)); break; case CMD_SET_SEARCH_STEP: memcpy(search_fb_step, cmd->set_search_step, sizeof(search_fb_step)); send_ack(); break; case CMD_GET_SEARCH_OBJ_GAINS: memcpy(reply.data, search_obj_gains, sizeof(search_obj_gains)); send_reply(&reply, 2+sizeof(search_obj_gains)); break; case CMD_SET_SEARCH_OBJ_GAINS: memcpy(search_obj_gains, cmd->set_search_obj_gains, sizeof(search_obj_gains)); send_ack(); break; case CMD_GET_SEARCH_OBJ_THRESH: memcpy(reply.data, &search_obj_thresh, sizeof(search_obj_thresh)); send_reply(&reply, 2+sizeof(search_obj_thresh)); break; case CMD_SET_SEARCH_OBJ_THRESH: search_obj_thresh = cmd->set_search_obj_thresh, send_ack(); break; case CMD_GET_COARSE_FB_PARAMS: memcpy(reply.data, &coarse_fb_channels, sizeof(coarse_fb_channels)); send_reply(&reply, 2+sizeof(coarse_fb_channels)); break; case CMD_SET_COARSE_FB_PARAMS: memcpy(coarse_fb_channels, cmd->set_coarse_fb_params, sizeof(coarse_fb_channels)); send_ack(); break; default: send_nack(); return; } }
/** * Process an incoming FILEINFO message. * Expected in the middle of a group with no current file. */ void handle_fileinfo(struct group_list_t *group, const unsigned char *message, unsigned meslen, struct timeval rxtime) { stat_struct statbuf; int found_dir; if (!read_fileinfo(group, message, meslen, rxtime)) { return; } glog2(group, "Name of file to receive: %s", group->fileinfo.name); switch (group->fileinfo.ftype) { case FTYPE_REG: glog2(group, "Bytes: %s, Blocks: %d, Sections: %d", printll(group->fileinfo.size), group->fileinfo.blocks, group->fileinfo.sections); glog3(group, "small section size: %d, " "big section size: %d, # big sections: %d", group->fileinfo.secsize_small, group->fileinfo.secsize_big, group->fileinfo.big_sections); break; case FTYPE_DIR: glog2(group, "Empty directory"); break; case FTYPE_LINK: glog2(group, "Symbolic link to %s", group->fileinfo.linkname); break; case FTYPE_DELETE: glog2(group, "Deleting file/directory"); break; case FTYPE_FREESPACE: glog2(group, "Get free space for path"); break; default: glog1(group, "Invalid file type: %d", group->fileinfo.ftype); send_abort(group, "Invalid file type"); return; } if (!setup_dest_file(group)) { // A rejected file is still a success because we responded with a // COMPLETE with status=rejected instead of with an ABORT return; } // Make sure the path to the destination file exists and // remove or back up any existing file if (!create_path_to_file(group, group->fileinfo.filepath)) { glog0(group, "Error creating path to data file"); early_complete(group, COMP_STAT_REJECTED, 0); return; } found_dir = 0; if (tempfile && !group->sync_preview) { clear_path(group->fileinfo.temppath, group); } if ((group->fileinfo.ftype != FTYPE_DELETE) || (group->fileinfo.ftype != FTYPE_FREESPACE)) { // Don't do path checks for metafile commands } else if (lstat_func(group->fileinfo.filepath, &statbuf) != -1) { glog3(group, "checking existing file"); if ((group->fileinfo.ftype != FTYPE_DIR) || !S_ISDIR(statbuf.st_mode)) { if ((group->fileinfo.ftype != FTYPE_REG) || !S_ISREG(statbuf.st_mode) || ((!group->restart) && (!group->sync_mode))) { // Don't clear/backup if we're receiving a regular file // and we're in either restart mode or sync mode glog3(group, "calling move_to_backup"); if (!tempfile) { move_to_backup(group); } } } else { glog3(group, "found dir"); found_dir = 1; } } else if (errno != ENOENT) { gsyserror(group, "Error checking file %s",group->fileinfo.filepath); } switch (group->fileinfo.ftype) { case FTYPE_REG: handle_fileinfo_regular(group); break; case FTYPE_DIR: handle_fileinfo_dir(group, found_dir); break; case FTYPE_LINK: handle_fileinfo_link(group); break; case FTYPE_DELETE: handle_fileinfo_delete(group); break; case FTYPE_FREESPACE: handle_fileinfo_freespace(group); break; default: glog0(group, "Error handling FILEINFO: shouldn't get here!"); } }
/** * Removes a full path from disk */ void clear_path(const char *path, int listidx) { stat_struct statbuf; char filename[MAXPATHNAME]; int len; if (lstat_func(path, &statbuf) == -1) { if (errno != ENOENT) { syserror(group_list[listidx].group_id, group_list[listidx].file_id, "Error getting file status for %s", path); } return; } if (!S_ISDIR(statbuf.st_mode)) { unlink(path); } else { #ifdef WINDOWS intptr_t ffhandle; struct _finddatai64_t finfo; char dirglob[MAXPATHNAME]; snprintf(dirglob, sizeof(dirglob), "%s%c*", path, PATH_SEP, group_list[listidx].group_id, PATH_SEP); if ((ffhandle = _findfirsti64(dirglob, &finfo)) == -1) { syserror(group_list[listidx].group_id, group_list[listidx].file_id, "Failed to open directory %s", path); return; } do { len = snprintf(filename, sizeof(filename), "%s%c%s", path, PATH_SEP, finfo.name); if ((len >= sizeof(filename)) || (len == -1)) { log0(group_list[listidx].group_id, group_list[listidx].file_id, "Max pathname length exceeded: %s%c%s", filename, PATH_SEP, finfo.name); continue; } if (strcmp(finfo.name, ".") && strcmp(finfo.name, "..")) { clear_path(filename, listidx); } } while (_findnexti64(ffhandle, &finfo) == 0); _findclose(ffhandle); #else DIR *dir; struct dirent *de; if ((dir = opendir(path)) == NULL) { syserror(group_list[listidx].group_id, group_list[listidx].file_id, "Failed to open directory %s", path); return; } // errno needs to be set to 0 before calling readdir, otherwise // we'll report a false error when we exhaust the directory while ((errno = 0, de = readdir(dir)) != NULL) { len = snprintf(filename, sizeof(filename), "%s%c%s", path, PATH_SEP, de->d_name); if ((len >= sizeof(filename)) || (len == -1)) { log0(group_list[listidx].group_id, group_list[listidx].file_id, "Max pathname length exceeded: %s%c%s", path, PATH_SEP, de->d_name); continue; } if (strcmp(de->d_name, ".") && strcmp(de->d_name, "..")) { clear_path(filename, listidx); } } if (errno && (errno != ENOENT)) { syserror(group_list[listidx].group_id, group_list[listidx].file_id, "Failed to read directory %s", path); } closedir(dir); #endif if (rmdir(path) == -1) { syserror(group_list[listidx].group_id, group_list[listidx].file_id, "Failed remove directory %s", path); } } }