Guest User

very bad key/value database

a guest
May 29th, 2020
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.25 KB | None | 0 0
  1. #include <errno.h>
  2. #include <fcntl.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <unistd.h>
  7.  
  8. static const char *dpath = "db.db";
  9. static int db_fd;
  10. static char *db_buf;
  11. static size_t db_len;
  12. static int keys(void);
  13. static int get(const char *key);
  14. static int set(const char *key, const char *value);
  15. static int delete(const char *key);
  16. static int readdb(void);
  17. static int openerr(void);
  18. static void setval(const char *value);
  19.  
  20. int main(int argc, const char **argv) {
  21.     if(argc >= 2) goto nousage;
  22.     usage:
  23.     fprintf(stderr,
  24.         "usage: %s\n"
  25.         " get <key>\n"
  26.         " set <key> <value>\n"
  27.         " delete <key>\n"
  28.         " keys\n",
  29.         argv[0]);
  30.     return 1;
  31.     nousage:
  32.     if(!strcmp(argv[1], "keys")) return keys();
  33.     if(argc < 3) goto usage;
  34.     if(!strcmp(argv[1], "get")) return get(argv[2]);
  35.     if(!strcmp(argv[1], "set")) return set(argv[2], argc >= 4 ? argv[3] : NULL);
  36.     if(!strcmp(argv[1], "delete")) return delete(argv[2]);
  37.     goto usage;
  38. }
  39.  
  40. static int keys(void) {
  41.     int ret;
  42.     if(ret = readdb()) return ret;
  43.     char *pos = db_buf;
  44.     char *end = db_buf + db_len;
  45.     loop:;
  46.     if(pos >= end) goto end;
  47.     size_t keylen = *(size_t *)pos;
  48.     pos += 8;
  49.     fwrite(pos, keylen, 1, stdout);
  50.     putchar('\n');
  51.     pos += keylen;
  52.     size_t vallen = *(size_t *)pos;
  53.     pos += 8 + vallen;
  54.     goto loop;
  55.     end:;
  56.     return 0;
  57. }
  58.  
  59. static int get(const char *key) {
  60.     int ret;
  61.     if(ret = readdb()) return ret;
  62.     char *pos = db_buf;
  63.     char *end = db_buf + db_len;
  64.     size_t keylen, vallen;
  65.     loop:;
  66.     if(pos >= end) goto end;
  67.     keylen = *(size_t *)pos;
  68.     if(keylen != strlen(key)) goto next;
  69.     pos += 8;
  70.     if(memcmp(key, pos, keylen)) goto next2;
  71.     pos += keylen;
  72.     vallen = *(size_t *)pos;
  73.     pos += 8;
  74.     fwrite(pos, vallen, 1, stdout);
  75.     return 0;
  76.     next:;
  77.     pos += 8;
  78.     next2:;
  79.     pos += keylen;
  80.     vallen = *(size_t *)pos;
  81.     pos += 8 + vallen;
  82.     goto loop;
  83.     end:;
  84.     fprintf(stderr, "no such key\n");
  85.     return 1;
  86. }
  87.  
  88. static int set(const char *key, const char *value) {
  89.     int ret;
  90.     if(ret = readdb()) return ret;
  91.     char *pos = db_buf;
  92.     char *end = db_buf + db_len;
  93.     char *last;
  94.     size_t keylen, vallen;
  95.     loop:;
  96.     if(pos >= end) goto new;
  97.     last = pos;
  98.     keylen = *(size_t *)pos;
  99.     if(keylen != strlen(key)) goto next;
  100.     pos += 8;
  101.     if(memcmp(key, pos, keylen)) goto next2;
  102.     pos += keylen;
  103.     ftruncate(db_fd, pos - db_buf);
  104.     lseek(db_fd, 0, SEEK_END);
  105.     setval(value);
  106.     vallen = *(size_t *)pos;
  107.     pos += 8 + vallen;
  108.     write(db_fd, pos, end - pos);
  109.     return 0;
  110.     next:;
  111.     pos += 8;
  112.     next2:;
  113.     pos += keylen;
  114.     vallen = *(size_t *)pos;
  115.     pos += 8 + vallen;
  116.     goto loop;
  117.     new:;
  118.     keylen = strlen(key);
  119.     write(db_fd, &keylen, 8);
  120.     write(db_fd, key, keylen);
  121.     setval(value);
  122.     return 0;
  123. }
  124.  
  125. static int delete(const char *key) {
  126.     int ret;
  127.     if(ret = readdb()) return ret;
  128.     char *pos = db_buf;
  129.     char *end = db_buf + db_len;
  130.     char *last;
  131.     size_t keylen, vallen;
  132.     loop:;
  133.     if(pos >= end) goto end;
  134.     last = pos;
  135.     keylen = *(size_t *)pos;
  136.     if(keylen != strlen(key)) goto next;
  137.     pos += 8;
  138.     if(memcmp(key, pos, keylen)) goto next2;
  139.     pos += keylen;
  140.     ftruncate(db_fd, last - db_buf);
  141.     lseek(db_fd, 0, SEEK_END);
  142.     vallen = *(size_t *)pos;
  143.     pos += 8 + vallen;
  144.     write(db_fd, pos, end - pos);
  145.     return 0;
  146.     next:;
  147.     pos += 8;
  148.     next2:;
  149.     pos += keylen;
  150.     vallen = *(size_t *)pos;
  151.     pos += 8 + vallen;
  152.     goto loop;
  153.     end:;
  154.     fprintf(stderr, "no such key\n");
  155.     return 1;
  156. }
  157.  
  158. static int readdb(void) {
  159.     db_fd = open(dpath, O_RDWR | O_CREAT, 0644);
  160.     if(db_fd < 0) return openerr();
  161.     db_len = lseek(db_fd, 0, SEEK_END);
  162.     lseek(db_fd, 0, SEEK_SET);
  163.     db_buf = malloc(db_len);
  164.     if(!db_buf) return openerr();
  165.     read(db_fd, db_buf, db_len);
  166.     return 0;
  167. }
  168.  
  169. static int openerr(void) {
  170.     fputs(strerror(errno), stderr);
  171.     putc('\n', stderr);
  172.     return 2;
  173. }
  174.  
  175. static void setval(const char *value) {
  176.     size_t vallen;
  177.     if(!value) goto fromstdin;
  178.     vallen = strlen(value);
  179.     write(db_fd, &vallen, 8);
  180.     write(db_fd, value, vallen);
  181.     return;
  182.     fromstdin:;
  183.     vallen = 0;
  184.     char buf[512];
  185.     size_t n;
  186.     write(db_fd, &vallen, 8);
  187.     off_t pos = lseek(db_fd, 0, SEEK_CUR);
  188.     loop:;
  189.     n = fread(buf, 1, 512, stdin);
  190.     if(!n) goto end;
  191.     write(db_fd, buf, n);
  192.     goto loop;
  193.     end:;
  194.     off_t end = lseek(db_fd, 0, SEEK_CUR);
  195.     lseek(db_fd, pos - 8, SEEK_SET);
  196.     vallen = end - pos;
  197.     write(db_fd, &vallen, 8);
  198.     lseek(db_fd, end, SEEK_SET);
  199. }
Advertisement
Add Comment
Please, Sign In to add comment