// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "file_utils.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
namespace {
bool IsNumeric(const char* str) {
if (!str[0])
return false;
for (const char* c = str; *c; c++) {
if (!isdigit(*c))
return false;
}
return true;
}
} // namespace
namespace file_utils {
void ForEachPidInProcPath(const char* proc_path,
std::function<void(int)> predicate) {
DIR* root_dir = opendir(proc_path);
ScopedDir autoclose(root_dir);
struct dirent* child_dir;
while ((child_dir = readdir(root_dir))) {
if (child_dir->d_type != DT_DIR || !IsNumeric(child_dir->d_name))
continue;
predicate(atoi(child_dir->d_name));
}
}
ssize_t ReadFile(const char* path, char* buf, size_t length) {
buf[0] = '\0';
int fd = open(path, O_RDONLY);
if (fd < 0 && errno == ENOENT)
return -1;
ScopedFD autoclose(fd);
size_t tot_read = 0;
do {
ssize_t rsize = read(fd, buf + tot_read, length - tot_read);
if (rsize == 0)
break;
if (rsize == -1 && errno == EINTR)
continue;
else if (rsize < 0)
return -1;
tot_read += static_cast<size_t>(rsize);
} while (tot_read < length);
buf[tot_read < length ? tot_read : length - 1] = '\0';
return tot_read;
}
bool ReadFileTrimmed(const char* path, char* buf, size_t length) {
ssize_t rsize = ReadFile(path, buf, length);
if (rsize < 0)
return false;
for (ssize_t i = 0; i < rsize; i++) {
const char c = buf[i];
if (c == '\0' || c == '\r' || c == '\n') {
buf[i] = '\0';
break;
}
buf[i] = isprint(c) ? c : '?';
}
return true;
}
ssize_t ReadProcFile(int pid, const char* proc_file, char* buf, size_t length) {
char proc_path[128];
snprintf(proc_path, sizeof(proc_path), "/proc/%d/%s", pid, proc_file);
return ReadFile(proc_path, buf, length);
}
// Reads a single-line proc file, stripping out any \0, \r, \n and replacing
// non-printable charcters with '?'.
bool ReadProcFileTrimmed(int pid,
const char* proc_file,
char* buf,
size_t length) {
char proc_path[128];
snprintf(proc_path, sizeof(proc_path), "/proc/%d/%s", pid, proc_file);
return ReadFileTrimmed(proc_path, buf, length);
}
LineReader::LineReader(char* buf, size_t size)
: ptr_(buf), end_(buf + size) {
}
LineReader::~LineReader() {
}
const char* LineReader::NextLine() {
if (ptr_ >= end_)
return nullptr;
const char* cur = ptr_;
char* next = strchr(ptr_, '\n');
if (next) {
*next = '\0';
ptr_ = next + 1;
} else {
ptr_ = end_;
}
return cur;
}
} // namespace file_utils