bool winwatch_root_init(watchman_global_watcher_t watcher, w_root_t *root, char **errmsg) { struct winwatch_root_state *state; WCHAR *wpath; int err; unused_parameter(watcher); state = calloc(1, sizeof(*state)); if (!state) { *errmsg = strdup("out of memory"); return false; } root->watch = state; wpath = w_utf8_to_win_unc(root->root_path->buf, root->root_path->len); if (!wpath) { asprintf(errmsg, "failed to convert root path to WCHAR: %s", win32_strerror(GetLastError())); return false; } // Create an overlapped handle so that we can avoid blocking forever // in ReadDirectoryChangesW state->dir_handle = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL); if (!state->dir_handle) { asprintf(errmsg, "failed to open dir %s: %s", root->root_path->buf, win32_strerror(GetLastError())); return false; } state->ping = CreateEvent(NULL, TRUE, FALSE, NULL); if (!state->ping) { asprintf(errmsg, "failed to create event: %s", win32_strerror(GetLastError())); return false; } state->olap = CreateEvent(NULL, TRUE, FALSE, NULL); if (!state->olap) { asprintf(errmsg, "failed to create event: %s", win32_strerror(GetLastError())); return false; } err = pthread_mutex_init(&state->mtx, NULL); if (err) { asprintf(errmsg, "failed to init mutex: %s", strerror(err)); return false; } err = pthread_cond_init(&state->cond, NULL); if (err) { asprintf(errmsg, "failed to init cond: %s", strerror(err)); return false; } return true; }
// Must be called with the mutex held static void initiate_write(struct win_handle *h) { struct write_buf *wbuf = h->write_head; if (h->write_pending || !wbuf) { return; } h->write_head = wbuf->next; if (!h->write_head) { h->write_tail = NULL; } h->write_pending = calloc(1, sizeof(*h->write_pending)); h->write_pending->h = h; h->write_pending->wbuf = wbuf; if (!WriteFileEx(h->h, wbuf->cursor, wbuf->len, &h->write_pending->olap, write_completed)) { stream_debug("WriteFileEx: failed %s\n", win32_strerror(GetLastError())); free(h->write_pending); h->write_pending = NULL; } else { stream_debug("WriteFileEx: queued %d bytes for later\n", wbuf->len); } }
static int win_read_blocking(struct win_handle *h, char *buf, int size) { int total_read = 0; DWORD bytes, err; move_from_read_buffer(h, &total_read, &buf, &size); if (size == 0) { return total_read; } stream_debug("blocking read of %d bytes\n", (int)size); if (ReadFile(h->h, buf, size, &bytes, NULL)) { total_read += bytes; stream_debug("blocking read provided %d bytes, total=%d\n", (int)bytes, total_read); return total_read; } err = GetLastError(); stream_debug("blocking read failed: %s\n", win32_strerror(err)); if (total_read) { stream_debug("but already got %d bytes from buffer\n", total_read); return total_read; } errno = map_win32_err(err); return -1; }
/** * Return the text for the most recent socket error. * * @return Error text */ static const char * socket_errtext(void) { #if !defined(_WIN32) /*[*/ return strerror(errno); #else /*][*/ return win32_strerror(GetLastError()); #endif /*]*/ }
static void CALLBACK write_completed(DWORD err, DWORD bytes, LPOVERLAPPED olap) { // Reverse engineer our handle from the olap pointer struct overlapped_op *op = (void*)olap; struct win_handle *h = op->h; struct write_buf *wbuf = op->wbuf; stream_debug("WriteFileEx: completion callback invoked: bytes=%d %s\n", (int)bytes, win32_strerror(err)); EnterCriticalSection(&h->mtx); if (h->write_pending == op) { h->write_pending = NULL; } if (err == 0) { wbuf->cursor += bytes; wbuf->len -= bytes; if (wbuf->len == 0) { // Consumed this buffer free(wbuf); } else { w_log(W_LOG_FATAL, "WriteFileEx: short write: %d written, %d remain\n", bytes, wbuf->len); } } else { stream_debug("WriteFilex: completion: failed: %s\n", win32_strerror(err)); h->errcode = err; h->error_pending = true; SetEvent(h->waitable); } // Send whatever else we have waiting to go initiate_write(h); LeaveCriticalSection(&h->mtx); // Free the prior struct after possibly initiating another write // to minimize the change of the same address being reused and // confusing the completion status free(op); }
static int win_read_non_blocking(struct win_handle *h, char *buf, int size) { int total_read = 0; char *target; DWORD target_space; DWORD bytes; stream_debug("non_blocking read for %d bytes\n", size); move_from_read_buffer(h, &total_read, &buf, &size); target = h->read_cursor + h->read_avail; target_space = (DWORD)((h->read_buf + sizeof(h->read_buf)) - target); stream_debug("initiate read for %d\n", target_space); // Create a unique olap for each request h->read_pending = calloc(1, sizeof(*h->read_pending)); if (h->read_avail == 0) { ResetEvent(h->waitable); } h->read_pending->olap.hEvent = h->waitable; h->read_pending->h = h; if (!ReadFile(h->h, target, target_space, &bytes, &h->read_pending->olap)) { DWORD err = GetLastError(); if (err != ERROR_IO_PENDING) { free(h->read_pending); h->read_pending = NULL; stream_debug("olap read failed immediately: %s\n", win32_strerror(err)); } else { stream_debug("olap read queued ok\n"); } stream_debug("returning %d\n", total_read == 0 ? -1 : total_read); errno = map_win32_err(err); return total_read == 0 ? -1 : total_read; } stream_debug("olap read succeeded immediately!? bytes=%d\n", (int)bytes); // We don't expect this to succeed in the overlapped case, // but we can handle the result anyway h->read_avail += bytes; free(h->read_pending); h->read_pending = NULL; move_from_read_buffer(h, &total_read, &buf, &size); stream_debug("read returning %d\n", total_read); return total_read; }
static bool win_read_handle_completion(struct win_handle *h) { BOOL olap_res; DWORD bytes, err; EnterCriticalSection(&h->mtx); if (!h->read_pending) { LeaveCriticalSection(&h->mtx); return false; } stream_debug("have read_pending, checking status\n"); // Don't hold the mutex while we're blocked LeaveCriticalSection(&h->mtx); olap_res = get_overlapped_result_ex(h->h, &h->read_pending->olap, &bytes, h->blocking ? INFINITE : 0, true); err = GetLastError(); EnterCriticalSection(&h->mtx); if (olap_res) { stream_debug("pending read completed, read %d bytes, %s\n", (int)bytes, win32_strerror(err)); h->read_avail += bytes; free(h->read_pending); h->read_pending = NULL; } else { stream_debug("pending read failed: %s\n", win32_strerror(err)); if (err != ERROR_IO_INCOMPLETE) { // Failed free(h->read_pending); h->read_pending = NULL; h->errcode = err; h->error_pending = true; } } LeaveCriticalSection(&h->mtx); return h->read_pending != NULL; }
/* * Remove a route from the kernel * @param destination the route to remove * @return negative on error */ int os_route_del_rtentry(const struct rt_entry *rt, int ip_version) { MIB_IPFORWARDROW Row; union olsr_ip_addr mask; unsigned long Res; struct interface *iface = rt->rt_nexthop.interface; if (AF_INET != ip_version) { /* * Not implemented */ return -1; } OLSR_DEBUG(LOG_NETWORKING, "KERN: Deleting %s\n", olsr_rt_to_string(rt)); memset(&Row, 0, sizeof(Row)); Row.dwForwardDest = rt->rt_dst.prefix.v4.s_addr; if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) { return -1; } Row.dwForwardMask = mask.v4.s_addr; Row.dwForwardPolicy = 0; Row.dwForwardNextHop = rt->rt_nexthop.gateway.v4.s_addr; Row.dwForwardIfIndex = iface->if_index; // MIB_IPROUTE_TYPE_DIRECT and MIB_IPROUTE_TYPE_INDIRECT Row.dwForwardType = (rt->rt_dst.prefix.v4.s_addr == rt->rt_nexthop.gateway.v4.s_addr) ? 3 : 4; Row.dwForwardProto = 3; // MIB_IPPROTO_NETMGMT Row.dwForwardAge = INFINITE; Row.dwForwardNextHopAS = 0; Row.dwForwardMetric1 = olsr_fib_metric(&rt->rt_metric); Row.dwForwardMetric2 = -1; Row.dwForwardMetric3 = -1; Row.dwForwardMetric4 = -1; Row.dwForwardMetric5 = -1; Res = DeleteIpForwardEntry(&Row); if (Res != NO_ERROR) { OLSR_WARN(LOG_NETWORKING, "DeleteIpForwardEntry() = %08lx, %s", Res, win32_strerror(Res)); // XXX - report error in a different way errno = Res; return -1; } return 0; }
static int win_write(w_stm_t stm, const void *buf, int size) { struct win_handle *h = stm->handle; struct write_buf *wbuf; EnterCriticalSection(&h->mtx); if (h->file_type != FILE_TYPE_PIPE && h->blocking && !h->write_head) { DWORD bytes; stream_debug("blocking write of %d\n", size); if (WriteFile(h->h, buf, size, &bytes, NULL)) { LeaveCriticalSection(&h->mtx); return bytes; } h->errcode = GetLastError(); h->error_pending = true; errno = map_win32_err(h->errcode); SetEvent(h->waitable); stream_debug("write failed: %s\n", win32_strerror(h->errcode)); LeaveCriticalSection(&h->mtx); return -1; } wbuf = malloc(sizeof(*wbuf) + size - 1); if (!wbuf) { return -1; } wbuf->next = NULL; wbuf->cursor = wbuf->data; wbuf->len = size; memcpy(wbuf->data, buf, size); if (h->write_tail) { h->write_tail->next = wbuf; } else { h->write_head = wbuf; } h->write_tail = wbuf; if (!h->write_pending) { initiate_write(h); } LeaveCriticalSection(&h->mtx); return size; }
/* * Start up a window to monitor the trace file. * * @param[in] path Trace file path. */ static void start_trace_window(const char *path) { STARTUPINFO startupinfo; PROCESS_INFORMATION process_information; memset(&startupinfo, 0, sizeof(STARTUPINFO)); startupinfo.cb = sizeof(STARTUPINFO); startupinfo.lpTitle = (char *)path; memset(&process_information, 0, sizeof(PROCESS_INFORMATION)); if (CreateProcess(lazyaf("%scatf.exe", instdir), lazyaf("\"%scatf.exe\" \"%s\"", instdir, path), NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &startupinfo, &process_information) == 0) { popup_an_error("CreateProcess(%scatf.exe \"%s\") failed: %s", instdir, path, win32_strerror(GetLastError())); } else { tracewindow_handle = process_information.hProcess; CloseHandle(process_information.hThread); } }
static const char *compute_user_name(void) { const char *user = get_env_with_fallback("USER", "LOGNAME", NULL); #ifdef _WIN32 static char user_buf[256]; #endif if (!user) { #ifdef _WIN32 DWORD size = sizeof(user_buf); if (GetUserName(user_buf, &size)) { user_buf[size] = 0; user = user_buf; } else { w_log(W_LOG_FATAL, "GetUserName failed: %s. I don't know who you are\n", win32_strerror(GetLastError())); } #else uid_t uid = getuid(); struct passwd *pw; pw = getpwuid(uid); if (!pw) { w_log(W_LOG_FATAL, "getpwuid(%d) failed: %s. I don't know who you are\n", uid, strerror(errno)); } user = pw->pw_name; #endif if (!user) { w_log(W_LOG_ERR, "watchman requires that you set $USER in your env\n"); abort(); } } return user; }
static void setup_sock_name(void) { const char *user = get_env_with_fallback("USER", "LOGNAME", NULL); #ifdef _WIN32 char user_buf[256]; #endif watchman_tmp_dir = get_env_with_fallback("TMPDIR", "TMP", "/tmp"); if (!user) { #ifdef _WIN32 DWORD size = sizeof(user_buf); if (GetUserName(user_buf, &size)) { user_buf[size] = 0; user = user_buf; } else { w_log(W_LOG_FATAL, "GetUserName failed: %s. I don't know who you are\n", win32_strerror(GetLastError())); } #else uid_t uid = getuid(); struct passwd *pw; pw = getpwuid(uid); if (!pw) { w_log(W_LOG_FATAL, "getpwuid(%d) failed: %s. I don't know who you are\n", uid, strerror(errno)); } user = pw->pw_name; #endif if (!user) { w_log(W_LOG_ERR, "watchman requires that you set $USER in your env\n"); abort(); } } #ifdef _WIN32 if (!sock_name) { asprintf(&sock_name, "\\\\.\\pipe\\watchman-%s", user); } #else compute_file_name(&sock_name, user, "sock", "sockname"); #endif compute_file_name(&watchman_state_file, user, "state", "statefile"); compute_file_name(&log_name, user, "log", "logname"); #ifdef USE_GIMLI compute_file_name(&pid_file, user, "pid", "pidfile"); #endif #ifndef _WIN32 un.sun_family = PF_LOCAL; strcpy(un.sun_path, sock_name); if (strlen(sock_name) >= sizeof(un.sun_path) - 1) { w_log(W_LOG_ERR, "%s: path is too long\n", sock_name); abort(); } #endif }
static void *readchanges_thread(void *arg) { w_root_t *root = arg; struct winwatch_root_state *state = root->watch; DWORD size = WATCHMAN_BATCH_LIMIT * (sizeof(FILE_NOTIFY_INFORMATION) + 512); char *buf; DWORD err, filter; OVERLAPPED olap; BOOL initiate_read = true; HANDLE handles[2] = { state->olap, state->ping }; DWORD bytes; w_set_thread_name("readchange %.*s", root->root_path->len, root->root_path->buf); // Block until winmatch_root_st is waiting for our initialization pthread_mutex_lock(&state->mtx); filter = FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME| FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_SIZE| FILE_NOTIFY_CHANGE_LAST_WRITE; memset(&olap, 0, sizeof(olap)); olap.hEvent = state->olap; buf = malloc(size); if (!buf) { w_log(W_LOG_ERR, "failed to allocate %u bytes for dirchanges buf\n", size); goto out; } if (!ReadDirectoryChangesW(state->dir_handle, buf, size, TRUE, filter, NULL, &olap, NULL)) { err = GetLastError(); w_log(W_LOG_ERR, "ReadDirectoryChangesW: failed, cancel watch. %s\n", win32_strerror(err)); w_root_lock(root); w_root_cancel(root); w_root_unlock(root); goto out; } // Signal that we are done with init. We MUST do this AFTER our first // successful ReadDirectoryChangesW, otherwise there is a race condition // where we'll miss observing the cookie for a query that comes in // after we've crawled but before the watch is established. w_log(W_LOG_DBG, "ReadDirectoryChangesW signalling as init done"); pthread_cond_signal(&state->cond); pthread_mutex_unlock(&state->mtx); initiate_read = false; // The state->mutex must not be held when we enter the loop while (!root->cancelled) { if (initiate_read) { if (!ReadDirectoryChangesW(state->dir_handle, buf, size, TRUE, filter, NULL, &olap, NULL)) { err = GetLastError(); w_log(W_LOG_ERR, "ReadDirectoryChangesW: failed, cancel watch. %s\n", win32_strerror(err)); w_root_lock(root); w_root_cancel(root); w_root_unlock(root); break; } else { initiate_read = false; } } w_log(W_LOG_DBG, "waiting for change notifications"); DWORD status = WaitForMultipleObjects(2, handles, FALSE, INFINITE); if (status == WAIT_OBJECT_0) { bytes = 0; if (!GetOverlappedResult(state->dir_handle, &olap, &bytes, FALSE)) { err = GetLastError(); w_log(W_LOG_ERR, "overlapped ReadDirectoryChangesW(%s): 0x%x %s\n", root->root_path->buf, err, win32_strerror(err)); if (err == ERROR_INVALID_PARAMETER && size > NETWORK_BUF_SIZE) { // May be a network buffer related size issue; the docs say that // we can hit this when watching a UNC path. Let's downsize and // retry the read just one time w_log(W_LOG_ERR, "retrying watch for possible network location %s " "with smaller buffer\n", root->root_path->buf); size = NETWORK_BUF_SIZE; initiate_read = true; continue; } if (err == ERROR_NOTIFY_ENUM_DIR) { w_root_schedule_recrawl(root, "ERROR_NOTIFY_ENUM_DIR"); } else { w_log(W_LOG_ERR, "Cancelling watch for %s\n", root->root_path->buf); w_root_lock(root); w_root_cancel(root); w_root_unlock(root); break; } } else { PFILE_NOTIFY_INFORMATION not = (PFILE_NOTIFY_INFORMATION)buf; struct winwatch_changed_item *head = NULL, *tail = NULL; while (true) { struct winwatch_changed_item *item; DWORD n_chars; w_string_t *name, *full; // FileNameLength is in BYTES, but FileName is WCHAR n_chars = not->FileNameLength / sizeof(not->FileName[0]); name = w_string_new_wchar(not->FileName, n_chars); full = w_string_path_cat(root->root_path, name); w_string_delref(name); if (w_is_ignored(root, full->buf, full->len)) { w_string_delref(full); } else { item = calloc(1, sizeof(*item)); item->name = full; if (tail) { tail->next = item; } else { head = item; } tail = item; } // Advance to next item if (not->NextEntryOffset == 0) { break; } not = (PFILE_NOTIFY_INFORMATION)(not->NextEntryOffset + (char*)not); } if (tail) { pthread_mutex_lock(&state->mtx); if (state->tail) { state->tail->next = head; } else { state->head = head; } state->tail = tail; pthread_mutex_unlock(&state->mtx); pthread_cond_signal(&state->cond); } ResetEvent(state->olap); initiate_read = true; } } else if (status == WAIT_OBJECT_0 + 1) { w_log(W_LOG_ERR, "signalled\n"); break; } else { w_log(W_LOG_ERR, "impossible wait status=%d\n", status); break; } } pthread_mutex_lock(&state->mtx); out: // Signal to winwatch_root_start that we're done initializing in // the failure path. We'll also do this after we've completed // the run loop in the success path; it's a spurious wakeup but // harmless and saves us from adding and setting a control flag // in each of the failure `goto` statements. winwatch_root_dtor // will `pthread_join` us before `state` is freed. pthread_cond_signal(&state->cond); pthread_mutex_unlock(&state->mtx); if (buf) { free(buf); } w_log(W_LOG_DBG, "done\n"); w_root_delref(root); return NULL; }
/* * Initalize the named GDI printer. If the name is NULL, use the default * printer. */ static gdi_status_t gdi_init(const char *printer_name, unsigned opts, const char **fail) { char *default_printer_name; LPDEVMODE devmode; HDC dc; DOCINFO docinfo; DEVNAMES *devnames; int rmargin, bmargin; /* right margin, bottom margin */ int maxphmargin, maxpvmargin; int i; static char get_fail[1024]; int fheight, fwidth; memset(&pstate.dlg, '\0', sizeof(pstate.dlg)); pstate.dlg.lStructSize = sizeof(pstate.dlg); pstate.dlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_HIDEPRINTTOFILE | PD_NOSELECTION; if (printer_name == NULL || !*printer_name) { default_printer_name = get_default_printer_name(get_fail, sizeof(get_fail)); if (default_printer_name == NULL) { *fail = get_fail; goto failed; } printer_name = default_printer_name; } if (!get_printer_device(printer_name, &pstate.dlg.hDevNames, &pstate.dlg.hDevMode)) { snprintf(get_fail, sizeof(get_fail), "GetPrinter(%s) failed: %s", printer_name, win32_strerror(GetLastError())); *fail = get_fail; goto failed; } if (uparm.orientation) { devmode = (LPDEVMODE)GlobalLock(pstate.dlg.hDevMode); devmode->dmFields |= DM_ORIENTATION; devmode->dmOrientation = uparm.orientation; GlobalUnlock(devmode); } if (opts & FPS_NO_DIALOG) { /* They don't want the print dialog. Allocate a DC for it. */ devmode = (LPDEVMODE)GlobalLock(pstate.dlg.hDevMode); pstate.dlg.hDC = CreateDC("WINSPOOL", printer_name, NULL, devmode); GlobalUnlock(devmode); if (pstate.dlg.hDC == NULL) { snprintf(get_fail, sizeof(get_fail), "Cannot create DC for " "printer '%s'", printer_name); *fail = get_fail; goto failed; } } else { if (default_printer_name != NULL) { Free(default_printer_name); default_printer_name = NULL; } /* Pop up the dialog to get the printer characteristics. */ if (!PrintDlg(&pstate.dlg)) { return GDI_STATUS_CANCEL; } } dc = pstate.dlg.hDC; if (default_printer_name != NULL) { Free(default_printer_name); default_printer_name = NULL; } /* Find out the printer characteristics. */ /* LOGPIXELSX and LOGPIXELSY are the pixels-per-inch for the printer. */ pchar.ppiX = GetDeviceCaps(dc, LOGPIXELSX); if (pchar.ppiX <= 0) { *fail = "Can't get LOGPIXELSX"; goto failed; } pchar.ppiY = GetDeviceCaps(dc, LOGPIXELSY); if (pchar.ppiY <= 0) { *fail = "Can't get LOGPIXELSY"; goto failed; } /* * PHYSICALOFFSETX and PHYSICALOFFSETY are the fixed top and left-hand * margins, in pixels. Whatever you print is offset by these amounts, so * you have to subtract them from your coordinates. You cannot print in * these areas. */ pchar.poffX = GetDeviceCaps(dc, PHYSICALOFFSETX); if (pchar.poffX < 0) { *fail = "Can't get PHYSICALOFFSETX"; goto failed; } pchar.poffY = GetDeviceCaps(dc, PHYSICALOFFSETY); if (pchar.poffY < 0) { *fail = "Can't get PHYSICALOFFSETY"; goto failed; } /* * HORZRES and VERTRES are the size of the usable area of the page, in * pixels. They implicitly give you the size of the right-hand and * bottom physical offsets. */ pchar.horzres = GetDeviceCaps(dc, HORZRES); if (pchar.horzres <= 0) { *fail = "Can't get HORZRES"; goto failed; } pchar.vertres = GetDeviceCaps(dc, VERTRES); if (pchar.vertres <= 0) { *fail = "Can't get VERTRES"; goto failed; } /* * PHYSICALWIDTH and PHYSICALHEIGHT are the size of the entire area of * the page, in pixels. */ pchar.pwidth = GetDeviceCaps(dc, PHYSICALWIDTH); if (pchar.pwidth <= 0) { *fail = "Can't get PHYSICALWIDTH"; goto failed; } pchar.pheight = GetDeviceCaps(dc, PHYSICALHEIGHT); if (pchar.pheight <= 0) { *fail = "Can't get PHYSICALHEIGHT"; goto failed; } /* Trace the device characteristics. */ devnames = (DEVNAMES *)GlobalLock(pstate.dlg.hDevNames); vtrace("[gdi] Printer '%s' capabilities:\n", (char *)devnames + devnames->wDeviceOffset); GlobalUnlock(devnames); vtrace("[gdi] LOGPIXELSX %d LOGPIXELSY %d\n", pchar.ppiX, pchar.ppiY); vtrace("[gdi] PHYSICALOFFSETX %d PHYSICALOFFSETY %d\n", pchar.poffX, pchar.poffY); vtrace("[gdi] HORZRES %d VERTRES %d\n", pchar.horzres, pchar.vertres); vtrace("[gdi] PHYSICALWIDTH %d PHYSICALHEIGHT %d\n", pchar.pwidth, pchar.pheight); /* Compute the scale factors (points to pixels). */ pstate.xptscale = (FLOAT)pchar.ppiX / (FLOAT)PPI; pstate.yptscale = (FLOAT)pchar.ppiY / (FLOAT)PPI; /* Compute the implied right and bottom margins. */ rmargin = pchar.pwidth - pchar.horzres - pchar.poffX; bmargin = pchar.pheight - pchar.vertres - pchar.poffY; if (rmargin > pchar.poffX) { maxphmargin = rmargin; } else { maxphmargin = pchar.poffX; } if (bmargin > pchar.poffY) { maxpvmargin = bmargin; } else { maxpvmargin = pchar.poffY; } vtrace("[gdi] maxphmargin is %d, maxpvmargin is %d pixels\n", maxphmargin, maxpvmargin); /* Compute the margins in pixels. */ pstate.hmargin_pixels = (int)(uparm.hmargin * pchar.ppiX); pstate.vmargin_pixels = (int)(uparm.vmargin * pchar.ppiY); /* See if the margins are too small. */ if (pstate.hmargin_pixels < maxphmargin) { pstate.hmargin_pixels = maxphmargin; vtrace("[gdi] hmargin is too small, setting to %g\"\n", (float)pstate.hmargin_pixels / pchar.ppiX); } if (pstate.vmargin_pixels < maxpvmargin) { pstate.vmargin_pixels = maxpvmargin; vtrace("[gdi] vmargin is too small, setting to %g\"\n", (float)pstate.vmargin_pixels / pchar.ppiX); } /* See if the margins are too big. */ if (pstate.hmargin_pixels * 2 >= pchar.horzres) { pstate.hmargin_pixels = pchar.ppiX; vtrace("[gdi] hmargin is too big, setting to 1\"\n"); } if (pstate.vmargin_pixels * 2 >= pchar.vertres) { pstate.vmargin_pixels = pchar.ppiY; vtrace("[gdi] vmargin is too big, setting to 1\"\n"); } /* * Compute the usable area in pixels. That's the physical page size * less the margins, now that we know that the margins are reasonable. */ pstate.usable_xpixels = pchar.pwidth - (2 * pstate.hmargin_pixels); pstate.usable_ypixels = pchar.pheight - (2 * pstate.vmargin_pixels); vtrace("[gdi] usable area is %dx%d pixels\n", pstate.usable_xpixels, pstate.usable_ypixels); /* * Create the Roman font. * * If they specified a particular font size, use that as the height, * and let the system pick the width. * * If they did not specify a font size, or chose "auto", then let the * "screens per page" drive what to do. If "screens per page" is set, * then divide the page Y pixels by the screens-per-page times the * display height to get the font height, and let the system pick the * width. * * Otherwise, divide the page X pixels by COLS to get the font width, * and let the system pick the height. */ if (uparm.font_size) { /* User-specified fixed font size. */ fheight = (int)(uparm.font_size * pstate.yptscale); fwidth = 0; } else { if (uparm.spp > 1) { /* * Scale the height so the specified number of screens will * fit. */ fheight = pstate.usable_ypixels / (uparm.spp * maxROWS /* spp screens */ + (uparm.spp - 1) /* spaces between screens */ + 2 /* space and caption*/ ); fwidth = 0; } else { /* * Scale the width so a screen will fit the page horizonally. */ fheight = 0; fwidth = pstate.usable_xpixels / maxCOLS; } } if (create_roman_font(dc, fheight, fwidth, fail) < 0) { goto failed; } /* * If we computed the font size, see if the other dimension is too * big. If it is, scale using the other dimension, which is guaranteed to * make the original computed dimension no bigger. * * XXX: This needs more testing. */ if (!uparm.font_size) { if (fwidth == 0) { /* * We computed the height because spp > 1. See if the width * overflows. */ if (pstate.space_size.cx * maxCOLS > pstate.usable_xpixels) { vtrace("[gdi] font too wide, retrying\n"); DeleteObject(pstate.font); pstate.font = NULL; fheight = 0; fwidth = pstate.usable_xpixels / maxCOLS; if (create_roman_font(dc, fheight, fwidth, fail) < 0) { goto failed; } } } else if (fheight == 0) { /* * We computed the width (spp <= 1). See if the height * overflows. */ if (pstate.space_size.cy * (maxROWS + 2) > pstate.usable_xpixels) { vtrace("[gdi] font too high, retrying\n"); DeleteObject(pstate.font); pstate.font = NULL; fheight = pstate.usable_xpixels / (maxROWS + 2); fwidth = 0; if (create_roman_font(dc, fheight, fwidth, fail) < 0) { goto failed; } } } } /* Create a bold font that is the same size, if possible. */ pstate.bold_font = CreateFont( pstate.space_size.cy, /* height */ pstate.space_size.cx, /* width */ 0, /* escapement */ 0, /* orientation */ FW_BOLD, /* weight */ FALSE, /* italic */ FALSE, /* underline */ FALSE, /* strikeout */ ANSI_CHARSET, /* character set */ OUT_OUTLINE_PRECIS, /* output precision */ CLIP_DEFAULT_PRECIS, /* clip precision */ DEFAULT_QUALITY, /* quality */ FIXED_PITCH|FF_DONTCARE,/* pitch and family */ uparm.font_name); /* face */ if (pstate.bold_font == NULL) { *fail = "CreateFont (bold) failed"; goto failed; } /* Create an underscore font that is the same size, if possible. */ pstate.underscore_font = CreateFont( pstate.space_size.cy, /* height */ pstate.space_size.cx, /* width */ 0, /* escapement */ 0, /* orientation */ FW_NORMAL, /* weight */ FALSE, /* italic */ TRUE, /* underline */ FALSE, /* strikeout */ ANSI_CHARSET, /* character set */ OUT_OUTLINE_PRECIS, /* output precision */ CLIP_DEFAULT_PRECIS, /* clip precision */ DEFAULT_QUALITY, /* quality */ FIXED_PITCH|FF_DONTCARE,/* pitch and family */ uparm.font_name); /* face */ if (pstate.underscore_font == NULL) { *fail = "CreateFont (underscore) failed"; goto failed; } /* Create a bold, underscore font that is the same size, if possible. */ pstate.bold_underscore_font = CreateFont( pstate.space_size.cy, /* height */ pstate.space_size.cx, /* width */ 0, /* escapement */ 0, /* orientation */ FW_BOLD, /* weight */ FALSE, /* italic */ TRUE, /* underline */ FALSE, /* strikeout */ ANSI_CHARSET, /* character set */ OUT_OUTLINE_PRECIS, /* output precision */ CLIP_DEFAULT_PRECIS, /* clip precision */ DEFAULT_QUALITY, /* quality */ FIXED_PITCH|FF_DONTCARE,/* pitch and family */ uparm.font_name); /* face */ if (pstate.bold_underscore_font == NULL) { *fail = "CreateFont (bold underscore) failed"; goto failed; } /* Create a caption font. */ pstate.caption_font = CreateFont( pstate.space_size.cy, /* height */ 0, /* width */ 0, /* escapement */ 0, /* orientation */ FW_NORMAL, /* weight */ TRUE, /* italic */ FALSE, /* underline */ FALSE, /* strikeout */ ANSI_CHARSET, /* character set */ OUT_OUTLINE_PRECIS, /* output precision */ CLIP_DEFAULT_PRECIS, /* clip precision */ DEFAULT_QUALITY, /* quality */ VARIABLE_PITCH|FF_DONTCARE,/* pitch and family */ "Times New Roman"); /* face */ if (pstate.bold_underscore_font == NULL) { *fail = "CreateFont (bold underscore) failed"; goto failed; } /* Set up the manual spacing array. */ pstate.dx = Malloc(sizeof(INT) * maxCOLS); for (i = 0; i < maxCOLS; i++) { pstate.dx[i] = pstate.space_size.cx; } /* Fill in the document info. */ memset(&docinfo, '\0', sizeof(docinfo)); docinfo.cbSize = sizeof(docinfo); docinfo.lpszDocName = "wc3270 screen"; /* Start the document. */ if (StartDoc(dc, &docinfo) <= 0) { *fail = "StartDoc failed"; goto failed; } return GDI_STATUS_SUCCESS; failed: /* Clean up what we can and return failure. */ if (default_printer_name != NULL) { Free(default_printer_name); } cleanup_fonts(); return GDI_STATUS_ERROR; }
static int posix_spawn_common( bool search_path, pid_t *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[]) { STARTUPINFO sinfo; SECURITY_ATTRIBUTES sec; PROCESS_INFORMATION pinfo; char *cmdbuf; char *env_block; DWORD create_flags = CREATE_NO_WINDOW; int ret; int i; unused_parameter(envp); // FIXME cmdbuf = build_command_line(argv); if (!cmdbuf) { return ENOMEM; } env_block = make_env_block(envp); if (!env_block) { free(cmdbuf); return ENOMEM; } memset(&sinfo, 0, sizeof(sinfo)); sinfo.cb = sizeof(sinfo); sinfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; sinfo.wShowWindow = SW_HIDE; memset(&sec, 0, sizeof(sec)); sec.nLength = sizeof(sec); sec.bInheritHandle = TRUE; memset(&pinfo, 0, sizeof(pinfo)); if (attrp->flags & POSIX_SPAWN_SETPGROUP) { create_flags |= CREATE_NEW_PROCESS_GROUP; } // Process any dup(2) actions for (i = 0; i < file_actions->ndups; i++) { struct _posix_spawn_file_dup *dup = &file_actions->dups[i]; HANDLE *target = NULL; DWORD err; switch (dup->target_fd) { case 0: target = &sinfo.hStdInput; break; case 1: target = &sinfo.hStdOutput; break; case 2: target = &sinfo.hStdError; break; } if (!target) { w_log(W_LOG_ERR, "posix_spawn: can't target fd outside range [0-2]\n"); ret = ENOSYS; goto done; } if (*target) { CloseHandle(*target); *target = INVALID_HANDLE_VALUE; } if (!DuplicateHandle(GetCurrentProcess(), dup->local_handle, GetCurrentProcess(), target, 0, TRUE, DUPLICATE_SAME_ACCESS)) { err = GetLastError(); w_log(W_LOG_ERR, "posix_spawn: failed to duplicate handle: %s\n", win32_strerror(err)); ret = map_win32_err(err); goto done; } } // Process any file opening actions for (i = 0; i < file_actions->nopens; i++) { struct _posix_spawn_file_open *op = &file_actions->opens[i]; HANDLE h; HANDLE *target = NULL; switch (op->target_fd) { case 0: target = &sinfo.hStdInput; break; case 1: target = &sinfo.hStdOutput; break; case 2: target = &sinfo.hStdError; break; } if (!target) { w_log(W_LOG_ERR, "posix_spawn: can't target fd outside range [0-2]\n"); ret = ENOSYS; goto done; } h = w_handle_open(op->name, op->flags & ~O_CLOEXEC); if (h == INVALID_HANDLE_VALUE) { ret = errno; w_log(W_LOG_ERR, "posix_spawn: failed to open %s:\n", op->name); goto done; } if (*target) { CloseHandle(*target); } *target = h; } if (!sinfo.hStdInput) { sinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); } if (!sinfo.hStdOutput) { sinfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); } if (!sinfo.hStdError) { sinfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); } if (!CreateProcess(search_path ? NULL : path, cmdbuf, &sec, &sec, TRUE, create_flags, env_block, attrp->working_dir, &sinfo, &pinfo)) { w_log(W_LOG_ERR, "CreateProcess: `%s`: (cwd=%s) %s\n", cmdbuf, attrp->working_dir ? attrp->working_dir : "<process cwd>", win32_strerror(GetLastError())); ret = EACCES; } else { *pid = (pid_t)pinfo.dwProcessId; // Record the pid -> handle mapping for later wait/reap pthread_mutex_lock(&child_proc_lock); if (!child_procs) { child_procs = w_ht_new(2, NULL); } w_ht_set(child_procs, pinfo.dwProcessId, w_ht_ptr_val(pinfo.hProcess)); pthread_mutex_unlock(&child_proc_lock); CloseHandle(pinfo.hThread); ret = 0; } done: free(cmdbuf); free(env_block); // If we manufactured any handles, close them out now if (sinfo.hStdInput != GetStdHandle(STD_INPUT_HANDLE)) { CloseHandle(sinfo.hStdInput); } if (sinfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE)) { CloseHandle(sinfo.hStdOutput); } if (sinfo.hStdError != GetStdHandle(STD_ERROR_HANDLE)) { CloseHandle(sinfo.hStdError); } return ret; }
int lstat(const char *path, struct stat *st) { FILE_BASIC_INFO binfo; FILE_STANDARD_INFO sinfo; WCHAR *wpath = w_utf8_to_win_unc(path, -1); HANDLE h; DWORD err; memset(st, 0, sizeof(*st)); if (!wpath) { return -1; } h = CreateFileW(wpath, FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); err = GetLastError(); free(wpath); if (h == INVALID_HANDLE_VALUE) { w_log(W_LOG_DBG, "lstat(%s): %s\n", path, win32_strerror(err)); errno = map_win32_err(err); return -1; } if (path[1] == ':') { int drive_letter = tolower(path[0]); st->st_rdev = st->st_dev = drive_letter - 'a'; } if (GetFileInformationByHandleEx(h, FileBasicInfo, &binfo, sizeof(binfo))) { FILETIME_LARGE_INTEGER_to_timespec(binfo.CreationTime, &st->st_ctim); st->st_ctime = st->st_ctim.tv_sec; FILETIME_LARGE_INTEGER_to_timespec(binfo.LastAccessTime, &st->st_atim); st->st_atime = st->st_atim.tv_sec; FILETIME_LARGE_INTEGER_to_timespec(binfo.LastWriteTime, &st->st_mtim); st->st_mtime = st->st_mtim.tv_sec; if (binfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { // This is a symlink, but msvcrt has no way to indicate that. // We'll treat it as a regular file until we have a better // representation :-/ st->st_mode = _S_IFREG; } else if (binfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { st->st_mode |= _S_IFDIR|S_IEXEC|S_IXGRP|S_IXOTH; } else { st->st_mode |= _S_IFREG; } if (binfo.FileAttributes & FILE_ATTRIBUTE_READONLY) { st->st_mode |= 0444; } else { st->st_mode |= 0666; } } if (GetFileInformationByHandleEx(h, FileStandardInfo, &sinfo, sizeof(sinfo))) { st->st_size = sinfo.EndOfFile.QuadPart; st->st_nlink = sinfo.NumberOfLinks; } CloseHandle(h); return 0; }
static void named_pipe_accept_loop(const char *path) { HANDLE handles[2]; OVERLAPPED olap; HANDLE connected_event = CreateEvent(NULL, FALSE, TRUE, NULL); if (!connected_event) { w_log(W_LOG_ERR, "named_pipe_accept_loop: CreateEvent failed: %s\n", win32_strerror(GetLastError())); return; } listener_thread_event = CreateEvent(NULL, FALSE, TRUE, NULL); handles[0] = connected_event; handles[1] = listener_thread_event; memset(&olap, 0, sizeof(olap)); olap.hEvent = connected_event; w_log(W_LOG_ERR, "waiting for pipe clients on %s\n", path); while (!stopping) { w_stm_t stm; HANDLE client_fd; DWORD res; client_fd = CreateNamedPipe( path, PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE|PIPE_READMODE_BYTE| PIPE_REJECT_REMOTE_CLIENTS, PIPE_UNLIMITED_INSTANCES, WATCHMAN_IO_BUF_SIZE, 512, 0, NULL); if (client_fd == INVALID_HANDLE_VALUE) { w_log(W_LOG_ERR, "CreateNamedPipe(%s) failed: %s\n", path, win32_strerror(GetLastError())); continue; } ResetEvent(connected_event); if (!ConnectNamedPipe(client_fd, &olap)) { res = GetLastError(); if (res == ERROR_PIPE_CONNECTED) { goto good_client; } if (res != ERROR_IO_PENDING) { w_log(W_LOG_ERR, "ConnectNamedPipe: %s\n", win32_strerror(GetLastError())); CloseHandle(client_fd); continue; } res = WaitForMultipleObjectsEx(2, handles, false, INFINITE, true); if (res == WAIT_OBJECT_0 + 1) { // Signalled to stop CancelIoEx(client_fd, &olap); CloseHandle(client_fd); continue; } if (res == WAIT_OBJECT_0) { goto good_client; } w_log(W_LOG_ERR, "WaitForMultipleObjectsEx: ConnectNamedPipe: " "unexpected status %u\n", res); CancelIoEx(client_fd, &olap); CloseHandle(client_fd); } else { good_client: stm = w_stm_handleopen(client_fd); if (!stm) { w_log(W_LOG_ERR, "Failed to allocate stm for pipe handle: %s\n", strerror(errno)); CloseHandle(client_fd); continue; } make_new_client(stm); } } }
/* Callback for "OK" button on trace popup */ static void tracefile_callback(Widget w, XtPointer client_data, XtPointer call_data _is_unused) { char *tfn = CN; int devfd = -1; #if defined(X3270_DISPLAY) /*[*/ int pipefd[2]; Boolean just_piped = False; #endif /*]*/ char *buf; #if defined(X3270_DISPLAY) /*[*/ if (w) tfn = XawDialogGetValueString((Widget)client_data); else #endif /*]*/ tfn = (char *)client_data; tfn = do_subst(tfn, DS_VARS | DS_TILDE | DS_UNIQUE); if (strchr(tfn, '\'') || ((int)strlen(tfn) > 0 && tfn[strlen(tfn)-1] == '\\')) { popup_an_error("Illegal file name: %s", tfn); Free(tfn); goto done; } tracef_max = 0; if (!strcmp(tfn, "stdout")) { tracef = stdout; } else { #if defined(X3270_DISPLAY) /*[*/ FILE *pipefile = NULL; if (!strcmp(tfn, "none") || !tfn[0]) { just_piped = True; if (!appres.trace_monitor) { popup_an_error("Must specify a trace file " "name"); free(tfn); goto done; } } if (appres.trace_monitor) { if (pipe(pipefd) < 0) { popup_an_errno(errno, "pipe() failed"); Free(tfn); goto done; } pipefile = fdopen(pipefd[1], "w"); if (pipefile == NULL) { popup_an_errno(errno, "fdopen() failed"); (void) close(pipefd[0]); (void) close(pipefd[1]); Free(tfn); goto done; } (void) SETLINEBUF(pipefile); (void) fcntl(pipefd[1], F_SETFD, 1); } if (just_piped) { tracef = pipefile; } else #endif /*]*/ { Boolean append = False; #if defined(X3270_DISPLAY) /*[*/ tracef_pipe = pipefile; #endif /*]*/ /* Get the trace file maximum. */ get_tracef_max(); /* Open and configure the file. */ if ((devfd = get_devfd(tfn)) >= 0) tracef = fdopen(dup(devfd), "a"); else if (!strncmp(tfn, ">>", 2)) { append = True; tracef = fopen(tfn + 2, "a"); } else tracef = fopen(tfn, "w"); if (tracef == (FILE *)NULL) { popup_an_errno(errno, "%s", tfn); #if defined(X3270_DISPLAY) /*[*/ fclose(tracef_pipe); (void) close(pipefd[0]); (void) close(pipefd[1]); #endif /*]*/ Free(tfn); goto done; } tracef_size = ftello(tracef); Replace(tracefile_name, NewString(append? tfn + 2: tfn)); (void) SETLINEBUF(tracef); #if !defined(_WIN32) /*[*/ (void) fcntl(fileno(tracef), F_SETFD, 1); #endif /*]*/ } } #if defined(X3270_DISPLAY) /*[*/ /* Start the monitor window */ if (tracef != stdout && appres.trace_monitor) { switch (tracewindow_pid = fork_child()) { case 0: /* child process */ { char cmd[64]; (void) snprintf(cmd, sizeof(cmd), "cat <&%d", pipefd[0]); (void) execlp("xterm", "xterm", "-title", just_piped? "trace": tfn, "-sb", "-e", "/bin/sh", "-c", cmd, CN); } (void) perror("exec(xterm) failed"); _exit(1); default: /* parent */ (void) close(pipefd[0]); ++children; break; case -1: /* error */ popup_an_errno(errno, "fork() failed"); break; } } #endif /*]*/ #if defined(_WIN32) && defined(C3270) /*[*/ /* Start the monitor window. */ if (tracef != stdout && appres.trace_monitor && is_installed) { STARTUPINFO startupinfo; PROCESS_INFORMATION process_information; char *path; char *args; (void) memset(&startupinfo, '\0', sizeof(STARTUPINFO)); startupinfo.cb = sizeof(STARTUPINFO); startupinfo.lpTitle = tfn; (void) memset(&process_information, '\0', sizeof(PROCESS_INFORMATION)); path = xs_buffer("%scatf.exe", instdir); args = xs_buffer("\"%scatf.exe\" \"%s\"", instdir, tfn); if (CreateProcess( path, args, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &startupinfo, &process_information) == 0) { popup_an_error("CreateProcess(%s) failed: %s", path, win32_strerror(GetLastError())); Free(path); Free(args); } else { Free(path); Free(args); tracewindow_handle = process_information.hProcess; CloseHandle(process_information.hThread); } } #endif /*]*/ Free(tfn); /* We're really tracing, turn the flag on. */ appres.toggle[trace_reason].value = True; appres.toggle[trace_reason].changed = True; menubar_retoggle(&appres.toggle[trace_reason], trace_reason); /* Display current status. */ buf = create_tracefile_header("started"); do_ts = False; wtrace("%s", buf); Free(buf); done: #if defined(X3270_DISPLAY) /*[*/ if (w) XtPopdown(trace_shell); #endif /*]*/ return; }
const std::string dlerror() { return win32_strerror(); }