Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-app / pithos / api / test / util / __init__.py @ 7e402b46

History | View | Annotate | Download (4.7 kB)

1
#!/usr/bin/env python
2
#coding=utf8
3

    
4
# Copyright 2011-2013 GRNET S.A. All rights reserved.
5
#
6
# Redistribution and use in source and binary forms, with or
7
# without modification, are permitted provided that the following
8
# conditions are met:
9
#
10
#   1. Redistributions of source code must retain the above
11
#      copyright notice, this list of conditions and the following
12
#      disclaimer.
13
#
14
#   2. Redistributions in binary form must reproduce the above
15
#      copyright notice, this list of conditions and the following
16
#      disclaimer in the documentation and/or other materials
17
#      provided with the distribution.
18
#
19
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
20
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
23
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
# POSSIBILITY OF SUCH DAMAGE.
31
#
32
# The views and conclusions contained in the software and
33
# documentation are those of the authors and should not be
34
# interpreted as representing official policies, either expressed
35
# or implied, of GRNET S.A.
36

    
37
import re
38
import hashlib
39
import random
40

    
41
from binascii import hexlify
42
from StringIO import StringIO
43

    
44
from pithos.backends.random_word import get_random_word
45

    
46
from pithos.api import settings as pithos_settings
47

    
48

    
49
def is_date(date):
50
    __D = r'(?P<day>\d{2})'
51
    __D2 = r'(?P<day>[ \d]\d)'
52
    __M = r'(?P<mon>\w{3})'
53
    __Y = r'(?P<year>\d{4})'
54
    __Y2 = r'(?P<year>\d{2})'
55
    __T = r'(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})'
56
    RFC1123_DATE = re.compile(r'^\w{3}, %s %s %s %s GMT$' % (
57
        __D, __M, __Y, __T))
58
    RFC850_DATE = re.compile(r'^\w{6,9}, %s-%s-%s %s GMT$' % (
59
        __D, __M, __Y2, __T))
60
    ASCTIME_DATE = re.compile(r'^\w{3} %s %s %s %s$' % (
61
        __M, __D2, __T, __Y))
62
    for regex in RFC1123_DATE, RFC850_DATE, ASCTIME_DATE:
63
        m = regex.match(date)
64
        if m is not None:
65
            return True
66
    return False
67

    
68

    
69
def strnextling(prefix):
70
    """Return the first unicode string
71
       greater than but not starting with given prefix.
72
       strnextling('hello') -> 'hellp'
73
    """
74
    if not prefix:
75
        ## all strings start with the null string,
76
        ## therefore we have to approximate strnextling('')
77
        ## with the last unicode character supported by python
78
        ## 0x10ffff for wide (32-bit unicode) python builds
79
        ## 0x00ffff for narrow (16-bit unicode) python builds
80
        ## We will not autodetect. 0xffff is safe enough.
81
        return unichr(0xffff)
82
    s = prefix[:-1]
83
    c = ord(prefix[-1])
84
    if c >= 0xffff:
85
        raise RuntimeError
86
    s += unichr(c + 1)
87
    return s
88

    
89

    
90
def get_random_data(length=None):
91
    length = length or random.randint(
92
        pithos_settings.BACKEND_BLOCK_SIZE,
93
        2 * pithos_settings.BACKEND_BLOCK_SIZE)
94
    return get_random_word(length)[:length]
95

    
96

    
97
def get_random_name(length=8):
98
    return get_random_data(length)
99

    
100

    
101
def md5_hash(data):
102
    md5 = hashlib.md5()
103
    md5.update(data)
104
    return md5.hexdigest().lower()
105

    
106

    
107
def file_read_iterator(fp, size=1024):
108
    while True:
109
        data = fp.read(size)
110
        if not data:
111
            break
112
        yield data
113

    
114

    
115
class HashMap(list):
116

    
117
    def __init__(self, blocksize, blockhash):
118
        super(HashMap, self).__init__()
119
        self.blocksize = blocksize
120
        self.blockhash = blockhash
121

    
122
    def _hash_raw(self, v):
123
        h = hashlib.new(self.blockhash)
124
        h.update(v)
125
        return h.digest()
126

    
127
    def _hash_block(self, v):
128
        return self._hash_raw(v.rstrip('\x00'))
129

    
130
    def hash(self):
131
        if len(self) == 0:
132
            return self._hash_raw('')
133
        if len(self) == 1:
134
            return self.__getitem__(0)
135

    
136
        h = list(self)
137
        s = 2
138
        while s < len(h):
139
            s = s * 2
140
        h += [('\x00' * len(h[0]))] * (s - len(h))
141
        while len(h) > 1:
142
            h = [self._hash_raw(h[x] + h[x + 1]) for x in range(0, len(h), 2)]
143
        return h[0]
144

    
145
    def load(self, data):
146
        self.size = 0
147
        fp = StringIO(data)
148
        for block in file_read_iterator(fp, self.blocksize):
149
            self.append(self._hash_block(block))
150
            self.size += len(block)
151

    
152

    
153
def merkle(data, blocksize, blockhash):
154
    hashes = HashMap(blocksize, blockhash)
155
    hashes.load(data)
156
    return hexlify(hashes.hash())