locksys.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package dav_ipfs
  2. import (
  3. "fmt"
  4. "golang.org/x/net/webdav"
  5. "strings"
  6. "sync"
  7. "time"
  8. )
  9. type locksystem struct {
  10. webdav.LockSystem
  11. fs *filesystem
  12. sync.RWMutex
  13. locks map[string]string
  14. tokens map[string]webdav.LockDetails
  15. holds map[string]bool
  16. idx chan string
  17. }
  18. func (l *locksystem) Confirm(now time.Time, name0, name1 string, conditions ...webdav.Condition) (release func(), err error) {
  19. const noLock = "DAV:no-lock"
  20. //log.Println("confirm", name0, name1, conditions)
  21. l.RLock()
  22. tok0, ok0 := l.locks[name0]
  23. if _, ok1 := l.locks[name1]; ok1 {
  24. panic(101)
  25. }
  26. ok := true
  27. etag, _ := l.fs.ETag(name0)
  28. for _, c := range conditions {
  29. token := c.Token
  30. if c.ETag != "" {
  31. tok0 = etag
  32. token = c.ETag
  33. }
  34. switch {
  35. case !c.Not && ok0:
  36. ok = tok0 == token
  37. case token == noLock:
  38. ok = !ok0 && c.Not
  39. default:
  40. ok = false
  41. }
  42. if ok == false {
  43. break
  44. }
  45. }
  46. //log.Println(ok)
  47. if ok && !l.holds[name0] {
  48. l.RUnlock()
  49. l.Lock()
  50. l.holds[name0] = true
  51. release = func() {
  52. delete(l.holds, name0)
  53. //log.Println(name0, "release")
  54. }
  55. l.RWMutex.Unlock()
  56. } else {
  57. err = webdav.ErrConfirmationFailed
  58. l.RUnlock()
  59. }
  60. return
  61. }
  62. func (l *locksystem) ParentLocks(name string) (ret []string) {
  63. l.RLock()
  64. ls := []string{"/"}
  65. ls = append(ls, strings.Split(strings.Trim(name, "/"), "/")...)
  66. var path = ""
  67. for i := 0; i < len(ls); i++ {
  68. path = path + ls[i]
  69. if tok, ok := l.locks[path]; ok {
  70. if details := l.tokens[tok]; !details.ZeroDepth {
  71. ret = append(ret, tok)
  72. }
  73. }
  74. if i > 0 {
  75. path = path + "/"
  76. if tok, ok := l.locks[path]; ok {
  77. if details := l.tokens[tok]; !details.ZeroDepth {
  78. ret = append(ret, tok)
  79. }
  80. }
  81. }
  82. }
  83. l.RUnlock()
  84. return
  85. }
  86. func (l *locksystem) Create(now time.Time, details webdav.LockDetails) (token string, err error) {
  87. //log.Println("lock", details)
  88. l.RLock()
  89. if _, ok := l.locks[details.Root]; !ok && len(l.ParentLocks(details.Root)) == 0 {
  90. l.RUnlock()
  91. l.Lock()
  92. token = <-l.idx + ":" + fmt.Sprint(now.UnixNano())
  93. l.locks[details.Root] = token
  94. l.tokens[token] = details
  95. //log.Println("locked", token)
  96. l.RWMutex.Unlock()
  97. } else {
  98. l.RUnlock()
  99. err = webdav.ErrLocked
  100. }
  101. return
  102. }
  103. func (l *locksystem) Refresh(now time.Time, token string, duration time.Duration) (ret webdav.LockDetails, err error) {
  104. l.Lock()
  105. if details, ok := l.tokens[token]; ok {
  106. details.Duration = duration
  107. l.tokens[token] = details
  108. ret = details
  109. } else {
  110. err = webdav.ErrNoSuchLock
  111. }
  112. l.RWMutex.Unlock()
  113. return
  114. }
  115. func (l *locksystem) Unlock(now time.Time, token string) (err error) {
  116. //log.Println("unlock", token)
  117. l.Lock()
  118. if details, ok := l.tokens[token]; ok {
  119. if !l.holds[details.Root] {
  120. delete(l.tokens, token)
  121. delete(l.locks, details.Root)
  122. } else {
  123. err = webdav.ErrLocked
  124. }
  125. } else {
  126. err = webdav.ErrNoSuchLock
  127. }
  128. l.RWMutex.Unlock()
  129. return
  130. }
  131. func NewLS(fs *filesystem) *locksystem {
  132. ret := &locksystem{}
  133. ret.fs = fs
  134. ret.locks = make(map[string]string)
  135. ret.tokens = make(map[string]webdav.LockDetails)
  136. ret.holds = make(map[string]bool)
  137. ret.idx = make(chan string)
  138. go func(ch chan string) {
  139. i := 0
  140. for {
  141. ch <- fmt.Sprint(i)
  142. i++
  143. }
  144. }(ret.idx)
  145. return ret
  146. }