123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185(*********************************************************************************)(* Ojs-base *)(* *)(* Copyright (C) 2014-2021 INRIA. All rights reserved. *)(* *)(* 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, version 3 of the License. *)(* *)(* 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 Library 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., 59 Temple Place, Suite 330, Boston, MA *)(* 02111-1307 USA *)(* *)(* As a special exception, you have permission to link this program *)(* with the OCaml compiler and distribute executables, as long as you *)(* follow the requirements of the GNU GPL in regard to all of the *)(* software in the executable aside from the OCaml compiler. *)(* *)(* Contact: Maxence.Guesdon@inria.fr *)(* *)(*********************************************************************************)(*c==m=[File.Find]=0.1=t==*)openUnixtypefilter=Maxdepthofint|TypeofUnix.file_kind|Follow|RegexpofStr.regexp|Atimeofinterval|Predicateof(string->bool)andinterval=Leofint|Eqofint|Geofinttypemode=|Ignore|Stderr|Failure|Customof(Unix.error*string*string->unit)(* To memorize visited inodes *)typeinode=int*intletinodest=st.st_dev,st.st_ino(* parameters driving the find *)typestatus={maxdepth:int;follow:bool;filters:(string->stats->bool)list;stat_function:string->stats;action:string->unit;handler:(error*string*string->unit)}exceptionHideofexn(* Used to hide user-level errors, so that they are no trap by the library *)lethide_exnfx=tryfxwithexn->raise(Hideexn)letreveal_exnfx=tryfxwithHideexn->raiseexnletstderr_handler(e,b,c)=prerr_endline("find: "^c^": "^(error_messagee))letignore_handler_=()letfailure_handler(e,b,c)=raise(Hide(Unix_error(e,b,c)))lethandler=functionStderr->stderr_handler|Ignore->ignore_handler|Failure->failure_handler|Customh->hide_exnh(* handlers of errors during the call. *)lettreat_unix_errorhfx=tryfxwithUnix_error(e,b,c)->h(e,b,c)letdefault_status={follow=false;maxdepth=max_int;filters=[];stat_function=lstat;action=prerr_endline;handler=handlerStderr;}letadd_filterstatusf={statuswithfilters=f::status.filters}letseconds_in_a_day=86400.exceptionFindofstringletrecparse_optionstatus=function|Maxdepthn->{statuswithmaxdepth=n}|Typek->add_filterstatus(funnamestat->stat.st_kind=k)|Follow->{statuswithfollow=true}|Regexpexp->add_filterstatus(funnamestat->Str.string_matchexpname0&&Str.match_beginning()=0&&Str.match_end()=String.lengthname)|Atimen->letmin,max=matchnwith|Eqdwhend>0->floatd*.seconds_in_a_day,float(d-1)*.seconds_in_a_day|Ledwhend>0->min_float,float(d-1)*.seconds_in_a_day|Ledwhend>0->min_float,float(d-1)*.seconds_in_a_day|Gedwhend>0->float(d)*.seconds_in_a_day,max_float|_->raise(Find"Ill_formed argument")inletnow=time()inadd_filterstatus(funnamestat->lettime=now-.stat.st_atimeinmin<=time&&time<=max)|Predicatef->add_filterstatus(funnamestat->fname)letparse_optionsoptions=List.fold_leftparse_optiondefault_statusoptions(* fonctions auxilaires *)letfilter_allfilenamefilestatfilters=List.for_all(funf->ffilenamefilestat)filtersletiter_dirfd=letdir_handle=opendirdintrywhiletruedof(readdirdir_handle)donewithEnd_of_file->closedirdir_handle|x->closedirdir_handle;raisex(* fonction principale seconde version *)letrecfind_recstatusvisiteddepthfilename=letfind()=letfilestat=ifstatus.followthenstatfilenameelselstatfilenameinletid=filestat.st_dev,filestat.st_inoiniffilter_allfilenamefilestatstatus.filtersthenstatus.actionfilename;iffilestat.st_kind=S_DIR&&depth<status.maxdepth&&(notstatus.follow||not(List.memidvisited))thenletprocess_childchild=if(child<>Filename.current_dir_name&&child<>Filename.parent_dir_name)thenletchild_name=Filename.concatfilenamechildinletvisited=ifstatus.followthenid::visitedelsevisitedinfind_recstatusvisited(depth+1)child_namein(* process_child is recursively protected from errors *)iter_dirprocess_childfilenameintreat_unix_errorstatus.handlerfind()letfind_entrystatusfilename=find_recstatus[]0filenameletfindmodefilenamesoptionsaction=letstatus={(parse_optionsoptions)withhandler=handlermode;action=hide_exnaction}inreveal_exn(List.iter(find_entrystatus))filenamesletfind_listmodefilenamesoptions=letl=ref[]infindmodefilenamesoptions(funs->l:=s::!l);List.rev!l(*/c==m=[File.Find]=0.1=t==*)