~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/_dirstate_helpers_c.pyx

Some tuning of update_entry.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
This is the python implementation for DirState functions.
20
20
"""
21
21
 
 
22
import binascii
 
23
 
22
24
from bzrlib import errors, osutils
23
25
from bzrlib.dirstate import DirState, pack_stat
24
26
 
37
39
    ctypedef int intptr_t
38
40
 
39
41
 
 
42
cdef extern from "arpa/inet.h":
 
43
    unsigned long htonl(unsigned long)
 
44
 
 
45
 
40
46
cdef extern from "stdlib.h":
41
47
    unsigned long int strtoul(char *nptr, char **endptr, int base)
42
48
 
 
49
cdef extern from "stdio.h":
 
50
    void printf(char *format, ...)
 
51
 
 
52
cdef extern from 'sys/stat.h':
 
53
    int S_ISDIR(int mode)
 
54
    int S_ISREG(int mode)
 
55
    int S_ISLNK(int mode)
43
56
 
44
57
# These functions allow us access to a bit of the 'bare metal' of python
45
58
# objects, rather than going through the object abstraction. (For example,
52
65
# a very short time.
53
66
cdef extern from "Python.h":
54
67
    ctypedef int Py_ssize_t
 
68
    ctypedef struct PyObject:
 
69
        pass
55
70
    int PyList_Append(object lst, object item) except -1
56
71
    void *PyList_GetItem_object_void "PyList_GET_ITEM" (object lst, int index)
 
72
    void *PyList_GetItem_void_void "PyList_GET_ITEM" (void * lst, int index)
57
73
    int PyList_CheckExact(object)
58
74
 
59
75
    void *PyTuple_GetItem_void_void "PyTuple_GET_ITEM" (void* tpl, int index)
 
76
    object PyTuple_GetItem_void_object "PyTuple_GET_ITEM" (void* tpl, int index)
60
77
 
61
78
    char *PyString_AsString(object p)
 
79
    char *PyString_AsString_obj "PyString_AsString" (PyObject *string)
62
80
    char *PyString_AS_STRING_void "PyString_AS_STRING" (void *p)
63
81
    object PyString_FromString(char *)
64
82
    object PyString_FromStringAndSize(char *, Py_ssize_t)
65
83
    int PyString_Size(object p)
66
84
    int PyString_GET_SIZE_void "PyString_GET_SIZE" (void *p)
67
85
    int PyString_CheckExact(object p)
 
86
    void Py_INCREF(object o)
 
87
    void Py_DECREF(object o)
68
88
 
69
89
 
70
90
cdef extern from "string.h":
721
741
    state._dirblock_state = DirState.IN_MEMORY_UNMODIFIED
722
742
 
723
743
 
724
 
_stat_to_minikind = DirState._stat_to_minikind
725
 
 
726
 
 
727
 
def update_entry(self, entry, abspath, stat_value,
728
 
                 _stat_to_minikind=_stat_to_minikind,
729
 
                 _pack_stat=pack_stat):
 
744
cdef int minikind_from_mode(int mode):
 
745
    # in order of frequency:
 
746
    if S_ISREG(mode):
 
747
        return c"f"
 
748
    if S_ISDIR(mode):
 
749
        return c"d"
 
750
    if S_ISLNK(mode):
 
751
        return c"l"
 
752
    return 0
 
753
 
 
754
 
 
755
#cdef object _encode
 
756
_encode = binascii.b2a_base64
 
757
 
 
758
from struct import pack
 
759
cdef _pack_stat(stat_value):
 
760
    """return a string representing the stat value's key fields.
 
761
 
 
762
    :param stat_value: A stat oject with st_size, st_mtime, st_ctime, st_dev,
 
763
        st_ino and st_mode fields.
 
764
    """
 
765
    cdef char result[6*4] # 6 long ints
 
766
    cdef int *aliased
 
767
    aliased = <int *>result
 
768
    aliased[0] = htonl(stat_value.st_size)
 
769
    aliased[1] = htonl(int(stat_value.st_mtime))
 
770
    aliased[2] = htonl(int(stat_value.st_ctime))
 
771
    aliased[3] = htonl(stat_value.st_dev)
 
772
    aliased[4] = htonl(stat_value.st_ino & 0xFFFFFFFF)
 
773
    aliased[5] = htonl(stat_value.st_mode)
 
774
    packed = PyString_FromStringAndSize(result, 6*4)
 
775
    return _encode(packed)[:-1]
 
776
 
 
777
 
 
778
def update_entry(self, entry, abspath, stat_value):
730
779
    """Update the entry based on what is actually on disk.
731
780
 
732
781
    :param entry: This is the dirblock entry for the file in question.
736
785
    :return: The sha1 hexdigest of the file (40 bytes) or link target of a
737
786
            symlink.
738
787
    """
739
 
    try:
740
 
        minikind = _stat_to_minikind[stat_value.st_mode & 0170000]
741
 
    except KeyError:
742
 
        # Unhandled kind
 
788
    # TODO - require pyrex 0.8, then use a pyd file to define access to the _st
 
789
    # mode of the compiled stat objects.
 
790
    cdef int minikind, saved_minikind
 
791
    cdef void * details
 
792
    # pyrex 0.9.7 would allow cdef list details_list, and direct access rather
 
793
    # than PyList_GetItem_void_void below
 
794
    minikind = minikind_from_mode(stat_value.st_mode)
 
795
    if 0 == minikind:
743
796
        return None
744
797
    packed_stat = _pack_stat(stat_value)
745
 
    (saved_minikind, saved_link_or_sha1, saved_file_size,
746
 
     saved_executable, saved_packed_stat) = entry[1][0]
 
798
    details = PyList_GetItem_void_void(PyTuple_GetItem_void_void(<void *>entry, 1), 0)
 
799
    saved_minikind = PyString_AsString_obj(<PyObject *>PyTuple_GetItem_void_void(details, 0))[0]
 
800
    saved_link_or_sha1 = PyTuple_GetItem_void_object(details, 1)
 
801
    saved_file_size = PyTuple_GetItem_void_object(details, 2)
 
802
    saved_executable = PyTuple_GetItem_void_object(details, 3)
 
803
    saved_packed_stat = PyTuple_GetItem_void_object(details, 4)
 
804
    # Deal with pyrex decrefing the objects
 
805
    Py_INCREF(saved_link_or_sha1)
 
806
    Py_INCREF(saved_file_size)
 
807
    Py_INCREF(saved_executable)
 
808
    Py_INCREF(saved_packed_stat)
 
809
    #(saved_minikind, saved_link_or_sha1, saved_file_size,
 
810
    # saved_executable, saved_packed_stat) = entry[1][0]
747
811
 
748
812
    if (minikind == saved_minikind
749
813
        and packed_stat == saved_packed_stat):
750
814
        # The stat hasn't changed since we saved, so we can re-use the
751
815
        # saved sha hash.
752
 
        if minikind == 'd':
 
816
        if minikind == c'd':
753
817
            return None
754
818
 
755
819
        # size should also be in packed_stat
756
820
        if saved_file_size == stat_value.st_size:
757
821
            return saved_link_or_sha1
 
822
    else:
 
823
        print "gararar", packed_stat, saved_packed_stat
758
824
 
759
825
    # If we have gotten this far, that means that we need to actually
760
826
    # process this entry.
761
827
    link_or_sha1 = None
762
 
    if minikind == 'f':
 
828
    if minikind == c'f':
763
829
        link_or_sha1 = self._sha1_file(abspath)
764
830
        executable = self._is_executable(stat_value.st_mode,
765
831
                                         saved_executable)
772
838
        else:
773
839
            entry[1][0] = ('f', '', stat_value.st_size,
774
840
                           executable, DirState.NULLSTAT)
775
 
    elif minikind == 'd':
 
841
    elif minikind == c'd':
776
842
        link_or_sha1 = None
777
843
        entry[1][0] = ('d', '', 0, False, packed_stat)
778
 
        if saved_minikind != 'd':
 
844
        if saved_minikind != c'd':
779
845
            # This changed from something into a directory. Make sure we
780
846
            # have a directory block for it. This doesn't happen very
781
847
            # often, so this doesn't have to be super fast.
783
849
                self._get_block_entry_index(entry[0][0], entry[0][1], 0)
784
850
            self._ensure_block(block_index, entry_index,
785
851
                               osutils.pathjoin(entry[0][0], entry[0][1]))
786
 
    elif minikind == 'l':
 
852
    elif minikind == c'l':
787
853
        link_or_sha1 = self._read_link(abspath, saved_link_or_sha1)
788
854
        if self._cutoff_time is None:
789
855
            self._sha_cutoff_time()