1034
def update_entry(self, entry, abspath, stat_value=None):
1035
"""Update the entry based on what is actually on disk.
1037
:param entry: This is the dirblock entry for the file in question.
1038
:param abspath: The path on disk for this file.
1039
:param stat_value: (optional) if we already have done a stat on the
1041
:return: The sha1 hexdigest of the file (40 bytes) or link target of a
1044
# This code assumes that the entry passed in is directly held in one of
1045
# the internal _dirblocks. So the dirblock state must have already been
1047
assert self._dirblock_state != DirState.NOT_IN_MEMORY
1048
if stat_value is None:
1050
# We could inline os.lstat but the common case is that
1051
# stat_value will be passed in, not read here.
1052
stat_value = self._lstat(abspath, entry)
1053
except (OSError, IOError), e:
1054
if e.errno in (errno.ENOENT, errno.EACCES,
1056
# The entry is missing, consider it gone
1060
kind = osutils.file_kind_from_stat_mode(stat_value.st_mode)
1062
minikind = DirState._kind_to_minikind[kind]
1063
except KeyError: # Unknown kind
1065
packed_stat = pack_stat(stat_value)
1066
(saved_minikind, saved_link_or_sha1, saved_file_size,
1067
saved_executable, saved_packed_stat) = entry[1][0]
1069
if (minikind == saved_minikind
1070
and packed_stat == saved_packed_stat
1071
# size should also be in packed_stat
1072
and saved_file_size == stat_value.st_size):
1073
# The stat hasn't changed since we saved, so we can potentially
1074
# re-use the saved sha hash.
1078
if self._cutoff_time is None:
1079
self._sha_cutoff_time()
1081
if (stat_value.st_mtime < self._cutoff_time
1082
and stat_value.st_ctime < self._cutoff_time):
1083
# Return the existing fingerprint
1084
return saved_link_or_sha1
1086
# If we have gotten this far, that means that we need to actually
1087
# process this entry.
1090
link_or_sha1 = self._sha1_file(abspath, entry)
1091
executable = self._is_executable(stat_value.st_mode,
1093
entry[1][0] = ('f', link_or_sha1, stat_value.st_size,
1094
executable, packed_stat)
1095
elif minikind == 'd':
1097
entry[1][0] = ('d', '', 0, False, packed_stat)
1098
if saved_minikind != 'd':
1099
# This changed from something into a directory. Make sure we
1100
# have a directory block for it. This doesn't happen very
1101
# often, so this doesn't have to be super fast.
1102
block_index, entry_index, dir_present, file_present = \
1103
self._get_block_entry_index(entry[0][0], entry[0][1], 0)
1104
self._ensure_block(block_index, entry_index,
1105
osutils.pathjoin(entry[0][0], entry[0][1]))
1106
elif minikind == 'l':
1107
link_or_sha1 = self._read_link(abspath, saved_link_or_sha1)
1108
entry[1][0] = ('l', link_or_sha1, stat_value.st_size,
1110
self._dirblock_state = DirState.IN_MEMORY_MODIFIED
1113
def _sha_cutoff_time(self):
1114
"""Return cutoff time.
1116
Files modified more recently than this time are at risk of being
1117
undetectably modified and so can't be cached.
1119
# Cache the cutoff time as long as we hold a lock.
1120
# time.time() isn't super expensive (approx 3.38us), but
1121
# when you call it 50,000 times it adds up.
1122
# For comparison, os.lstat() costs 7.2us if it is hot.
1123
self._cutoff_time = int(time.time()) - 3
1124
return self._cutoff_time
1126
def _lstat(self, abspath, entry):
1127
"""Return the os.lstat value for this path."""
1128
return os.lstat(abspath)
1130
def _sha1_file(self, abspath, entry):
1131
"""Calculate the SHA1 of a file by reading the full text"""
1132
f = file(abspath, 'rb', buffering=65000)
1134
return osutils.sha_file(f)
1138
def _is_executable(self, mode, old_executable):
1139
"""Is this file executable?"""
1140
return bool(S_IEXEC & mode)
1142
def _is_executable_win32(self, mode, old_executable):
1143
"""On win32 the executable bit is stored in the dirstate."""
1144
return old_executable
1146
if sys.platform == 'win32':
1147
_is_executable = _is_executable_win32
1149
def _read_link(self, abspath, old_link):
1150
"""Read the target of a symlink"""
1151
# TODO: jam 200700301 On Win32, this could just return the value
1152
# already in memory. However, this really needs to be done at a
1153
# higher level, because there either won't be anything on disk,
1154
# or the thing on disk will be a file.
1155
return os.readlink(abspath)
1036
1157
def get_ghosts(self):
1037
1158
"""Return a list of the parent tree revision ids that are ghosts."""
1038
1159
self._read_header_if_needed()
1523
1644
num_entries_line = self._state_file.readline()
1524
1645
assert num_entries_line.startswith('num_entries: '), 'missing num_entries line'
1525
1646
self._num_entries = int(num_entries_line[len('num_entries: '):-1])
1527
1648
def save(self):
1528
1649
"""Save any pending changes created during this session.
1530
1651
We reuse the existing file, because that prevents race conditions with
1531
file creation, and we expect to be using oslocks on it in the near
1532
future to prevent concurrent modification and reads - because dirstates
1533
incremental data aggretation is not compatible with reading a modified
1534
file, and replacing a file in use by another process is impossible on
1652
file creation, and use oslocks on it to prevent concurrent modification
1653
and reads - because dirstates incremental data aggretation is not
1654
compatible with reading a modified file, and replacing a file in use by
1655
another process is impossible on windows.
1537
1657
A dirstate in read only mode should be smart enough though to validate
1538
1658
that the file has not changed, and otherwise discard its cache and
1542
1662
if (self._header_state == DirState.IN_MEMORY_MODIFIED or
1543
1663
self._dirblock_state == DirState.IN_MEMORY_MODIFIED):
1544
self._state_file.seek(0)
1545
self._state_file.writelines(self.get_lines())
1546
self._state_file.truncate()
1547
self._state_file.flush()
1548
self._header_state = DirState.IN_MEMORY_UNMODIFIED
1549
self._dirblock_state = DirState.IN_MEMORY_UNMODIFIED
1665
if self._lock_state == 'w':
1666
out_file = self._state_file
1669
# Try to grab a write lock so that we can update the file.
1671
wlock = lock.WriteLock(self._filename)
1672
except (errors.LockError, errors.LockContention), e:
1673
# We couldn't grab the lock, so just leave things dirty in
1677
# This may be a read-only tree, or someone else may have a
1678
# ReadLock. so handle the case when we cannot grab a write
1680
if e.errno in (errno.ENOENT, errno.EPERM, errno.EACCES,
1682
# Ignore these errors and just don't save anything
1688
out_file.writelines(self.get_lines())
1691
self._header_state = DirState.IN_MEMORY_UNMODIFIED
1692
self._dirblock_state = DirState.IN_MEMORY_UNMODIFIED
1694
if wlock is not None:
1551
1697
def _set_data(self, parent_ids, dirblocks):
1552
1698
"""Set the full dirstate data in memory.