source: trunk/libtransmission/platform.c @ 5065

Last change on this file since 5065 was 5065, checked in by charles, 13 years ago

cleanup #includes for errno & strerror

  • Property svn:keywords set to Date Rev Author Id
File size: 10.3 KB
Line 
1/******************************************************************************
2 * $Id: platform.c 5065 2008-02-19 04:16:04Z charles $
3 *
4 * Copyright (c) 2005-2008 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#ifdef __BEOS__
26  #include <signal.h> 
27  #include <fs_info.h>
28  #include <FindDirectory.h>
29  #include <kernel/OS.h>
30  #define BEOS_MAX_THREADS 256
31#elif defined(WIN32)
32  #include <windows.h>
33  #include <shlobj.h> /* for CSIDL_APPDATA, CSIDL_PROFILE */
34#else
35  #define _XOPEN_SOURCE 500 /* needed for recursive locks. */
36  #ifndef __USE_UNIX98
37  #define __USE_UNIX98 /* some older Linuxes need it spelt out for them */
38  #endif
39  #include <pthread.h>
40#endif
41
42#include <assert.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46
47#include <sys/types.h>
48#include <dirent.h>
49#include <fcntl.h>
50#include <unistd.h> /* getuid getpid close */
51
52#include "transmission.h"
53#include "list.h"
54#include "net.h"
55#include "platform.h"
56#include "trcompat.h"
57#include "utils.h"
58
59/***
60****  THREADS
61***/
62
63#ifdef __BEOS__
64typedef thread_id tr_thread_id;
65#elif defined(WIN32)
66typedef DWORD tr_thread_id;
67#else
68typedef pthread_t tr_thread_id;
69#endif
70
71static tr_thread_id
72tr_getCurrentThread( void )
73{
74#ifdef __BEOS__
75    return find_thread( NULL );
76#elif defined(WIN32)
77    return GetCurrentThreadId();
78#else
79    return pthread_self( );
80#endif
81}
82
83static int
84tr_areThreadsEqual( tr_thread_id a, tr_thread_id b )
85{
86#ifdef __BEOS__
87    return a == b;
88#elif defined(WIN32)
89    return a == b;
90#else
91    return pthread_equal( a, b );
92#endif
93}
94
95struct tr_thread
96{
97    void          (* func ) ( void * );
98    void           * arg;
99    const char     * name;
100
101#ifdef __BEOS__
102    thread_id        thread;
103#elif defined(WIN32)
104    HANDLE           thread;
105    unsigned int     thread_id;
106#else
107    pthread_t        thread;
108#endif
109
110};
111
112int
113tr_amInThread ( const tr_thread * t )
114{
115    return tr_areThreadsEqual( tr_getCurrentThread(), t->thread );
116}
117
118#ifdef WIN32
119#define ThreadFuncReturnType unsigned WINAPI
120#else
121#define ThreadFuncReturnType void
122#endif
123
124static ThreadFuncReturnType
125ThreadFunc( void * _t )
126{
127    tr_thread * t = _t;
128    const char * name = t->name;
129
130#ifdef __BEOS__
131    /* This is required because on BeOS, SIGINT is sent to each thread,
132       which kills them not nicely */
133    signal( SIGINT, SIG_IGN );
134#endif
135
136    tr_dbg( "Thread '%s' started", name );
137    t->func( t->arg );
138    tr_dbg( "Thread '%s' exited", name );
139
140#ifdef WIN32
141    _endthreadex( 0 );
142    return 0;
143#endif
144}
145
146tr_thread *
147tr_threadNew( void (*func)(void *),
148              void * arg,
149              const char * name )
150{
151    tr_thread * t = tr_new0( tr_thread, 1 );
152    t->func = func;
153    t->arg  = arg;
154    t->name = name;
155
156#ifdef __BEOS__
157    t->thread = spawn_thread( (void*)ThreadFunc, name, B_NORMAL_PRIORITY, t );
158    resume_thread( t->thread );
159#elif defined(WIN32)
160    t->thread = (HANDLE) _beginthreadex( NULL, 0, &ThreadFunc, t, 0, &t->thread_id );
161#else
162    pthread_create( &t->thread, NULL, (void * (*) (void *)) ThreadFunc, t );
163#endif
164
165    return t;
166}
167   
168void
169tr_threadJoin( tr_thread * t )
170{
171    if( t != NULL )
172    {
173#ifdef __BEOS__
174        long exit;
175        wait_for_thread( t->thread, &exit );
176#elif defined(WIN32)
177        WaitForSingleObject( t->thread, INFINITE );
178        CloseHandle( t->thread );
179#else
180        pthread_join( t->thread, NULL );
181#endif
182
183        tr_dbg( "Thread '%s' joined", t->name );
184        t->name = NULL;
185        t->func = NULL;
186        tr_free( t );
187    }
188}
189
190/***
191****  LOCKS
192***/
193
194struct tr_lock
195{
196    int depth;
197#ifdef __BEOS__
198    sem_id lock;
199    thread_id lockThread;
200#elif defined(WIN32)
201    CRITICAL_SECTION lock;
202    DWORD lockThread;
203#else
204    pthread_mutex_t lock;
205    pthread_t lockThread;
206#endif
207};
208
209tr_lock*
210tr_lockNew( void )
211{
212    tr_lock * l = tr_new0( tr_lock, 1 );
213
214#ifdef __BEOS__
215    l->lock = create_sem( 1, "" );
216#elif defined(WIN32)
217    InitializeCriticalSection( &l->lock ); /* critical sections support recursion */
218#else
219    pthread_mutexattr_t attr;
220    pthread_mutexattr_init( &attr );
221    pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
222    pthread_mutex_init( &l->lock, &attr );
223#endif
224
225    return l;
226}
227
228void
229tr_lockFree( tr_lock * l )
230{
231#ifdef __BEOS__
232    delete_sem( l->lock );
233#elif defined(WIN32)
234    DeleteCriticalSection( &l->lock );
235#else
236    pthread_mutex_destroy( &l->lock );
237#endif
238    tr_free( l );
239}
240
241void
242tr_lockLock( tr_lock * l )
243{
244#ifdef __BEOS__
245    acquire_sem( l->lock );
246#elif defined(WIN32)
247    EnterCriticalSection( &l->lock );
248#else
249    pthread_mutex_lock( &l->lock );
250#endif
251    assert( l->depth >= 0 );
252    if( l->depth )
253        assert( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ) );
254    l->lockThread = tr_getCurrentThread( );
255    ++l->depth;
256}
257
258int
259tr_lockHave( const tr_lock * l )
260{
261    return ( l->depth > 0 )
262        && ( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ) );
263}
264
265void
266tr_lockUnlock( tr_lock * l )
267{
268    assert( l->depth > 0 );
269    assert( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ));
270
271    --l->depth;
272    assert( l->depth >= 0 );
273#ifdef __BEOS__
274    release_sem( l->lock );
275#elif defined(WIN32)
276    LeaveCriticalSection( &l->lock );
277#else
278    pthread_mutex_unlock( &l->lock );
279#endif
280}
281
282/***
283****  PATHS
284***/
285
286#if !defined(WIN32) && !defined(__BEOS__) && !defined(__AMIGAOS4__)
287#include <pwd.h>
288#endif
289
290static const char *
291tr_getHomeDirectory( void )
292{
293    static char buf[MAX_PATH_LENGTH];
294    static int init = 0;
295    const char * envHome;
296
297    if( init )
298        return buf;
299
300    envHome = getenv( "HOME" );
301    if( envHome )
302        snprintf( buf, sizeof(buf), "%s", envHome );
303    else {
304#ifdef WIN32
305        SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, buf );
306#elif defined(__BEOS__) || defined(__AMIGAOS4__)
307        *buf = '\0';
308#else
309        struct passwd * pw = getpwuid( getuid() );
310        endpwent();
311        if( pw != NULL )
312            snprintf( buf, sizeof(buf), "%s", pw->pw_dir );
313#endif
314    }
315
316    init = 1;
317    return buf;
318}
319
320
321static void
322tr_migrateResume( const char *oldDirectory, const char *newDirectory )
323{
324    DIR * dirh = opendir( oldDirectory );
325
326    if( dirh != NULL )
327    {
328        struct dirent * dirp;
329
330        while( ( dirp = readdir( dirh ) ) )
331        {
332            if( !strncmp( "resume.", dirp->d_name, 7 ) )
333            {
334                char o[MAX_PATH_LENGTH];
335                char n[MAX_PATH_LENGTH];
336                tr_buildPath( o, sizeof(o), oldDirectory, dirp->d_name, NULL );
337                tr_buildPath( n, sizeof(n), newDirectory, dirp->d_name, NULL );
338                rename( o, n );
339            }
340        }
341
342        closedir( dirh );
343    }
344}
345
346const char *
347tr_getPrefsDirectory( void )
348{
349    static char   buf[MAX_PATH_LENGTH];
350    static int    init = 0;
351    const char * trhome;
352
353    if( init )
354        return buf;
355
356    trhome = getenv( "TRANSMISSION_HOME" );
357    if( trhome != NULL )
358    {
359        strlcpy( buf, trhome, sizeof( buf ) );
360    }
361    else
362    {
363#ifdef __BEOS__
364        find_directory( B_USER_SETTINGS_DIRECTORY,
365                        dev_for_path("/boot"), true,
366                        buf, sizeof( buf ) );
367        strcat( buf, "/Transmission" );
368#elif defined( SYS_DARWIN )
369        tr_buildPath ( buf, sizeof( buf ),
370                       tr_getHomeDirectory( ),
371                       "Library",
372                       "Application Support",
373                       "Transmission",
374                       NULL );
375#elif defined(__AMIGAOS4__)
376        strlcpy( buf, "PROGDIR:.transmission", sizeof( buf ) );
377#elif defined(WIN32)
378        char appdata[MAX_PATH_LENGTH];
379        SHGetFolderPath( NULL, CSIDL_APPDATA, NULL, 0, appdata );
380        tr_buildPath( buf, sizeof(buf),
381                      appdata,
382                      "Transmission",
383                      NULL );
384#else
385        tr_buildPath ( buf, sizeof(buf), tr_getHomeDirectory( ), ".transmission", NULL );
386#endif
387    }
388
389    tr_mkdirp( buf, 0777 );
390    init = 1;
391
392#ifdef SYS_DARWIN
393    char old[MAX_PATH_LENGTH];
394    tr_buildPath ( old, sizeof(old),
395                   tr_getHomeDirectory(), ".transmission", NULL );
396    tr_migrateResume( old, buf );
397    rmdir( old );
398#endif
399
400    return buf;
401}
402
403const char *
404tr_getCacheDirectory( void )
405{
406    static char buf[MAX_PATH_LENGTH];
407    static int  init = 0;
408    static const size_t buflen = sizeof(buf);
409    const char * p;
410
411    if( init )
412        return buf;
413
414    p = tr_getPrefsDirectory();
415#if defined(__BEOS__) || defined(WIN32)
416    tr_buildPath( buf, buflen, p, "Cache", NULL );
417#elif defined( SYS_DARWIN )
418    tr_buildPath( buf, buflen, tr_getHomeDirectory(),
419                  "Library", "Caches", "Transmission", NULL );
420#else
421    tr_buildPath( buf, buflen, p, "cache", NULL );
422#endif
423
424    tr_mkdirp( buf, 0777 );
425    init = 1;
426
427    if( strcmp( p, buf ) )
428        tr_migrateResume( p, buf );
429
430    return buf;
431}
432
433const char *
434tr_getTorrentsDirectory( void )
435{
436    static char buf[MAX_PATH_LENGTH];
437    static int  init = 0;
438    static const size_t buflen = sizeof(buf);
439    const char * p;
440
441    if( init )
442        return buf;
443
444    p = tr_getPrefsDirectory ();
445
446#if defined(__BEOS__) || defined(WIN32)
447    tr_buildPath( buf, buflen, p, "Torrents", NULL );
448#elif defined( SYS_DARWIN )
449    tr_buildPath( buf, buflen, p, "Torrents", NULL );
450#else
451    tr_buildPath( buf, buflen, p, "torrents", NULL );
452#endif
453
454    tr_mkdirp( buf, 0777 );
455    init = 1;
456    return buf;
457}
Note: See TracBrowser for help on using the repository browser.