#include #include #include #include #include #include #include #include #include #define BUF_CAP 1024 int main(int argc, char **argv) { if (argc != 3) { printf("%s: Invalid number of arguments.\n", argv[0]); printf("Usage: %s linecount filename\n", argv[0]); printf("to remove linecount lines from the end of the file\n"); } int number = atoi(argv[1]); char *file = argv[2]; // No copy int count = 0; if (number <= 0) { printf("Bad number of line\n"); exit(1); } struct stat file_stat; if (stat(file, &file_stat) < 0) { printf("Stat failed: %d\n", errno); return 2; } int file_size = file_stat.st_size; if (file_size == 0) { printf("No change: file does not end with a newline\n"); return 1; } int fd = open(file, O_RDWR | O_APPEND); if (lseek(fd, -1, SEEK_END) < 0) { printf("Lseek1 failed: %d\n", errno); close(fd); return 2; } char c; if (read(fd, &c, 1) < 0) { printf("Read1 failed: %d\n", errno); close(fd); return 2; } if (c != '\n') { printf("No change: file does not end with a newline\n"); close(fd); return 1; } while (1) { // We can't seek back before the beginning of the file int buf_size = MIN(BUF_CAP, file_size); char buf[buf_size]; // Go back in the file to read the length of the buffer if (lseek(fd, -buf_size, SEEK_CUR) < 0) { printf("Lseek2 failed: %d\n", errno); close(fd); return 2; } // ~lseek(fd, buf_size, os.SEEK_CUR) int buf_len = read(fd, buf, buf_size); if (buf_len < 0) { printf("Read2 failed: %d\n", errno); close(fd); return 2; } char *char_pos = memrchr(buf, '\n', buf_len); if (char_pos != NULL) { count++; // Go to position found ; a read would read a '\n' if (lseek(fd, (ssize_t)(char_pos - buf) - buf_len, SEEK_CUR) < 0) { printf("Lseek3 failed: %d\n", errno); close(fd); return 2; } // "resize" the file to look for next '\n' from this point file_size -= buf_len - (ssize_t)(char_pos - buf); } else { // Go back to previous position if (lseek(fd, -buf_len, SEEK_CUR) < 0) { printf("Lseek4 failed: %d\n", errno); close(fd); return 2; } file_size -= buf_len; } if (file_size < 0) break; if (count == number + 1) { file_size++; // Keep the last '\n' if (ftruncate(fd, file_size) < 0) { printf("Ftruncate failed: %d\n", errno); close(fd); return 2; } close(fd); return 0; } // Beginning of file? if (lseek(fd, 0, SEEK_CUR) == 0) { printf("No change: requested removal would leave empty file\n"); return 3; } } close(fd); if (count < number + 1) { printf("No change: requested removal would leave empty file\n"); return 3; } }