disk.c 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #include "sam.h"
  2. static Block *blist;
  3. static int
  4. tempdisk(void)
  5. {
  6. char buf[128];
  7. int i, fd;
  8. snprint(buf, sizeof buf, "/tmp/X%d.%.4ssam", getpid(), getuser());
  9. for(i='A'; i<='Z'; i++){
  10. buf[5] = i;
  11. if(access(buf, AEXIST) == 0)
  12. continue;
  13. fd = create(buf, ORDWR|ORCLOSE|OCEXEC, 0600);
  14. if(fd >= 0)
  15. return fd;
  16. }
  17. return -1;
  18. }
  19. Disk*
  20. diskinit()
  21. {
  22. Disk *d;
  23. d = emalloc(sizeof(Disk));
  24. d->fd = tempdisk();
  25. if(d->fd < 0){
  26. fprint(2, "sam: can't create temp file: %r\n");
  27. exits("diskinit");
  28. }
  29. return d;
  30. }
  31. static
  32. uint
  33. ntosize(uint n, uint *ip)
  34. {
  35. uint size;
  36. if(n > Maxblock)
  37. panic("internal error: ntosize");
  38. size = n;
  39. if(size & (Blockincr-1))
  40. size += Blockincr - (size & (Blockincr-1));
  41. /* last bucket holds blocks of exactly Maxblock */
  42. if(ip)
  43. *ip = size/Blockincr;
  44. return size * sizeof(Rune);
  45. }
  46. Block*
  47. disknewblock(Disk *d, uint n)
  48. {
  49. uint i, j, size;
  50. Block *b;
  51. size = ntosize(n, &i);
  52. b = d->free[i];
  53. if(b)
  54. d->free[i] = b->next;
  55. else{
  56. /* allocate in chunks to reduce malloc overhead */
  57. if(blist == nil){
  58. blist = emalloc(100*sizeof(Block));
  59. for(j=0; j<100-1; j++)
  60. blist[j].next = &blist[j+1];
  61. }
  62. b = blist;
  63. blist = b->next;
  64. b->addr = d->addr;
  65. d->addr += size;
  66. }
  67. b->n = n;
  68. return b;
  69. }
  70. void
  71. diskrelease(Disk *d, Block *b)
  72. {
  73. uint i;
  74. ntosize(b->n, &i);
  75. b->next = d->free[i];
  76. d->free[i] = b;
  77. }
  78. void
  79. diskwrite(Disk *d, Block **bp, Rune *r, uint n)
  80. {
  81. int size, nsize;
  82. Block *b;
  83. b = *bp;
  84. size = ntosize(b->n, nil);
  85. nsize = ntosize(n, nil);
  86. if(size != nsize){
  87. diskrelease(d, b);
  88. b = disknewblock(d, n);
  89. *bp = b;
  90. }
  91. if(pwrite(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune))
  92. panic("write error to temp file");
  93. b->n = n;
  94. }
  95. void
  96. diskread(Disk *d, Block *b, Rune *r, uint n)
  97. {
  98. if(n > b->n)
  99. panic("internal error: diskread");
  100. ntosize(b->n, nil); /* called only for sanity check on Maxblock */
  101. if(pread(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune))
  102. panic("read error from temp file");
  103. }