int can_play_card(struct board_t board, int side) { int corr = 0; for(corr = 0; corr < 5; corr++) { if( open_slot(board, side, corr) ) return 1; } return 0; }
int play_card(struct board_t *board, struct card_t card, int side) { int corr; for(corr = 0; corr < 5; corr++) { if( open_slot(*board, side, corr) ) { board->slot[side][corr] = card; return 1; } } return 0; }
int cache_ls(const char *path) { DIR *dir; struct dirent *ent; int err = 0; struct cache_slot slot = { NULL }; struct strbuf fullname = STRBUF_INIT; size_t prefixlen; if (!path) { cache_log("[cgit] cache path not specified\n"); return -1; } dir = opendir(path); if (!dir) { err = errno; cache_log("[cgit] unable to open path %s: %s (%d)\n", path, strerror(err), err); return err; } strbuf_addstr(&fullname, path); strbuf_ensure_end(&fullname, '/'); prefixlen = fullname.len; while ((ent = readdir(dir)) != NULL) { if (strlen(ent->d_name) != 8) continue; strbuf_setlen(&fullname, prefixlen); strbuf_addstr(&fullname, ent->d_name); slot.cache_name = fullname.buf; if ((err = open_slot(&slot)) != 0) { cache_log("[cgit] unable to open path %s: %s (%d)\n", fullname.buf, strerror(err), err); continue; } htmlf("%s %s %10"PRIuMAX" %s\n", fullname.buf, sprintftime("%Y-%m-%d %H:%M:%S", slot.cache_st.st_mtime), (uintmax_t)slot.cache_st.st_size, slot.buf); close_slot(&slot); } closedir(dir); strbuf_release(&fullname); return 0; }
static int process_slot(struct cache_slot *slot) { int err; err = open_slot(slot); if (!err && slot->match) { if (is_expired(slot)) { if (!lock_slot(slot)) { /* If the cachefile has been replaced between * `open_slot` and `lock_slot`, we'll just * serve the stale content from the original * cachefile. This way we avoid pruning the * newly generated slot. The same code-path * is chosen if fill_slot() fails for some * reason. * * TODO? check if the new slot contains the * same key as the old one, since we would * prefer to serve the newest content. * This will require us to open yet another * file-descriptor and read and compare the * key from the new file, so for now we're * lazy and just ignore the new file. */ if (is_modified(slot) || fill_slot(slot)) { unlock_slot(slot, 0); close_lock(slot); } else { close_slot(slot); unlock_slot(slot, 1); slot->cache_fd = slot->lock_fd; } } } if ((err = print_slot(slot)) != 0) { cache_log("[cgit] error printing cache %s: %s (%d)\n", slot->cache_name, strerror(err), err); } close_slot(slot); return err; } /* If the cache slot does not exist (or its key doesn't match the * current key), lets try to create a new cache slot for this * request. If this fails (for whatever reason), lets just generate * the content without caching it and fool the caller to belive * everything worked out (but print a warning on stdout). */ close_slot(slot); if ((err = lock_slot(slot)) != 0) { cache_log("[cgit] Unable to lock slot %s: %s (%d)\n", slot->lock_name, strerror(err), err); slot->fn(); return 0; } if ((err = fill_slot(slot)) != 0) { cache_log("[cgit] Unable to fill slot %s: %s (%d)\n", slot->lock_name, strerror(err), err); unlock_slot(slot, 0); close_lock(slot); slot->fn(); return 0; } // We've got a valid cache slot in the lock file, which // is about to replace the old cache slot. But if we // release the lockfile and then try to open the new cache // slot, we might get a race condition with a concurrent // writer for the same cache slot (with a different key). // Lets avoid such a race by just printing the content of // the lock file. slot->cache_fd = slot->lock_fd; unlock_slot(slot, 1); if ((err = print_slot(slot)) != 0) { cache_log("[cgit] error printing cache %s: %s (%d)\n", slot->cache_name, strerror(err), err); } close_slot(slot); return err; }