【问题标题】:Reading from a data file in c从c中的数据文件中读取
【发布时间】:2019-09-08 10:55:26
【问题描述】:

我一直在努力完成剥削的艺术 作者 Jon Erickson,但我遇到了一个关于从文件和他的代码中读取数据的症结。

./notetaker 和 ./notesearch 有两个程序,前者用于创建带有用户 id 的便笺,后者用于检索当前用户的便笺。

但是,在做笔记并尝试通过 ./notesearch 访问它后,该笔记不会显示为书中建议的文本。

到目前为止,我推断出在 ./notetaker 中创建的文件是数据文件,而不是文本文件,因此打印出来时不可读。

那么为什么作者建议他的代码可以工作,而实际上却没有,最简单的解决方法是什么。

我已经开始将 fopen、fgets() 等作为解决方案,但它似乎与原始代码相去甚远。

如果我让 ./notesearch 查看随机文本文件,它将以人类可读的形式打印出来,所以我认为问题在于原始文件的创建及其类型。

但不幸的是,我不知道如何克服这个问题

来自 ./notetaker 的片段

int main(int argc, char *argv[]) {
    int userid;
    int file_descriptor;
    char *buffer, *datafile;

    buffer = (char *) ec_malloc(100);
    datafile = (char *) ec_malloc(20);
    strcpy(datafile, "notes");

    if (argc < 2)
        usage(argv[0], datafile);

    strcpy(buffer, argv[1]);

    printf("[DEBUG] buffer @ %p: '%s'\n", buffer, buffer);
    printf("[DEBUG] datafile @ %p: '%s'\n", datafile, datafile);

    strncat(buffer, "\n", 1); //adds a newline to end

    // opening file
    file_descriptor = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
    if (file_descriptor == -1)
        fatal("in main() while opening file");
    printf("[DEBUG] file descriptor is %d\n", file_descriptor);
    userid = getuid();

    // write data
    if (write(file_descriptor, &userid, 4) == -1)
        fatal("in main() while writing userid to file");
    write(file_descriptor, "\n", 1);
    if (write(file_descriptor, buffer, strlen(buffer)) == -1)
        fatal("in main() while writing buffer to file");
    write(file_descriptor, "\n", 1);

    // closing file
    if (close(file_descriptor) == -1)
        fatal("in main() while closing file");

来自 ./notesearch 的片段

#define FILENAME "notes"

int print_notes(int, int, char *);
int find_user_note(int, int);
int search_note(char *, char *);

int main(int argc, char *argv[]) {
    int userid, printing = 1, file_descriptor;
    char search_string[100];

    if (argc > 1)
        strcpy(search_string, argv[1]);
    else
        search_string[0] = 0;

    userid = getuid();
    file_descriptor = open(FILENAME, O_RDONLY);
    if (file_descriptor == -1)
        fatal("in main() while opening file for reading");

    while (printing)
        printing = print_notes(file_descriptor, userid, search_string);

    printf("------ [ end of note data ] ------\n");
    close(file_descriptor);
}

// print notes for a given uid
// can match an optional search string
int print_notes(int file_descriptor, int uid, char *search_string) {
    int note_length;
    char byte = 0, note_buffer[100];

    note_length = find_user_note(file_descriptor, uid);

    // if EOF return 0
    if (note_length == -1)
        return 0;

    read(file_descriptor, note_buffer, note_length); // read note data
    note_buffer[note_length] = 0; // terminate string

    // print note if search_string
    if (search_note(note_buffer, search_string))
        printf("------ [ note data ] ------\n");
        printf(note_buffer);
        printf("\n");
    return 1;
}

// finds next note for given uid
int find_user_note(int file_descriptor, int user_uid) {
    int note_uid = -1;
    unsigned char byte;
    int length;

    while (note_uid != user_uid) {
        if (read(file_descriptor, &note_uid, 4) != 4) // read uid data
            return -1;
        if (read(file_descriptor, &byte, 1) != 1) // read newline separator
            return -1;

        byte = length = 0;

        while (byte != '\n') {
            if (read(file_descriptor, &byte, 1) != 1) // read a single byte
                return -1;
            length++;
        }
    }

    // rewind file by bytes length
    lseek(file_descriptor, length * -1, SEEK_CUR);

    printf("[DEBUG] found a %d byte note for user id %d\n", length, note_uid);
    return length;
}

【问题讨论】:

  • 你能告诉我们notetaker创建的数据文件包含什么吗?
  • 是的,抱歉,省略了该信息,它仅包含在命令行中作为参数编写的文本,即 ./notetaker 'this is my note'
  • printf(note_buffer); 这是一个非常不安全的操作,请执行printf("%s", note_buffer); so the problem I believe lies in the creation of the original file and its type - 所以用cat 或任何文本编辑器检查文件也会发现问题?
  • 不,这就是我难以理解的,如果我 cat 文件我可以看到纯文本,除了不可读的用户 ID,但如果我 file 文件它说'数据'
  • 数据文件应该由 { int, '\n' , string,\n'} 的块组成,混合文本和二进制,你可以在你创建的数据文件上运行od在此处发布输出

标签: c


【解决方案1】:

已解决:在 32 位 vm 上尝试了代码,一切都很好,虽然不完全确定为什么会这样,但目前我一直在解决这个问题。

这可能是因为代码对整数和其他类型的大小做了不应该的假设。比如……

int userid;
... 
userid = getuid();
...
if (write(file_descriptor, &userid, 4) == -1)
    fatal("in main() while writing userid to file");

这里有两个错误。 getuid 返回 uid_t,而不是 int。它们的大小可能相同,因此可能会起作用。

更重要的是,他们将 userid 的大小硬编码为 4 个字节。 userid 是一个 int,它只保证至少有 2 个字节。在 32 位机器上,它通常是 4 个字节(32 位)。在 64 位机器上,它是 8 个字节(64 位)。

它适用于 32 位 VM,因为 int 是 4 个字节。

改为使用正确的类型和sizeof 来获取大小。

uid_t userid;
... 
userid = getuid();
...
if (write(file_descriptor, &userid, sizeof(userid)) == -1)
    fatal("in main() while writing userid to file");

总体而言,这段代码的质量很差。我希望这样写是为了便于说明。

  • strcpy(buffer, argv[1])strcpy(search_string, argv[1]) 存在缓冲区溢出的风险。
  • 有很多地方他们无法检查文件操作是否成功。
  • 存在欺骗性的if 条件。
    if (search_note(note_buffer, search_string))
        printf("------ [ note data ] ------\n");
        printf(note_buffer);
        printf("\n");

缩进让它看起来像是在if 中,但没有大括号意味着它真的是这样的:

    if (search_note(note_buffer, search_string)) {
        printf("------ [ note data ] ------\n");
    }
    printf(note_buffer);
    printf("\n");

【讨论】:

    猜你喜欢
    • 2013-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    相关资源
    最近更新 更多