我试图在Linux上使用C的opendir/readdir函数从给定目录中读取文件,如果文件满足某些参数(如大小和类型)将被复制到某些目录,则从中读取文件的目录以及目标和大小为从“.ini”文件读取,问题是当我将opendir与ie.opendir(argv [1])一起使用时没有问题,但是如果我将“.ini”文件中的值转换为char *,即search_path和将其传递给opendir
作为opendir(search_path)的代码不起作用,我收到消息“没有这样的文件或目录”,这是代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include "minIni.h"
#define sizearray(a) (sizeof(a) / sizeof((a)[0]))
/*Default values for minIni library function ini_gets*/
#define DEFAULT_FILE_SIZE "100000"
#define DEFAULT_FIREFOX_CACHE "~/.cache/mozilla/firefox/43ty8soo.default-release/cache2/entries/"
#define DEFAULT_CHROMIUM_CACHE "~/.cache/chromium/Default/Cache/"
#define DEFAULT_DEST_DIR "/home/newbee/found/"
/*Utility functions*/
void error(const char *s);
int OSCopyFile(const char *, const char *);
int interesting(char *);
int filesize(char *);
int get_config(char *browser, int *min_filesize, char *cache_dir, char *dest);
int main(int argc, char * argv[]){
if (argc < 2) {
fprintf(stderr, "Usage: %s <browser-name>\n", argv[0]);
exit(EXIT_FAILURE);
}
/*the only argument to the program is the browser in which cache*/
/*we want the exploration.*/
char *browser_name = argv[1];
/*Here i call get_config, that function returns the minimum size for*/
/*the files (min_file_size), where to search (cache), and where to*/
/*put the files that met the requirements (dest_dir_conf).*/
char *cache = malloc(PATH_MAX);
char *dest_dir_conf = malloc(PATH_MAX);
int min_file_size;
int result_config = get_config(
browser_name, &min_file_size, cache, dest_dir_conf);
if (result_config != 1)
exit(EXIT_FAILURE);
DIR *dir;
struct dirent *ent;
printf("[DEBUG] %s\n", cache);
/*And there is the problem, no matters if i pass the 'cache' variable*/
/*or if i harcoded a string here, opendir failed and error is:*/
/*No such file or directory*/
chdir(cache);
dir = opendir(cache);
if (dir == NULL)
error("Error");
char *dest = NULL;
int count = 0;
while ((ent = readdir(dir)) != NULL) {
if ((strcmp(ent->d_name, ".") != 0) && (strcmp(ent->d_name, "..") != 0)) {
/*The interesting function determine if the file is of a given type and*/
/*return 1 if true, and 0 if not.*/
if ((interesting(ent->d_name))
&& (filesize(ent->d_name) >= min_file_size)) {
dest = malloc(strlen(dest_dir_conf) + strlen(ent->d_name));
strcpy(dest, dest_dir_conf);
strcat(dest, ent->d_name);
OSCopyFile(ent->d_name, dest);
count++;
}
}
}
closedir(dir);
printf("[Job finish, %d files was copied.]\n", count);
return EXIT_SUCCESS;
}
/** errors info. **/
void error(const char *s) {
perror(s);
exit(EXIT_FAILURE);
}
/** get the file size. **/
int filesize(char *archivo) {
FILE *fp;
long fsize;
fp = fopen(archivo, "r");
if (fp) {
fseek(fp, 0L, SEEK_END);
fsize = ftell(fp);
fclose(fp);
return fsize;
}
return -1;
}
/** copy files. **/
int OSCopyFile(const char *source, const char *destination) {
int input, output;
if ((input = open(source, O_RDONLY)) == -1)
return -1;
if ((output = creat(destination, 0660)) == -1) {
close(input);
return EXIT_FAILURE;
}
#if defined(__APPLE__) || defined(__FreeBSD__)
int result = fcopyfile(input, output, 0, COPYFILE_ALL);
#else
off_t bytesCopied = 0;
struct stat fileinfo = {0};
fstat(input, &fileinfo);
int result = sendfile(output, input, &bytesCopied, fileinfo.st_size);
#endif
close(input);
close(output);
return result;
}
/** determine if the file is interesting (for me, at least ;) ). **/
int interesting(char *filename) {
uint16_t type;
FILE *f = fopen(filename, "r");
if (!f) {
printf("Error opening file '%s'.\n", filename);
return 0;
}
fread(&type, sizeof(uint16_t), 1, f);
fclose(f);
switch (type) {
case 0xD8FF: // jpg
case 0x5089: // png
case 0x4D42: // bmp
case 0x4952: // webp
case 0x4947: // gif
case 0x3F3C: // possible svg.
case 0x0000: // possible mp4.
case 0x5025: // pdf.
return 1;
default: // not interesting.
return 0;
}
}
/*Gets the configuration from a INI file*/
int get_config(
char *browser, int *min_filesize, char *cache_dir, char *dest) {
const char ini_file[] = "config.ini";
char filesize_conf[100];
long entry_length;
entry_length = ini_gets("settings", "image_size_bytes", DEFAULT_FILE_SIZE,
filesize_conf, sizearray(filesize_conf), ini_file);
*min_filesize = atoi(filesize_conf);
if (strcmp(browser, "firefox") == 0)
entry_length = ini_gets("settings", "firefox_cache",
DEFAULT_FIREFOX_CACHE, cache_dir, 255, ini_file);
else if (strcmp(browser, "chromium") == 0)
entry_length = ini_gets("settings", "chromium_cache",
DEFAULT_CHROMIUM_CACHE, cache_dir, 255, ini_file);
else {
fprintf(stderr,
"There is no configuration for %s browser.\n", browser);
exit(EXIT_FAILURE);
}
entry_length = ini_gets("settings", "destination_dir", DEFAULT_DEST_DIR,
dest, 255, ini_file);
if (entry_length <= 0)
return 0;
return 1;
}
还有问题,如果我传递'cache'变量也没关系
或者如果我在这里编码一个字符串,则opendir失败,错误是:
没有此类文件或目录
dir = opendir(cache);
读取“.ini”文件的代码来自https://www.compuphase.com/minini.htm,在其中有点新手,但我很快就学到了,所以请帮我一下。
最佳答案
这是因为argv[1]
包含~/.cache/...
的扩展版本,这要归功于启动可执行文件之前调用 shell 程序的评估。
但是,将像~/.cache/...
这样的路径传递给opendir
不起作用:C库不会将~
评估到用户目录或环境变量。
您可以通过显式测试~
并替换为getenv("HOME")
来使其兼容,类似于这样的非常不安全(但有效)的代码:
const char *s = "~/.cache/.something";
...
char aux[1024];
if (s[0]=='~')
{
sprintf(aux,"%s%s",getenv("HOME"),s+1);
s = aux;
}
现在,如果
s
以~
开头,则将被评估并替换为(将指向)aux
。如果必须将变量返回给调用者,则即使不进行替换,也最好使用
malloc
分配字符串(稍后再对其进行free
)。这不是重点,但是在C中正确处理字符串始终很棘手。