/ src / libsystem_coreservices / NSSystemDirectories.c
NSSystemDirectories.c
  1  /*
  2   * Copyright (c) 1999, 2008 Apple Inc. All rights reserved.
  3   *
  4   * @APPLE_LICENSE_HEADER_START@
  5   * 
  6   * This file contains Original Code and/or Modifications of Original Code
  7   * as defined in and that are subject to the Apple Public Source License
  8   * Version 2.0 (the 'License'). You may not use this file except in
  9   * compliance with the License. Please obtain a copy of the License at
 10   * http://www.opensource.apple.com/apsl/ and read it before using this
 11   * file.
 12   * 
 13   * The Original Code and all software distributed under the License are
 14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 18   * Please see the License for the specific language governing rights and
 19   * limitations under the License.
 20   * 
 21   * @APPLE_LICENSE_HEADER_END@
 22   */
 23  #include <NSSystemDirectories.h>
 24  #include <stdlib.h>
 25  #include <string.h>
 26  #include <sys/param.h>
 27  #include <unistd.h>
 28  #include <pthread.h>
 29  
 30  #define NSUserDomainIndex	0
 31  #define NSLocalDomainIndex	1
 32  #define NSNetworkDomainIndex	2
 33  #define NSSystemDomainIndex	3
 34  
 35  #define numDomains		(NSSystemDomainIndex + 1)
 36  #define DomainMask		((1 << numDomains) - 1)
 37  
 38  #define addNextRoot(x)		(*(x) == '/' || *(x) == 0)
 39  
 40  #define Network					"/Network"
 41  #define System					"/System"
 42  #define Tilde					"~"
 43  
 44  #define NSApplicationDirectoryBase		"/Applications"
 45  #define NSDemoApplicationDirectoryBase		"/Applications/Demos"
 46  #define NSDeveloperApplicationDirectoryBase	"/Developer/Applications"
 47  #define NSAdminApplicationDirectoryBase		"/Applications/Utilities"
 48  #define NSLibraryDirectoryBase			"/Library"
 49  #define NSDeveloperDirectoryBase		"/Developer"
 50  #define NSUserDirectoryBase			"/Users"
 51  #define NSDocumentationDirectoryBase		"/Library/Documentation"
 52  #define NSDocumentDirectoryBase			"/Documents"
 53  #define NSCoreServiceDirectoryBase		"/Library/CoreServices"
 54  #define NSAutosavedDocumentsDirectoryBase	"/Library/Autosave Information"
 55  #define NSDesktopDirectoryBase			"/Desktop"
 56  #define NSCachesDirectoryBase			"/Library/Caches"
 57  #define NSInputMethodsDirectoryBase		"/Library/Input Methods"
 58  #define NSMoviesDirectoryBase			"/Movies"
 59  #define NSMusicDirectoryBase			"/Music"
 60  #define NSPicturesDirectoryBase			"/Pictures"
 61  #define NSPrinterDescriptionDirectoryBase	"/Library/Printers/PPDs"
 62  #define NSSharedPublicDirectoryBase		"/Public"
 63  #define NSPreferencePanesDirectoryBase		"/Library/PreferencePanes"
 64  #define NSApplicationSupportDirectoryBase	"/Library/Application Support"
 65  #define NSDownloadsDirectoryBase		"/Downloads"
 66  
 67  static const char * const prefixAll[] = {
 68      Tilde,
 69      "",
 70      Network,
 71      ""
 72  };
 73  static const char * const prefixAllSystem[] = {
 74      Tilde,
 75      "",
 76      Network,
 77      System
 78  };
 79  static const char * const prefixNoUserSystem[] = {
 80      NULL,
 81      "",
 82      Network,
 83      NULL
 84  };
 85  static const char * const prefixNoNetwork[] = {
 86      Tilde,
 87      "",
 88      NULL,
 89      System
 90  };
 91  static const char * const prefixSystemOnly[] = {
 92      NULL,
 93      NULL,
 94      NULL,
 95      System
 96  };
 97  static const char * const prefixUserOnly[] = {
 98      Tilde,
 99      NULL,
100      NULL,
101      NULL
102  };
103  
104  static const char * const _prefixNetwork4[] = {
105      Network,
106      Network,
107      Network,
108      Network
109  };
110  static const char * const _prefixNone4[] = {
111      "",
112      "",
113      "",
114      ""
115  };
116  static const char * const _prefixTilde4[] = {
117      Tilde,
118      Tilde,
119      Tilde,
120      Tilde
121  };
122  static const char * const * const prefixAllApplicationsDirectory[] = {
123      _prefixTilde4,
124      _prefixNone4,
125      _prefixNetwork4,
126      _prefixNone4
127  };
128  static const char * const baseAllApplicationsDirectory[] = {
129      NSApplicationDirectoryBase,
130      NSAdminApplicationDirectoryBase,
131      NSDeveloperApplicationDirectoryBase,
132      NSDemoApplicationDirectoryBase
133  };
134  
135  static const char * const _prefixNetwork2[] = {
136      Network,
137      Network
138  };
139  static const char * const _prefixNone2[] = {
140      "",
141      ""
142  };
143  static const char * const _prefixSystemNone2[] = {
144      System,
145      ""
146  };
147  static const char * const _prefixTilde2[] = {
148      Tilde,
149      Tilde
150  };
151  static const char * const * const prefixAllLibrariesDirectory[] = {
152      _prefixTilde2,
153      _prefixNone2,
154      _prefixNetwork2,
155      _prefixSystemNone2
156  };
157  static const char * const baseAllLibrariesDirectory[] = {
158      NSLibraryDirectoryBase,
159      NSDeveloperDirectoryBase
160  };
161  
162  // The dirInfo table drives path creation
163  static struct {
164      int pathsPerDomain;
165      const void * const * const prefix;
166      const void * const base;
167  } dirInfo[] = {
168      { // NSApplicationDirectory
169  	1,
170  	(const void * const * const)prefixAll,
171  	(const void * const)NSApplicationDirectoryBase
172      },
173      { // NSDemoApplicationDirectory
174  	1,
175  	(const void * const * const)prefixAll,
176  	(const void * const)NSDemoApplicationDirectoryBase
177      },
178      { // NSDeveloperApplicationDirectory
179  	1,
180  	(const void * const * const)prefixAll,
181  	(const void * const)NSDeveloperApplicationDirectoryBase
182      },
183      { // NSAdminApplicationDirectory
184  	1,
185  	(const void * const * const)prefixAll,
186  	(const void * const)NSAdminApplicationDirectoryBase
187      },
188      { // NSLibraryDirectory
189  	1,
190  	(const void * const * const)prefixAllSystem,
191  	(const void * const)NSLibraryDirectoryBase
192      },
193      { // NSDeveloperDirectory
194  	1,
195  	(const void * const * const)prefixAll,
196  	(const void * const)NSDeveloperDirectoryBase
197      },
198      { // NSUserDirectory
199  	1,
200  	(const void * const * const)prefixNoUserSystem,
201  	(const void * const)NSUserDirectoryBase
202      },
203      { // NSDocumentationDirectory
204  	1,
205  	(const void * const * const)prefixAllSystem,
206  	(const void * const)NSDocumentationDirectoryBase
207      },
208      { // NSDocumentDirectory
209  	1,
210  	(const void * const * const)prefixUserOnly,
211  	(const void * const)NSDocumentDirectoryBase
212      },
213      { // NSCoreServiceDirectory
214  	1,
215  	(const void * const * const)prefixSystemOnly,
216  	(const void * const)NSCoreServiceDirectoryBase
217      },
218      { // NSAutosavedInformationDirectory
219  	1,
220  	(const void * const * const)prefixUserOnly,
221  	(const void * const)NSAutosavedDocumentsDirectoryBase
222      },
223      { // NSDesktopDirectory
224  	1,
225  	(const void * const * const)prefixUserOnly,
226  	(const void * const)NSDesktopDirectoryBase
227      },
228      { // NSCachesDirectory
229  	1,
230  	(const void * const * const)prefixNoNetwork,
231  	(const void * const)NSCachesDirectoryBase
232      },
233      { // NSApplicationSupportDirectory
234  	1,
235  	(const void * const * const)prefixAll,
236  	(const void * const)NSApplicationSupportDirectoryBase
237      },
238      { // NSDownloadsDirectory
239  	1,
240  	(const void * const * const)prefixUserOnly,
241  	(const void * const)NSDownloadsDirectoryBase
242      },
243      { // NSInputMethodsDirectory
244  	1,
245  	(const void * const * const)prefixAllSystem,
246  	(const void * const)NSInputMethodsDirectoryBase
247      },
248      { // NSMoviesDirectory
249  	1,
250  	(const void * const * const)prefixUserOnly,
251  	(const void * const)NSMoviesDirectoryBase
252      },
253      { // NSMusicDirectory
254  	1,
255  	(const void * const * const)prefixUserOnly,
256  	(const void * const)NSMusicDirectoryBase
257      },
258      { // NSPicturesDirectory
259  	1,
260  	(const void * const * const)prefixUserOnly,
261  	(const void * const)NSPicturesDirectoryBase
262      },
263      { // NSPrinterDescriptionDirectory
264  	1,
265  	(const void * const * const)prefixSystemOnly,
266  	(const void * const)NSPrinterDescriptionDirectoryBase
267      },
268      { // NSSharedPublicDirectory
269  	1,
270  	(const void * const * const)prefixUserOnly,
271  	(const void * const)NSSharedPublicDirectoryBase
272      },
273      { // NSPreferencePanesDirectory
274  	1,
275  	(const void * const * const)prefixNoNetwork,
276  	(const void * const)NSPreferencePanesDirectoryBase
277      },
278      { // NSAllApplicationsDirectory
279  	4,
280  	(const void * const * const)prefixAllApplicationsDirectory,
281  	(const void * const)baseAllApplicationsDirectory
282      },
283      { // NSAllLibrariesDirectory
284  	2,
285  	(const void * const * const)prefixAllLibrariesDirectory,
286  	(const void * const)baseAllLibrariesDirectory
287      }
288  };
289  
290  #define Index(dir)	(((dir) >= NSApplicationDirectory && (dir) <= NSPreferencePanesDirectory) ? ((dir) - 1) : (((dir) >= NSAllApplicationsDirectory && (dir) <= NSAllLibrariesDirectory) ? ((dir) - NSAllApplicationsDirectory + NSPreferencePanesDirectory) : -1))
291  
292  #define invalidDomains	0x00	// some domains may be invalid on non-Mach systems
293  #define ByteMask	0xff
294  #define DirShift	24
295  #define IndexShift	16
296  
297  NSSearchPathEnumerationState NSStartSearchPathEnumeration(NSSearchPathDirectory dir, NSSearchPathDomainMask domainMask) {
298      // The state is AABBCCCC, where
299      // AA is the dir(s) requested
300      // BB is the current state of dirs (if AA < 100, then this is always 0; otherwise it goes up to number of dirs)
301      // CCCC is the domains requested
302      // the state always contains the next item; if CCCC is 0, then we're done
303      int i;
304  
305      if((i = Index(dir)) < 0) {
306  	return 0;
307      }
308      domainMask = domainMask & DomainMask & ~invalidDomains;	// Just leave useful bits in there
309  
310      // Trim Duplicates - This assumes the compiler generates a single address
311      // for multiple occurrences of the same literal strings.
312      if ((domainMask & (NSLocalDomainMask | NSSystemDomainMask)) == (NSLocalDomainMask | NSSystemDomainMask) && dirInfo[i].prefix[NSLocalDomainIndex] == dirInfo[i].prefix[NSSystemDomainIndex]) {
313  	 domainMask &= ~NSSystemDomainMask;
314      }
315  
316      return (dir << DirShift) + domainMask;
317  }
318  
319  static const char       *nextRoot = NULL;
320  static pthread_once_t   nextRoot_init_once = PTHREAD_ONCE_INIT;
321  
322  static void
323  nextRoot_init(void)
324  {
325      if (!issetugid() && (nextRoot = getenv("NEXT_ROOT")) != NULL) {
326  	nextRoot = strdup(nextRoot);
327      }
328      if (nextRoot == NULL) {
329  	nextRoot = "";
330      }
331  }
332  
333  NSSearchPathEnumerationState NSGetNextSearchPathEnumeration(NSSearchPathEnumerationState state, char *path) {
334      int dir = (state >> DirShift) & ByteMask;
335      int domainMask = state & DomainMask;
336      int domain, i, n;
337      const char *prefix, *base;
338      
339      if ((i = Index(dir)) < 0 || (domain = ffs(domainMask)) == 0)
340  	return 0;
341      domain--; // adjust to zero-based index
342  
343      if ((n = dirInfo[i].pathsPerDomain) == 1) {
344  	const char * const *p = (const char * const *)dirInfo[i].prefix;
345  	for (;;) { // loop, skipping over invalid domains (prefix is NULL)
346  	    domainMask &= ~(1 << domain);
347  	    if ((prefix = p[domain]) != NULL) {
348  		break;
349  	    }
350  	    if ((domain = ffs(domainMask)) == 0) {
351  		return 0;
352  	    }
353  	    domain--; // adjust to zero-based index
354  	}
355  	base = (const char *)dirInfo[i].base;
356  	state = (dir << DirShift) + domainMask;
357      } else { // multiple paths per domain
358  	const char * const **p = (const char * const **)dirInfo[i].prefix;
359  	const char * const *b = (const char * const *)dirInfo[i].base;
360  	int dirIndex = (state >> IndexShift) & ByteMask;
361  
362  	if (dirIndex >= n) { // done with the current domain, go to the next
363  	    domainMask &= ~(1 << domain);
364  	    if ((domain = ffs(domainMask)) == 0) {
365  		return 0;
366  	    }
367  	    domain--; // adjust to zero-based index
368  	    dirIndex = 0;
369  	}
370  	prefix = p[domain][dirIndex];
371  	base = b[dirIndex];
372  	state = (dir << DirShift) + (++dirIndex << IndexShift) + domainMask;
373      }
374  
375      if (addNextRoot(prefix)) {
376  	if (pthread_once(&nextRoot_init_once, nextRoot_init) != 0 || nextRoot == NULL)// Error
377  	    return 0;
378  	strlcpy(path, nextRoot, PATH_MAX);
379      } else {
380  	*path = 0;
381      }
382      strlcat(path, prefix, PATH_MAX);
383      strlcat(path, base, PATH_MAX);
384   
385      return state;
386  }