]> arthur.barton.de Git - netatalk.git/blob - libatalk/vfs/unix.c
Fix several warnings, remove const
[netatalk.git] / libatalk / vfs / unix.c
1 /*
2  * Copyright (c) 1990,1993 Regents of The University of Michigan.
3  * All Rights Reserved.  See COPYRIGHT.
4  */
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif /* HAVE_CONFIG_H */
9
10 #include <unistd.h>
11 #include <errno.h>
12 #include <stdlib.h>
13 #include <sys/param.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <string.h>
17
18 #include <atalk/afp.h>
19 #include <atalk/util.h>
20 #include <atalk/directory.h>
21 #include <atalk/volume.h>
22 #include <atalk/logger.h>
23 #include <atalk/unix.h>
24 #include <atalk/acl.h>
25 #include <atalk/compat.h>
26 #include <atalk/errchk.h>
27 #include <atalk/ea.h>
28
29 /* ------------------------- */
30 int dir_rx_set(mode_t mode)
31 {
32     return (mode & (S_IXUSR | S_IRUSR)) == (S_IXUSR | S_IRUSR);
33 }
34
35 /* --------------------- */
36 int setfilmode(const struct vol *vol, const char *name, mode_t mode, struct stat *st)
37 {
38     struct stat sb;
39     mode_t mask = S_IRWXU | S_IRWXG | S_IRWXO;  /* rwx for owner group and other, by default */
40
41     if (!st) {
42         if (lstat(name, &sb) != 0)
43             return -1;
44         st = &sb;
45     }
46
47     mode |= st->st_mode & ~mask; /* keep other bits from previous mode */
48
49     if (ochmod((char *)name, mode & ~vol->v_umask, st, vol_syml_opt(vol) | O_NETATALK_ACL) < 0 && errno != EPERM ) {
50         return -1;
51     }
52     return 0;
53 }
54
55 /*
56  * @brief system rmdir with afp error code.
57  *
58  * Supports *at semantics (cf openat) if HAVE_ATFUNCS. Pass dirfd=-1 to ignore this.
59  */
60 int netatalk_rmdir_all_errors(int dirfd, const char *name)
61 {
62     int err;
63
64 #ifdef HAVE_ATFUNCS
65     if (dirfd == -1)
66         dirfd = AT_FDCWD;
67     err = unlinkat(dirfd, name, AT_REMOVEDIR);
68 #else
69     err = rmdir(name);
70 #endif
71
72     if (err < 0) {
73         switch ( errno ) {
74         case ENOENT :
75             return AFPERR_NOOBJ;
76         case ENOTEMPTY :
77             return AFPERR_DIRNEMPT;
78         case EPERM:
79         case EACCES :
80             return AFPERR_ACCESS;
81         case EROFS:
82             return AFPERR_VLOCK;
83         default :
84             return AFPERR_PARAM;
85         }
86     }
87     return AFP_OK;
88 }
89
90 /*
91  * @brief System rmdir with afp error code, but ENOENT is not an error.
92  *
93  * Supports *at semantics (cf openat) if HAVE_ATFUNCS. Pass dirfd=-1 to ignore this.
94  */
95 int netatalk_rmdir(int dirfd, const char *name)
96 {
97     int ret = netatalk_rmdir_all_errors(dirfd, name);
98     if (ret == AFPERR_NOOBJ)
99         return AFP_OK;
100     return ret;
101 }
102
103 /* -------------------
104    system unlink with afp error code.
105    ENOENT is not an error.
106 */
107 int netatalk_unlink(const char *name)
108 {
109     if (unlink(name) < 0) {
110         switch (errno) {
111         case ENOENT :
112             break;
113         case EROFS:
114             return AFPERR_VLOCK;
115         case EPERM:
116         case EACCES :
117             return AFPERR_ACCESS;
118         default :
119             return AFPERR_PARAM;
120         }
121     }
122     return AFP_OK;
123 }
124
125 /**************************************************************************
126  * *at semnatics support functions (like openat, renameat standard funcs)
127  **************************************************************************/
128
129 /* Copy all file data from one file fd to another */
130 int copy_file_fd(int sfd, int dfd)
131 {
132     EC_INIT;
133     ssize_t cc;
134     size_t  buflen;
135     char   filebuf[NETATALK_DIOSZ_STACK];
136
137     while ((cc = read(sfd, filebuf, sizeof(filebuf)))) {
138         if (cc < 0) {
139             if (errno == EINTR)
140                 continue;
141             LOG(log_error, logtype_afpd, "copy_file_fd: %s", strerror(errno));
142             EC_FAIL;
143         }
144
145         buflen = cc;
146         while (buflen > 0) {
147             if ((cc = write(dfd, filebuf, buflen)) < 0) {
148                 if (errno == EINTR)
149                     continue;
150                 LOG(log_error, logtype_afpd, "copy_file_fd: %s", strerror(errno));
151                 EC_FAIL;
152             }
153             buflen -= cc;
154         }
155     }
156
157 EC_CLEANUP:
158     EC_EXIT;
159 }
160
161 /* 
162  * Supports *at semantics if HAVE_ATFUNCS, pass dirfd=-1 to ignore this
163  */
164 int copy_file(int dirfd, const char *src, const char *dst, mode_t mode)
165 {
166     int    ret = 0;
167     int    sfd = -1;
168     int    dfd = -1;
169     ssize_t cc;
170     size_t  buflen;
171     char   filebuf[NETATALK_DIOSZ_STACK];
172
173 #ifdef HAVE_ATFUNCS
174     if (dirfd == -1)
175         dirfd = AT_FDCWD;
176     sfd = openat(dirfd, src, O_RDONLY);
177 #else
178     sfd = open(src, O_RDONLY);
179 #endif
180     if (sfd < 0) {
181         LOG(log_info, logtype_afpd, "copy_file('%s'/'%s'): open '%s' error: %s",
182             src, dst, src, strerror(errno));
183         return -1;
184     }
185
186     if ((dfd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, mode)) < 0) {
187         LOG(log_info, logtype_afpd, "copy_file('%s'/'%s'): open '%s' error: %s",
188             src, dst, dst, strerror(errno));
189         ret = -1;
190         goto exit;
191     }
192
193     ret = copy_file_fd(sfd, dfd);
194
195 exit:
196     if (sfd != -1)
197         close(sfd);
198
199     if (dfd != -1) {
200         int err;
201
202         err = close(dfd);
203         if (!ret && err) {
204             /* don't bother to report an error if there's already one */
205             LOG(log_error, logtype_afpd, "copy_file('%s'/'%s'): close '%s' error: %s",
206                 src, dst, dst, strerror(errno));
207             ret = -1;
208         }
209     }
210
211     return ret;
212 }
213
214 /*!
215  * Copy an EA from one file to another
216  *
217  * Supports *at semantics if HAVE_ATFUNCS, pass dirfd=-1 to ignore this
218  */
219 int copy_ea(const char *ea, int dirfd, const char *src, const char *dst, mode_t mode)
220 {
221     EC_INIT;
222     int    sfd = -1;
223     int    dfd = -1;
224     size_t easize;
225     char   *eabuf = NULL;
226
227 #ifdef HAVE_ATFUNCS
228     if (dirfd == -1)
229         dirfd = AT_FDCWD;
230     EC_NEG1_LOG( sfd = openat(dirfd, src, O_RDONLY) );
231 #else
232     EC_NEG1_LOG( sfd = open(src, O_RDONLY) );
233 #endif
234     EC_NEG1_LOG( dfd = open(dst, O_WRONLY, mode) );
235
236     if ((easize = sys_fgetxattr(sfd, ea, NULL, 0)) > 0) {
237         EC_NULL_LOG( eabuf = malloc(easize));
238         EC_NEG1_LOG( easize = sys_fgetxattr(sfd, ea, eabuf, easize) );
239         EC_NEG1_LOG( easize = sys_fsetxattr(dfd, ea, eabuf, easize, 0) );
240     }
241
242 EC_CLEANUP:
243     if (sfd != -1)
244         close(sfd);
245     if (dfd != -1)
246         close(dfd);
247     free(eabuf);
248     EC_EXIT;
249 }
250
251 /* 
252  * at wrapper for netatalk_unlink
253  */
254 int netatalk_unlinkat(int dirfd, const char *name)
255 {
256 #ifdef HAVE_ATFUNCS
257     if (dirfd == -1)
258         dirfd = AT_FDCWD;
259
260     if (unlinkat(dirfd, name, 0) < 0) {
261         switch (errno) {
262         case ENOENT :
263             break;
264         case EROFS:
265             return AFPERR_VLOCK;
266         case EPERM:
267         case EACCES :
268             return AFPERR_ACCESS;
269         default :
270             return AFPERR_PARAM;
271         }
272     }
273     return AFP_OK;
274 #else
275     return netatalk_unlink(name);
276 #endif
277
278     /* DEADC0DE */
279     return 0;
280 }
281
282 /*
283  * @brief This is equivalent of unix rename()
284  *
285  * unix_rename mulitplexes rename and renameat. If we dont HAVE_ATFUNCS, sfd and dfd
286  * are ignored.
287  *
288  * @param sfd        (r) if we HAVE_ATFUNCS, -1 gives AT_FDCWD
289  * @param oldpath    (r) guess what
290  * @param dfd        (r) same as sfd
291  * @param newpath    (r) guess what
292  */
293 int unix_rename(int sfd, const char *oldpath, int dfd, const char *newpath)
294 {
295 #ifdef HAVE_ATFUNCS
296     if (sfd == -1)
297         sfd = AT_FDCWD;
298     if (dfd == -1)
299         dfd = AT_FDCWD;
300
301     if (renameat(sfd, oldpath, dfd, newpath) < 0)
302         return -1;        
303 #else
304     if (rename(oldpath, newpath) < 0)
305         return -1;
306 #endif  /* HAVE_ATFUNCS */
307
308     return 0;
309 }
310
311 /* 
312  * @brief stat/fsstatat multiplexer
313  *
314  * statat mulitplexes stat and fstatat. If we dont HAVE_ATFUNCS, dirfd is ignored.
315  *
316  * @param dirfd   (r) Only used if HAVE_ATFUNCS, ignored else, -1 gives AT_FDCWD
317  * @param path    (r) pathname
318  * @param st      (rw) pointer to struct stat
319  */
320 int statat(int dirfd, const char *path, struct stat *st)
321 {
322 #ifdef HAVE_ATFUNCS
323     if (dirfd == -1)
324         dirfd = AT_FDCWD;
325     return (fstatat(dirfd, path, st, 0));
326 #else
327     return (stat(path, st));
328 #endif            
329
330     /* DEADC0DE */
331     return -1;
332 }
333
334 /* 
335  * @brief opendir wrapper for *at semantics support
336  *
337  * opendirat chdirs to dirfd if dirfd != -1 before calling opendir on path.
338  *
339  * @param dirfd   (r) if != -1, chdir(dirfd) before opendir(path)
340  * @param path    (r) pathname
341  */
342 DIR *opendirat(int dirfd, const char *path)
343 {
344     DIR *ret;
345     int cwd = -1;
346
347     if (dirfd != -1) {
348         if (((cwd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) {
349             ret = NULL;
350             goto exit;
351         }
352     }
353
354     ret = opendir(path);
355
356     if (dirfd != -1 && fchdir(cwd) != 0) {
357         LOG(log_error, logtype_afpd, "opendirat: cant chdir back. exit!");
358         exit(EXITERR_SYS);
359     }
360
361 exit:
362     if (cwd != -1)
363         close(cwd);
364
365     return ret;
366 }