]>
git.saurik.com Git - apt.git/blob - apt-pkg/sourcelist.cc
0502f0e1dca48ac4254ccdb2e2d4b6365901c517
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/error.h>
15 #include <apt-pkg/fileutl.h>
16 #include <apt-pkg/strutl.h>
17 #include <apt-pkg/configuration.h>
18 #include <apt-pkg/metaindex.h>
19 #include <apt-pkg/indexfile.h>
20 #include <apt-pkg/tagfile.h>
21 #include <apt-pkg/pkgcache.h>
22 #include <apt-pkg/cacheiterators.h>
39 // Global list of Items supported
40 static pkgSourceList :: Type
* ItmList
[ 10 ];
41 pkgSourceList :: Type
** pkgSourceList :: Type :: GlobalList
= ItmList
;
42 unsigned long pkgSourceList :: Type :: GlobalListLen
= 0 ;
44 // Type::Type - Constructor /*{{{*/
45 // ---------------------------------------------------------------------
46 /* Link this to the global list of items*/
47 pkgSourceList :: Type :: Type ( char const * const pName
, char const * const pLabel
) : Name ( pName
), Label ( pLabel
)
49 ItmList
[ GlobalListLen
] = this ;
52 pkgSourceList :: Type ::~ Type () {}
54 // Type::GetType - Get a specific meta for a given type /*{{{*/
55 // ---------------------------------------------------------------------
57 pkgSourceList :: Type
* pkgSourceList :: Type :: GetType ( const char * Type
)
59 for ( unsigned I
= 0 ; I
!= GlobalListLen
; ++ I
)
60 if ( strcmp ( GlobalList
[ I
]-> Name
, Type
) == 0 )
65 // Type::FixupURI - Normalize the URI and check it.. /*{{{*/
66 // ---------------------------------------------------------------------
68 bool pkgSourceList :: Type :: FixupURI ( string
& URI
) const
70 if ( URI
. empty () == true )
73 if ( URI
. find ( ':' ) == string :: npos
)
76 URI
= SubstVar ( URI
, "$(ARCH)" , _config
-> Find ( "APT::Architecture" ));
78 // Make sure that the URI is / postfixed
79 if ( URI
[ URI
. size () - 1 ] != '/' )
85 bool pkgSourceList :: Type :: ParseStanza ( vector
< metaIndex
*> & List
, /*{{{*/
90 map
< string
, string
> Options
;
92 string Enabled
= Tags
. FindS ( "Enabled" );
93 if ( Enabled
. empty () == false && StringToBool ( Enabled
) == false )
96 std :: map
< char const * const , char const * const > mapping
;
97 #define APT_PLUSMINUS(X, Y) \
98 mapping.insert(std::make_pair(X, Y)); \
99 mapping.insert(std::make_pair(X "Add" , Y "+" )); \
100 mapping.insert(std::make_pair(X "Remove" , Y "-" ))
101 APT_PLUSMINUS ( "Architectures" , "arch" );
102 APT_PLUSMINUS ( "Languages" , "lang" );
103 APT_PLUSMINUS ( "Targets" , "target" );
105 mapping
. insert ( std :: make_pair ( "Trusted" , "trusted" ));
107 for ( std :: map
< char const * const , char const * const >:: const_iterator m
= mapping
. begin (); m
!= mapping
. end (); ++ m
)
108 if ( Tags
. Exists ( m
-> first
))
110 // for deb822 the " " is the delimiter, but the backend expects ","
111 std :: string option
= Tags
. FindS ( m
-> first
);
112 std :: replace ( option
. begin (), option
. end (), ' ' , ',' );
113 Options
[ m
-> second
] = option
;
116 // now create one item per suite/section
117 string Suite
= Tags
. FindS ( "Suites" );
118 Suite
= SubstVar ( Suite
, "$(ARCH)" , _config
-> Find ( "APT::Architecture" ));
119 string
const Component
= Tags
. FindS ( "Components" );
120 string
const URIS
= Tags
. FindS ( "URIs" );
122 std :: vector
< std :: string
> const list_uris
= VectorizeString ( URIS
, ' ' );
123 std :: vector
< std :: string
> const list_suite
= VectorizeString ( Suite
, ' ' );
124 std :: vector
< std :: string
> const list_comp
= VectorizeString ( Component
, ' ' );
126 if ( list_uris
. empty ())
127 // 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
128 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), i
, "sources" , Fd
. Name (). c_str (), "URI" );
130 for ( std :: vector
< std :: string
>:: const_iterator U
= list_uris
. begin ();
131 U
!= list_uris
. end (); ++ U
)
133 std :: string URI
= * U
;
134 if ( U
-> empty () || FixupURI ( URI
) == false )
135 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), i
, "sources" , Fd
. Name (). c_str (), "URI parse" );
137 if ( list_suite
. empty ())
138 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), i
, "sources" , Fd
. Name (). c_str (), "Suite" );
140 for ( std :: vector
< std :: string
>:: const_iterator S
= list_suite
. begin ();
141 S
!= list_suite
. end (); ++ S
)
143 if ( S
-> empty () == false && (* S
)[ S
-> size () - 1 ] == '/' )
145 if ( list_comp
. empty () == false )
146 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), i
, "sources" , Fd
. Name (). c_str (), "absolute Suite Component" );
147 if ( CreateItem ( List
, URI
, * S
, "" , Options
) == false )
152 if ( list_comp
. empty ())
153 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), i
, "sources" , Fd
. Name (). c_str (), "Component" );
155 for ( std :: vector
< std :: string
>:: const_iterator C
= list_comp
. begin ();
156 C
!= list_comp
. end (); ++ C
)
158 if ( CreateItem ( List
, URI
, * S
, * C
, Options
) == false )
169 // Type::ParseLine - Parse a single line /*{{{*/
170 // ---------------------------------------------------------------------
171 /* This is a generic one that is the 'usual' format for sources.list
172 Weird types may override this. */
173 bool pkgSourceList :: Type :: ParseLine ( vector
< metaIndex
*> & List
,
175 unsigned int const CurLine
,
176 string
const & File
) const
178 for (; Buffer
!= 0 && isspace (* Buffer
); ++ Buffer
); // Skip whitespaces
180 // Parse option field if it exists
181 // e.g.: [ option1=value1 option2=value2 ]
182 map
< string
, string
> Options
;
183 if ( Buffer
!= 0 && Buffer
[ 0 ] == '[' )
185 ++ Buffer
; // ignore the [
186 for (; Buffer
!= 0 && isspace (* Buffer
); ++ Buffer
); // Skip whitespaces
187 while (* Buffer
!= ']' )
189 // get one option, e.g. option1=value1
191 if ( ParseQuoteWord ( Buffer
, option
) == false )
192 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "[option] unparseable" );
194 if ( option
. length () < 3 )
195 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "[option] too short" );
197 // accept options even if the last has no space before the ]-end marker
198 if ( option
. at ( option
. length ()- 1 ) == ']' )
200 for (; * Buffer
!= ']' ; -- Buffer
);
201 option
. resize ( option
. length ()- 1 );
204 size_t const needle
= option
. find ( '=' );
205 if ( needle
== string :: npos
)
206 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "[option] not assignment" );
208 string
const key
= string ( option
, 0 , needle
);
209 string
const value
= string ( option
, needle
+ 1 , option
. length ());
211 if ( key
. empty () == true )
212 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "[option] no key" );
214 if ( value
. empty () == true )
215 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "[option] no value" );
217 Options
[ key
] = value
;
219 ++ Buffer
; // ignore the ]
220 for (; Buffer
!= 0 && isspace (* Buffer
); ++ Buffer
); // Skip whitespaces
227 if ( ParseQuoteWord ( Buffer
, URI
) == false )
228 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "URI" );
229 if ( ParseQuoteWord ( Buffer
, Dist
) == false )
230 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "Suite" );
232 if ( FixupURI ( URI
) == false )
233 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "URI parse" );
235 // Check for an absolute dists specification.
236 if ( Dist
. empty () == false && Dist
[ Dist
. size () - 1 ] == '/' )
238 if ( ParseQuoteWord ( Buffer
, Section
) == true )
239 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "absolute Suite Component" );
240 Dist
= SubstVar ( Dist
, "$(ARCH)" , _config
-> Find ( "APT::Architecture" ));
241 return CreateItem ( List
, URI
, Dist
, Section
, Options
);
244 // Grab the rest of the dists
245 if ( ParseQuoteWord ( Buffer
, Section
) == false )
246 return _error
-> Error ( _ ( "Malformed entry %u in %s file %s ( %s )" ), CurLine
, "list" , File
. c_str (), "Component" );
250 if ( CreateItem ( List
, URI
, Dist
, Section
, Options
) == false )
253 while ( ParseQuoteWord ( Buffer
, Section
) == true );
258 // SourceList::pkgSourceList - Constructors /*{{{*/
259 // ---------------------------------------------------------------------
261 pkgSourceList :: pkgSourceList () : d ( NULL
)
265 // SourceList::~pkgSourceList - Destructor /*{{{*/
266 // ---------------------------------------------------------------------
268 pkgSourceList ::~ pkgSourceList ()
270 for ( const_iterator I
= SrcList
. begin (); I
!= SrcList
. end (); ++ I
)
274 // SourceList::ReadMainList - Read the main source list from etc /*{{{*/
275 // ---------------------------------------------------------------------
277 bool pkgSourceList :: ReadMainList ()
279 // CNC:2003-03-03 - Multiple sources list support.
288 // CNC:2003-11-28 - Entries in sources.list have priority over
289 // entries in sources.list.d.
290 string Main
= _config
-> FindFile ( "Dir::Etc::sourcelist" );
291 string Parts
= _config
-> FindDir ( "Dir::Etc::sourceparts" );
293 if ( RealFileExists ( Main
) == true )
294 Res
&= ReadAppend ( Main
);
295 else if ( DirectoryExists ( Parts
) == false )
296 // Only warn if there are no sources.list.d.
297 _error
-> WarningE ( "DirectoryExists" , _ ( "Unable to read %s " ), Parts
. c_str ());
299 if ( DirectoryExists ( Parts
) == true )
300 Res
&= ReadSourceDir ( Parts
);
301 else if ( RealFileExists ( Main
) == false )
302 // Only warn if there is no sources.list file.
303 _error
-> WarningE ( "RealFileExists" , _ ( "Unable to read %s " ), Main
. c_str ());
308 // SourceList::Reset - Clear the sourcelist contents /*{{{*/
309 // ---------------------------------------------------------------------
311 void pkgSourceList :: Reset ()
313 for ( const_iterator I
= SrcList
. begin (); I
!= SrcList
. end (); ++ I
)
315 SrcList
. erase ( SrcList
. begin (), SrcList
. end ());
318 // SourceList::Read - Parse the sourcelist file /*{{{*/
319 // ---------------------------------------------------------------------
321 bool pkgSourceList :: Read ( string
const & File
)
324 return ReadAppend ( File
);
327 // SourceList::ReadAppend - Parse a sourcelist file /*{{{*/
328 // ---------------------------------------------------------------------
330 bool pkgSourceList :: ReadAppend ( string
const & File
)
332 if ( flExtension ( File
) == "sources" )
333 return ParseFileDeb822 ( File
);
335 return ParseFileOldStyle ( File
);
338 // SourceList::ReadFileOldStyle - Read Traditional style sources.list /*{{{*/
339 // ---------------------------------------------------------------------
341 bool pkgSourceList :: ParseFileOldStyle ( std :: string
const & File
)
343 // Open the stream for reading
344 ifstream
F ( File
. c_str (), ios :: in
/*| ios::nocreate*/ );
345 if ( F
. fail () == true )
346 return _error
-> Errno ( "ifstream::ifstream" , _ ( "Opening %s " ), File
. c_str ());
349 for ( unsigned int CurLine
= 1 ; std :: getline ( F
, Buffer
); ++ CurLine
)
353 while (( curpos
= Buffer
. find ( '#' , curpos
)) != std :: string :: npos
)
355 size_t const openbrackets
= std :: count ( Buffer
. begin (), Buffer
. begin () + curpos
, '[' );
356 size_t const closedbrackets
= std :: count ( Buffer
. begin (), Buffer
. begin () + curpos
, ']' );
357 if ( openbrackets
> closedbrackets
)
359 // a # in an option, unlikely, but oh well, it was supported so stick to it
363 Buffer
. erase ( curpos
);
366 // remove spaces before/after
367 curpos
= Buffer
. find_first_not_of ( " \t\r " );
369 Buffer
. erase ( 0 , curpos
);
370 curpos
= Buffer
. find_last_not_of ( " \t\r " );
371 if ( curpos
!= std :: string :: npos
)
372 Buffer
. erase ( curpos
+ 1 );
378 std :: string
const LineType
= Buffer
. substr ( 0 , Buffer
. find ( ' ' ));
379 if ( LineType
. empty () || LineType
== Buffer
)
380 return _error
-> Error ( _ ( "Malformed line %u in source list %s (type)" ), CurLine
, File
. c_str ());
382 Type
* Parse
= Type :: GetType ( LineType
. c_str ());
384 return _error
-> Error ( _ ( "Type ' %s ' is not known on line %u in source list %s " ), LineType
. c_str (), CurLine
, File
. c_str ());
386 if ( Parse
-> ParseLine ( SrcList
, Buffer
. c_str () + LineType
. length (), CurLine
, File
) == false )
392 // SourceList::ParseFileDeb822 - Parse deb822 style sources.list /*{{{*/
393 // ---------------------------------------------------------------------
394 /* Returns: the number of stanzas parsed*/
395 bool pkgSourceList :: ParseFileDeb822 ( string
const & File
)
397 pkgUserTagSection Tags
;
400 // see if we can read the file
401 FileFd
Fd ( File
, FileFd :: ReadOnly
);
402 pkgTagFile
Sources (& Fd
);
403 if ( _error
-> PendingError () == true )
404 return _error
-> Error ( _ ( "Malformed stanza %u in source list %s (type)" ), i
, File
. c_str ());
407 while ( Sources
. Step ( Tags
) == true )
409 if ( Tags
. Exists ( "Types" ) == false )
410 return _error
-> Error ( _ ( "Malformed stanza %u in source list %s (type)" ), i
, File
. c_str ());
412 string
const types
= Tags
. FindS ( "Types" );
413 std :: vector
< std :: string
> const list_types
= VectorizeString ( types
, ' ' );
414 for ( std :: vector
< std :: string
>:: const_iterator I
= list_types
. begin ();
415 I
!= list_types
. end (); ++ I
)
417 Type
* Parse
= Type :: GetType ((* I
). c_str ());
420 _error
-> Error ( _ ( "Type ' %s ' is not known on stanza %u in source list %s " ), (* I
). c_str (), i
, Fd
. Name (). c_str ());
424 if (! Parse
-> ParseStanza ( SrcList
, Tags
, i
, Fd
))
433 // SourceList::FindIndex - Get the index associated with a file /*{{{*/
434 // ---------------------------------------------------------------------
436 bool pkgSourceList :: FindIndex ( pkgCache :: PkgFileIterator File
,
437 pkgIndexFile
*& Found
) const
439 for ( const_iterator I
= SrcList
. begin (); I
!= SrcList
. end (); ++ I
)
441 vector
< pkgIndexFile
*> * Indexes
= (* I
)-> GetIndexFiles ();
442 for ( vector
< pkgIndexFile
*>:: const_iterator J
= Indexes
-> begin ();
443 J
!= Indexes
-> end (); ++ J
)
445 if ((* J
)-> FindInCache (* File
. Cache ()) == File
)
456 // SourceList::GetIndexes - Load the index files into the downloader /*{{{*/
457 // ---------------------------------------------------------------------
459 bool pkgSourceList :: GetIndexes ( pkgAcquire
* Owner
, bool GetAll
) const
461 for ( const_iterator I
= SrcList
. begin (); I
!= SrcList
. end (); ++ I
)
462 if ((* I
)-> GetIndexes ( Owner
, GetAll
) == false )
467 // CNC:2003-03-03 - By Anton V. Denisov <avd@altlinux.org>.
468 // SourceList::ReadSourceDir - Read a directory with sources files
469 // Based on ReadConfigDir() /*{{{*/
470 // ---------------------------------------------------------------------
472 bool pkgSourceList :: ReadSourceDir ( string
const & Dir
)
474 std :: vector
< std :: string
> ext
;
475 ext
. push_back ( "list" );
476 ext
. push_back ( "sources" );
477 std :: vector
< std :: string
> const List
= GetListOfFilesInDir ( Dir
, ext
, true );
480 for ( vector
< string
>:: const_iterator I
= List
. begin (); I
!= List
. end (); ++ I
)
481 if ( ReadAppend (* I
) == false )
487 // GetLastModified() /*{{{*/
488 // ---------------------------------------------------------------------
490 time_t pkgSourceList :: GetLastModifiedTime ()
494 string Main
= _config
-> FindFile ( "Dir::Etc::sourcelist" );
495 string Parts
= _config
-> FindDir ( "Dir::Etc::sourceparts" );
498 if ( DirectoryExists ( Parts
) == true )
499 List
= GetListOfFilesInDir ( Parts
, "list" , true );
501 // calculate the time
502 time_t mtime_sources
= GetModificationTime ( Main
);
503 for ( vector
< string
>:: const_iterator I
= List
. begin (); I
!= List
. end (); ++ I
)
504 mtime_sources
= std :: max ( mtime_sources
, GetModificationTime (* I
));
506 return mtime_sources
;