source: trunk/third/mozilla/xpinstall/cleanup/InstallCleanupMac.cpp @ 18860

Revision 18860, 15.5 KB checked in by rbasch, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18859, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Netscape Public License
6 * Version 1.1 (the "License"); you may not use this file except in
7 * compliance with the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/NPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is Mozilla Communicator client code.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 *   Don Bragg <dbragg@netscape.com>
24 *   Samir Gehani <sgehani@netscape.com>
25 *
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the NPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the NPL, the GPL or the LGPL.
37 *
38 * ***** END LICENSE BLOCK ***** */
39
40#include <stdio.h>
41#include <string.h>
42#include <unistd.h>
43#include <MacTypes.h>
44#include "MoreFiles.h"
45#include "MoreFilesExtras.h"
46#include "FullPath.h" 
47#include <AppleEvents.h>
48#include <Gestalt.h>
49#include <TextUtils.h>
50#include <Folders.h>
51#include <Processes.h>
52#include <Resources.h>
53#include <Aliases.h>
54
55#include "InstallCleanup.h"
56#include "InstallCleanupDefines.h"
57
58#define kSleepMax 60  // sleep 1 second
59
60Boolean gAppleEventsFlag, gQuitFlag;
61long gSleepVal;
62
63
64int   strcasecmp(const char *str1, const char *str2);
65OSErr GetFSSpecFromPath(char *aPath, FSSpec *aSpec);
66void  my_c2pstrcpy(Str255 aDstPStr, const char *aSrcCStr);
67OSErr GetCWD(short *aVRefNum, long *aDirID);
68OSErr GetCleanupReg(FSSpec *aCleanupReg);
69
70int strcasecmp(const char *str1, const char *str2)
71{
72    char    currentChar1, currentChar2;
73
74    while (1) {
75   
76        currentChar1 = *str1;
77        currentChar2 = *str2;
78       
79        if ((currentChar1 >= 'a') && (currentChar1 <= 'z'))
80            currentChar1 += ('A' - 'a');
81       
82        if ((currentChar2 >= 'a') && (currentChar2 <= 'z'))
83            currentChar2 += ('A' - 'a');
84               
85        if (currentChar1 == '\0')
86            break;
87   
88        if (currentChar1 != currentChar2)
89            return currentChar1 - currentChar2;
90           
91        str1++;
92        str2++;
93   
94    }
95   
96    return currentChar1 - currentChar2;
97}
98
99OSErr GetFSSpecFromPath(const char *aPath, FSSpec *aSpec)
100{
101    if (!aPath || !aSpec)
102        return paramErr;
103       
104    // 1> verify path is not an empty string
105    // 2> verify path has leaf
106    // 3> verify path does not start with leading ':'
107   
108    if ((!*aPath) ||
109       (*(aPath + strlen(aPath) - 1) == ':') ||
110       (*aPath == ':'))
111    {
112       return paramErr;
113    }
114   
115    // path is kosher: get FSSpec for it
116    return FSpLocationFromFullPath(strlen(aPath), (const void *) aPath, aSpec);
117}
118
119void
120my_c2pstrcpy(Str255 aDstPStr, const char *aSrcCStr)
121{
122    if (!aSrcCStr)
123        return;
124   
125    memcpy(&aDstPStr[1], aSrcCStr, strlen(aSrcCStr) > 255 ? 255 : strlen(aSrcCStr));
126    aDstPStr[0] = strlen(aSrcCStr);
127}
128
129OSErr
130GetCWD(short *aVRefNum, long *aDirID)
131{
132    OSErr               err = noErr;
133    ProcessSerialNumber psn;
134    ProcessInfoRec      pInfo;
135    FSSpec              tmp;
136       
137    if (!aVRefNum || !aDirID)
138        return paramErr;
139   
140    *aVRefNum = 0;
141    *aDirID = 0;
142   
143    /* get cwd based on curr ps info */
144    if (!(err = GetCurrentProcess(&psn)))
145    {
146        pInfo.processName = nil;
147        pInfo.processAppSpec = &tmp;
148        pInfo.processInfoLength = (sizeof(ProcessInfoRec));
149             
150        if(!(err = GetProcessInformation(&psn, &pInfo)))
151        {   
152            *aVRefNum = pInfo.processAppSpec->vRefNum;
153            *aDirID = pInfo.processAppSpec->parID;
154        }
155    }
156     
157    return err;
158}
159
160OSErr
161GetCleanupReg(FSSpec *aCleanupReg)
162{
163    OSErr err = noErr;
164    short efVRefNum = 0;
165    long efDirID = 0;
166   
167    if (!aCleanupReg)
168        return paramErr;
169       
170    err = GetCWD(&efVRefNum, &efDirID);
171    if (err == noErr)
172    {
173        Str255 pCleanupReg;
174        my_c2pstrcpy(pCleanupReg, CLEANUP_REGISTRY);
175        err = FSMakeFSSpec(efVRefNum, efDirID, pCleanupReg, aCleanupReg);
176    }
177   
178    return err;
179}
180
181
182#pragma mark -
183
184//----------------------------------------------------------------------------
185// Native Mac file deletion function
186//----------------------------------------------------------------------------
187int NativeDeleteFile(const char* aFileToDelete)
188{
189    OSErr err;
190    FSSpec delSpec;
191   
192    if (!aFileToDelete)
193        return DONE;
194       
195    // stat the file
196    err = GetFSSpecFromPath(aFileToDelete, &delSpec);
197    if (err != noErr)
198    {
199        // return fine if it doesn't exist
200        return DONE;
201    }
202       
203    // else try to delete it
204    err = FSpDelete(&delSpec);
205    if (err != noErr)
206    {
207        // tell user to try again later if deletion failed
208        return TRY_LATER;
209    }
210
211    return DONE;
212}
213
214//----------------------------------------------------------------------------
215// Native Mac file replacement function
216//----------------------------------------------------------------------------
217int NativeReplaceFile(const char* aReplacementFile, const char* aDoomedFile )
218{
219    OSErr err;
220    FSSpec replSpec, doomSpec, tgtDirSpec;
221    long dirID;
222    Boolean isDir;
223   
224    if (!aReplacementFile || !aDoomedFile)
225        return DONE;
226       
227    err = GetFSSpecFromPath(aReplacementFile, &replSpec);
228    if (err != noErr)
229        return DONE;
230                     
231    // stat replacement file
232    err = FSpGetDirectoryID(&replSpec, &dirID, &isDir);
233    if (err != noErr || isDir)
234    {
235        // return fine if it doesn't exist
236        return DONE;
237    }
238       
239    // check if the replacement file and doomed file are the same
240    if (strcasecmp(aReplacementFile, aDoomedFile) == 0)
241    {
242        // return fine if they are the same
243        return DONE;
244    }
245       
246    // try and delete doomed file (NOTE: this call also stats)
247    err = GetFSSpecFromPath(aDoomedFile, &doomSpec);
248    if (err == noErr)
249    {
250        // (will even try to delete a dir with this name)
251        err = FSpDelete(&doomSpec);
252       
253        // if deletion failed tell user to try again later
254        if (err != noErr)
255            return TRY_LATER;
256    }
257   
258    // get the target dir spec (parent directory of doomed file)
259    err = FSMakeFSSpec(doomSpec.vRefNum, doomSpec.parID, "\p", &tgtDirSpec);
260    if (err == noErr)
261    {
262        // now try and move replacment file to path of doomed file
263        err = FSpMoveRename(&replSpec, &tgtDirSpec, doomSpec.name);
264        if (err != noErr)
265        {
266            // if move failed tell user to try agian later
267            return TRY_LATER;
268        }
269    }
270       
271    return DONE;
272}
273
274
275#pragma mark -
276
277//----------------------------------------------------------------------------
278// Routines for recovery on reboot
279//----------------------------------------------------------------------------
280OSErr
281GetProgramSpec(FSSpecPtr aProgSpec)
282{
283        OSErr                           err = noErr;
284        ProcessSerialNumber     psn;
285        ProcessInfoRec          pInfo;
286       
287        if (!aProgSpec)
288            return paramErr;
289           
290        /* get cwd based on curr ps info */
291        if (!(err = GetCurrentProcess(&psn)))
292        {
293                pInfo.processName = nil;
294                pInfo.processAppSpec = aProgSpec;
295                pInfo.processInfoLength = (sizeof(ProcessInfoRec));
296               
297                err = GetProcessInformation(&psn, &pInfo);
298        }
299       
300        return err;
301}
302
303void
304PutAliasInStartupItems(FSSpecPtr aAlias)
305{
306    OSErr err;
307    FSSpec fsProg, fsAlias;
308    long strtDirID = 0;
309    short strtVRefNum = 0;
310    FInfo info;
311    AliasHandle aliasH;
312
313    if (!aAlias)
314        return;
315       
316    // find cwd
317    err = GetProgramSpec(&fsProg);
318    if (err != noErr)
319        return;  // fail silently
320     
321    // get startup items folder
322    err = FindFolder(kOnSystemDisk, kStartupFolderType, kCreateFolder,
323                     &strtVRefNum, &strtDirID);
324    if (err != noErr)
325        return;
326             
327    // check that an alias to ourselves doesn't already
328    // exist in the Startup Items folder
329    err = FSMakeFSSpec(strtVRefNum, strtDirID, fsProg.name, &fsAlias);
330    if (err == noErr)
331    {
332        // one's already there; not sure it's us so delete and recreate
333        // (being super paranoid; but hey it's a mac)
334        err = FSpDelete(&fsAlias);
335        if (err != noErr)
336            return;  // fail silently
337    }
338     
339    // create the alias file
340    err = NewAliasMinimal(&fsProg, &aliasH);
341    if (err != noErr)
342        return;
343       
344    FSpGetFInfo(&fsProg, &info);
345    FSpCreateResFile(&fsAlias, info.fdCreator, info.fdType, smRoman);
346    short refNum = FSpOpenResFile(&fsAlias, fsRdWrPerm);
347    if (refNum != -1)
348    {
349        UseResFile(refNum);
350        AddResource((Handle)aliasH, rAliasType, 0, fsAlias.name);
351        ReleaseResource((Handle)aliasH);
352        UpdateResFile(refNum);
353        CloseResFile(refNum);
354    }
355    else
356    {
357        ReleaseResource((Handle)aliasH);
358        FSpDelete(&fsAlias);
359        return;  // non-fatal error
360    }
361
362    // mark newly created file as an alias file
363    FSpGetFInfo(&fsAlias, &info);
364    info.fdFlags |= kIsAlias;
365    FSpSetFInfo(&fsAlias, &info);   
366   
367    *aAlias = fsAlias;
368}
369
370void
371RemoveAliasFromStartupItems(FSSpecPtr aAlias)
372{
373    // try to delete the alias
374    FSpDelete(aAlias);
375}
376
377
378#pragma mark -
379
380//----------------------------------------------------------------------------
381// Apple event handlers to be installed
382//----------------------------------------------------------------------------
383
384static pascal OSErr DoAEOpenApplication(const AppleEvent * theAppleEvent, AppleEvent * replyAppleEvent, long refCon)
385{
386#pragma unused (theAppleEvent, replyAppleEvent, refCon)
387    return noErr;
388}
389
390static pascal OSErr DoAEOpenDocuments(const AppleEvent * theAppleEvent, AppleEvent * replyAppleEvent, long refCon)
391{
392#pragma unused (theAppleEvent, replyAppleEvent, refCon)
393    return errAEEventNotHandled;
394}
395
396static pascal OSErr DoAEPrintDocuments(const AppleEvent * theAppleEvent, AppleEvent * replyAppleEvent, long refCon)
397{
398#pragma unused (theAppleEvent, replyAppleEvent, refCon)
399    return errAEEventNotHandled;
400}
401
402static pascal OSErr DoAEQuitApplication(const AppleEvent * theAppleEvent, AppleEvent * replyAppleEvent, long refCon)
403{
404#pragma unused (theAppleEvent, replyAppleEvent, refCon)
405    gQuitFlag = true;
406    return noErr;
407}
408
409
410//----------------------------------------------------------------------------
411// install Apple event handlers
412//----------------------------------------------------------------------------
413
414static void InitAppleEventsStuff(void)
415{
416    OSErr retCode;
417
418    if (gAppleEventsFlag) {
419
420        retCode = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
421                    NewAEEventHandlerUPP(DoAEOpenApplication), 0, false);
422
423        if (retCode == noErr)
424            retCode = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
425                    NewAEEventHandlerUPP(DoAEOpenDocuments), 0, false);
426
427        if (retCode == noErr)
428            retCode = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
429                    NewAEEventHandlerUPP(DoAEPrintDocuments), 0, false);
430        if (retCode == noErr)
431            retCode = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
432                    NewAEEventHandlerUPP(DoAEQuitApplication), 0, false);
433
434        if (retCode != noErr) DebugStr("\pInstall event handler failed");
435        // a better way to indicate an error is to post a notification
436    }
437}
438
439
440//----------------------------------------------------------------------------
441// high-level event dispatching
442//----------------------------------------------------------------------------
443
444static void DoHighLevelEvent(EventRecord * theEventRecPtr)
445{
446    (void) AEProcessAppleEvent(theEventRecPtr);
447}
448
449
450#pragma mark -
451
452void main(void)
453{
454    OSErr retCode;
455    long gestResponse;
456    FSSpec aliasToSelf;
457    FSSpec fsCleanupReg;
458
459    EventRecord mainEventRec;
460    Boolean eventFlag, bDone = false, bHaveCleanupReg = false;
461   
462    HREG reg;
463    int rv = DONE;
464
465#if !TARGET_CARBON
466    // initialize QuickDraw globals
467    InitGraf(&qd.thePort);
468#endif
469
470    // initialize application globals
471    gQuitFlag = false;
472    gSleepVal = kSleepMax;
473
474    // is the Apple Event Manager available?
475    retCode = Gestalt(gestaltAppleEventsAttr, &gestResponse);
476    if (retCode == noErr &&
477        (gestResponse & (1 << gestaltAppleEventsPresent)) != 0)
478        gAppleEventsFlag = true;
479    else gAppleEventsFlag = false;
480
481    // install Apple event handlers
482    InitAppleEventsStuff();
483
484    // put an alias to ourselves in the Startup Items folder
485    // so that if we are shutdown before finishing we do our
486    // tasks at startup
487    FSMakeFSSpec(0, 0, "\p", &aliasToSelf);  // initialize
488    PutAliasInStartupItems(&aliasToSelf);
489   
490    if ( REGERR_OK == NR_StartupRegistry() )
491    {
492        char *regName = "";
493        Boolean regNameAllocd = false;
494        Handle pathH = 0;
495        short pathLen = 0;
496       
497        // check if XPICleanup data file exists
498        retCode = GetCleanupReg(&fsCleanupReg);
499        if (retCode == noErr)
500        {
501            bHaveCleanupReg = true;
502           
503            // get full path to give to libreg open routine
504            retCode = FSpGetFullPath(&fsCleanupReg, &pathLen, &pathH);
505            if (retCode == noErr && pathH)
506            {
507                HLock(pathH);
508                if (*pathH)
509                {
510                    regName = (char *) malloc(sizeof(char) * (pathLen + 1));
511                    if (regName)
512                        regNameAllocd = true;
513                    else
514                        retCode = memFullErr;
515                    strncpy(regName, *pathH, pathLen);
516                    *(regName + pathLen) = 0;
517                }
518                HUnlock(pathH);
519                DisposeHandle(pathH);
520            }
521        }
522           
523        if ( (retCode == noErr) && (REGERR_OK == NR_RegOpen(regName, &reg)) )
524        {
525            // main event loop
526
527            while (!gQuitFlag)
528            {
529                eventFlag = WaitNextEvent(everyEvent, &mainEventRec, gSleepVal, nil);
530
531                if (mainEventRec.what == kHighLevelEvent)
532                    DoHighLevelEvent(&mainEventRec);
533
534                rv = PerformScheduledTasks(reg);
535                if (rv == DONE)
536                {
537                    bDone = true;
538                    gQuitFlag = true;
539                }
540            }
541            NR_RegClose(&reg);
542            NR_ShutdownRegistry();
543        }
544       
545        if (regNameAllocd)
546            free(regName);     
547    }
548   
549    // clean up the alias to ouselves since we have
550    // completed our tasks successfully
551    if (bDone)
552    {
553        if (bHaveCleanupReg)
554            FSpDelete(&fsCleanupReg);
555        RemoveAliasFromStartupItems(&aliasToSelf);
556    }
557}
558
Note: See TracBrowser for help on using the repository browser.