文件操作 - device.py
返回文件管理
返回主菜单
删除本文件
文件: /usr/lib64/python2.7/site-packages/block/device.py
编辑文件内容
#!/usr/bin/python # # Copyright 2005-2007 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # import sys as _sys import os as _os import stat as _stat import string as _string def DeviceMaps(): import dm as _dm mlist = _dm.maps() del _dm devs = {} for m in mlist: devs[m.dev] = m maps = {} for d,m in devs.items(): mdeps = filter(lambda x: devs.has_key(x), m.deps) for mdep in mdeps: key = devs[mdep] maps.setdefault(key, []).append(m) return maps def removeDeviceMap(map): maps = DeviceMaps() try: for m in maps[map]: removeDeviceMap(m) except KeyError: pass map.remove() def map_dev(path): if path[0] != '/': return path try: statinfo = _os.stat(path) if not _stat.S_ISBLK(statinfo.st_mode): return path return "%d:%d" % (statinfo.st_rdev/256, statinfo.st_rdev%256, ) except: return path # Helper function for get_map # The tables will be considered the same if for every row, with everything else # being the same, they contain the same sets of devices. def compare_tables(t1, t2): for table1, table2 in zip(t1, t2): table1 = str(table1).strip().split(' ') table2 = str(table2).strip().split(' ') table1sets = [] table2sets = [] # We do this to avoid the index out of range exception if len(table1) != len(table2): return False for i in range(len(table1)): d1 = map_dev(table1[i]) d2 = map_dev(table2[i]) # when at least one changes its a device. if (table1[i] != d1) or (table2[i] != d2): # The d{1,2} will always have the major:minor string # We also need what comes after the dev, the offset. try: table1sets.append("%s %s" % (d1, table1[i+1])) table2sets.append("%s %s" % (d2, table2[i+1])) i += 1 except IndexError, msg: # The device must have an offset, if not its nonesense return False continue # these are not devices if d1 == d2: continue if d1 != d2: return False # For mirror sets the devices can be in disorder. if table1[2] == "mirror": if set(table1sets) != set(table2sets): return False # For none mirror the devs have to be in order. else: for i in range(len(table1sets)): if table1sets[i] != table2sets[i]: return False return True class BlockDev: def get_major(self): return self._BlockDev__device.major def set_major(self, major): self._BlockDev__device.major = major major = property(get_major, set_major, None, "major device number") def get_minor(self): return self.__device.minor def set_minor(self, minor): self._BlockDev__device.minor = minor minor = property(get_minor, set_minor, None, "minor device number") def get_device(self): return self._BlockDev__device device = property(get_device, None, None, "device number") def get_dmdev(self): return "%s:%s" % (self._BlockDev__device.major, self._BlockDev__device.minor) dmdev = property(get_dmdev, None, None, "device number formatted for dm") def get_path(self): return self._BlockDev__path def set_path(self, path): self._BlockDev__path = str(path) path = property(get_path, set_path, None, "path to device node") def get_mode(self): return self._BlockDev__device.mode def set_mode(self, mode): self._BlockDev__device.mode = int(mode) mode = property(get_mode, set_mode, None, "mode for device node") def __init__(self, path=None, major=None, minor=None, dev=None): self._BlockDev__context = None self._BlockDev__path = None if not path is None: self.FromFile(path) elif not (major is None and minor is None): self.FromMajorMinor(major, minor) elif not dev is None: self.FromDev(dev) else: import dm as _dm self._BlockDev__device = _dm.device(0,0) del _dm # self.sysfs = None # XXX not handling yet # XXX should probe parents/children/etc self.parents = [] self.children = [] self.group = None self.group_position = None self.group_siblings = [] def FromFile(self, path): import dm as _dm path = str(path) self._BlockDev__path = path self._BlockDev__device = _dm.device(path=path) del _dm return self; def FromMajorMinor(self, major, minor): import dm as _dm self._BlockDev__device = _dm.device(major, minor) del _dm return self def FromDev(self, dev): import dm as _dm self._BlockDev__device == _dm.device(0,0) self._BlockDev__device.dev = dev del _dm return self def create(self, path=None, mode=None, context=None): args = {} if path is None: path = self.path if path is None: raise ValueError, "no path set for %s" % (self,) args['path'] = path args['mode'] = self.mode if not mode is None: args['mode'] = mode if context is None: context = self._BlockDev__context if not context is None: args['context'] = context return apply(self.device.mknod, (), args) def output(self, *args): for x in args: print x def remove(self): if not self.path: raise RuntimeError, "no path set for %s" % (self,) if self.path.split('/')[-1].startswith('VolGroup'): raise RuntimeError, "trying to unlink %s" % (self.path,) _os.unlink(self.path) class Device: def get_major(self): return self.__bdev.major def set_major(self, major): self.__bdev.major = major major = property(get_major, set_major, None, "major device number") def get_minor(self): return self.__bdev.minor def set_minor(self, major): self.__bdev.minor = major minor = property(get_major, set_major, None, "major device number") def get_dmdev(self): return self.__bdev.dmdev dmdev = property(get_dmdev, None, None, "device number formatted for dm") def get_map(self): return self.__map def set_map(self, map): # XXX type chek this self.__map = map map = property(get_map, set_map, None, "device map for this device") def __init__(self, bdev=BlockDev(), map=None): if not isinstance(bdev, BlockDev): raise TypeError, "bdev must be an instance of block.BlockDev" self.__bdev = bdev self.__map = map def FromFile(self, path): self.__bdev = BlockDev().FromFile(path) self.__map = None from UserDict import IterableUserDict as _IUD class MPNameCache(_IUD): import dm as _dm # we'll get other maps here which will never be dereffed, but we # also won't wind up using them for .new(), so that's good. data = {} for map in _dm.maps(): data.setdefault(map.name, 1) del _dm def __init__(self): _IUD.__init__(self) self.data = MPNameCache.data def new(self): n = 0 while True: name = 'mpath%s' % (n,) if self.try_get(name): return name n += 1 def get(self, name): self.setdefault(name, 0) self[name] += 1 return name def try_get(self, name): if not self.has_key(name): self.get(name) return True return False def put(self, name): self[name] -= 1 if self[name] == 0: del self[name] def rename(self, old_name, new_name): self[new_name] = self[old_name] del self[old_name] return new_name nameCache = MPNameCache() del _IUD class MultiPath: def __init__(self, *bdevs): self._MultiPath__prefix = "/dev/mapper/" self._MultiPath__bdev = None self._MultiPath__table = None self._MultiPath__map = None self._MultiPath__parts = [] # this sets the refcount to 1 (undone by __del__) self._MultiPath__name = nameCache.new() self.active = False self.mknod = False self.bdevs = [] if bdevs: self.checkBdevs(bdevs) table = self.get_table() import dm as _dm self.get_map() # this sets the refcount to 2 (undone by __deactivate__) nameCache.get(self.name) def __del__(self): if not nameCache[self.name] in [1, 2]: raise RuntimeError, "%s has refcount %s on __del__" % (self.name, nameCache[self.name]) nameCache.put(self.name) def firstDevPath(self): l = list(self.member_devpaths) l.sort() return l[0] def __cmp__(self, other): s = self.firstDevPath() o = other.firstDevPath() if s < o: return -1 elif s == o: return cmp(self.map, other.map) return 1 def checkBdevs(self, bdevs): bdh = {} for x in self.bdevs: bdh[x] = None for bdev in bdevs: if not bdh.has_key(bdev): self.bdevs.append(bdev) import os as _os self.size = None rdevs = {} for bdev in self.bdevs: sb = _os.stat(bdev) rdev = sb.st_rdev if rdevs.has_key(rdev): continue rdevs[rdev] = 1 sysfile = '/sys/block/%s/size' % (bdev.split('/')[-1],) f = open(sysfile) size = f.readlines()[0] del f size = int(size.strip()) if self.size is None: self.size = size if self.size != size: raise ValueError, "mismatched sizes" del _os def get_prefix(self): return self._MultiPath__prefix def set_prefix(self, value): self._MultiPath__prefix = value prefix = property(get_prefix, set_prefix, None, \ "prefix for path to device nodes") def _set_map_uuid(self, map): if map and not map.uuid: map.uuid = "MPATH-%s" % map.name def get_PedDevice(self): import parted as _parted ret = _parted.getDevice(self.bdev.path) del _parted return ret PedDevice = property(get_PedDevice, None, None, "parted.PedDevice") def get_members(self, descend=True): for bdev in self.bdevs: yield bdev members = property(get_members, None, None, "members") def get_member_devpaths(self, descend=True): for m in self.get_members(descend): if str(m).startswith("/dev/"): yield str(m) else: yield "/dev/" + m member_devpaths = property(get_member_devpaths, None, None, "member devpaths") def get_bdev(self): if not self._MultiPath__bdev is None: return self._MultiPath__bdev try: self._MultiPath__bdev = BlockDev(self.prefix + self.name) return self._MultiPath__bdev except: raise pass bdev = property(get_bdev, None, None, "block.BlockDev") def get_table(self): if not self._MultiPath__table is None: return self._MultiPath__table # we get "/dev/hda" from one and "3:0" from the other, so we have to # fix up the device name def munge_dev(path): if path[0] != '/': return path.strip() bd = map_dev(path) # starting with 2.6.17-1.2510.fc6 or so, there's an implicit # minimum IOs of 1000, which gets _added_ to the line "dmsetup ls" # shows. This sucks. return "%s 1000" % (bd,) tableParts = [0, self.size, 'multipath'] params = '0 0 1 1 round-robin 0 %s 1 %s' % (len(self.bdevs), \ _string.join(map(munge_dev, self.bdevs))) tableParts.append(params) import dm as _dm table = apply(_dm.table, tableParts, {}) del _dm self._MultiPath__table = [ table ] return self._MultiPath__table table = property(get_table, None, None, "block.dm.table") def get_map(self): if not self._MultiPath__map is None: return self._MultiPath__map table = self.get_table() import dm as _dm for map in _dm.maps(): if compare_tables(map.table, table): if self.name != map.name: self.name = nameCache.rename(self.name, map.name) self._MultiPath__map = map self.buildParts() self.active = True del _dm return self._MultiPath__map # all else has failed, make a new map... self._MultiPath__map = _dm.map(name=self.name, table=table) self.buildParts() self.active = True del _dm return self._MultiPath__map map = property(get_map, None, None, "block.dm.map") def get_name(self): return self._MultiPath__name def set_name(self, name): bdev = self._MultiPath__bdev prefix = self.prefix self.deactivate() self._MultiPath__name = nameCache.rename(self._MultiPath__name, name) self._MultiPath__bdev = BlockDev().FromMajorMinor(bdev.major, bdev.minor) self.bdev.mode = 0600 self.bdev.path = prefix + name self.activate() name = property(get_name, set_name, None, "the name of this MultiPath") def get_parts(self): if self._MultiPath__parts is None: self.buildParts() for x in self._MultiPath__parts: yield x partitions = property(get_parts, None, None, "this device's partitions") def output(self, *args): for x in args: print x def buildPartMaps(self): from maps import PartitionDeviceMap as _PartitionDeviceMap import parted as _parted import _ped dev = self.PedDevice dev.open() try: disk = _parted.Disk(dev) except (_ped.DiskLabelException,_parted.DiskException), msg: dev.close() del dev return for part in disk.partitions: if part.active: name = "%sp%s" % (self.name, part.number) bdev = BlockDev(self.prefix + self.name) bdev.mode = 0600 if part.type != _parted.PARTITION_EXTENDED: map = _PartitionDeviceMap(0, part.geometry.length, bdev, part.geometry.start, part.number) else: # special mapping for extended partitions see the comment # in RaidSet.buildPartMaps() map = _PartitionDeviceMap(0, 2, bdev, part.geometry.start, part.number) map.name = name self._set_map_uuid(map) yield map del disk dev.close() del dev del _PartitionDeviceMap del _parted del _ped def buildParts(self): import dm as _dm maps = self.buildPartMaps() for map in maps: map.create() self._MultiPath__parts.append(map) def removeMemberParts(self): import dm as _dm for x in range(1,257): for m in self.member_devpaths: _dm.rmpart(m, x) del _dm def scanMemberParts(self): import dm as _dm for m in self.member_devpaths: _dm.scanparts(m) del _dm def activate(self, mknod=False): if self.active: return if mknod: try: _os.unlink(self.prefix+self.name) except: pass self.map.dev.mknod(self.prefix+self.name) self.mknod = True self._set_map_uuid(self.map) nameCache.get(self.name) # this should set the refcount to 2 self.removeMemberParts() self.buildParts() ret = self.partitions return ret def deactivate(self): if not self.active: return parts = self._MultiPath__parts self._MultiPath__parts = [] for part in parts: try: part.map.remove() except: pass parts = list(self.partitions) if len(parts) == 0 and not self._MultiPath__map is None: removeDeviceMap(self._MultiPath__map) self._MultiPath__map = None self.active = False nameCache.put(self.name) # this should take the refcount to 1 elif len(parts) > 0: raise RuntimeError, "multipath has active partitions" self.scanMemberParts() def display(self, space=0, printer=lambda x,y: _sys.stdout.write("%s%s\n" % (x*' ',y))): printer(space, self) for m in self.members: m.display(space+1, printer=printer) class RaidSet: def __init__(self, rs, prefix="/dev/mapper/"): self.rs = rs self._RaidSet__prefix = prefix self._RaidSet__bdev = None self._RaidSet__map = None self._RaidSet__parts = [] self._RaidSet__name = rs.name self._RaidSet__activeMembers = [] self.active = False self.mknod = False def __cmp__(self, other): return cmp(self.map, other.map) def get_prefix(self): return self._RaidSet__prefix def set_prefix(self, value): self._RaidSet__prefix = value prefix = property(get_prefix, set_prefix, None, \ "prefix for path to device nodes") def _set_map_uuid(self, map): if map and not map.uuid: # make sure the map has a uuid complete with subsystem prefix map.uuid = "DMRAID-%s" % map.name def get_PedDevice(self): import parted as _parted ret = _parted.getDevice(self.bdev.path) del _parted return ret PedDevice = property(get_PedDevice, None, None, "parted.PedDevice") def get_level(self): # We do not handle layered raid properly here, nor raid5 nor JBOD raise NotImplementedError, "FIXME" if self.rs.dmtype in ("stripe", "striped"): return 0 elif self.rs.dmtype == "mirror": return 1 raise NotImplementedError, "unknown dmtype %s" % (self.rs.dmtype,) level = property(get_level, None, None, "raid level") def get_members(self, descend=True): import dmraid as _dmraid for c in self.rs.children: if isinstance(c, _dmraid.raidset): r = RaidSet(c, prefix=self.prefix) yield r if descend: for m in r.members: yield m elif isinstance(c, _dmraid.raiddev): yield RaidDev(c) del _dmraid members = property(get_members, None, None, "members") def get_member_devpaths(self, descend=True): for m in self.get_members(descend): if isinstance(m, RaidDev): yield m.devpath member_devpaths = property(get_member_devpaths, None, None, "member devpaths") def get_spares(self, descend=True): import dmraid as _dmraid for s in self.rs.spares: if isinstance(c, _dmraid.raidset): r = RaidSet(c) yield r if descend: for m in r.members: yield m for m in r.spares: yield m elif isinstance(c, _dmraid.raiddev): yield RaidDev(c) # members might have spares as well for c in self.rs.children: if isinstance(c, _dmraid.raidset) and descend: for spare in RaidSet(c).spares: yield spare del _dmraid spares = property(get_spares, None, None, "spares") def get_bdev(self): if not self._RaidSet__bdev is None: return self._RaidSet__bdev try: self._RaidSet__bdev = BlockDev(self.prefix + self.name) return self._RaidSet__bdev except: pass bdev = property(get_bdev, None, None, "block.BlockDev") def get_map(self): if not self._RaidSet__map is None: return self._RaidSet__map import dm as _dm for map in _dm.maps(): if compare_tables(map.table, self.rs.dmTable): self._RaidSet__map = map self.active = True del _dm return self._RaidSet__map # all else has failed, make a new map... self._RaidSet__map = _dm.map(name=self.name, table=self.rs.dmTable) self.active = True del _dm return self._RaidSet__map map = property(get_map, None, None, "block.dm.map") def get_name(self): return self._RaidSet__name def set_name(self, name): bdev = self._RaidSet__bdev prefix = self.prefix self.deactivate() self.rs.name = name self._RaidSet__name = name self._RaidSet__bdev = BlockDev().FromMajorMinor(bdev.major, bdev.minor) self.bdev.mode = 0600 self.bdev.path = prefix + name self.activate() name = property(get_name, set_name, None, "this name of this RaidSet") def get_parts(self): for x in self._RaidSet__parts: yield x partitions = property(get_parts, None, None, "this device's partitions") def get_valid(self): if self.rs.broken: return False if self.rs.degraded: return False for x in self.members: if isinstance(x, RaidDev) or isinstance(x, RaidSet): if not x.valid: return False return True valid = property(get_valid, None, None, "test a raidset for validity") def output(self, *args): for x in args: print x def buildParts(self): from maps import PartitionDeviceMap as _PartitionDeviceMap import parted as _parted import _ped dev = self.PedDevice dev.open() try: disk = _parted.Disk(device=dev) except (_ped.DiskLabelException, _parted.DiskException,_parted.IOException), msg: dev.close() del dev return for part in disk.partitions: if part.active: name = "%sp%s" % (self.name, part.number) bdev = BlockDev(self.prefix + self.name) bdev.mode = 0600 if part.type != _parted.PARTITION_EXTENDED: map = _PartitionDeviceMap(0, part.geometry.length, bdev, part.geometry.start, part.number) else: # Various tools create different mappings for ext. parts: # dmraid: Does not create a mapping for extended parts # kpartx: Creates a mapping with a size of 2 sectors # parted: Creates a mapping with the actual partition size # # The kernel does the same as kpartx for regular disks. # We do as kpartx and create a 2 sector mapping, so that if # there is a pre-existing mapping (ie a livecd install), we # recognize it and don't try to create one. map = _PartitionDeviceMap(0, 2, bdev, part.geometry.start, part.number) map.name = name self._set_map_uuid(map) map.create() self._RaidSet__parts.append(map) del disk dev.close() del dev del _PartitionDeviceMap del _parted del _ped def removeMemberParts(self): for m in self.members: if isinstance(m, RaidDev): m.removeParts() elif isinstance(m, RaidSet): m.removeMemberParts() def scanMemberParts(self): for m in self.members: if isinstance(m, RaidDev): m.scanParts() elif isinstance(m, RaidSet): m.scanMemberParts() def activate(self, degradedOk=False, mknod=False, mkparts=True): if self.active: return # We put the active members in a list so we can deactivate them later. for member in self.members: if isinstance(member, RaidSet): member.activate(degradedOk=degradedOk, mknod=mknod, mkparts=False) self._RaidSet__activeMembers.append(member) if mknod: try: _os.unlink(self.prefix+self.name) except: pass self.map.dev.mknod(self.prefix+self.name) self.mknod = True self._set_map_uuid(self.map) self.removeMemberParts() if mkparts: self.buildParts() ret = self.partitions return ret def deactivate(self): if not self.active: return parts = self._RaidSet__parts self._RaidSet__parts = [] for part in parts: try: part.map.remove() except: pass parts = list(self.partitions) if len(parts) == 0 and not self._RaidSet__map is None: removeDeviceMap(self._RaidSet__map) self._RaidSet__map = None self.active = False elif len(parts) > 0: raise RuntimeError, "raidset has active partitions" for activeMember in self._RaidSet__activeMembers: activeMember.deactivate() self._RaidSet__activeMembers = [] self.scanMemberParts() def display(self, space=0, printer=lambda x,y: _sys.stdout.write("%s%s\n" % (x*' ',y))): printer(space, self) for m in self.members: m.display(space+1, printer=printer) class RaidDev: def __init__(self, rd, prefix=None): self.rd = rd self._RaidDev__bdev = None self._RaidDev__prefix = None def get_prefix(self): if self._RaidDev__prefix is None: self._RaidDev__prefix = \ _string.join(self.rd.device.path.split('/')[:-1],'/') + '/' return self._RaidDev__prefix prefix = property(get_prefix, None, None, "prefix for device node path") def get_bdev(self): if self._RaidDev__bdev is None: bdev = BlockDev().FromFile(self.rd.device.path) self._RaidDev__bdev = bdev return self._RaidDev__bdev bdev = property(get_bdev, None, None, "block.BlockDev") def get_PedDevice(self): import parted as _parted ret = _parted.getDevice(self.bdev.path) del _parted return ret PedDevice = property(get_PedDevice, None, None, "parted.PedDevice") def get_devpath(self): return self.rd.device.path.split('/')[-1] devpath = property(get_devpath, None, None, "path relative to /dev") def get_valid(self): if self.bdev is not None and \ hasattr(self.bdev, 'path') and self.bdev.path is not None: return True return False valid = property(get_valid, None, None, "test a raiddev for validity") def __cmp__(self, other): # Dear Python, you are retarded. def strcmp(a,b): ab = zip(reduce(lambda x,y: x + [ord(y)], list(a), []), reduce(lambda x,y: x + [ord(y)], list(b), [])) cmps = filter(None, map(lambda (x,y): cmp(x,y), ab)) or \ [len(a) - len(b),] return cmps[0] obdev = other if isinstance(other, "".__class__): filename = '/dev/' + other if other[0].isdigit(): maj,min = (0,0) if ':' in other: maj,min = other.split(':')[0:2] obdev = BlockDev().FromMajorMinor(maj,min) else: device = str(self.bdev.device) return strcmp(device, other) elif other.startswith("/"): try: obdev = BlockDev().FromFile(other) except: filename = self.devpath elif other.startswith('/dev/mapper/'): filename = '/dev/mapper/' + self.devpath elif other.startswith('/dev/'): filename = '/dev/' + self.devpath elif other.startswith('/tmp/'): filename = '/tmp/' + self.devpath try: obdev = BlockDev().FromFile(filename) except: return strcmp(filename, other) if isinstance(obdev, BlockDev): try: return cmp(self.bdev.device.dev, obdev.device.dev) except: pass elif isinstance(other, RaidDev): if self.rd.device.serial is not None and \ other.rd.device.serial is not None: return strcmp(self.rd.device.serial, other.rd.device.serial) elif self.bdev is not None and other.bdev is not None: return strcmp(self.bdev.device.dev, other.bdev.device.dev) else: return strcmp(self.devpath, other.devpath) return -1 def removeParts(self): for x in range(1,257): self.rd.device.rmpart(x) def scanParts(self): self.rd.device.scanparts() def display(self, space=0, printer=lambda x,y: _sys.stdout.write("%s%s\n" % (x*' ',y))): printer(space, self) # # vim:ts=8:sts=4:sw=8:et #
修改文件时间
将文件时间修改为当前时间的前一年
删除文件