]>
git.saurik.com Git - apt.git/blob - apt-pkg/sourcelist.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: sourcelist.cc,v 1.3 2002/08/15 20:51:37 niemeyer Exp $
4 /* ######################################################################
8 ##################################################################### */
10 // Include Files /*{{{*/
13 #include <apt-pkg/sourcelist.h>
14 #include <apt-pkg/cmndline.h>
15 #include <apt-pkg/error.h>
16 #include <apt-pkg/fileutl.h>
17 #include <apt-pkg/strutl.h>
18 #include <apt-pkg/configuration.h>
19 #include <apt-pkg/metaindex.h>
20 #include <apt-pkg/indexfile.h>
21 #include <apt-pkg/tagfile.h>
22 #include <apt-pkg/pkgcache.h>
23 #include <apt-pkg/cacheiterators.h>
24 #include <apt-pkg/debindexfile.h>
25 #include <apt-pkg/debsrcrecords.h>
42 // Global list of Items supported
43 static pkgSourceList :: Type
* ItmList
[ 10 ];
44 pkgSourceList :: Type
** pkgSourceList :: Type :: GlobalList
= ItmList
;
45 unsigned long pkgSourceList :: Type :: GlobalListLen
= 0 ;
47 // Type::Type - Constructor /*{{{*/
48 // ---------------------------------------------------------------------
49 /* Link this to the global list of items*/
50 pkgSourceList :: Type :: Type ( char const * const pName
, char const * const pLabel
) : Name ( pName
), Label ( pLabel
)
52 ItmList
[ GlobalListLen
] = this ;
55 pkgSourceList :: Type ::~ Type () {}
57 // Type::GetType - Get a specific meta for a given type /*{{{*/
58 // ---------------------------------------------------------------------
60 pkgSourceList :: Type
* pkgSourceList :: Type :: GetType ( const char * Type
)
62 for ( unsigned I
= 0 ; I
!= GlobalListLen
; ++ I
)
63 if ( strcmp ( GlobalList
[ I
]-> Name
, Type
) == 0 )
68 // Type::FixupURI - Normalize the URI and check it.. /*{{{*/
69 // ---------------------------------------------------------------------
71 bool pkgSourceList :: Type :: FixupURI ( string
& URI
) const
73 if ( URI
. empty () == true )
76 if ( URI
. find ( ':' ) == string :: npos
)
79 URI
= SubstVar ( URI
, "$(ARCH)" , _config
-> Find ( "APT::Architecture" ));
81 // Make sure that the URI is / postfixed
82 if ( URI
[ URI
. size () - 1 ] != '/' )
88 bool pkgSourceList :: Type :: ParseStanza ( vector
< metaIndex
*> & List
, /*{{{*/
93 map
< string
, string
> Options
;
95 string Enabled
= Tags
. FindS ( "Enabled" );
96 if ( Enabled
. empty () == false && StringToBool ( Enabled
) == false )
99 std :: map
< char const * const , std :: pair
< char const * const , bool > > mapping
;
100 #define APT_PLUSMINUS(X, Y) \
101 mapping.insert(std::make_pair(X, std::make_pair(Y, true))); \
102 mapping.insert(std::make_pair(X "-Add" , std::make_pair(Y "+" , true))); \
103 mapping.insert(std::make_pair(X "-Remove" , std::make_pair(Y "-" , true)))
104 APT_PLUSMINUS ( "Architectures" , "arch" );
105 APT_PLUSMINUS ( "Languages" , "lang" );
106 APT_PLUSMINUS ( "Targets" , "target" );
108 mapping
. insert ( std :: make_pair ( "Trusted" , std :: make_pair ( "trusted" , false )));
109 mapping
. insert ( std :: make_pair ( "Check-Valid-Until" , std :: make_pair ( "check-valid-until" , false )));
110 mapping
. insert ( std :: make_pair ( "Valid-Until-Min" , std :: make_pair ( "valid-until-min" , false )));
111 mapping
. insert ( std :: make_pair ( "Valid-Until-Max" , std :: make_pair ( "valid-until-max" , false )));
112 mapping
. insert ( std :: make_pair ( "Signed-By" , std :: make_pair ( "signed-by" , false )));
113 mapping
. insert ( std :: make_pair ( "PDiffs" , std :: make_pair ( "pdiffs" , false )));
114 mapping
. insert ( std :: make_pair ( "By-Hash" , std :: make_pair ( "by-hash" , false )));
116 for ( std :: map
< char const * const , std :: pair
< char const * const , bool > >:: const_iterator m
= mapping
. begin (); m
!= mapping
. end (); ++ m
)
117 if ( Tags
. Exists ( m
-> first
))
119 std :: string option
= Tags
. FindS ( m
-> first
);
120 // for deb822 the " " is the delimiter, but the backend expects ","
121 if ( m
-> second
. second
== true )
122 std :: replace ( option
. begin (), option
. end (), ' ' , ',' );
123 Options
[ m
-> second
. first
] = option
;
128 strprintf ( entry
, " %s : %i " , Fd
. Name (). c_str (), i
);
129 Options
[ "sourceslist-entry" ] = entry
;
132 // now create one item per suite/section
133 string Suite
= Tags
. FindS ( "Suites" );
134 Suite
= SubstVar ( Suite
, "$(ARCH)" , _config
-> Find ( "APT::Architecture" ));
135 string
const Component
= Tags
. FindS ( "Components" );
136 string
const URIS
= Tags
. FindS ( "URIs" );
138 std :: vector
< std :: string
> const list_uris
= VectorizeString ( URIS
, ' ' );
139 std :: vector
< std :: string
> const list_suite
= VectorizeString ( Suite
, ' ' );
140 std :: vector
< std :: string
> const list_comp
= VectorizeString ( Component
, ' ' );
142 if ( list_uris
. empty ())
143 // TRANSLATOR: %u is a line number, the first %s is a filename of a file with the extension "second %s" and the third %s is a unique identifier for bugreports
144 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), i
, "sources" , Fd
. Name (). c_str (), "URI" );
146 for ( std :: vector
< std :: string
>:: const_iterator U
= list_uris
. begin ();
147 U
!= list_uris
. end (); ++ U
)
149 std :: string URI
= * U
;
150 if ( U
-> empty () || FixupURI ( URI
) == false )
151 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), i
, "sources" , Fd
. Name (). c_str (), "URI parse" );
153 if ( list_suite
. empty ())
154 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), i
, "sources" , Fd
. Name (). c_str (), "Suite" );
156 for ( std :: vector
< std :: string
>:: const_iterator S
= list_suite
. begin ();
157 S
!= list_suite
. end (); ++ S
)
159 if ( S
-> empty () == false && (* S
)[ S
-> size () - 1 ] == '/' )
161 if ( list_comp
. empty () == false )
162 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), i
, "sources" , Fd
. Name (). c_str (), "absolute Suite Component" );
163 if ( CreateItem ( List
, URI
, * S
, "" , Options
) == false )
168 if ( list_comp
. empty ())
169 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), i
, "sources" , Fd
. Name (). c_str (), "Component" );
171 for ( std :: vector
< std :: string
>:: const_iterator C
= list_comp
. begin ();
172 C
!= list_comp
. end (); ++ C
)
174 if ( CreateItem ( List
, URI
, * S
, * C
, Options
) == false )
185 // Type::ParseLine - Parse a single line /*{{{*/
186 // ---------------------------------------------------------------------
187 /* This is a generic one that is the 'usual' format for sources.list
188 Weird types may override this. */
189 bool pkgSourceList :: Type :: ParseLine ( vector
< metaIndex
*> & List
,
191 unsigned int const CurLine
,
192 string
const & File
) const
194 for (; Buffer
!= 0 && isspace (* Buffer
); ++ Buffer
); // Skip whitespaces
196 // Parse option field if it exists
197 // e.g.: [ option1=value1 option2=value2 ]
198 map
< string
, string
> Options
;
201 strprintf ( entry
, " %s : %i " , File
. c_str (), CurLine
);
202 Options
[ "sourceslist-entry" ] = entry
;
204 if ( Buffer
!= 0 && Buffer
[ 0 ] == '[' )
206 ++ Buffer
; // ignore the [
207 for (; Buffer
!= 0 && isspace (* Buffer
); ++ Buffer
); // Skip whitespaces
208 while (* Buffer
!= ']' )
210 // get one option, e.g. option1=value1
212 if ( ParseQuoteWord ( Buffer
, option
) == false )
213 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "[option] unparseable" );
215 if ( option
. length () < 3 )
216 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "[option] too short" );
218 // accept options even if the last has no space before the ]-end marker
219 if ( option
. at ( option
. length ()- 1 ) == ']' )
221 for (; * Buffer
!= ']' ; -- Buffer
);
222 option
. resize ( option
. length ()- 1 );
225 size_t const needle
= option
. find ( '=' );
226 if ( needle
== string :: npos
)
227 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "[option] not assignment" );
229 string
const key
= string ( option
, 0 , needle
);
230 string
const value
= string ( option
, needle
+ 1 , option
. length ());
232 if ( key
. empty () == true )
233 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "[option] no key" );
235 if ( value
. empty () == true )
236 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "[option] no value" );
238 Options
[ key
] = value
;
240 ++ Buffer
; // ignore the ]
241 for (; Buffer
!= 0 && isspace (* Buffer
); ++ Buffer
); // Skip whitespaces
248 if ( ParseQuoteWord ( Buffer
, URI
) == false )
249 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "URI" );
250 if ( ParseQuoteWord ( Buffer
, Dist
) == false )
251 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "Suite" );
253 if ( FixupURI ( URI
) == false )
254 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "URI parse" );
256 // Check for an absolute dists specification.
257 if ( Dist
. empty () == false && Dist
[ Dist
. size () - 1 ] == '/' )
259 if ( ParseQuoteWord ( Buffer
, Section
) == true )
260 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "absolute Suite Component" );
261 Dist
= SubstVar ( Dist
, "$(ARCH)" , _config
-> Find ( "APT::Architecture" ));
262 return CreateItem ( List
, URI
, Dist
, Section
, Options
);
265 // Grab the rest of the dists
266 if ( ParseQuoteWord ( Buffer
, Section
) == false )
267 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "Component" );
271 if ( CreateItem ( List
, URI
, Dist
, Section
, Options
) == false )
274 while ( ParseQuoteWord ( Buffer
, Section
) == true );
279 // SourceList::pkgSourceList - Constructors /*{{{*/
280 // ---------------------------------------------------------------------
282 pkgSourceList :: pkgSourceList () : d ( NULL
)
286 // SourceList::~pkgSourceList - Destructor /*{{{*/
287 // ---------------------------------------------------------------------
289 pkgSourceList ::~ pkgSourceList ()
291 for ( const_iterator I
= SrcList
. begin (); I
!= SrcList
. end (); ++ I
)
294 for ( auto F
= VolatileFiles
. begin (); F
!= VolatileFiles
. end (); ++ F
)
296 VolatileFiles
. clear ();
299 // SourceList::ReadMainList - Read the main source list from etc /*{{{*/
300 // ---------------------------------------------------------------------
302 bool pkgSourceList :: ReadMainList ()
304 // CNC:2003-03-03 - Multiple sources list support.
313 // CNC:2003-11-28 - Entries in sources.list have priority over
314 // entries in sources.list.d.
315 string Main
= _config
-> FindFile ( "Dir::Etc::sourcelist" , "/dev/null" );
316 string Parts
= _config
-> FindDir ( "Dir::Etc::sourceparts" , "/dev/null" );
318 if ( RealFileExists ( Main
) == true )
319 Res
&= ReadAppend ( Main
);
320 else if ( DirectoryExists ( Parts
) == false && APT :: String :: Endswith ( Parts
, "/dev/null" ) == false )
321 // Only warn if there are no sources.list.d.
322 _error
-> WarningE ( "DirectoryExists" , _ ( "Unable to read %s " ), Parts
. c_str ());
324 if ( DirectoryExists ( Parts
) == true )
325 Res
&= ReadSourceDir ( Parts
);
326 else if ( Main
. empty () == false && RealFileExists ( Main
) == false &&
327 APT :: String :: Endswith ( Parts
, "/dev/null" ) == false )
328 // Only warn if there is no sources.list file.
329 _error
-> WarningE ( "RealFileExists" , _ ( "Unable to read %s " ), Main
. c_str ());
334 // SourceList::Reset - Clear the sourcelist contents /*{{{*/
335 // ---------------------------------------------------------------------
337 void pkgSourceList :: Reset ()
339 for ( const_iterator I
= SrcList
. begin (); I
!= SrcList
. end (); ++ I
)
344 // SourceList::Read - Parse the sourcelist file /*{{{*/
345 // ---------------------------------------------------------------------
347 bool pkgSourceList :: Read ( string
const & File
)
350 return ReadAppend ( File
);
353 // SourceList::ReadAppend - Parse a sourcelist file /*{{{*/
354 // ---------------------------------------------------------------------
356 bool pkgSourceList :: ReadAppend ( string
const & File
)
358 if ( flExtension ( File
) == "sources" )
359 return ParseFileDeb822 ( File
);
361 return ParseFileOldStyle ( File
);
364 // SourceList::ReadFileOldStyle - Read Traditional style sources.list /*{{{*/
365 // ---------------------------------------------------------------------
367 bool pkgSourceList :: ParseFileOldStyle ( std :: string
const & File
)
369 // Open the stream for reading
370 ifstream
F ( File
. c_str (), ios :: in
/*| ios::nocreate*/ );
371 if ( F
. fail () == true )
372 return _error
-> Errno ( "ifstream::ifstream" , _ ( "Opening %s " ), File
. c_str ());
375 for ( unsigned int CurLine
= 1 ; std :: getline ( F
, Buffer
); ++ CurLine
)
379 while (( curpos
= Buffer
. find ( '#' , curpos
)) != std :: string :: npos
)
381 size_t const openbrackets
= std :: count ( Buffer
. begin (), Buffer
. begin () + curpos
, '[' );
382 size_t const closedbrackets
= std :: count ( Buffer
. begin (), Buffer
. begin () + curpos
, ']' );
383 if ( openbrackets
> closedbrackets
)
385 // a # in an option, unlikely, but oh well, it was supported so stick to it
389 Buffer
. erase ( curpos
);
392 // remove spaces before/after
393 curpos
= Buffer
. find_first_not_of ( " \t\r " );
395 Buffer
. erase ( 0 , curpos
);
396 curpos
= Buffer
. find_last_not_of ( " \t\r " );
397 if ( curpos
!= std :: string :: npos
)
398 Buffer
. erase ( curpos
+ 1 );
404 std :: string
const LineType
= Buffer
. substr ( 0 , Buffer
. find_first_of ( " \t\v " ));
405 if ( LineType
. empty () || LineType
== Buffer
)
406 return _error
-> Error ( _ ( "Malformed line %u in source list %s (type)" ), CurLine
, File
. c_str ());
408 Type
* Parse
= Type :: GetType ( LineType
. c_str ());
410 return _error
-> Error ( _ ( "Type ' %s ' is not known on line %u in source list %s " ), LineType
. c_str (), CurLine
, File
. c_str ());
412 if ( Parse
-> ParseLine ( SrcList
, Buffer
. c_str () + LineType
. length (), CurLine
, File
) == false )
418 // SourceList::ParseFileDeb822 - Parse deb822 style sources.list /*{{{*/
419 // ---------------------------------------------------------------------
420 /* Returns: the number of stanzas parsed*/
421 bool pkgSourceList :: ParseFileDeb822 ( string
const & File
)
425 // see if we can read the file
426 FileFd
Fd ( File
, FileFd :: ReadOnly
);
427 pkgTagFile
Sources (& Fd
, pkgTagFile :: SUPPORT_COMMENTS
);
428 if ( Fd
. IsOpen () == false || Fd
. Failed ())
429 return _error
-> Error ( _ ( "Malformed stanza %u in source list %s (type)" ), i
, File
. c_str ());
433 while ( Sources
. Step ( Tags
) == true )
435 if ( Tags
. Exists ( "Types" ) == false )
436 return _error
-> Error ( _ ( "Malformed stanza %u in source list %s (type)" ), i
, File
. c_str ());
438 string
const types
= Tags
. FindS ( "Types" );
439 std :: vector
< std :: string
> const list_types
= VectorizeString ( types
, ' ' );
440 for ( std :: vector
< std :: string
>:: const_iterator I
= list_types
. begin ();
441 I
!= list_types
. end (); ++ I
)
443 Type
* Parse
= Type :: GetType ((* I
). c_str ());
446 _error
-> Error ( _ ( "Type ' %s ' is not known on stanza %u in source list %s " ), (* I
). c_str (), i
, Fd
. Name (). c_str ());
450 if (! Parse
-> ParseStanza ( SrcList
, Tags
, i
, Fd
))
459 // SourceList::FindIndex - Get the index associated with a file /*{{{*/
460 static bool FindInIndexFileContainer ( std :: vector
< pkgIndexFile
*> const & Cont
, pkgCache :: PkgFileIterator
const & File
, pkgIndexFile
*& Found
)
462 auto const J
= std :: find_if ( Cont
. begin (), Cont
. end (), [& File
]( pkgIndexFile
const * const J
) {
463 return J
-> FindInCache (* File
. Cache ()) == File
;
472 bool pkgSourceList :: FindIndex ( pkgCache :: PkgFileIterator File
,
473 pkgIndexFile
*& Found
) const
475 for ( const_iterator I
= SrcList
. begin (); I
!= SrcList
. end (); ++ I
)
476 if ( FindInIndexFileContainer (*(* I
)-> GetIndexFiles (), File
, Found
))
479 return FindInIndexFileContainer ( VolatileFiles
, File
, Found
);
482 // SourceList::GetIndexes - Load the index files into the downloader /*{{{*/
483 // ---------------------------------------------------------------------
485 bool pkgSourceList :: GetIndexes ( pkgAcquire
* Owner
, bool GetAll
) const
487 for ( const_iterator I
= SrcList
. begin (); I
!= SrcList
. end (); ++ I
)
488 if ((* I
)-> GetIndexes ( Owner
, GetAll
) == false )
493 // CNC:2003-03-03 - By Anton V. Denisov <avd@altlinux.org>.
494 // SourceList::ReadSourceDir - Read a directory with sources files
495 // Based on ReadConfigDir() /*{{{*/
496 // ---------------------------------------------------------------------
498 bool pkgSourceList :: ReadSourceDir ( string
const & Dir
)
500 std :: vector
< std :: string
> ext
;
501 ext
. push_back ( "list" );
502 ext
. push_back ( "sources" );
503 std :: vector
< std :: string
> const List
= GetListOfFilesInDir ( Dir
, ext
, true );
506 for ( vector
< string
>:: const_iterator I
= List
. begin (); I
!= List
. end (); ++ I
)
507 if ( ReadAppend (* I
) == false )
513 // GetLastModified() /*{{{*/
514 // ---------------------------------------------------------------------
516 time_t pkgSourceList :: GetLastModifiedTime ()
520 string Main
= _config
-> FindFile ( "Dir::Etc::sourcelist" );
521 string Parts
= _config
-> FindDir ( "Dir::Etc::sourceparts" );
524 if ( DirectoryExists ( Parts
) == true )
525 List
= GetListOfFilesInDir ( Parts
, "list" , true );
527 // calculate the time
528 std :: vector
< time_t > modtimes
;
529 modtimes
. reserve ( 1 + List
. size ());
530 modtimes
. push_back ( GetModificationTime ( Main
));
531 std :: transform ( List
. begin (), List
. end (), std :: back_inserter ( modtimes
), GetModificationTime
);
532 auto const maxmtime
= std :: max_element ( modtimes
. begin (), modtimes
. end ());
536 std :: vector
< pkgIndexFile
*> pkgSourceList :: GetVolatileFiles () const /*{{{*/
538 return VolatileFiles
;
541 void pkgSourceList :: AddVolatileFile ( pkgIndexFile
* const File
) /*{{{*/
544 VolatileFiles
. push_back ( File
);
547 bool pkgSourceList :: AddVolatileFile ( std :: string
const & File
, std :: vector
< std :: string
> * const VolatileCmdL
) /*{{{*/
549 // Note: FileExists matches directories and links, too!
550 if ( File
. empty () || FileExists ( File
) == false )
553 std :: string
const ext
= flExtension ( File
);
555 AddVolatileFile ( new debDebPkgFileIndex ( File
));
556 else if ( ext
== "dsc" )
557 AddVolatileFile ( new debDscFileIndex ( File
));
558 else if ( FileExists ( flCombine ( File
, "debian/control" )))
559 AddVolatileFile ( new debDscFileIndex ( flCombine ( File
, "debian/control" )));
560 else if ( ext
== "changes" )
562 debDscRecordParser
changes ( File
, nullptr );
563 std :: vector
< pkgSrcRecords :: File2
> fileslst
;
564 if ( changes
. Files2 ( fileslst
) == false || fileslst
. empty ())
566 auto const basedir
= flNotFile ( File
);
567 for ( auto && file
: fileslst
)
569 auto const name
= flCombine ( basedir
, file
. Path
);
570 AddVolatileFile ( name
, VolatileCmdL
);
571 if ( file
. Hashes
. VerifyFile ( name
) == false )
572 return _error
-> Error ( "The file %s does not match with the hashes in the %s file!" , name
. c_str (), File
. c_str ());
579 if ( VolatileCmdL
!= nullptr )
580 VolatileCmdL
-> push_back ( File
);
583 bool pkgSourceList :: AddVolatileFile ( std :: string
const & File
)
585 return AddVolatileFile ( File
, nullptr );
588 void pkgSourceList :: AddVolatileFiles ( CommandLine
& CmdL
, std :: vector
< std :: string
> * const VolatileCmdL
) /*{{{*/
590 std :: remove_if ( CmdL
. FileList
+ 1 , CmdL
. FileList
+ 1 + CmdL
. FileSize (), [&]( char const * const I
) {
591 if ( I
!= nullptr && ( I
[ 0 ] == '/' || ( I
[ 0 ] == '.' && (( I
[ 1 ] == '.' && I
[ 2 ] == '/' ) || I
[ 1 ] == '/' ))))
593 if ( AddVolatileFile ( I
, VolatileCmdL
))
596 _error
-> Error ( _ ( "Unsupported file %s given on commandline" ), I
);
602 void pkgSourceList :: AddVolatileFiles ( CommandLine
& CmdL
, std :: vector
< const char *> * const VolatileCmdL
)
604 std :: remove_if ( CmdL
. FileList
+ 1 , CmdL
. FileList
+ 1 + CmdL
. FileSize (), [&]( char const * const I
) {
605 if ( I
!= nullptr && ( I
[ 0 ] == '/' || ( I
[ 0 ] == '.' && (( I
[ 1 ] == '.' && I
[ 2 ] == '/' ) || I
[ 1 ] == '/' ))))
607 if ( AddVolatileFile ( I
))
609 if ( VolatileCmdL
!= nullptr )
610 VolatileCmdL
-> push_back ( I
);
613 _error
-> Error ( _ ( "Unsupported file %s given on commandline" ), I
);