summaryrefslogtreecommitdiffstats
path: root/src/osxsupport.c
blob: aeae58711014b5721030868cb81c5992febcba41 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/* Unison file synchronizer: src/osxsupport.c */
/* Copyright 1999-2008 (see COPYING for details) */

#include <caml/mlvalues.h>
#include <caml/alloc.h>
#include <caml/memory.h>
#ifdef __APPLE__
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/attr.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif
#include <errno.h>

extern void unix_error (int errcode, char * cmdname, value arg) Noreturn;
extern void uerror (char * cmdname, value arg) Noreturn;

CAMLprim value isMacOSX (value nothing) {
#ifdef __APPLE__
  return Val_true;
#else
  return Val_false;
#endif
}

CAMLprim value getFileInfos (value path, value need_size) {
#ifdef __APPLE__

  CAMLparam1(path);
  CAMLlocal3(res, fInfo, length);
  int retcode;
  struct attrlist attrList;
  unsigned long options = FSOPT_REPORT_FULLSIZE;
  struct {
    u_int32_t length;
    char      finderInfo [32];
    off_t     rsrcLength;
  } __attribute__ ((packed)) attrBuf;

  attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
  attrList.reserved = 0;
  attrList.commonattr = ATTR_CMN_FNDRINFO;
  attrList.volattr = 0;     /* volume attribute group */
  attrList.dirattr = 0;     /* directory attribute group */
  if (Bool_val (need_size))
    attrList.fileattr = ATTR_FILE_RSRCLENGTH;    /* file attribute group */
  else
    attrList.fileattr = 0;
  attrList.forkattr = 0;    /* fork attribute group */

  retcode = getattrlist(String_val (path), &attrList, &attrBuf,
                        sizeof attrBuf, options);

  if (retcode == -1) uerror("getattrlist", path);

  if (Bool_val (need_size)) {
    if (attrBuf.length != sizeof attrBuf)
      unix_error (EINVAL, "getattrlist", path);
  } else {
    if (attrBuf.length != sizeof (u_int32_t) + 32)
      unix_error (EINVAL, "getattrlist", path);
  }

  fInfo = alloc_string (32);
  memcpy (String_val (fInfo), attrBuf.finderInfo, 32);
  if (Bool_val (need_size))
    length = copy_int64 (attrBuf.rsrcLength);
  else
    length = copy_int64 (0);

  res = alloc_small (2, 0);
  Field (res, 0) = fInfo;
  Field (res, 1) = length;

  CAMLreturn (res);

#else

  unix_error (ENOSYS, "getattrlist", path);

#endif
}

CAMLprim value setFileInfos (value path, value fInfo) {
#ifdef __APPLE__

  CAMLparam2(path, fInfo);
  int retcode;
  struct attrlist attrList;
  unsigned long options = 0;
  struct {
    u_int32_t length;
    char      finderInfo [32];
  } __attribute__ ((packed))  attrBuf;

  attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
  attrList.reserved = 0;
  attrList.commonattr = ATTR_CMN_FNDRINFO;
  attrList.volattr = 0;     /* volume attribute group */
  attrList.dirattr = 0;     /* directory attribute group */
  attrList.fileattr = 0;    /* file attribute group */
  attrList.forkattr = 0;    /* fork attribute group */

  memcpy (attrBuf.finderInfo, String_val (fInfo), 32);

  retcode = setattrlist(String_val (path), &attrList, attrBuf.finderInfo,
                        sizeof attrBuf.finderInfo, options);

  if (retcode == -1 && errno == EACCES) {
    /* Unlike with normal Unix attributes, we cannot set OS X attributes
       if file is read-only.  Try making it writable temporarily. */
    struct stat st;
    int r = stat(String_val(path), &st);
    if (r == -1) uerror("setattrlist", path);
    r = chmod(String_val(path), st.st_mode | S_IWUSR);
    if (r == -1) uerror("setattrlist", path);
    /* Try again */
    retcode = setattrlist(String_val (path), &attrList, attrBuf.finderInfo,
                          sizeof attrBuf.finderInfo, options);
    /* Whether or not that worked, we should try to set the mode back. */
    chmod(String_val(path), st.st_mode);
  }

  if (retcode == -1) uerror("setattrlist", path);

  CAMLreturn (Val_unit);

#else

  unix_error (ENOSYS, "setattrlist", path);

#endif
}