我试图在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中正确处理字符串始终很棘手。

09-11 17:32