source: trunk/libtransmission/platform.c @ 5081

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

remove unnecessary #includes

  • Property svn:keywords set to Date Rev Author Id
File size: 10.2 KB
Line 
1/******************************************************************************
2 * $Id: platform.c 5081 2008-02-19 18:39:49Z 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 "platform.h"
54#include "trcompat.h"
55#include "utils.h"
56
57/***
58****  THREADS
59***/
60
61#ifdef __BEOS__
62typedef thread_id tr_thread_id;
63#elif defined(WIN32)
64typedef DWORD tr_thread_id;
65#else
66typedef pthread_t tr_thread_id;
67#endif
68
69static tr_thread_id
70tr_getCurrentThread( void )
71{
72#ifdef __BEOS__
73    return find_thread( NULL );
74#elif defined(WIN32)
75    return GetCurrentThreadId();
76#else
77    return pthread_self( );
78#endif
79}
80
81static int
82tr_areThreadsEqual( tr_thread_id a, tr_thread_id b )
83{
84#ifdef __BEOS__
85    return a == b;
86#elif defined(WIN32)
87    return a == b;
88#else
89    return pthread_equal( a, b );
90#endif
91}
92
93struct tr_thread
94{
95    void          (* func ) ( void * );
96    void           * arg;
97    const char     * name;
98
99#ifdef __BEOS__
100    thread_id        thread;
101#elif defined(WIN32)
102    HANDLE           thread;
103    unsigned int     thread_id;
104#else
105    pthread_t        thread;
106#endif
107
108};
109
110int
111tr_amInThread ( const tr_thread * t )
112{
113    return tr_areThreadsEqual( tr_getCurrentThread(), t->thread );
114}
115
116#ifdef WIN32
117#define ThreadFuncReturnType unsigned WINAPI
118#else
119#define ThreadFuncReturnType void
120#endif
121
122static ThreadFuncReturnType
123ThreadFunc( void * _t )
124{
125    tr_thread * t = _t;
126    const char * name = t->name;
127
128#ifdef __BEOS__
129    /* This is required because on BeOS, SIGINT is sent to each thread,
130       which kills them not nicely */
131    signal( SIGINT, SIG_IGN );
132#endif
133
134    tr_dbg( "Thread '%s' started", name );
135    t->func( t->arg );
136    tr_dbg( "Thread '%s' exited", name );
137
138#ifdef WIN32
139    _endthreadex( 0 );
140    return 0;
141#endif
142}
143
144tr_thread *
145tr_threadNew( void (*func)(void *),
146              void * arg,
147              const char * name )
148{
149    tr_thread * t = tr_new0( tr_thread, 1 );
150    t->func = func;
151    t->arg  = arg;
152    t->name = name;
153
154#ifdef __BEOS__
155    t->thread = spawn_thread( (void*)ThreadFunc, name, B_NORMAL_PRIORITY, t );
156    resume_thread( t->thread );
157#elif defined(WIN32)
158    t->thread = (HANDLE) _beginthreadex( NULL, 0, &ThreadFunc, t, 0, &t->thread_id );
159#else
160    pthread_create( &t->thread, NULL, (void * (*) (void *)) ThreadFunc, t );
161#endif
162
163    return t;
164}
165   
166void
167tr_threadJoin( tr_thread * t )
168{
169    if( t != NULL )
170    {
171#ifdef __BEOS__
172        long exit;
173        wait_for_thread( t->thread, &exit );
174#elif defined(WIN32)
175        WaitForSingleObject( t->thread, INFINITE );
176        CloseHandle( t->thread );
177#else
178        pthread_join( t->thread, NULL );
179#endif
180
181        tr_dbg( "Thread '%s' joined", t->name );
182        t->name = NULL;
183        t->func = NULL;
184        tr_free( t );
185    }
186}
187
188/***
189****  LOCKS
190***/
191
192struct tr_lock
193{
194    int depth;
195#ifdef __BEOS__
196    sem_id lock;
197    thread_id lockThread;
198#elif defined(WIN32)
199    CRITICAL_SECTION lock;
200    DWORD lockThread;
201#else
202    pthread_mutex_t lock;
203    pthread_t lockThread;
204#endif
205};
206
207tr_lock*
208tr_lockNew( void )
209{
210    tr_lock * l = tr_new0( tr_lock, 1 );
211
212#ifdef __BEOS__
213    l->lock = create_sem( 1, "" );
214#elif defined(WIN32)
215    InitializeCriticalSection( &l->lock ); /* critical sections support recursion */
216#else
217    pthread_mutexattr_t attr;
218    pthread_mutexattr_init( &attr );
219    pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
220    pthread_mutex_init( &l->lock, &attr );
221#endif
222
223    return l;
224}
225
226void
227tr_lockFree( tr_lock * l )
228{
229#ifdef __BEOS__
230    delete_sem( l->lock );
231#elif defined(WIN32)
232    DeleteCriticalSection( &l->lock );
233#else
234    pthread_mutex_destroy( &l->lock );
235#endif
236    tr_free( l );
237}
238
239void
240tr_lockLock( tr_lock * l )
241{
242#ifdef __BEOS__
243    acquire_sem( l->lock );
244#elif defined(WIN32)
245    EnterCriticalSection( &l->lock );
246#else
247    pthread_mutex_lock( &l->lock );
248#endif
249    assert( l->depth >= 0 );
250    if( l->depth )
251        assert( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ) );
252    l->lockThread = tr_getCurrentThread( );
253    ++l->depth;
254}
255
256int
257tr_lockHave( const tr_lock * l )
258{
259    return ( l->depth > 0 )
260        && ( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ) );
261}
262
263void
264tr_lockUnlock( tr_lock * l )
265{
266    assert( l->depth > 0 );
267    assert( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ));
268
269    --l->depth;
270    assert( l->depth >= 0 );
271#ifdef __BEOS__
272    release_sem( l->lock );
273#elif defined(WIN32)
274    LeaveCriticalSection( &l->lock );
275#else
276    pthread_mutex_unlock( &l->lock );
277#endif
278}
279
280/***
281****  PATHS
282***/
283
284#if !defined(WIN32) && !defined(__BEOS__) && !defined(__AMIGAOS4__)
285#include <pwd.h>
286#endif
287
288static const char *
289tr_getHomeDirectory( void )
290{
291    static char buf[MAX_PATH_LENGTH];
292    static int init = 0;
293    const char * envHome;
294
295    if( init )
296        return buf;
297
298    envHome = getenv( "HOME" );
299    if( envHome )
300        snprintf( buf, sizeof(buf), "%s", envHome );
301    else {
302#ifdef WIN32
303        SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, buf );
304#elif defined(__BEOS__) || defined(__AMIGAOS4__)
305        *buf = '\0';
306#else
307        struct passwd * pw = getpwuid( getuid() );
308        endpwent();
309        if( pw != NULL )
310            snprintf( buf, sizeof(buf), "%s", pw->pw_dir );
311#endif
312    }
313
314    init = 1;
315    return buf;
316}
317
318
319static void
320tr_migrateResume( const char *oldDirectory, const char *newDirectory )
321{
322    DIR * dirh = opendir( oldDirectory );
323
324    if( dirh != NULL )
325    {
326        struct dirent * dirp;
327
328        while( ( dirp = readdir( dirh ) ) )
329        {
330            if( !strncmp( "resume.", dirp->d_name, 7 ) )
331            {
332                char o[MAX_PATH_LENGTH];
333                char n[MAX_PATH_LENGTH];
334                tr_buildPath( o, sizeof(o), oldDirectory, dirp->d_name, NULL );
335                tr_buildPath( n, sizeof(n), newDirectory, dirp->d_name, NULL );
336                rename( o, n );
337            }
338        }
339
340        closedir( dirh );
341    }
342}
343
344const char *
345tr_getPrefsDirectory( void )
346{
347    static char   buf[MAX_PATH_LENGTH];
348    static int    init = 0;
349    const char * trhome;
350
351    if( init )
352        return buf;
353
354    trhome = getenv( "TRANSMISSION_HOME" );
355    if( trhome != NULL )
356    {
357        strlcpy( buf, trhome, sizeof( buf ) );
358    }
359    else
360    {
361#ifdef __BEOS__
362        find_directory( B_USER_SETTINGS_DIRECTORY,
363                        dev_for_path("/boot"), true,
364                        buf, sizeof( buf ) );
365        strcat( buf, "/Transmission" );
366#elif defined( SYS_DARWIN )
367        tr_buildPath ( buf, sizeof( buf ),
368                       tr_getHomeDirectory( ),
369                       "Library",
370                       "Application Support",
371                       "Transmission",
372                       NULL );
373#elif defined(__AMIGAOS4__)
374        strlcpy( buf, "PROGDIR:.transmission", sizeof( buf ) );
375#elif defined(WIN32)
376        char appdata[MAX_PATH_LENGTH];
377        SHGetFolderPath( NULL, CSIDL_APPDATA, NULL, 0, appdata );
378        tr_buildPath( buf, sizeof(buf),
379                      appdata,
380                      "Transmission",
381                      NULL );
382#else
383        tr_buildPath ( buf, sizeof(buf), tr_getHomeDirectory( ), ".transmission", NULL );
384#endif
385    }
386
387    tr_mkdirp( buf, 0777 );
388    init = 1;
389
390#ifdef SYS_DARWIN
391    char old[MAX_PATH_LENGTH];
392    tr_buildPath ( old, sizeof(old),
393                   tr_getHomeDirectory(), ".transmission", NULL );
394    tr_migrateResume( old, buf );
395    rmdir( old );
396#endif
397
398    return buf;
399}
400
401const char *
402tr_getCacheDirectory( void )
403{
404    static char buf[MAX_PATH_LENGTH];
405    static int  init = 0;
406    static const size_t buflen = sizeof(buf);
407    const char * p;
408
409    if( init )
410        return buf;
411
412    p = tr_getPrefsDirectory();
413#if defined(__BEOS__) || defined(WIN32)
414    tr_buildPath( buf, buflen, p, "Cache", NULL );
415#elif defined( SYS_DARWIN )
416    tr_buildPath( buf, buflen, tr_getHomeDirectory(),
417                  "Library", "Caches", "Transmission", NULL );
418#else
419    tr_buildPath( buf, buflen, p, "cache", NULL );
420#endif
421
422    tr_mkdirp( buf, 0777 );
423    init = 1;
424
425    if( strcmp( p, buf ) )
426        tr_migrateResume( p, buf );
427
428    return buf;
429}
430
431const char *
432tr_getTorrentsDirectory( void )
433{
434    static char buf[MAX_PATH_LENGTH];
435    static int  init = 0;
436    static const size_t buflen = sizeof(buf);
437    const char * p;
438
439    if( init )
440        return buf;
441
442    p = tr_getPrefsDirectory ();
443
444#if defined(__BEOS__) || defined(WIN32)
445    tr_buildPath( buf, buflen, p, "Torrents", NULL );
446#elif defined( SYS_DARWIN )
447    tr_buildPath( buf, buflen, p, "Torrents", NULL );
448#else
449    tr_buildPath( buf, buflen, p, "torrents", NULL );
450#endif
451
452    tr_mkdirp( buf, 0777 );
453    init = 1;
454    return buf;
455}
Note: See TracBrowser for help on using the repository browser.