~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/xpinstall/src/ScheduledTasks.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/*
 
3
 * The contents of this file are subject to the Netscape Public
 
4
 * License Version 1.1 (the "License"); you may not use this file
 
5
 * except in compliance with the License. You may obtain a copy of
 
6
 * the License at http://www.mozilla.org/NPL/
 
7
 *
 
8
 * Software distributed under the License is distributed on an "AS
 
9
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
10
 * implied. See the License for the specific language governing
 
11
 * rights and limitations under the License.
 
12
 *
 
13
 * The Original Code is Mozilla Communicator client code, 
 
14
 * released March 31, 1998. 
 
15
 *
 
16
 * The Initial Developer of the Original Code is Netscape Communications 
 
17
 * Corporation.  Portions created by Netscape are
 
18
 * Copyright (C) 1998 Netscape Communications Corporation. All
 
19
 * Rights Reserved.
 
20
 *
 
21
 * Contributor(s): 
 
22
 *     Daniel Veditz <dveditz@netscape.com>
 
23
 *     Douglas Turner <dougt@netscape.com>
 
24
 */
 
25
 
 
26
#include "nscore.h"
 
27
#include "nsXPIDLString.h"
 
28
#include "nsInstall.h" // for error codes
 
29
#include "prmem.h"
 
30
#include "ScheduledTasks.h"
 
31
#include "InstallCleanupDefines.h"
 
32
 
 
33
#include "nsDirectoryService.h"
 
34
#include "nsDirectoryServiceDefs.h"
 
35
#include "nsAppDirectoryServiceDefs.h"
 
36
 
 
37
static nsresult 
 
38
GetPersistentStringFromSpec(nsIFile* inSpec, nsACString &string)
 
39
{
 
40
    nsresult rv;
 
41
 
 
42
    nsCOMPtr<nsILocalFile> LocalFile = do_QueryInterface(inSpec, &rv);
 
43
 
 
44
    if (NS_SUCCEEDED(rv)) {
 
45
        rv = LocalFile->GetNativePath(string);
 
46
    } 
 
47
    else {
 
48
        string.Truncate();
 
49
    }
 
50
    return rv;
 
51
}
 
52
 
 
53
 
 
54
 
 
55
 
 
56
 
 
57
#ifdef _WINDOWS
 
58
#include <sys/stat.h>
 
59
#include <windows.h>
 
60
 
 
61
PRInt32 ReplaceWindowsSystemFile(nsIFile* currentSpec, nsIFile* finalSpec)
 
62
{
 
63
    PRInt32 err = -1;
 
64
 
 
65
    // Get OS version info 
 
66
    DWORD dwVersion = GetVersion();
 
67
 
 
68
    nsCAutoString final;
 
69
    nsCAutoString current;
 
70
 
 
71
    finalSpec->GetNativePath(final);
 
72
    currentSpec->GetNativePath(current);
 
73
 
 
74
    // Get build numbers for Windows NT or Win32s 
 
75
 
 
76
    if (dwVersion > 0x80000000)
 
77
    {
 
78
        // Windows 95 or Win16
 
79
 
 
80
        // Place an entry in the WININIT.INI file in the Windows directory
 
81
        // to delete finalName and rename currentName to be finalName at reboot
 
82
 
 
83
        int     strlen;
 
84
        char    Src[_MAX_PATH];   // 8.3 name
 
85
        char    Dest[_MAX_PATH];  // 8.3 name
 
86
        
 
87
        strlen = GetShortPathName( (LPCTSTR)current.get(), (LPTSTR)Src, (DWORD)sizeof(Src) );
 
88
        if ( strlen > 0 ) 
 
89
        {
 
90
            current = Src;
 
91
        }
 
92
 
 
93
        strlen = GetShortPathName( (LPCTSTR) final.get(), (LPTSTR) Dest, (DWORD) sizeof(Dest));
 
94
        if ( strlen > 0 ) 
 
95
        {
 
96
            final = Dest;
 
97
        }
 
98
        
 
99
        // NOTE: use OEM filenames! Even though it looks like a Windows
 
100
        //       .INI file, WININIT.INI is processed under DOS 
 
101
        
 
102
        AnsiToOem( final.BeginWriting(), final.BeginWriting() );
 
103
        AnsiToOem( current.BeginWriting(), current.BeginWriting() );
 
104
 
 
105
        if ( WritePrivateProfileString( "Rename", final.get(), current.get(), "WININIT.INI" ) )
 
106
            err = 0;
 
107
    }
 
108
    else
 
109
    {
 
110
       // Windows NT
 
111
        if ( MoveFileEx(final.get(), current.get(), MOVEFILE_DELAY_UNTIL_REBOOT) )
 
112
          err = 0;
 
113
    }
 
114
    
 
115
    return err;
 
116
}
 
117
#endif
 
118
 
 
119
nsresult GetRegFilePath(nsACString &regFilePath)
 
120
{
 
121
    nsresult rv;
 
122
    nsCOMPtr<nsILocalFile> iFileUtilityPath;
 
123
    //Get the program directory
 
124
    nsCOMPtr<nsIProperties> directoryService = 
 
125
             do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
 
126
    if (NS_FAILED(rv))
 
127
        return nsnull;
 
128
 
 
129
    if (nsSoftwareUpdate::GetProgramDirectory()) // In the stub installer
 
130
    {
 
131
        nsCOMPtr<nsIFile> tmp;
 
132
        rv = nsSoftwareUpdate::GetProgramDirectory()->Clone(getter_AddRefs(tmp));
 
133
 
 
134
        if (NS_FAILED(rv) || !tmp) 
 
135
            return nsnull;
 
136
 
 
137
#if defined (XP_MAC)
 
138
        tmp->AppendNative(ESSENTIAL_FILES);
 
139
#endif
 
140
        iFileUtilityPath = do_QueryInterface(tmp);
 
141
    }
 
142
    else
 
143
    {
 
144
        rv = directoryService->Get(NS_APP_INSTALL_CLEANUP_DIR,
 
145
                                  NS_GET_IID(nsIFile),
 
146
                                  getter_AddRefs(iFileUtilityPath));
 
147
    }
 
148
    if (NS_FAILED(rv) || !iFileUtilityPath) 
 
149
        return nsnull;
 
150
 
 
151
    iFileUtilityPath->AppendNative(CLEANUP_REGISTRY);
 
152
 
 
153
    //Yes, we know using GetPath is buggy on the Mac.
 
154
    //When libreg is fixed to accept nsIFiles we'll change this to match.
 
155
    return iFileUtilityPath->GetNativePath(regFilePath);
 
156
}
 
157
 
 
158
 
 
159
PRInt32 DeleteFileNowOrSchedule(nsIFile* filename)
 
160
{
 
161
    PRBool flagExists;  
 
162
    PRInt32 result = nsInstall::SUCCESS;
 
163
 
 
164
    filename->Remove(PR_FALSE);
 
165
    filename->Exists(&flagExists);
 
166
    if (flagExists)
 
167
        result = ScheduleFileForDeletion(filename);
 
168
 
 
169
    return result;
 
170
 
171
 
 
172
PRInt32 ScheduleFileForDeletion(nsIFile *filename)
 
173
{
 
174
    // could not delete, schedule it for later
 
175
 
 
176
    RKEY newkey;
 
177
    HREG reg;
 
178
    REGERR  err;
 
179
    PRInt32 result = nsInstall::UNEXPECTED_ERROR;
 
180
 
 
181
    nsCAutoString path;
 
182
    GetRegFilePath(path);
 
183
    err = NR_RegOpen(NS_CONST_CAST(char*, path.get()), &reg);
 
184
 
 
185
    if ( err == REGERR_OK )
 
186
    {
 
187
        err = NR_RegAddKey(reg,ROOTKEY_PRIVATE,REG_DELETE_LIST_KEY,&newkey);
 
188
        if ( err == REGERR_OK )
 
189
        {
 
190
            char    valname[20];
 
191
 
 
192
            err = NR_RegGetUniqueName( reg, valname, sizeof(valname) );
 
193
            if ( err == REGERR_OK )
 
194
            {
 
195
                nsCAutoString nameowner;
 
196
                nsresult rv = GetPersistentStringFromSpec(filename, nameowner);
 
197
                if ( NS_SUCCEEDED(rv) && !nameowner.IsEmpty() )
 
198
                {
 
199
                    const char *fnamestr = nameowner.get();
 
200
                    err = NR_RegSetEntry( reg, newkey, valname, 
 
201
                                          REGTYPE_ENTRY_BYTES, 
 
202
                                          (void*)fnamestr, 
 
203
                                          strlen(fnamestr)+sizeof('\0'));
 
204
 
 
205
                    if ( err == REGERR_OK )
 
206
                    {
 
207
                         result = nsInstall::REBOOT_NEEDED;
 
208
                         nsSoftwareUpdate::NeedCleanup();
 
209
                    }
 
210
                }
 
211
            }
 
212
        }
 
213
 
 
214
        NR_RegClose(reg);
 
215
    }
 
216
 
 
217
    return result;
 
218
}
 
219
 
 
220
 
 
221
 
 
222
 
 
223
PRInt32 ReplaceFileNow(nsIFile* aReplacementFile, nsIFile* aDoomedFile )
 
224
{
 
225
    PRBool flagExists, flagRenamedDoomedFileExists, flagIsEqual;
 
226
    nsCOMPtr<nsIFile> replacementFile;
 
227
    nsresult rv;
 
228
 
 
229
    // make a clone of aReplacement file so we touch affect callers
 
230
    aReplacementFile->Clone(getter_AddRefs(replacementFile));
 
231
 
 
232
    // replacement file must exist, doomed file doesn't have to
 
233
    replacementFile->Exists(&flagExists);
 
234
    if ( !flagExists )
 
235
        return nsInstall::DOES_NOT_EXIST;
 
236
 
 
237
    // don't have to do anything if the files are the same
 
238
    replacementFile->Equals(aDoomedFile, &flagIsEqual);
 
239
    if ( flagIsEqual )
 
240
        return nsInstall::SUCCESS;
 
241
 
 
242
 
 
243
    PRInt32 result = nsInstall::ACCESS_DENIED;
 
244
 
 
245
    // first try to rename the doomed file out of the way (if it exists)
 
246
    nsCOMPtr<nsIFile>      renamedDoomedFile;
 
247
    nsCOMPtr<nsILocalFile> tmpLocalFile;
 
248
    
 
249
    aDoomedFile->Clone(getter_AddRefs(renamedDoomedFile));
 
250
    renamedDoomedFile->Exists(&flagRenamedDoomedFileExists);
 
251
    if ( flagRenamedDoomedFileExists )
 
252
    {
 
253
#ifdef XP_MACOSX
 
254
        // If we clone an nsIFile, and move the clone, the FSRef of the *original*
 
255
        // file is not what you would expect - it points to the moved file. This
 
256
        // is despite the fact that the two FSRefs are independent objects. Until
 
257
        // the OS X file impl is changed to not use FSRefs, need to do this (see
 
258
        // bug 200024).
 
259
        nsCOMPtr<nsILocalFile> doomedFileLocal = do_QueryInterface(aDoomedFile);
 
260
        nsCAutoString doomedFilePath;
 
261
        rv = doomedFileLocal->GetNativePath(doomedFilePath);
 
262
        if (NS_FAILED(rv))
 
263
            return nsInstall::UNEXPECTED_ERROR;
 
264
#endif
 
265
 
 
266
        tmpLocalFile = do_QueryInterface(renamedDoomedFile, &rv); // Convert to an nsILocalFile
 
267
 
 
268
        //get the doomedLeafname so we can convert its extension to .old
 
269
        nsAutoString doomedLeafname;
 
270
        nsCAutoString uniqueLeafName;
 
271
        tmpLocalFile->GetLeafName(doomedLeafname);
 
272
 
 
273
        // do not RFind on the native charset! UTF8 or Unicode are OK
 
274
        PRInt32 extpos = doomedLeafname.RFindChar('.');
 
275
        if (extpos != -1)
 
276
        {
 
277
            // We found the extension; 
 
278
            doomedLeafname.Truncate(extpos + 1); //strip off the old extension
 
279
        }
 
280
        doomedLeafname.Append(NS_LITERAL_STRING("old"));
 
281
        
 
282
        //Now reset the doomedLeafname
 
283
        tmpLocalFile->SetLeafName(doomedLeafname);
 
284
        tmpLocalFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0644);
 
285
        tmpLocalFile->GetNativeLeafName(uniqueLeafName);//this is the new "unique" doomedLeafname
 
286
 
 
287
        rv = aDoomedFile->Clone(getter_AddRefs(renamedDoomedFile));// Reset renamedDoomed file so aDoomedfile
 
288
                                                                   // isn't changed during the MoveTo call
 
289
        if (NS_FAILED(rv))
 
290
            result = nsInstall::UNEXPECTED_ERROR;
 
291
        else
 
292
        {
 
293
            rv = renamedDoomedFile->MoveToNative(nsnull, uniqueLeafName);        
 
294
            if (NS_FAILED(rv))
 
295
            {
 
296
                // MoveToNative() failing is OK.  It simply means that the file
 
297
                // was locked in memory and needs to be replaced on browser
 
298
                // shutdown or system reboot.
 
299
                //
 
300
                // Since renamedDoomedFile->MoveToNative() failed, it created a
 
301
                // 0 byte '-old' file that needs to be cleaned up.
 
302
                tmpLocalFile->Remove(PR_FALSE);
 
303
            }
 
304
            else
 
305
            {
 
306
                // The implementation of MoveToNative() on some platforms (osx and win32) resets
 
307
                // the object to the 'moved to' filename.  This is incorrect behavior.  This
 
308
                // implementation will be fixed in the future.  We need to take into account that
 
309
                // fix by setting renamedDoomedFile to the filename that it was moved to above.
 
310
                // See bug 200024.
 
311
                //
 
312
                // renamedDoomedFile needs to be reset because it's used later on in this
 
313
                // function.
 
314
                rv = renamedDoomedFile->SetNativeLeafName(uniqueLeafName);        
 
315
                if (NS_FAILED(rv))
 
316
                    result = nsInstall::UNEXPECTED_ERROR;
 
317
            }
 
318
        }
 
319
 
 
320
#ifdef XP_MACOSX
 
321
        rv = doomedFileLocal->InitWithNativePath(doomedFilePath);
 
322
        if (NS_FAILED(rv))
 
323
            result = nsInstall::UNEXPECTED_ERROR;
 
324
#endif
 
325
 
 
326
        if (result == nsInstall::UNEXPECTED_ERROR)
 
327
            return result;
 
328
    }
 
329
 
 
330
 
 
331
    // if aDoomedFile is still in the way, give up and return result.
 
332
    aDoomedFile->Exists(&flagExists);
 
333
    if ( flagExists )
 
334
        return result;
 
335
 
 
336
    nsCOMPtr<nsIFile> parentofDoomedFile;
 
337
    nsCAutoString doomedLeafname;
 
338
 
 
339
    rv = aDoomedFile->GetParent(getter_AddRefs(parentofDoomedFile));
 
340
    if ( NS_SUCCEEDED(rv) )
 
341
        rv = aDoomedFile->GetNativeLeafName(doomedLeafname);
 
342
    if ( NS_SUCCEEDED(rv) )
 
343
    {
 
344
        rv = replacementFile->MoveToNative(parentofDoomedFile, doomedLeafname);
 
345
        // The implementation of MoveToNative() on some platforms (osx and win32) resets
 
346
        // the object to the 'moved to' filename.  This is incorrect behavior.  This
 
347
        // implementation will be fixed in the future.  We need to take into account that
 
348
        // fix by setting replacementFile to the filename that it was moved to above.
 
349
        // See bug 200024.
 
350
        //
 
351
        // However, since replacementFile is a clone of aReplacementFile and is also
 
352
        // not used beyond here, there's no need to set the path+leafname to what
 
353
        // it was MoveToNative()'ed to.
 
354
    }
 
355
 
 
356
    if (NS_SUCCEEDED(rv))
 
357
    {
 
358
        if (flagRenamedDoomedFileExists)
 
359
        {
 
360
            // we replaced the old file OK, now we have to
 
361
            // get rid of it if it was renamed out of the way
 
362
            result = DeleteFileNowOrSchedule( renamedDoomedFile );
 
363
        }
 
364
    }
 
365
    else
 
366
    {
 
367
        // couldn't rename file, try to put old file back
 
368
        renamedDoomedFile->MoveToNative(nsnull, doomedLeafname);
 
369
        // No need to reset remanedDoomedFile after a MoveToNative() call
 
370
        // because renamedDoomedFile is not used beyond here.
 
371
    }
 
372
 
 
373
    return result;
 
374
}
 
375
 
 
376
 
 
377
 
 
378
 
 
379
 
 
380
PRInt32 ReplaceFileNowOrSchedule(nsIFile* aReplacementFile, nsIFile* aDoomedFile, PRInt32 aMode)
 
381
{
 
382
    PRInt32 result = ReplaceFileNow( aReplacementFile, aDoomedFile );
 
383
 
 
384
    if ( result == nsInstall::ACCESS_DENIED )
 
385
    {
 
386
        // if we couldn't replace the file schedule it for later
 
387
#ifdef _WINDOWS
 
388
        if ( (aMode & WIN_SYSTEM_FILE) && 
 
389
             (ReplaceWindowsSystemFile(aReplacementFile, aDoomedFile) == 0) )
 
390
                return nsInstall::REBOOT_NEEDED;
 
391
#endif
 
392
 
 
393
        RKEY    listkey;
 
394
        RKEY    filekey;
 
395
        HREG    reg;
 
396
        REGERR  err;
 
397
 
 
398
        nsCAutoString regFilePath;
 
399
        GetRegFilePath(regFilePath);
 
400
        if ( REGERR_OK == NR_RegOpen(NS_CONST_CAST(char*, regFilePath.get()), &reg) ) 
 
401
        {
 
402
            err = NR_RegAddKey( reg, ROOTKEY_PRIVATE, REG_REPLACE_LIST_KEY, &listkey );
 
403
            if ( err == REGERR_OK ) 
 
404
            {
 
405
                char     valname[20];
 
406
                REGERR   err2;
 
407
 
 
408
                err = NR_RegGetUniqueName( reg, valname, sizeof(valname) );
 
409
                if ( err == REGERR_OK )
 
410
                {
 
411
                    err = NR_RegAddKey( reg, listkey, valname, &filekey );
 
412
                    if ( REGERR_OK == err )
 
413
                    {
 
414
                        nsCAutoString srcowner;
 
415
                        nsCAutoString destowner;
 
416
                        nsresult rv = GetPersistentStringFromSpec(aReplacementFile, srcowner);
 
417
                        nsresult rv2 = GetPersistentStringFromSpec(aDoomedFile, destowner);
 
418
                        if ( NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv2) )
 
419
                        {
 
420
                            const char *fsrc  = srcowner.get();
 
421
                            const char *fdest = destowner.get();
 
422
                            err = NR_RegSetEntry( reg, filekey, 
 
423
                                                  REG_REPLACE_SRCFILE,
 
424
                                                  REGTYPE_ENTRY_BYTES, 
 
425
                                                  (void*)fsrc, 
 
426
                                                  strlen(fsrc)+sizeof('\0'));
 
427
 
 
428
                            err2 = NR_RegSetEntry(reg, filekey,
 
429
                                                  REG_REPLACE_DESTFILE,
 
430
                                                  REGTYPE_ENTRY_BYTES,
 
431
                                                  (void*)fdest,
 
432
                                                  strlen(fdest)+sizeof('\0'));
 
433
 
 
434
                            if ( err == REGERR_OK && err2 == REGERR_OK )
 
435
                            {
 
436
                                result = nsInstall::REBOOT_NEEDED;
 
437
                                nsSoftwareUpdate::NeedCleanup();
 
438
                            }
 
439
                            else
 
440
                                NR_RegDeleteKey( reg, listkey, valname );
 
441
                        }
 
442
                    }
 
443
                }
 
444
            }
 
445
            NR_RegClose(reg);
 
446
        }
 
447
    }
 
448
 
 
449
    return result;
 
450
}
 
451
 
 
452
 
 
453
 
 
454
 
 
455
//-----------------------------------------------------------------------------
 
456
//
 
457
//          STARTUP: DO SCHEDULED ACTIONS
 
458
//
 
459
//-----------------------------------------------------------------------------
 
460
 
 
461
void DeleteScheduledFiles(HREG);
 
462
void ReplaceScheduledFiles(HREG);
 
463
 
 
464
void PerformScheduledTasks(HREG reg)
 
465
{
 
466
    DeleteScheduledFiles( reg );
 
467
    ReplaceScheduledFiles( reg );
 
468
}
 
469
 
 
470
 
 
471
 
 
472
void DeleteScheduledFiles( HREG reg )
 
473
{
 
474
    REGERR  err;
 
475
    RKEY    key;
 
476
    REGENUM state = 0;
 
477
    nsresult rv = NS_OK;
 
478
 
 
479
    // perform scheduled file deletions  
 
480
    if (REGERR_OK == NR_RegGetKey(reg,ROOTKEY_PRIVATE,REG_DELETE_LIST_KEY,&key))
 
481
    {
 
482
        // the delete key exists, so we loop through its children
 
483
        // and try to delete all the listed files
 
484
 
 
485
        char    namebuf[MAXREGNAMELEN];
 
486
        char    valbuf[MAXREGPATHLEN];
 
487
 
 
488
        nsCOMPtr<nsIFile>        doomedFile;
 
489
        nsCOMPtr<nsILocalFile>   spec;
 
490
 
 
491
        if (NS_SUCCEEDED(rv))
 
492
        {
 
493
            while (REGERR_OK == NR_RegEnumEntries( reg, key, &state, namebuf,
 
494
                                                   sizeof(namebuf), 0 ) )
 
495
            {
 
496
                uint32 bufsize = sizeof(valbuf); // gets changed, must reset
 
497
                err = NR_RegGetEntry( reg, key, namebuf, valbuf, &bufsize );
 
498
                if ( err == REGERR_OK )
 
499
                {
 
500
                    // no need to check return value of 
 
501
                    // SetPersistentDescriptorString, it's always NS_OK
 
502
                    //spec->SetPersistentDescriptorString(valbuf);
 
503
                    //nsIFileXXX: Do we still need this instead of InitWithPath?
 
504
                    NS_NewNativeLocalFile(nsDependentCString(valbuf), PR_TRUE, getter_AddRefs(spec));
 
505
                    spec->Clone(getter_AddRefs(doomedFile));
 
506
                    if (NS_SUCCEEDED(rv)) 
 
507
                    {
 
508
                        PRBool flagExists;
 
509
                        doomedFile->Remove(PR_FALSE);
 
510
                        doomedFile->Exists(&flagExists);
 
511
                        if ( !flagExists )
 
512
                        {
 
513
                            // deletion successful, don't have to retry
 
514
                            NR_RegDeleteEntry( reg, key, namebuf );
 
515
                        }
 
516
                    }
 
517
                }
 
518
            }
 
519
 
 
520
            // delete list node if empty 
 
521
            state = 0;
 
522
            err = NR_RegEnumEntries(reg, key, &state, namebuf, sizeof(namebuf), 0);
 
523
            if ( err == REGERR_NOMORE )
 
524
            {
 
525
                NR_RegDeleteKey(reg, ROOTKEY_PRIVATE, REG_DELETE_LIST_KEY);
 
526
            }
 
527
        }
 
528
    }
 
529
}
 
530
 
 
531
 
 
532
 
 
533
void ReplaceScheduledFiles( HREG reg )
 
534
{
 
535
    RKEY    key;
 
536
 
 
537
    // replace files if any listed 
 
538
    if (REGERR_OK == NR_RegGetKey(reg,ROOTKEY_PRIVATE,REG_REPLACE_LIST_KEY,&key))
 
539
    {
 
540
        char keyname[MAXREGNAMELEN];
 
541
        char doomedFile[MAXREGPATHLEN];
 
542
        char srcFile[MAXREGPATHLEN];
 
543
 
 
544
        nsCOMPtr<nsIFile>       doomedSpec;
 
545
        nsCOMPtr<nsIFile>       srcSpec;
 
546
        nsCOMPtr<nsILocalFile>       src;
 
547
        nsCOMPtr<nsILocalFile>       dest;
 
548
        nsresult                rv1, rv2;
 
549
 
 
550
        uint32 bufsize;
 
551
        REGENUM state = 0;
 
552
        while (REGERR_OK == NR_RegEnumSubkeys( reg, key, &state, 
 
553
                               keyname, sizeof(keyname), REGENUM_CHILDREN))
 
554
        {
 
555
            bufsize = sizeof(srcFile);
 
556
            REGERR err1 = NR_RegGetEntry( reg, (RKEY)state,
 
557
                               REG_REPLACE_SRCFILE, srcFile, &bufsize);
 
558
 
 
559
            bufsize = sizeof(doomedFile);
 
560
            REGERR err2 = NR_RegGetEntry( reg, (RKEY)state,
 
561
                               REG_REPLACE_DESTFILE, doomedFile, &bufsize);
 
562
 
 
563
            if ( err1 == REGERR_OK && err2 == REGERR_OK )
 
564
            {
 
565
                rv1 = NS_NewNativeLocalFile(nsDependentCString(srcFile), PR_TRUE, getter_AddRefs(src));
 
566
                rv1 = src->Clone(getter_AddRefs(srcSpec));
 
567
 
 
568
                rv2 = NS_NewNativeLocalFile(nsDependentCString(doomedFile), PR_TRUE, getter_AddRefs(dest));
 
569
                rv2 = dest->Clone(getter_AddRefs(doomedSpec));
 
570
 
 
571
                if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2))
 
572
                {
 
573
                    // finally now try to do the replace
 
574
                    PRInt32 result = ReplaceFileNow( srcSpec, doomedSpec );
 
575
 
 
576
                    if ( result == nsInstall::DOES_NOT_EXIST ||
 
577
                         result == nsInstall::SUCCESS )
 
578
                    {
 
579
                        // This one is done
 
580
                        NR_RegDeleteKey( reg, key, keyname );
 
581
                    }
 
582
                }
 
583
            }
 
584
        }
 
585
 
 
586
 
 
587
        // delete list node if empty 
 
588
        state = 0;
 
589
        if (REGERR_NOMORE == NR_RegEnumSubkeys( reg, key, &state, keyname,
 
590
                                     sizeof(keyname), REGENUM_CHILDREN ))
 
591
        {
 
592
            NR_RegDeleteKey(reg, ROOTKEY_PRIVATE, REG_REPLACE_LIST_KEY);
 
593
        }
 
594
    }
 
595
}
 
596
 
 
597