posix_errno_t efile_read_info(const efile_path_t *path, int follow_links, efile_fileinfo_t *result) { BY_HANDLE_FILE_INFORMATION native_file_info; DWORD attributes; int is_link; sys_memset(&native_file_info, 0, sizeof(native_file_info)); is_link = 0; attributes = GetFileAttributesW((WCHAR*)path->data); if(attributes == INVALID_FILE_ATTRIBUTES) { DWORD last_error = GetLastError(); /* Querying a network share root fails with ERROR_BAD_NETPATH, so we'll * fake it as a directory just like local roots. */ if(!is_path_root(path) || last_error != ERROR_BAD_NETPATH) { return windows_to_posix_errno(last_error); } attributes = FILE_ATTRIBUTE_DIRECTORY; } else if(is_path_root(path)) { /* Local (or mounted) roots can be queried with GetFileAttributesW but * lack support for GetFileInformationByHandle, so we'll skip that * part. */ } else { HANDLE handle; if(attributes & FILE_ATTRIBUTE_REPARSE_POINT) { is_link = is_name_surrogate(path); } if(follow_links && is_link) { posix_errno_t posix_errno; efile_path_t resolved_path; posix_errno = internal_read_link(path, &resolved_path); if(posix_errno != 0) { return posix_errno; } return efile_read_info(&resolved_path, 0, result); } handle = CreateFileW((const WCHAR*)path->data, GENERIC_READ, FILE_SHARE_FLAGS, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); /* The old driver never cared whether this succeeded. */ if(handle != INVALID_HANDLE_VALUE) { GetFileInformationByHandle(handle, &native_file_info); CloseHandle(handle); } FILETIME_TO_EPOCH(result->m_time, native_file_info.ftLastWriteTime); FILETIME_TO_EPOCH(result->a_time, native_file_info.ftLastAccessTime); FILETIME_TO_EPOCH(result->c_time, native_file_info.ftCreationTime); if(result->m_time == -EPOCH_DIFFERENCE) { /* Default to 1970 just like the old driver. */ result->m_time = 0; } if(result->a_time == -EPOCH_DIFFERENCE) { result->a_time = result->m_time; } if(result->c_time == -EPOCH_DIFFERENCE) { result->c_time = result->m_time; } } if(is_link) { result->type = EFILE_FILETYPE_SYMLINK; /* This should be _S_IFLNK, but the old driver always set * non-directories to _S_IFREG. */ result->mode |= _S_IFREG; } else if(attributes & FILE_ATTRIBUTE_DIRECTORY) { result->type = EFILE_FILETYPE_DIRECTORY; result->mode |= _S_IFDIR | _S_IEXEC; } else { if(is_executable_file(path)) { result->mode |= _S_IEXEC; } result->type = EFILE_FILETYPE_REGULAR; result->mode |= _S_IFREG; } if(!(attributes & FILE_ATTRIBUTE_READONLY)) { result->access = EFILE_ACCESS_READ | EFILE_ACCESS_WRITE; result->mode |= _S_IREAD | _S_IWRITE; } else { result->access = EFILE_ACCESS_READ; result->mode |= _S_IREAD; } /* Propagate user mode-bits to group/other fields */ result->mode |= (result->mode & 0700) >> 3; result->mode |= (result->mode & 0700) >> 6; result->size = ((Uint64)native_file_info.nFileSizeHigh << 32ull) | (Uint64)native_file_info.nFileSizeLow; result->links = MAX(1, native_file_info.nNumberOfLinks); result->major_device = get_drive_number(path); result->minor_device = 0; result->inode = 0; result->uid = 0; result->gid = 0; return 0; }
int which_main(int argc, char **argv) { int status; size_t i, count; char *path_list; if (argc <= 1 || **(argv + 1) == '-') { bb_show_usage(); } argc--; path_list = getenv("PATH"); if (path_list != NULL) { size_t path_len = strlen(path_list); char *new_list = NULL; count = 1; for (i = 0; i <= path_len; i++) { char *this_i = &path_list[i]; if (*this_i == ':') { /* ^::[^:] == \.: */ if (!i && (*(this_i + 1) == ':')) { *this_i = '.'; continue; } *this_i = 0; count++; /* ^:[^:] == \.0 and [^:]::[^:] == 0\.0 and [^:]:$ == 0\.0 */ if (!i || (*(this_i + 1) == ':') || (i == path_len-1)) { new_list = xrealloc(new_list, path_len += 1); if (i) { memmove(&new_list[i+2], &path_list[i+1], path_len-i); new_list[i+1] = '.'; memmove(new_list, path_list, i); } else { memmove(&new_list[i+1], &path_list[i], path_len-i); new_list[i] = '.'; } path_list = new_list; } } } } else { path_list = "/bin\0/sbin\0/usr/bin\0/usr/sbin\0/usr/local/bin"; count = 5; } status = EXIT_SUCCESS; while (argc-- > 0) { struct stat stat_b; char *buf; char *path_n; int found = 0; argv++; path_n = path_list; buf = *argv; /* if filename is either absolute or contains slashes, * stat it */ if (strchr(buf, '/') != NULL && is_executable_file(buf, &stat_b)) { found++; } else { /* Couldn't access file and file doesn't contain slashes */ for (i = 0; i < count; i++) { buf = concat_path_file(path_n, *argv); if (is_executable_file(buf, &stat_b)) { found++; break; } free(buf); path_n += (strlen(path_n) + 1); } } if (found) { puts(buf); } else { status = EXIT_FAILURE; } } bb_fflush_stdout_and_exit(status); }