yaffs Further name changes and file reorganisation
[yaffs2.git] / direct / python / yaffs_importer.py
1 ##
2 ## YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 ##
4 ## Copyright (C) 2002-2010 Aleph One Ltd.
5 ##   for Toby Churchill Ltd and Brightstar Engineering
6 ##
7 ## Created by Timothy Manning <timothy@yaffs.net>
8 ##
9 ## This program is free software; you can redistribute it and/or modify
10 ## it under the terms of the GNU General Public License version 2 as
11 ## published by the Free Software Foundation.
12 ##
13
14 import os
15 from yaffsfs import *
16 import sys
17 import ctypes
18
19
20 dir_in_snapshot=[]
21 files_in_snapshot=[]
22 symlinks_in_snapshot=[]
23 unknown_in_snapshot=[]
24 is_mount_in_snapshot=[]
25 def check_for_yaffs_errors(output):
26     if output<0:
27         ##error has happened
28         error=ctypes.c_int()
29         error=yaffs_get_error()
30         debug_message("error######################################",0)
31         debug_message(("error code", error),  0)
32
33 def debug_message(message, debug_level):
34     """note: that debug level 0 will always be printed unless debug_level is set to -1"""
35     """level 0 error messages"""
36     """level 1 basic tasks are shown(creating, deleating,ect)"""
37     """level 2 all process are shown"""
38     """level 3 shows minor tasks such as join_paths, ect"""
39     """level 4 is used for bug hunting and shows each step in detail"""
40     if current_debug_level>=debug_level:
41 #        for i in range(0, len(message)):
42 #            print message, 
43 #        print"\n \n \n"
44         print message
45 def join_paths(path1, path2):
46     new_path=path1
47     if path1[len(path1)-1]=="/"and path2[0]=="/":
48         new_path+=path2[1:]
49     elif path1[len(path1)-1]!="/"and path2[0]!="/":
50         new_path+="/"
51         new_path+=path2
52     else:
53         new_path+=path2
54     
55     debug_message(("adding path ", path1, " to ",  path2, " resulting path: ", new_path), 3)
56     return new_path
57     
58 def subtract_paths(path1, path2):
59     if len(path1)>len(path2):
60         if path1[len(path1)-1]!="/":
61             path1 +="/"
62         if path2[len(path2)-1]!="/":
63             path2 += "/"
64         debug_message("the two path1 is longer than path2 and can therefore be subtracted.", 4)
65         ##if the two paths are diretly subtractable
66         if path1[0:len (path2)-1]==path2:
67             debug_message("the two paths are direcly subtractable", 4)
68             new_path=path1[len(path2):]
69         elif path1[1:len (path2)-1]==path2:
70             debug_message("the path1 has one more charecter at the begining. assuming that the first chareter is a slash", 4)##fix this assumption.
71             new_path=path1[len(path2)+1:]
72         elif path1[1:len (path2)]==path2[1:]:
73             debug_message("the path2 has one more charecter at the begining. assuming that the first chareter is a slash", 4)##fix this assumption.
74
75             new_path=path1[len(path2)-1:]
76         else :
77             debug_message("error:could not subtract paths", 0)
78             debug_message( ("paths do not match:"+ path1+ "  "+path2), 0)
79             return 0
80     else :
81         debug_message( ("cannot subtract path2(:", path2, ") from path1(", path1, ")because path 2 is too long"), 0)
82         
83         return 0
84     debug_message(("subtracting paths ", path2, " from ",  path1, " resulting path: ", new_path), 3)
85     return new_path
86     
87 def create_file(file):
88     debug_message( "\n \n \n", 2)
89     file_path= join_paths(yaffs_root_dir_path, file["path"][len(path):])
90     debug_message( ("creating file:", file_path), 2)
91     debug_message (("mode", file["mode"]), 2)
92     debug_message("opening file",2)
93 #    yaffs_ls(file["path"])
94
95     ##if there is already a file in yaffs then remove the file . this is to prevent yaffs from opening a nd writing to a read only file
96     if yaffs_access(file_path, 0)==0:##the 0 means does it exist. 
97         debug_message ("file already exists in yaffs", 2)
98         output=yaffs_unlink(file_path)
99         debug_message(("unlinking", file_path, output), 2)
100         check_for_yaffs_errors(output)
101     
102     current_handle=yaffs_open(file_path, yaffs_O_CREAT | yaffs_O_TRUNC| yaffs_O_RDWR, yaffs_S_IREAD | yaffs_S_IWRITE)  ##opens a file with mode set to write
103     debug_message(("current_handle", current_handle), 2)
104     data_file=open(file["path"], "r")
105     output=yaffs_lseek(current_handle, 0, 0)
106     if output==-1:
107         debug_message("error with yaffs lseeking", 2)
108         
109         check_for_yaffs_errors(output)
110     data_to_be_written= data_file.read()
111     
112     
113     length_of_file=len(data_to_be_written)
114     debug_message (("length of data to be written",length_of_file), 3) 
115     output=yaffs_write(current_handle,data_to_be_written , length_of_file)
116     if output>=0:
117         debug_message(( "writing to ", file_path," ",  output), 1)
118     else :
119         debug_message(( "error writing file:", output), 0)
120         check_for_yaffs_errors(output)
121     output=yaffs_ftruncate(current_handle, length_of_file)
122     if output>=0:
123         debug_message(( "truncating file:", output), 2)
124     else :
125         debug_message(( "error truncating file:", output), 0)
126         check_for_yaffs_errors(output)
127     output=yaffs_close(current_handle)
128     if output>=0:
129         debug_message(( "closing file:", output), 2)
130     else :
131         debug_message(( "error closing file:", output), 0)
132         check_for_yaffs_errors(output)
133     ##changes the mode of the yaffs file to be the same as the scanned file
134     yaffs_chmod(file_path, file["mode"]);
135     if output>=0:
136         debug_message(( "chmoding file:", output), 2)
137     else :
138         debug_message(( "error chmoding file:", output), 0)
139         check_for_yaffs_errors(output)
140
141
142
143 def create_dir(dir, scanned_path, yaffs_path):
144     debug_message( "\n \n \n", 2)
145     absolute_dir_path=join_paths(yaffs_path, subtract_paths(dir["path"],scanned_path)) 
146     debug_message( ("creating dir:", absolute_dir_path), 2)
147     debug_message (("mode(in octal", oct(dir["mode"])), 2)
148
149        ##this is a bug in yaffs which will not make a dir if there is a slash on the end
150     if absolute_dir_path[len(absolute_dir_path)-1]=="/":
151         absolute_dir_path=absolute_dir_path[0:len(absolute_dir_path)-1]
152         debug_message (("path has slash on the end. removing slash new path is:",absolute_dir_path) , 4)
153         
154         
155     ##if there is already a dir in yaffs then remove the dir . this is to clean the yaffs folder if it already exists.
156     ##in yaffs all of the files in the dir to be removed must be empty.
157     ##need to create a reverse ls to delete all of the files first.
158 #    if yaffs_access(absolute_dir_path, 0)==0:##the 0 means does it exist. 
159 #        debug_message ("folder already exists in yaffs", 2)
160 #        output=yaffs_rmdir(absolute_dir_path)
161 #        debug_message(("unlinking", absolute_dir_path, output), 2)
162 #        check_for_yaffs_errors(output)
163         
164  
165         
166     output=yaffs_mkdir(absolute_dir_path, dir["mode"] )
167     if output>=0:
168         debug_message(( "created dir:", absolute_dir_path," ", output), 1)
169     else :
170         debug_message(( "error creating dir ", absolute_dir_path, " ", output), 0)
171         check_for_yaffs_errors(output)
172         if output==17:
173             printf("the directory already exists")
174     
175     
176
177
178 def remove_file_from_path(path):
179     slash_id=[]
180     for i in range(0, len(path)):
181         if path[i]=="/":
182             slash_id.append(i)
183     new_path=path[:slash_id[len(slash_id)-1]]
184     debug_message( ("removed file from path", new_path), 2)
185     return new_path
186     
187 def is_dir_hidden(dir):
188     """this code tests if a directory is hidden (has a ./<name> format) and returns true if it is hidden"""
189     slash_id=[]
190     for i in range(0, len(dir)):
191         if dir[i]=="/":
192             slash_id.append(i)
193
194     if dir[slash_id[len(slash_id)-1]+1]==".":
195         return True
196     else :
197         return False
198     
199 def scan_dir(path, search_hidden_directories=True, ):
200     """this function scans all of the files and directories in a directory. The function then calls its self on any of the directories that it found. this causes it to build up a tree of all the files and directories """
201     global files_in_snapshot
202     global symlinks_in_snapshot
203     global dir_in_snapshot
204     dir_in_current_dir=[]
205     global unknown_in_snapshot
206 #    files_in_snapshot=[]
207 #    symlinks_in_snapshot=[]
208 #    dir_in_snapshot=[]
209 #    dir_in_current_dir=[]
210 #    unknown_in_snapshot=[]
211     if os.path.exists(path)==False:
212         debug_message ("error#############################",0)
213         debug_message (("path:", path, "  doesnot exist"), 0)
214         return 0
215     dir_snapshot=os.listdir(path)
216     for i in range(0, len(dir_snapshot)):
217
218         current_snapshot=os.path.join(path, dir_snapshot[i])
219         ##debug_message (("current snapshot:", current_snapshot), 2)
220         isDir=os.path.isdir(current_snapshot)
221         isFile=os.path.isfile(current_snapshot)
222         isLink=os.path.islink(current_snapshot)
223         isMount=os.path.ismount(current_snapshot)
224
225         stat=os.lstat(current_snapshot)
226         
227         ##note the order of these if and elif statemens is importaint since a file can be symbloic link and a file
228         if isDir:
229             if search_hidden_directories==True or (is_dir_hidden(current_snapshot) ==False or search_hidden_directories==True ) :
230 #                st_mode ##mode of the folder read/write ect
231                 dir_in_snapshot.append({"path":current_snapshot, "mode":stat.st_mode})
232                 dir_in_current_dir.append(current_snapshot)
233             else :
234                 debug_message( ("file is hidden so it is ingored", current_snapshot,), 1)
235         elif  isLink:
236
237             ##for some reason the os.readlink only gives the target link realative to the directory which the symbloic link is in. change this into a absolute path
238             x=current_snapshot
239             x=remove_file_from_path(x)
240             target=join_paths(x,os.readlink(current_snapshot) )
241             symlinks_in_snapshot.append({"path":current_snapshot, "target":target})
242         elif isFile:
243
244 #            stat.st_ino ##inode number
245 #            st_nlink ##number of hard links to this file
246 #            st_size ##size of file
247             files_in_snapshot.append({"path":current_snapshot, "inode": stat.st_ino, "size":stat.st_size, "num_of_hardlinks":stat.st_nlink, "mode":stat.st_mode})
248
249 #        elif isMount:
250 #            is_mount_in_snapshot.append(current_snapshot)
251         else:
252             unknown_in_snapshot.append(current_snapshot)
253             
254     for i in range(0, len(dir_in_current_dir)):
255         debug_message(("scanning dir", dir_in_current_dir[i]) , 2)
256         scan_dir(dir_in_current_dir[i], search_hidden_directories)
257         
258 #        #debug_message(("data 0", data[0][0]), 2)
259 #        if len(files)
260 #        files_in_snapshot.append(data[0][0])
261 #        dir_in_snapshot.append(data[1][0])
262 #        symlinks_in_snapshot.append(data[2][0])
263 #        unknown_in_snapshot.append(data[3][0])
264     return (files_in_snapshot, dir_in_snapshot, symlinks_in_snapshot, unknown_in_snapshot)
265 ##
266 ##def print_scanned_dir_list():
267 ##    global files_in_snapshot
268 ##    global symlinks_in_snapshot
269 ##    print( "scanning dir", 2)
270 ##
271 ##
272 ##    for i in range(0, len(files_in_snapshot)):
273 ##        if files_in_snapshot[i]["num_of_hardlinks"]>1:
274 ##            print "inode",files_in_snapshot[i]["inode"],"size",files_in_snapshot[i]["size"],"path:", files_in_snapshot[i]["path"], "    num of hard links",  files_in_snapshot[i]["num_of_hardlinks"] 
275 ##
276 ##        else :
277 ##            print "inode",files_in_snapshot[i]["inode"],"size",files_in_snapshot[i]["size"],"path:", files_in_snapshot[i]["path"]
278 ###        current_open_file=open(files_in_snapshot[i], "r")
279 ###        #current_open_file.f.read(3)
280 ###        lines_in_file=current_open_file.readlines()
281 ###        #use for loop to write code into yaffs file
282 ###        print "number of line of code:", len(lines_in_file)
283 ###    print current_open_file
284 ##    for i in range(0, len(symlinks_in_snapshot)):
285 ##        print "symlinks in snapshot:", symlinks_in_snapshot[i]
286 ##    for i in range(0, len(dir_in_snapshot)):
287 ##        print "directories in snapshot:", dir_in_snapshot[i]
288 ##    for i in range(0, len(unknown_in_snapshot)):
289 ##        print "unknown objects in snapshot:", unknown_in_snapshot[i]
290 ##
291
292
293 def copy_scanned_files_into_yaffs(files_in_snapshot, dir_in_snapshot,  symlinks_in_snapshot, unknown_in_snapshot,   path, yaffs_root_dir_path="/yaffs2/", yaffs_mount_point_path="/yaffs2/" ):
294 #files_in_snapshot, dir_in_snapshot, symlinks_in_snapshot, unknown_in_snapshot
295 #########################################copy directories into yaffs so the files can be created in these directories
296     debug_message("making directories in yaffs", 1)
297     if yaffs_root_dir_path!=yaffs_mount_point_path:
298         slash_id=[]
299         debug_message("making directories to the place in yaffs where the directories will copied to", 2)
300         root_branch_path=subtract_paths(yaffs_root_dir_path, yaffs_mount_point_path)
301         for i in range(0, len(root_branch_path)):
302
303             if root_branch_path[i]=="/" and i != 0:
304                slash_id.append(i)
305         debug_message(("slash_id", slash_id),4) 
306         for i in range(0, len(slash_id)):
307             create_dir({"path":root_branch_path[:slash_id[i]], "mode": yaffs_S_IREAD | yaffs_S_IWRITE}, "/", yaffs_mount_point_path) 
308     
309     for i in range(0, len(dir_in_snapshot)):
310         create_dir(dir_in_snapshot[i], path, yaffs_root_dir_path)
311   
312     
313     
314 #########################################copy file into yaffs
315     debug_message("copying scanned files into yaffs", 1)
316     list=[]
317     inode_blacklist=[]
318
319     debug_message("files to be copyied into yaffs", 2)
320     for a in range(0, len(files_in_snapshot)):
321         debug_message(files_in_snapshot[a], 2)
322     debug_message("\n\n\n", 2)
323     for i in range(0, len(files_in_snapshot)):
324         list=[]
325         if files_in_snapshot[i]["num_of_hardlinks"]>1 and files_in_snapshot[i]["inode"] not in inode_blacklist :
326             debug_message("found a hard link", 2)
327             debug_message(("inode",files_in_snapshot[i]["inode"],"size",files_in_snapshot[i]["size"],"path:", files_in_snapshot[i]["path"], "    num of hard links",  files_in_snapshot[i]["num_of_hardlinks"] ), 2)
328             for a in range(0, len(files_in_snapshot) ) :
329                 if files_in_snapshot[a]["inode"] ==files_in_snapshot[i]["inode"]  :
330                     ##and os.path.isfile(files_in_snapshot[i])
331                     debug_message(("found this file which matches inode",files_in_snapshot[a]), 2) 
332                     list.append(files_in_snapshot[a])
333                     debug_message(("length of list", len(list)), 2)
334                 if len(list)==files_in_snapshot[i]["num_of_hardlinks"]:
335                     break
336             for a in range(0, len(list)):
337                 debug_message(list[a], 2)
338             ##add inode to blacklist. all of the indoes in the list should be the same.
339             inode_blacklist.append(list[0]["inode"])
340             ##create a file from the first hardlink.
341             create_file(list[0])
342             target_path=yaffs_root_dir_path+list[0]["path"][len(path):]
343             for i in range(1, len(list)):
344                 debug_message("creating_symlink", 2)
345                 debug_message(("target path", target_path), 2)
346                 hardlink_path=yaffs_root_dir_path+list[i]["path"][len(path):]
347                 debug_message(("hardlink path", hardlink_path), 2)
348                 output=yaffs_link(target_path,hardlink_path)
349                 debug_message(("creating hardlink:", list[i]["path"], "output:", output), 1)
350         elif files_in_snapshot[i]["inode"] not in inode_blacklist :
351             create_file(files_in_snapshot[i])
352
353
354 ############################copy symlinks into yaffs
355
356     for i in range(0, len(symlinks_in_snapshot)):
357         debug_message(("symlinks in snapshot:", symlinks_in_snapshot[i]), 2)
358         target_path=join_paths(yaffs_root_dir_path, subtract_paths(symlinks_in_snapshot[i]["target"],  path))
359         new_path=join_paths(yaffs_root_dir_path, subtract_paths(symlinks_in_snapshot[i]["path"], path))
360         output=yaffs_symlink(target_path, new_path)
361         debug_message(("created symlink",new_path , " > ", target_path, "  output:", output), 1)
362         ##yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath);
363    
364     
365     for i in range(0, len(unknown_in_snapshot)):
366         debug_message( ("unknown object in snapshot:", unknown_in_snapshot[i]), 0)
367     
368     
369 def import_into_yaffs(file_path, yaffs_path="/yaffs2/", debug_level=1,  copy_hidden_dir=True ,new_yaffs_trace_val=-1 ):
370 #    global current_debug_level
371 #    global search_hidden_directories
372 #    global yaffs_root_dir_path
373 #    global path
374     
375 #    current_debug_level=debug_level
376 #    search_hidden_directories=copy_hidden_dir
377 #    yaffs_root_dir_path=yaffs_path
378 #    path=file_path
379     old_yaffs_trace_val=yaffs_get_trace()
380     if new_yaffs_trace_val!=-1:
381         yaffs_set_trace(new_yaffs_trace_val)
382     
383     data=scan_dir(file_path, copy_hidden_dir)
384     copy_scanned_files_into_yaffs(data[0], data[1], data[2], data[3],file_path,  yaffs_path)
385     
386     yaffs_set_trace(old_yaffs_trace_val)
387     
388     
389 if __name__=="__main__":
390     yaffs_start_up()
391     yaffs_mount("/yaffs2/")
392     #yaffs_set_trace(0)
393 #    absolute_path = os.path.abspath(os.path.curdir)
394     #print "absolute path:", absolute_path
395     current_debug_level=1
396     search_hidden_directories=True
397     yaffs_root_dir_path="/yaffs2/"
398     yaffs_trace=-1
399     #print sys.argv
400     path=sys.argv[1]
401     for i in range(2, len(sys.argv)):
402         if sys.argv[i]=="-d":
403             current_debug_level=int( sys.argv[i+1])
404         if sys.argv[i]=="-ignore_hidden_directories":
405             search_hidden_directories=False
406         if sys.argv[i]=="-o":
407             yaffs_root_dir_path=sys.argv[i+1]
408         if sys.argv[i]=="-yaffs_trace":
409             yaffs_trace=int(sys.argv[i+1])
410 #
411 #
412 #    path="/home/timothy/work/yaffs/git/yaffs2"
413 #    path="/home/timothy/my_stuff/old_laptop/timothy/programming_lejos/"
414
415
416     import_into_yaffs(path, yaffs_root_dir_path, current_debug_level,  search_hidden_directories, yaffs_trace )
417 #    scan_dir(path)
418 #    copy_scanned_files_into_yaffs()
419     #print_scanned_dir_list()
420
421     print"unmounting yaffs:", yaffs_unmount("/yaffs2/")