source: trunk/libtransmission/platform.c @ 13696

Last change on this file since 13696 was 13696, checked in by jordan, 8 years ago

(trunk, libT) #3833 'freespace' argument for 'session-get' RPC method -- apply taem's 0001-Check-for-available-quota-when-getting-free-disk-spa.patch​ to check for available quota when getting free disk space

  • Property svn:keywords set to Date Rev Author Id
File size: 20.8 KB
Line 
1/*
2 * This file Copyright (C) Mnemosyne LLC
3 *
4 * This file is licensed by the GPL version 2. Works owned by the
5 * Transmission project are granted a special exemption to clause 2 (b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: platform.c 13696 2012-12-27 19:39:44Z jordan $
11 */
12
13#ifndef WIN32
14 #include <sys/quota.h> /* quotactl */
15 #ifdef HAVE_GETMNTENT
16  #include <mntent.h>
17  #include <paths.h> /* _PATH_MOUNTED */
18 #else /* BSD derived systems */
19  #include <sys/param.h>
20  #include <sys/ucred.h>
21  #include <sys/mount.h>
22 #endif
23#endif
24
25#ifdef WIN32
26 #include <w32api.h>
27 #define WINVER  WindowsXP
28 #include <windows.h>
29 #include <shlobj.h> /* for CSIDL_APPDATA, CSIDL_MYDOCUMENTS */
30#else
31 #ifdef SYS_DARWIN
32  #include <CoreFoundation/CoreFoundation.h>
33 #endif
34 #ifdef __HAIKU__
35  #include <FindDirectory.h>
36 #endif
37 #define _XOPEN_SOURCE 600  /* needed for recursive locks. */
38 #ifndef __USE_UNIX98
39  #define __USE_UNIX98 /* some older Linuxes need it spelt out for them */
40 #endif
41 #include <pthread.h>
42#endif
43
44#include <assert.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48
49#ifdef SYS_DARWIN
50 #define HAVE_SYS_STATVFS_H
51 #define HAVE_STATVFS
52#endif
53
54#include <sys/stat.h>
55#include <sys/types.h>
56#ifdef HAVE_SYS_STATVFS_H
57 #include <sys/statvfs.h>
58#endif
59#ifdef WIN32
60#include <libgen.h>
61#endif
62#include <dirent.h>
63#include <fcntl.h>
64#include <unistd.h> /* getuid getpid close */
65
66#include "transmission.h"
67#include "session.h"
68#include "list.h"
69#include "platform.h"
70#include "utils.h"
71
72/***
73****  THREADS
74***/
75
76#ifdef WIN32
77typedef DWORD tr_thread_id;
78#else
79typedef pthread_t tr_thread_id;
80#endif
81
82static tr_thread_id
83tr_getCurrentThread (void)
84{
85#ifdef WIN32
86  return GetCurrentThreadId ();
87#else
88  return pthread_self ();
89#endif
90}
91
92static bool
93tr_areThreadsEqual (tr_thread_id a, tr_thread_id b)
94{
95#ifdef WIN32
96  return a == b;
97#else
98  return pthread_equal (a, b) != 0;
99#endif
100}
101
102/** @brief portability wrapper around OS-dependent threads */
103struct tr_thread
104{
105  void          (* func)(void *);
106  void           * arg;
107  tr_thread_id     thread;
108#ifdef WIN32
109  HANDLE           thread_handle;
110#endif
111};
112
113bool
114tr_amInThread (const tr_thread * t)
115{
116  return tr_areThreadsEqual (tr_getCurrentThread (), t->thread);
117}
118
119#ifdef WIN32
120 #define ThreadFuncReturnType unsigned WINAPI
121#else
122 #define ThreadFuncReturnType void
123#endif
124
125static ThreadFuncReturnType
126ThreadFunc (void * _t)
127{
128  tr_thread * t = _t;
129
130  t->func (t->arg);
131
132  tr_free (t);
133#ifdef WIN32
134  _endthreadex (0);
135  return 0;
136#endif
137}
138
139tr_thread *
140tr_threadNew (void (*func)(void *), void * arg)
141{
142  tr_thread * t = tr_new0 (tr_thread, 1);
143
144  t->func = func;
145  t->arg  = arg;
146
147#ifdef WIN32
148  {
149    unsigned int id;
150    t->thread_handle = (HANDLE) _beginthreadex (NULL, 0, &ThreadFunc, t, 0, &id);
151    t->thread = (DWORD) id;
152  }
153#else
154  pthread_create (&t->thread, NULL, (void* (*)(void*))ThreadFunc, t);
155  pthread_detach (t->thread);
156#endif
157
158  return t;
159}
160
161/***
162****  LOCKS
163***/
164
165/** @brief portability wrapper around OS-dependent thread mutexes */
166struct tr_lock
167{
168  int                 depth;
169#ifdef WIN32
170  CRITICAL_SECTION    lock;
171  DWORD               lockThread;
172#else
173  pthread_mutex_t     lock;
174  pthread_t           lockThread;
175#endif
176};
177
178tr_lock*
179tr_lockNew (void)
180{
181  tr_lock * l = tr_new0 (tr_lock, 1);
182
183#ifdef WIN32
184  InitializeCriticalSection (&l->lock); /* supports recursion */
185#else
186  pthread_mutexattr_t attr;
187  pthread_mutexattr_init (&attr);
188  pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
189  pthread_mutex_init (&l->lock, &attr);
190#endif
191
192  return l;
193}
194
195void
196tr_lockFree (tr_lock * l)
197{
198#ifdef WIN32
199    DeleteCriticalSection (&l->lock);
200#else
201    pthread_mutex_destroy (&l->lock);
202#endif
203    tr_free (l);
204}
205
206void
207tr_lockLock (tr_lock * l)
208{
209#ifdef WIN32
210  EnterCriticalSection (&l->lock);
211#else
212  pthread_mutex_lock (&l->lock);
213#endif
214
215  assert (l->depth >= 0);
216  assert (!l->depth || tr_areThreadsEqual (l->lockThread, tr_getCurrentThread ()));
217  l->lockThread = tr_getCurrentThread ();
218  ++l->depth;
219}
220
221int
222tr_lockHave (const tr_lock * l)
223{
224  return (l->depth > 0) &&
225         (tr_areThreadsEqual (l->lockThread, tr_getCurrentThread ()));
226}
227
228void
229tr_lockUnlock (tr_lock * l)
230{
231  assert (l->depth > 0);
232  assert (tr_areThreadsEqual (l->lockThread, tr_getCurrentThread ()));
233
234  --l->depth;
235  assert (l->depth >= 0);
236#ifdef WIN32
237  LeaveCriticalSection (&l->lock);
238#else
239  pthread_mutex_unlock (&l->lock);
240#endif
241}
242
243/***
244****  PATHS
245***/
246
247#ifndef WIN32
248 #include <pwd.h>
249#endif
250
251static const char *
252getHomeDir (void)
253{
254  static char * home = NULL;
255
256  if (!home)
257    {
258      home = tr_strdup (getenv ("HOME"));
259
260      if (!home)
261        {
262#ifdef WIN32
263          char appdata[MAX_PATH]; /* SHGetFolderPath () requires MAX_PATH */
264          *appdata = '\0';
265          SHGetFolderPath (NULL, CSIDL_PERSONAL, NULL, 0, appdata);
266          home = tr_strdup (appdata);
267#else
268          struct passwd * pw = getpwuid (getuid ());
269          if (pw)
270            home = tr_strdup (pw->pw_dir);
271          endpwent ();
272#endif
273        }
274
275      if (!home)
276        home = tr_strdup ("");
277    }
278
279  return home;
280}
281
282static const char *
283getOldConfigDir (void)
284{
285  static char * path = NULL;
286
287  if (!path)
288    {
289#ifdef SYS_DARWIN
290      path = tr_buildPath (getHomeDir (), "Library",
291                           "Application Support",
292                           "Transmission", NULL);
293#elif defined (WIN32)
294      char appdata[MAX_PATH]; /* SHGetFolderPath () requires MAX_PATH */
295      SHGetFolderPath (NULL, CSIDL_APPDATA, NULL, 0, appdata);
296      path = tr_buildPath (appdata, "Transmission", NULL);
297#elif defined (__HAIKU__)
298      char buf[TR_PATH_MAX];
299      find_directory (B_USER_SETTINGS_DIRECTORY, -1, true, buf, sizeof (buf));
300      path = tr_buildPath (buf, "Transmission", NULL);
301#else
302      path = tr_buildPath (getHomeDir (), ".transmission", NULL);
303#endif
304    }
305
306  return path;
307}
308
309#if defined (SYS_DARWIN) || defined (WIN32)
310 #define RESUME_SUBDIR  "Resume"
311 #define TORRENT_SUBDIR "Torrents"
312#else
313 #define RESUME_SUBDIR  "resume"
314 #define TORRENT_SUBDIR "torrents"
315#endif
316
317static const char *
318getOldTorrentsDir (void)
319{
320  static char * path = NULL;
321
322  if (!path)
323    path = tr_buildPath (getOldConfigDir (), TORRENT_SUBDIR, NULL);
324
325  return path;
326}
327
328static const char *
329getOldCacheDir (void)
330{
331  static char * path = NULL;
332
333  if (!path)
334    {
335#if defined (WIN32)
336      path = tr_buildPath (getOldConfigDir (), "Cache", NULL);
337#elif defined (SYS_DARWIN)
338      path = tr_buildPath (getHomeDir (), "Library", "Caches", "Transmission", NULL);
339#else
340      path = tr_buildPath (getOldConfigDir (), "cache", NULL);
341#endif
342    }
343
344  return path;
345}
346
347static void
348moveFiles (const char * oldDir, const char * newDir)
349{
350  if (oldDir && newDir && strcmp (oldDir, newDir))
351    {
352      DIR * dirh = opendir (oldDir);
353      if (dirh)
354        {
355          int count = 0;
356          struct dirent * dirp;
357          while ((dirp = readdir (dirh)))
358            {
359              const char * name = dirp->d_name;
360              if (name && strcmp (name, ".") && strcmp (name, ".."))
361                {
362                  char * o = tr_buildPath (oldDir, name, NULL);
363                  char * n = tr_buildPath (newDir, name, NULL);
364                  rename (o, n);
365                  ++count;
366                  tr_free (n);
367                  tr_free (o);
368                }
369            }
370
371          if (count)
372            tr_inf (_("Migrated %1$d files from \"%2$s\" to \"%3$s\""), count, oldDir, newDir);
373
374          closedir (dirh);
375        }
376    }
377}
378
379/**
380 * This function is for transmission-gtk users to migrate the config files
381 * from $HOME/.transmission/ (where they were kept before Transmission 1.30)
382 * to $HOME/.config/$appname as per the XDG directory spec.
383 */
384static void
385migrateFiles (const tr_session * session)
386{
387  static int migrated = false;
388  const bool should_migrate = strstr (getOldConfigDir (), ".transmission") != NULL;
389
390  if (!migrated && should_migrate)
391    {
392      const char * oldDir;
393      const char * newDir;
394
395      migrated = true;
396
397      oldDir = getOldTorrentsDir ();
398      newDir = tr_getTorrentDir (session);
399      moveFiles (oldDir, newDir);
400
401      oldDir = getOldCacheDir ();
402      newDir = tr_getResumeDir (session);
403      moveFiles (oldDir, newDir);
404    }
405}
406
407void
408tr_setConfigDir (tr_session * session, const char * configDir)
409{
410  char * path;
411
412  session->configDir = tr_strdup (configDir);
413
414  path = tr_buildPath (configDir, RESUME_SUBDIR, NULL);
415  tr_mkdirp (path, 0777);
416  session->resumeDir = path;
417
418  path = tr_buildPath (configDir, TORRENT_SUBDIR, NULL);
419  tr_mkdirp (path, 0777);
420  session->torrentDir = path;
421
422  migrateFiles (session);
423}
424
425const char *
426tr_sessionGetConfigDir (const tr_session * session)
427{
428  return session->configDir;
429}
430
431const char *
432tr_getTorrentDir (const tr_session * session)
433{
434  return session->torrentDir;
435}
436
437const char *
438tr_getResumeDir (const tr_session * session)
439{
440  return session->resumeDir;
441}
442
443const char*
444tr_getDefaultConfigDir (const char * appname)
445{
446  static char * s = NULL;
447
448  if (!appname || !*appname)
449    appname = "Transmission";
450
451  if (!s)
452    {
453      if ((s = getenv ("TRANSMISSION_HOME")))
454        {
455          s = tr_strdup (s);
456        }
457        else
458        {
459#ifdef SYS_DARWIN
460          s = tr_buildPath (getHomeDir (), "Library", "Application Support", appname, NULL);
461#elif defined (WIN32)
462          char appdata[TR_PATH_MAX]; /* SHGetFolderPath () requires MAX_PATH */
463          SHGetFolderPath (NULL, CSIDL_APPDATA, NULL, 0, appdata);
464          s = tr_buildPath (appdata, appname, NULL);
465#elif defined (__HAIKU__)
466          char buf[TR_PATH_MAX];
467          find_directory (B_USER_SETTINGS_DIRECTORY, -1, true, buf, sizeof (buf));
468          s = tr_buildPath (buf, appname, NULL);
469#else
470          if ((s = getenv ("XDG_CONFIG_HOME")))
471            s = tr_buildPath (s, appname, NULL);
472          else
473            s = tr_buildPath (getHomeDir (), ".config", appname, NULL);
474#endif
475        }
476    }
477
478  return s;
479}
480
481const char*
482tr_getDefaultDownloadDir (void)
483{
484  static char * user_dir = NULL;
485
486  if (user_dir == NULL)
487    {
488      const char * config_home;
489      char * config_file;
490      char * content;
491      size_t content_len;
492
493      /* figure out where to look for user-dirs.dirs */
494      config_home = getenv ("XDG_CONFIG_HOME");
495      if (config_home && *config_home)
496        config_file = tr_buildPath (config_home, "user-dirs.dirs", NULL);
497      else
498        config_file = tr_buildPath (getHomeDir (), ".config", "user-dirs.dirs", NULL);
499
500      /* read in user-dirs.dirs and look for the download dir entry */
501      content = (char *) tr_loadFile (config_file, &content_len);
502      if (content && content_len>0)
503        {
504          const char * key = "XDG_DOWNLOAD_DIR=\"";
505          char * line = strstr (content, key);
506          if (line != NULL)
507            {
508              char * value = line + strlen (key);
509              char * end = strchr (value, '"');
510
511              if (end)
512                {
513                  *end = '\0';
514
515                  if (!memcmp (value, "$HOME/", 6))
516                    user_dir = tr_buildPath (getHomeDir (), value+6, NULL);
517                  else if (!strcmp (value, "$HOME"))
518                    user_dir = tr_strdup (getHomeDir ());
519                  else
520                    user_dir = tr_strdup (value);
521                }
522            }
523        }
524
525      if (user_dir == NULL)
526#ifdef __HAIKU__
527        user_dir = tr_buildPath (getHomeDir (), "Desktop", NULL);
528#else
529        user_dir = tr_buildPath (getHomeDir (), "Downloads", NULL);
530#endif
531
532      tr_free (content);
533      tr_free (config_file);
534    }
535
536  return user_dir;
537}
538
539/***
540****
541***/
542
543static int
544isWebClientDir (const char * path)
545{
546  struct stat sb;
547  char * tmp = tr_buildPath (path, "index.html", NULL);
548  const int ret = !stat (tmp, &sb);
549  tr_inf (_("Searching for web interface file \"%s\""), tmp);
550  tr_free (tmp);
551
552  return ret;
553}
554
555const char *
556tr_getWebClientDir (const tr_session * session UNUSED)
557{
558  static char * s = NULL;
559
560  if (!s)
561    {
562      if ((s = getenv ("CLUTCH_HOME")))
563        {
564          s = tr_strdup (s);
565        }
566      else if ((s = getenv ("TRANSMISSION_WEB_HOME")))
567        {
568          s = tr_strdup (s);
569        }
570      else
571        {
572
573#ifdef SYS_DARWIN /* on Mac, look in the Application Support folder first, then in the app bundle. */
574
575          /* Look in the Application Support folder */
576          s = tr_buildPath (tr_sessionGetConfigDir (session), "web", NULL);
577
578          if (!isWebClientDir (s))
579            {
580              tr_free (s);
581
582              CFURLRef appURL = CFBundleCopyBundleURL (CFBundleGetMainBundle ());
583              CFStringRef appRef = CFURLCopyFileSystemPath (appURL,
584                                                            kCFURLPOSIXPathStyle);
585              const CFIndex appStringLength = CFStringGetMaximumSizeOfFileSystemRepresentation (appRef);
586
587              char * appString = tr_malloc (appStringLength);
588              const bool success = CFStringGetFileSystemRepresentation (appRef, appString, appStringLength);
589              assert (success);
590
591              CFRelease (appURL);
592              CFRelease (appRef);
593
594              /* Fallback to the app bundle */
595              s = tr_buildPath (appString, "Contents", "Resources", "web", NULL);
596              if (!isWebClientDir (s))
597                {
598                  tr_free (s);
599                  s = NULL;
600                }
601
602              tr_free (appString);
603            }
604
605#elif defined (WIN32)
606
607          /* SHGetFolderPath explicitly requires MAX_PATH length */
608          char dir[MAX_PATH];
609
610          /* Generally, Web interface should be stored in a Web subdir of
611           * calling executable dir. */
612
613          if (s == NULL) /* check personal AppData/Transmission/Web */
614            {
615              SHGetFolderPath (NULL, CSIDL_COMMON_APPDATA, NULL, 0, dir);
616              s = tr_buildPath (dir, "Transmission", "Web", NULL);
617              if (!isWebClientDir (s))
618                {
619                  tr_free (s);
620                  s = NULL;
621                }
622            }
623
624          if (s == NULL) /* check personal AppData */
625            {
626              SHGetFolderPath (NULL, CSIDL_APPDATA, NULL, 0, dir);
627              s = tr_buildPath (dir, "Transmission", "Web", NULL);
628              if (!isWebClientDir (s))
629                {
630                  tr_free (s);
631                  s = NULL;
632                }
633            }
634
635            if (s == NULL) /* check calling module place */
636              {
637                GetModuleFileName (GetModuleHandle (NULL), dir, sizeof (dir));
638                s = tr_buildPath (dirname (dir), "Web", NULL);
639                if (!isWebClientDir (s))
640                  {
641                    tr_free (s);
642                    s = NULL;
643                  }
644            }
645
646#else /* everyone else, follow the XDG spec */
647
648          tr_list *candidates = NULL, *l;
649          const char * tmp;
650
651          /* XDG_DATA_HOME should be the first in the list of candidates */
652          tmp = getenv ("XDG_DATA_HOME");
653          if (tmp && *tmp)
654            {
655              tr_list_append (&candidates, tr_strdup (tmp));
656            }
657          else
658            {
659              char * dhome = tr_buildPath (getHomeDir (), ".local", "share", NULL);
660              tr_list_append (&candidates, dhome);
661            }
662
663          /* XDG_DATA_DIRS are the backup directories */
664          {
665            const char * pkg = PACKAGE_DATA_DIR;
666            const char * xdg = getenv ("XDG_DATA_DIRS");
667            const char * fallback = "/usr/local/share:/usr/share";
668            char * buf = tr_strdup_printf ("%s:%s:%s", (pkg?pkg:""), (xdg?xdg:""), fallback);
669            tmp = buf;
670            while (tmp && *tmp)
671              {
672                const char * end = strchr (tmp, ':');
673                if (end)
674                  {
675                    if ((end - tmp) > 1)
676                      tr_list_append (&candidates, tr_strndup (tmp, end - tmp));
677                    tmp = end + 1;
678                  }
679                else if (tmp && *tmp)
680                  {
681                    tr_list_append (&candidates, tr_strdup (tmp));
682                    break;
683                  }
684              }
685            tr_free (buf);
686          }
687
688          /* walk through the candidates & look for a match */
689          for (l=candidates; l; l=l->next)
690            {
691              char * path = tr_buildPath (l->data, "transmission", "web", NULL);
692              const int found = isWebClientDir (path);
693              if (found)
694                {
695                  s = path;
696                  break;
697                }
698              tr_free (path);
699            }
700
701          tr_list_free (&candidates, tr_free);
702
703#endif
704
705        }
706    }
707
708  return s;
709}
710
711/***
712****
713***/
714
715#ifndef WIN32
716static char *
717getdev( const char * path )
718{
719#ifdef HAVE_GETMNTENT
720        FILE *fp;
721        struct mntent *mnt;
722
723        if ((fp = setmntent(_PATH_MOUNTED, "r")) == NULL)
724        {
725                return NULL;
726        }
727        while ((mnt = getmntent(fp)) != NULL)
728        {
729                if (strcmp(path, mnt->mnt_dir) == 0)
730                {
731                        break;
732                }
733        }
734        endmntent(fp);
735        return mnt ? mnt->mnt_fsname : NULL;
736#else /* BSD derived systems */
737        int n, i;
738        struct statfs *mnt;
739
740        if ((n = getmntinfo(&mnt, MNT_WAIT)) == 0)
741        {
742                return NULL;
743        }
744        for (i=0; i<n; i++)
745        {
746                if (strcmp(path, mnt[i].f_mntonname) == 0)
747                {
748                        break;
749                }
750        }
751        return (i < n) ? mnt[i].f_mntfromname : NULL;
752#endif
753}
754
755static char *
756getblkdev( const char * path )
757{
758        char *dir, *c;
759        char *device;
760
761        dir = tr_strdup(path);
762        while (1)
763        {
764                if ((device = getdev(dir)) != NULL)
765                {
766                        break;
767                }
768                if ((c = strrchr(dir, '/')) != NULL)
769                {
770                        *c = '\0';
771                }
772                else
773                {
774                        break;
775                }
776        }
777        tr_free(dir);
778        return device;
779}
780
781static int64_t
782getquota( char * device )
783{
784        struct dqblk dq;
785        int64_t freespace, limit;
786
787        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device, getuid(),
788                        (caddr_t) & dq) == 0)
789        {
790                if (dq.dqb_bsoftlimit > 0)
791                {
792                        /* Use soft limit first */
793                        limit = dq.dqb_bsoftlimit;
794                }
795                else if (dq.dqb_bhardlimit > 0)
796                {
797                        limit = dq.dqb_bhardlimit;
798                }
799                else
800                {
801                        /* No quota enabled for this user */
802                        return -1;
803                }
804                freespace = limit - btodb(dq.dqb_curspace);
805                return (freespace < 0) ? 0 : freespace * 1024;
806        }
807
808        /* Something went wrong */
809        return -1;
810}
811#endif
812
813static int64_t
814tr_getQuotaFreeSpace( const char * path )
815{
816    int64_t ret=-1;
817#ifndef WIN32
818    char *device;
819
820    if ((device = getblkdev(path)) != NULL)
821    {
822        ret = getquota(device);
823    }
824#endif
825    return ret;
826}
827
828static int64_t
829tr_getDiskFreeSpace( const char * path )
830{
831#ifdef WIN32
832    uint64_t freeBytesAvailable = 0;
833    return GetDiskFreeSpaceEx( path, &freeBytesAvailable, NULL, NULL)
834        ? (int64_t)freeBytesAvailable
835        : -1;
836#elif defined(HAVE_STATVFS)
837    struct statvfs buf;
838    return statvfs( path, &buf ) ? -1 : (int64_t)buf.f_bavail * (int64_t)buf.f_frsize;
839#else
840    #warning FIXME: not implemented
841    return -1;
842#endif
843}
844
845int64_t
846tr_getFreeSpace( const char * path )
847{
848    int64_t i = tr_getQuotaFreeSpace( path );
849    if( i < 0 )
850        i = tr_getDiskFreeSpace( path );
851    return i;
852}
853
854/***
855****
856***/
857
858#ifdef WIN32
859
860/* The following mmap functions are by Joerg Walter, and were taken from
861 * his paper at: http://www.genesys-e.de/jwalter/mix4win.htm */
862
863#if defined (_MSC_VER)
864__declspec (align (4)) static LONG volatile g_sl;
865#else
866static LONG volatile g_sl __attribute__((aligned (4)));
867#endif
868
869/* Wait for spin lock */
870static int
871slwait (LONG volatile *sl)
872{
873  while (InterlockedCompareExchange (sl, 1, 0) != 0)
874    Sleep (0);
875
876  return 0;
877}
878
879/* Release spin lock */
880static int
881slrelease (LONG volatile *sl)
882{
883  InterlockedExchange (sl, 0);
884  return 0;
885}
886
887/* getpagesize for windows */
888static long
889getpagesize (void)
890{
891  static long g_pagesize = 0;
892
893  if (!g_pagesize)
894    {
895      SYSTEM_INFO system_info;
896      GetSystemInfo (&system_info);
897      g_pagesize = system_info.dwPageSize;
898    }
899
900  return g_pagesize;
901}
902
903static long
904getregionsize (void)
905{
906  static long g_regionsize = 0;
907
908  if (!g_regionsize)
909    {
910      SYSTEM_INFO system_info;
911      GetSystemInfo (&system_info);
912      g_regionsize = system_info.dwAllocationGranularity;
913    }
914
915  return g_regionsize;
916}
917
918void *
919mmap (void *ptr, long  size, long  prot, long  type, long  handle, long  arg)
920{
921  static long g_pagesize;
922  static long g_regionsize;
923
924  /* Wait for spin lock */
925  slwait (&g_sl);
926
927  /* First time initialization */
928  if (!g_pagesize)
929    g_pagesize = getpagesize ();
930  if (!g_regionsize)
931    g_regionsize = getregionsize ();
932
933  /* Allocate this */
934  ptr = VirtualAlloc (ptr, size, MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE);
935  if (!ptr)
936    {
937      ptr = (void *) -1;
938      goto mmap_exit;
939    }
940
941mmap_exit:
942  /* Release spin lock */
943  slrelease (&g_sl);
944  return ptr;
945}
946
947long
948munmap (void *ptr, long size)
949{
950  static long g_pagesize;
951  static long g_regionsize;
952  int rc = -1;
953
954  /* Wait for spin lock */
955  slwait (&g_sl);
956
957  /* First time initialization */
958  if (!g_pagesize)
959    g_pagesize = getpagesize ();
960  if (!g_regionsize)
961    g_regionsize = getregionsize ();
962
963  /* Free this */
964  if (!VirtualFree (ptr, 0, MEM_RELEASE))
965    goto munmap_exit;
966
967  rc = 0;
968
969munmap_exit:
970  /* Release spin lock */
971  slrelease (&g_sl);
972  return rc;
973}
974
975#endif
Note: See TracBrowser for help on using the repository browser.