150af88b1a8fdddb02dc33a34b68a3051cc69fb3
[certmaster.git] / certmaster / minion / modules / copyfile.py
1 # Copyright 2007, Red Hat, Inc
2 # seth vidal
3 #
4 # This software may be freely redistributed under the terms of the GNU
5 # general public license.
6 #
7 # You should have received a copy of the GNU General Public License
8 # along with this program; if not, write to the Free Software
9 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
10
11
12 import sha
13 import os
14 import time
15 import shutil
16
17 import func_module
18
19
20 class CopyFile(func_module.FuncModule):
21
22 version = "0.0.1"
23 api_version = "0.0.2"
24 description = "Allows for smart copying of a file."
25
26 def _checksum_blob(self, blob):
27 thissum = sha.new()
28 thissum.update(blob)
29 return thissum.hexdigest()
30
31 def checksum(self, thing):
32
33 CHUNK=2**16
34 thissum = sha.new()
35 if os.path.exists(thing):
36 fo = open(thing, 'r', CHUNK)
37 chunk = fo.read
38 while chunk:
39 chunk = fo.read(CHUNK)
40 thissum.update(chunk)
41 fo.close()
42 del fo
43 else:
44 # assuming it's a string of some kind
45 thissum.update(thing)
46
47 return thissum.hexdigest()
48
49
50 def copyfile(self, filepath, filebuf, mode=0644, uid=0, gid=0, force=None):
51 # -1 = problem file was not copied
52 # 1 = file was copied
53 # 0 = file was not copied b/c file is unchanged
54
55
56 # we should probably verify mode,uid,gid are valid as well
57
58 dirpath = os.path.dirname(filepath)
59 if not os.path.exists(dirpath):
60 os.makedirs(dirpath)
61
62 remote_sum = self._checksum_blob(filebuf.data)
63 local_sum = 0
64 if os.path.exists(filepath):
65 local_sum = self.checksum(filepath)
66
67 if remote_sum != local_sum or force is not None:
68 # back up the localone
69 if os.path.exists(filepath):
70 if not self._backuplocal(filepath):
71 return -1
72
73 # do the new write
74 try:
75 fo = open(filepath, 'w')
76 fo.write(filebuf.data)
77 fo.close()
78 del fo
79 except (IOError, OSError), e:
80 # XXX logger output here
81 return -1
82 else:
83 return 0
84
85 # hmm, need to figure out proper exceptions -akl
86 try:
87 # we could intify the mode here if it's a string
88 os.chmod(filepath, mode)
89 os.chown(filepath, uid, gid)
90 except (IOError, OSError), e:
91 return -1
92
93 return 1
94
95 def _backuplocal(self, fn):
96 """
97 make a date-marked backup of the specified file,
98 return True or False on success or failure
99 """
100 # backups named basename-YYYY-MM-DD@HH:MM~
101 ext = time.strftime("%Y-%m-%d@%H:%M~", time.localtime(time.time()))
102 backupdest = '%s.%s' % (fn, ext)
103
104 try:
105 shutil.copy2(fn, backupdest)
106 except shutil.Error, e:
107 #XXX logger output here
108 return False
109 return True