Package phones ::
Module com_brew
|
|
1
2
3
4
5
6
7
8
9
10 """Implements the "Brew" filesystem protocol"""
11
12 import os
13 import p_brew
14 import time
15 import cStringIO
16 import com_phone
17 import prototypes
18 import common
19
21 """This phone not supported"""
22 pass
23
26 if str is None:
27 str="Brew Error 0x%02x" % (errnum,)
28 Exception.__init__(self, str)
29 self.errnum=errnum
30
34
38
42
46
50
54
58
62
66
68 - def __init__(self, errnum=0x04, filename=None):
70
72 - def __init__(self, errnum=0x16, filename=None):
74
79
80
81 modeignoreerrortypes=com_phone.modeignoreerrortypes+(BrewCommandException,common.CommsDataCorruption)
82
84 """This is a class that lets you do various filesystem manipulations and
85 it remembers the data. Typical usage would be if you make changes to
86 files (adding, removing, rewriting) and then have to keep checking if
87 files exist, add sizes etc. This class saves the hassle of rereading
88 the directory every single time. Note that it will only see changes
89 you make via this class. If you go directly to the Brew class then
90 those won't be seen.
91 """
93 "@param target: where operations should be done after recording them here"
94 self.__target=target
95 self.__cache={}
96
104
105 - def stat(self, filename):
108
120
132
144
146 """ Emulate a phone file system using a local file system. This is used
147 when you may not have access to a physical phone, but have a copy of its
148 file system.
149 """
150 MODEBREW="modebrew"
151 _fs_path=''
157 self.log("Trying stuff with command 0x0c")
159 self.log("Taking phone offline")
160 if reset:
161 self.log("Resetting phone")
163 self.log("Attempting to put phone in modem mode")
168 if len(directory)<1:
169 return
170 dirs=directory.split('/')
171 for i in range(0,len(dirs)):
172 try:
173 self.mkdir("/".join(dirs[:i+1]))
174 except:
175 pass
205
207 results={}
208 self.log("Listing files in dir: '"+dir+"'")
209 results={}
210 _pwd=os.path.join(self._fs_path, dir)
211 for _root,_dir,_file in os.walk(_pwd):
212 break
213 try:
214 for f in _file:
215 _stat=os.stat(os.path.join(_pwd, f))
216 _date=_stat[8]
217 _name=dir+'/'+f
218 _timestr=''
219 try:
220
221 _timestr=time.strftime("%x %X", time.gmtime(_date))
222 except:
223 pass
224 results[_name]={ 'name': _name, 'type': 'file', 'size': _stat[6],
225 'date': (_date, _timestr) }
226 except:
227 pass
228 return results
229
231 results={}
232 self.log("Listing subdirs in dir: '"+dir+"'")
233 _pwd=os.path.join(self._fs_path, dir)
234 for _root,_dir,_file in os.walk(_pwd):
235 break
236 for d in _dir:
237 if len(dir):
238 d=dir+"/"+d
239 results[d]={ 'name': d, 'type': 'directory' }
240 if recurse>0:
241 results.update(self.listsubdirs(d, recurse-1))
242 return results
243
245 results={}
246 _file=[]
247 _dir=[]
248 self.log("Listing dir '"+dir+"'")
249 _pwd=os.path.join(self._fs_path, dir)
250 for _root,_dir,_file in os.walk(_pwd):
251 break
252 for f in _file:
253 _stat=os.stat(os.path.join(_pwd, f))
254 _date=_stat[8]
255 _name=dir+'/'+f
256 _timestr=''
257 try:
258
259 _timestr=time.strftime("%x %X", time.gmtime(_date))
260 except:
261 pass
262 results[_name]={ 'name': _name, 'type': 'file', 'size': _stat[6],
263 'date': (_date, _timestr) }
264 for d in _dir:
265 _name=dir+'/'+d
266 results[_name]={ 'name': _name, 'type': 'directory' }
267 if recurse>0:
268 results.update(self.getfilesystem(_name, recurse-1))
269 return results
270
272 try:
273 _stat=os.stat(os.path.join(self._fs_path, name))
274 _date=_stat[8]
275 results={ 'name': name, 'type': 'file', 'size': _stat[6], 'datevalue': 0x0DEB0DEB,
276 'date': (_date,
277 time.strftime("%x %X", time.gmtime(_date))) }
278 return results
279 except:
280
281 return None
282
286
287 - def getfilecontents(self, name, use_cache=False):
288 self.log("Getting file contents '"+name+"'")
289 try:
290 if name[0]=='/':
291 return file(os.path.join(self._fs_path, name[1:]), 'rb').read()
292 return file(os.path.join(self._fs_path, name), 'rb').read()
293 except:
294 raise BrewNoSuchFileException
295
297
298 return "DEBUGESN"
300 self.log('_setmodebrew: in mode BREW')
301 return True
303 return NotImplementedError
306 - def logdata(self, s, data, klass=None):
308
311
312 DirCache=_DirCache
313
315 "Talk to a phone using the 'brew' protocol"
316
317 MODEBREW="modebrew"
318 brewterminator="\x7e"
319
320
321 _brewepochtounix=315964800
322
326
331
336
338 self.log("Trying stuff with command 0x0c")
339 req=p_brew.testing0crequest()
340 res=self.sendbrewcommand(req, p_brew.testing0cresponse)
341
343 time.sleep(delay)
344 req=p_brew.setmoderequest()
345 req.request=1
346 self.log("Taking phone offline")
347 self.sendbrewcommand(req, p_brew.setmoderesponse)
348 time.sleep(delay)
349 if reset:
350 req=p_brew.setmoderequest()
351 req.request=2
352 self.log("Resetting phone")
353 self.sendbrewcommand(req, p_brew.setmoderesponse)
354
368
380
382 if len(directory)<1:
383 return
384 dirs=directory.split('/')
385 for i in range(0,len(dirs)):
386 try:
387 self.mkdir("/".join(dirs[:i+1]))
388 except:
389 pass
390
391
397
404
420
422
423 return bool(self.statfile(path))
424
443
450
452
453
454 _dirs=[x for x in path.split('/') if x]
455 if _dirs:
456 return _dirs[-1]
457 return ''
458
460
461
462 _dirs=[x for x in filename.split('/') if x]
463 if len(_dirs)<2:
464
465 return '/'
466 return '/'.join(_dirs[:-1])
467
468 - def join(self, *args):
469
470 return '/'.join([x.strip('/') for x in args if x])
471
473 results={}
474 self.log("Listing subdirs in dir: '"+dir+"'")
475 self.log("X recurse="+`recurse`)
476
477 req=p_brew.listdirectoryrequest()
478 req.dirname=dir
479 for i in xrange(10000):
480 try:
481 req.entrynumber=i
482 res=self.sendbrewcommand(req,p_brew.listdirectoryresponse)
483
484 f=res.subdir.rfind("/")
485 if f>=0:
486 subdir=res.subdir[f+1:]
487 else:
488 subdir=res.subdir
489 if len(dir):
490 subdir=dir+"/"+subdir
491 self.log("subdir="+subdir)
492 results[subdir]={ 'name': subdir, 'type': 'directory' }
493 except BrewNoMoreEntriesException:
494 break
495 except (BrewBadPathnameException, BrewAccessDeniedException):
496 self.log('Failed to list dir '+dir)
497 return {}
498 if recurse:
499 for k,_subdir in results.items():
500 results.update(self.listsubdirs(_subdir['name'], recurse-1))
501 return results
502
504 self.log('Checking for subdirs in dir: "'+dir+'"')
505 req=p_brew.listdirectoryrequest()
506 req.dirname=dir
507 req.entrynumber=0
508 try:
509 res=self.sendbrewcommand(req,p_brew.listdirectoryresponse)
510
511 return True
512 except BrewNoMoreEntriesException:
513 return False
514 except:
515 if __debug__:
516 raise
517 return False
518
520 results={}
521 self.log("Listing files in dir: '"+dir+"'")
522
523 _broken_date=hasattr(self.protocolclass, 'broken_filelist_date') and \
524 self.protocolclass.broken_filelist_date
525 req=p_brew.listfilerequest()
526 req.dirname=dir
527
528 for i in xrange(10000):
529 try:
530 req.entrynumber=i
531 res=self.sendbrewcommand(req,p_brew.listfileresponse)
532 results[res.filename]={ 'name': res.filename, 'type': 'file',
533 'size': res.size }
534 if not _broken_date:
535 if res.date<=0:
536 results[res.filename]['date']=(0, "")
537 else:
538 try:
539 date=res.date+self._brewepochtounix
540 results[res.filename]['date']=(date, time.strftime("%x %X", time.localtime(date)))
541 except:
542
543 results[res.filename]['date']=(0, "")
544 except BrewNoMoreEntriesException:
545 break
546 except (BrewBadPathnameException, BrewAccessDeniedException):
547 self.log('Failed to list files in dir '+dir)
548 return {}
549 if _broken_date:
550 for _key,_entry in results.items():
551 _stat=self.statfile(_key)
552 if _stat:
553 _entry['date']=_stat.get('date', (0, ''))
554 else:
555 _entry['date']=(0, '')
556 return results
557
559 self.log("Getting file system in dir '"+dir+"'")
560 results=self.listsubdirs(dir)
561 subdir_list=[x['name'] for k,x in results.items()]
562 results.update(self.listfiles(dir))
563 if recurse:
564 for _subdir in subdir_list:
565 results.update(self.getfilesystem(_subdir, recurse-1))
566 return results
567
595
604
606 start=time.time()
607 self.log("Writing file '"+name+"' bytes "+`len(contents)`)
608 desc="Writing "+name
609 req=p_brew.writefilerequest()
610 req.filesize=len(contents)
611 req.data=contents[:0x100]
612 req.filename=name
613 self.sendbrewcommand(req, p_brew.writefileresponse)
614
615 numblocks=len(contents)/0x100
616 count=0
617 for offset in range(0x100, len(contents), 0x100):
618 req=p_brew.writefileblockrequest()
619 count+=1
620 if count>=0x100: count=1
621 if count % 5==0:
622 self.progress(offset>>8,numblocks,desc)
623 req.blockcounter=count
624 req.thereismore=offset+0x100<len(contents)
625 block=contents[offset:]
626 l=min(len(block), 0x100)
627 block=block[:l]
628 req.data=block
629 self.sendbrewcommand(req, p_brew.writefileblockresponse)
630 end=time.time()
631 if end-start>3:
632 self.log("Wrote "+`len(contents)`+" bytes at "+`int(len(contents)/(end-start))`+" bytes/second")
633
634
635 - def getfilecontents(self, file, use_cache=False):
636 if use_cache:
637 node=self.statfile(file)
638 if node and file_cache.hit(file, node['date'][0], node['size']):
639 self.log('Reading from cache: '+file)
640 _data=file_cache.data(file)
641 if _data:
642 return _data
643 self.log('Cache file corrupted and discarded')
644
645 start=time.time()
646 self.log("Getting file contents '"+file+"'")
647 desc="Reading "+file
648
649 data=cStringIO.StringIO()
650
651 req=p_brew.readfilerequest()
652 req.filename=file
653
654 res=self.sendbrewcommand(req, p_brew.readfileresponse)
655
656 filesize=res.filesize
657 data.write(res.data)
658
659 counter=0
660 while res.thereismore:
661 counter+=1
662 if counter>0xff:
663 counter=0x01
664 if counter%5==0:
665 self.progress(data.tell(), filesize, desc)
666 req=p_brew.readfileblockrequest()
667 req.blockcounter=counter
668 res=self.sendbrewcommand(req, p_brew.readfileblockresponse)
669 data.write(res.data)
670
671 self.progress(1,1,desc)
672
673 data=data.getvalue()
674
675
676 end=time.time()
677 if end-start>3:
678 self.log("Read "+`filesize`+" bytes at "+`int(filesize/(end-start))`+" bytes/second")
679
680 if filesize!=len(data):
681 self.log("expected size "+`filesize`+" actual "+`len(data)`)
682 self.raisecommsexception("Brew file read is incorrect size", common.CommsDataCorruption)
683 if use_cache and node:
684 file_cache.add(file, node.get('date', [0])[0], data)
685 return data
686
687 DirCache=_DirCache
688
690 req=p_brew.memoryconfigrequest()
691 respc=p_brew.memoryconfigresponse
692 try:
693 self.sendbrewcommand(req, respc, callsetmode=False)
694 return True
695 except modeignoreerrortypes:
696 pass
697
698 for baud in 0, 38400,115200:
699 if baud:
700 if not self.comm.setbaudrate(baud):
701 continue
702 try:
703 self.sendbrewcommand(req, respc, callsetmode=False)
704 return True
705 except modeignoreerrortypes:
706 pass
707
708
709 for baud in (0, 115200, 19200, 230400):
710 if baud:
711 if not self.comm.setbaudrate(baud):
712 continue
713 print "Baud="+`baud`
714
715 try:
716 for line in self.comm.sendatcommand("+GMM"):
717 if line.find("SPH-A700")>0:
718 raise BrewNotSupported("This phone is not supported by BitPim", self.desc)
719 except modeignoreerrortypes:
720 self.log("No response to AT+GMM")
721 except:
722 print "GMM Exception"
723 self.mode=self.MODENONE
724 self.comm.shouldloop=True
725 raise
726
727 try:
728 self.comm.write("AT$QCDMG\r\n")
729 except:
730
731 self.mode=self.MODENONE
732 self.comm.shouldloop=True
733 raise
734 try:
735
736 if self.comm.readsome().find("OK")>=0:
737 break
738 except modeignoreerrortypes:
739 self.log("No response to setting QCDMG mode")
740
741
742 for baud in 0,38400,115200:
743 if baud:
744 if not self.comm.setbaudrate(baud):
745 continue
746 try:
747 self.sendbrewcommand(req, respc, callsetmode=False)
748 return True
749 except modeignoreerrortypes:
750 pass
751 return False
752
754 if callsetmode:
755 self.setmode(self.MODEBREW)
756 buffer=prototypes.buffer()
757 request.writetobuffer(buffer, logtitle="sendbrewcommand")
758 data=buffer.getvalue()
759 data=common.pppescape(data+common.crcs(data))+common.pppterminator
760 firsttwo=data[:2]
761 try:
762
763 data=self.comm.writethenreaduntil(data, False, common.pppterminator, logreaduntilsuccess=False)
764 except modeignoreerrortypes:
765 self.mode=self.MODENONE
766 self.raisecommsdnaexception("manipulating the filesystem")
767 self.comm.success=True
768 origdata=data
769
770
771
772
773
774 d=data.rfind(common.pppterminator,0,-1)
775 if d>=0:
776 self.log("Multiple packets in data - taking last one starting at "+`d+1`)
777 self.logdata("Original data", origdata, None)
778 data=data[d+1:]
779
780
781 data=common.pppunescape(data)
782
783
784 crc=data[-3:-1]
785 data=data[:-3]
786
787 calccrc=common.crcs(data)
788 if calccrc!=crc:
789
790 d=data.find(firsttwo)
791 if d>0:
792 self.log("Junk at begining of packet, data at "+`d`)
793 self.logdata("Original data", origdata, None)
794 self.logdata("Working on data", data, None)
795 data=data[d:]
796
797 calccrc=common.crcs(data)
798
799 if calccrc!=crc:
800 self.logdata("Original data", origdata, None)
801 self.logdata("Working on data", data, None)
802 raise common.CommsDataCorruption("Brew packet failed CRC check", self.desc)
803
804
805 self.logdata("brew response", data, responseclass)
806
807 if firsttwo=="Y\x0c" and data==firsttwo:
808
809
810 raise common.CommsWrongPort("The port you are using is echoing data back, and is not valid for Brew data. Most likely you have selected the modem interface when you should be using the diagnostic interface.", self.desc)
811
812
813 if data[0]=="Y" and data[2]!="\x00":
814 err=ord(data[2])
815 if err==0x1c:
816 raise BrewNoMoreEntriesException()
817 if err==0x08:
818 raise BrewNoSuchDirectoryException()
819 if err==0x06:
820 raise BrewNoSuchFileException()
821 if err==0x1a:
822 raise BrewBadPathnameException()
823 if err==0x0b:
824 raise BrewFileLockedException()
825 if err==0x0d:
826 raise BrewNameTooLongException()
827 if err==0x07:
828 raise BrewDirectoryExistsException()
829 if err==0x04:
830 raise BrewAccessDeniedException()
831 if err==0x16:
832 raise BrewFileSystemFullException()
833 raise BrewCommandException(err)
834
835
836 if ord(data[0])==0x13:
837 if firsttwo[0]=="Y" or firsttwo[0]=="\x4b":
838 raise BrewAccessDeniedException()
839 else:
840 raise BrewBadBrewCommandException()
841 if ord(data[0])==0x14:
842 raise BrewMalformedBrewCommandException()
843
844
845 if ord(data[0])==0x4b and ord(data[2])==0x1c:
846 raise BrewAccessDeniedException()
847
848
849 buffer=prototypes.buffer(data)
850 res=responseclass()
851 try:
852 res.readfrombuffer(buffer, autolog=False)
853 except:
854
855
856 self.log(formatpacketerrorlog("Error decoding response", origdata, data, responseclass))
857 raise
858 return res
859
861 """Talk to a phone using the 'brew' protocol
862 This class uses the new filesystem commands which are supported
863 by newer qualcomm chipsets used in phones like the LG vx8100
864 """
865
872
874
875
876
877 req=p_brew.new_reconfigfilesystemrequest()
878 self.sendbrewcommand(req, p_brew.new_reconfigfilesystemresponse)
879
887
895
904
911
916
918 start=time.time()
919 self.log("Writing file '"+name+"' bytes "+`len(contents)`)
920 desc="Writing "+name
921 size=len(contents)
922 exists=self.exists(name)
923 if exists:
924 info=self.statfile(name)
925 current_size=info['size']
926 else:
927 current_size=0
928 try:
929 block_size = self.protocolclass.BREW_WRITE_SIZE
930 except AttributeError:
931 block_size = p_brew.BREW_WRITE_SIZE
932
933
934 if exists and size<current_size:
935 self.rmfile(name)
936 exists=False
937 if exists:
938 handle=self.openfile(name, p_brew.new_fileopen_mode_write, p_brew.new_fileopen_flag_existing)
939 else:
940 handle=self.openfile(name, p_brew.new_fileopen_mode_write, p_brew.new_fileopen_flag_create)
941 try:
942 remain=size
943 pos=0
944 count=0
945 while remain:
946 req=p_brew.new_writefilerequest()
947 req.handle=handle
948 if remain > block_size:
949 req.bytes=block_size
950 else:
951 req.bytes=remain
952 req.position=size-remain
953 req.data=contents[req.position:(req.position+req.bytes)]
954 count=(count&0xff)+1
955 if count % 5==0:
956 self.progress(req.position,size,desc)
957 res=self.sendbrewcommand(req, p_brew.new_writefileresponse)
958 if res.bytes!=req.bytes:
959 self.raisecommsexception("Brew file write error", common.CommsDataCorruption)
960 remain-=req.bytes
961 finally:
962 self.closefile(handle)
963 self.progress(1,1,desc)
964 end=time.time()
965 if end-start>3:
966 self.log("Wrote "+`len(contents)`+" bytes at "+`int(len(contents)/(end-start))`+" bytes/second")
967
968 - def getfilecontents(self, file, use_cache=False):
969 node=self.statfile(file)
970 if use_cache:
971 if node and file_cache.hit(file, node['date'][0], node['size']):
972 self.log('Reading from cache: '+file)
973 _data=file_cache.data(file)
974 if _data:
975 return _data
976 self.log('Cache file corrupted and discarded')
977 try:
978 block_size = self.protocolclass.BREW_READ_SIZE
979 except AttributeError:
980 block_size = p_brew.BREW_READ_SIZE
981 start=time.time()
982 self.log("Getting file contents '"+file+"'")
983 desc="Reading "+file
984 data=cStringIO.StringIO()
985 handle=self.openfile(file, p_brew.new_fileopen_mode_read)
986 try:
987 filesize=node['size']
988 read=0
989 counter=0
990 req=p_brew.new_readfilerequest(handle=handle, bytes=block_size)
991 while True:
992 counter=(counter&0xff)+1
993 if counter%5==0:
994 self.progress(data.tell(), filesize, desc)
995 req.position=read
996 res=self.sendbrewcommand(req, p_brew.new_readfileresponse)
997 if res.bytes:
998 data.write(res.data)
999 read+=res.bytes
1000 else:
1001 break
1002 if read==filesize:
1003 break
1004 finally:
1005 self.closefile(handle)
1006 self.progress(1,1,desc)
1007 data=data.getvalue()
1008
1009 end=time.time()
1010 if end-start>3:
1011 self.log("Read "+`filesize`+" bytes at "+`int(filesize/(end-start))`+" bytes/second")
1012 if filesize!=len(data):
1013 self.log("expected size "+`filesize`+" actual "+`len(data)`)
1014 self.raisecommsexception("Brew file read is incorrect size", common.CommsDataCorruption)
1015 if use_cache and node:
1016 file_cache.add(file, node.get('date', [0])[0], data)
1017 return data
1018
1019 - def getfilecontents2(self, filename, start, size):
1020
1021 try:
1022 block_size = self.protocolclass.BREW_READ_SIZE
1023 except AttributeError:
1024 block_size = p_brew.BREW_READ_SIZE
1025 self.log("Getting file contents2 '"+filename+"'")
1026 desc="Reading "+filename
1027 data=cStringIO.StringIO()
1028 handle=self.openfile(filename, p_brew.new_fileopen_mode_read)
1029 _readsize=start+size
1030 try:
1031 read=start
1032 counter=0
1033 while True:
1034 counter+=1
1035 if counter%5==0:
1036 self.progress(read, _readsize, desc)
1037 req=p_brew.new_readfilerequest()
1038 req.handle=handle
1039 req.bytes=block_size
1040 req.position=read
1041 res=self.sendbrewcommand(req, p_brew.new_readfileresponse)
1042 if res.bytes:
1043 data.write(res.data)
1044 read+=res.bytes
1045 else:
1046 break
1047 if read>=_readsize:
1048 break
1049 finally:
1050 self.closefile(handle)
1051 self.progress(1,1,desc)
1052 return data.getvalue()[:size]
1053
1062
1066
1068 self.log("Listing subdirs in dir: '"+dir+"'")
1069 self.log("X recurse="+`recurse`)
1070 return self.getfilesystem(dir, recurse, files=0)
1071
1073 self.log("Listing files in dir: '"+dir+"'")
1074 return self.getfilesystem(dir, recurse=0, directories=0)
1075
1076 - def getfilesystem(self, dir="", recurse=0, directories=1, files=1):
1077 results={}
1078 self.log("Listing dir '"+dir+"'")
1079 handle=self._get_dir_handle(dir)
1080 dirs={}
1081 count=0
1082 try:
1083
1084 req=p_brew.new_listentryrequest(handle=handle)
1085 for i in xrange(1, 10000):
1086 req.entrynumber=i
1087 res=self.sendbrewcommand(req, p_brew.new_listentryresponse)
1088 if len(res.entryname) == 0:
1089 break
1090 if len(dir):
1091 direntry=dir+"/"+res.entryname
1092 else:
1093 direntry=res.entryname
1094 if files and (res.type==0 or res.type == 0x0f):
1095 results[direntry]={ 'name': direntry, 'type': 'file', 'size': res.size, 'special': res.type==0xf }
1096 try:
1097 if res.date<=0:
1098 results[direntry]['date']=(0, "")
1099 else:
1100 results[direntry]['date']=(res.date, time.strftime("%x %X", time.localtime(res.date)))
1101 except:
1102 results[direntry]['date']=(0, "")
1103 elif directories and (res.type and res.type != 0x0f):
1104 results[direntry]={ 'name': direntry, 'type': 'directory' }
1105 if recurse>0:
1106 dirs[count]=direntry
1107 count+=1
1108 finally:
1109
1110 self._close_dir(handle)
1111
1112 for i in range(count):
1113 results.update(self.getfilesystem(dirs[i], recurse-1))
1114 return results
1115
1117
1118 self.log('stat file '+name)
1119 req=p_brew.new_statfilerequest()
1120 req.filename=name
1121 res=self.sendbrewcommand(req, p_brew.new_statfileresponse)
1122 if res.error==2:
1123 raise BrewNoSuchFileException
1124 elif res.error==0x13:
1125
1126 raise BrewFileLockedException
1127 elif res.error != 0:
1128 raise BrewStatFileException(res.error, name)
1129
1130
1131 if res.type==1 or res.type==0x86:
1132
1133 results={ 'name': name, 'type': 'file', 'size': res.size }
1134 else:
1135 results={ 'name': name, 'type': 'directory' }
1136 try:
1137 if res.created_date<=0:
1138 results['date']=(0, '')
1139 else:
1140 results['date']=(res.created_date, time.strftime("%x %X", time.localtime(res.created_date)))
1141 except:
1142
1143 results['date']=(0, '')
1144 return results
1145
1146 phone_path=os.environ.get('PHONE_FS', None)
1147 if __debug__ and phone_path:
1148 DebugBrewProtocol._fs_path=os.path.normpath(phone_path)
1149 BrewProtocol=DebugBrewProtocol
1150 else:
1151 BrewProtocol=RealBrewProtocol
1152 del phone_path
1153
1169
1171 "returns basename of str"
1172 if str.rfind("/")>0:
1173 return str[str.rfind("/")+1:]
1174 return str
1175
1177 "returns dirname of str"
1178 if str.rfind("/")>0:
1179 return str[:str.rfind("/")]
1180 return str
1181
1182
1184 """This is a special class used to consume the spurious zero in some p_brew.listfileresponse
1185
1186 The three bytes are formatted as follows:
1187
1188 - An optional 'null' byte (this class)
1189 - A byte specifying how long the directory name portion is, including trailing slash
1190 - A byte specifying the length of the whole name
1191 - The bytes of the filename (which includes the full directory name)
1192
1193 Fun and games ensue because files in the root directory have a zero length directory
1194 name, so we have some heuristics to try and distinguish if the first byte is the
1195 spurious zero or not
1196
1197 Also allow for zero length filenames.
1198
1199 """
1206
1214
1216 self._bufferstartoffset=buf.getcurrentoffset()
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237 while True:
1238
1239
1240 if buf.peeknextbyte()!=0:
1241 self._value=-1
1242 break
1243
1244
1245 if buf.peeknextbyte(1)==0:
1246
1247 if buf.howmuchmore()==2:
1248 break
1249 self._value=buf.getnextbyte()
1250 break
1251
1252
1253
1254
1255
1256 all=buf.peeknextbytes(min(max(2+buf.peeknextbyte(1), 3+buf.peeknextbyte(2)), buf.howmuchmore()))
1257
1258
1259 ddirlen=ord(all[1])
1260 dfulllen=ord(all[2])
1261
1262 if ddirlen<dfulllen and ddirlen<len(all)-3 and all[3+ddirlen-1]=='/':
1263 self._value=buf.getnextbyte()
1264 break
1265
1266
1267 self._value=-2
1268 break
1269
1270 self._bufferendoffset=buf.getcurrentoffset()
1271
1273 """This is a special class used to consume the spurious zero in some p_brew.listfileresponse or p_brew.listdirectoryresponse
1274
1275 The two bytes are formatted as follows:
1276
1277 - An optional 'null' byte (this class)
1278 - A byte specifying the length of the whole name
1279 - The bytes of the filename (which includes the full directory name)
1280
1281 Allow for zero length filenames.
1282
1283 """
1290
1298
1300 self._bufferstartoffset=buf.getcurrentoffset()
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320 while True:
1321
1322
1323 if buf.peeknextbyte()!=0:
1324 self._value=-1
1325 break
1326
1327
1328 if buf.howmuchmore()==1:
1329 self._value=-1
1330 break
1331
1332
1333 self._value=buf.getnextbyte()
1334
1335 break
1336
1337 self._bufferendoffset=buf.getcurrentoffset()
1338
1340 raise NotImplementedError()
1341
1343 raise NotImplementedError()
1344
1351
1352 file_cache=None
1353
1356 self._path=None
1357 self._cache_file_name=None
1358 self._data={ 'file_index': 0 }
1359 self.esn=None
1360 - def hit(self, file_name, datetime, data_len):
1362 - def data(self, file_name):
1364 - def add(self, file_name, datetime, data):
1366 - def clear(self, file_name):
1383
1385 _cache_index_file_name='index.idx'
1386 current_version=1
1402
1404 try:
1405 os.makedirs(self._path)
1406 except:
1407 pass
1408 if not os.path.isdir(self._path):
1409 raise Exception("Bad cache directory: '"+self._path+"'")
1410
1420
1425
1426 - def _entry(self, file_name):
1427 k=self._data.get(self.esn, None)
1428 if k:
1429 return k.get(file_name, None)
1430
1431 - def hit(self, file_name, datetime, data_len):
1432 try:
1433 e=self._entry(file_name)
1434 if e:
1435 return e['datetime']==datetime and \
1436 e['size']==data_len
1437 return False
1438 except:
1439 if __debug__:
1440 raise
1441 return False
1442
1443 - def data(self, file_name):
1444 try:
1445 e=self._entry(file_name)
1446 if e:
1447 _data=file(os.path.join(self._path, e['cache']), 'rb').read()
1448 if len(_data)==e['size']:
1449 return _data
1450 except IOError:
1451 return None
1452 except:
1453 if __debug__:
1454 raise
1455 return None
1456
1457 - def add(self, file_name, datetime, data):
1458 try:
1459 if self.esn:
1460 e=self._entry(file_name)
1461 if not e:
1462
1463 self._data.setdefault(self.esn, {})[file_name]={}
1464 e=self._data[self.esn][file_name]
1465 e['cache']='F%05d'%self._data['file_index']
1466 self._data['file_index']+=1
1467
1468 e['datetime']=datetime
1469 e['size']=len(data)
1470 _cache_file_name=os.path.join(self._path, e['cache'])
1471 try:
1472 file(_cache_file_name, 'wb').write(data)
1473 self._write_index()
1474 except IOError:
1475
1476 self._read_index()
1477 except:
1478 if __debug__:
1479 raise
1480
1481 - def clear(self, file_name):
1482 try:
1483
1484 e=self._entry(file_name)
1485 if e:
1486 try:
1487
1488 os.remove(os.path.join(self._path, e['cache']))
1489 except:
1490 pass
1491
1492 del self._data[self.esn][file_name]
1493 self._write_index()
1494 except:
1495 if __debug__:
1496 raise
1497
1512