]> arthur.barton.de Git - netatalk.git/blob - libatalk/vfs/unix.c
copy_file use the right type ssize_t for ccor cc < 0 is always false
[netatalk.git] / libatalk / vfs / unix.c
1 /*
2  * $Id: unix.c,v 1.3 2009-10-16 00:40:48 didg Exp $
3  *
4  * Copyright (c) 1990,1993 Regents of The University of Michigan.
5  * All Rights Reserved.  See COPYRIGHT.
6  *
7  */
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif /* HAVE_CONFIG_H */
12
13 #include <unistd.h>
14 #include <errno.h>
15 #include <sys/param.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <string.h>
19
20 #include <atalk/afp.h>
21 #include <atalk/util.h>
22 #include <atalk/directory.h>
23 #include <atalk/volume.h>
24 #include <atalk/logger.h>
25 #include <atalk/unix.h>
26
27 /* -----------------------------
28    a dropbox is a folder where w is set but not r eg:
29    rwx-wx-wx or rwx-wx-- 
30    rwx----wx (is not asked by a Mac with OS >= 8.0 ?)
31 */
32 int stickydirmode(const char *name, const mode_t mode, const int dropbox, const mode_t v_umask)
33 {
34     int retval = 0;
35
36 #ifdef DROPKLUDGE
37     /* Turn on the sticky bit if this is a drop box, also turn off the setgid bit */
38     if ((dropbox & AFPVOL_DROPBOX)) {
39         int uid;
40
41         if ( ( (mode & S_IWOTH) && !(mode & S_IROTH)) ||
42              ( (mode & S_IWGRP) && !(mode & S_IRGRP)) )
43         {
44             uid=geteuid();
45             if ( seteuid(0) < 0) {
46                 LOG(log_error, logtype_afpd, "stickydirmode: unable to seteuid root: %s", strerror(errno));
47             }
48             if ( (retval=chmod( name, ( (DIRBITS | mode | S_ISVTX) & ~v_umask) )) < 0) {
49                 LOG(log_error, logtype_afpd, "stickydirmode: chmod \"%s\": %s", fullpathname(name), strerror(errno) );
50             } else {
51                 LOG(log_debug, logtype_afpd, "stickydirmode: chmod \"%s\": %s", fullpathname(name), strerror(retval) );
52             }
53             seteuid(uid);
54             return retval;
55         }
56     }
57 #endif /* DROPKLUDGE */
58
59     /*
60      *  Ignore EPERM errors:  We may be dealing with a directory that is
61      *  group writable, in which case chmod will fail.
62      */
63     if ( (chmod( name, (DIRBITS | mode) & ~v_umask ) < 0) && errno != EPERM && 
64                 !(errno == ENOENT && (dropbox & AFPVOL_NOADOUBLE)) )  
65     {
66         LOG(log_error, logtype_afpd, "stickydirmode: chmod \"%s\": %s", fullpathname(name), strerror(errno) );
67         retval = -1;
68     }
69
70     return retval;
71 }
72
73 /* ------------------------- */
74 int dir_rx_set(mode_t mode)
75 {
76     return (mode & (S_IXUSR | S_IRUSR)) == (S_IXUSR | S_IRUSR);
77 }
78
79 /* --------------------- */
80 int setfilmode(const char * name, mode_t mode, struct stat *st, mode_t v_umask)
81 {
82 struct stat sb;
83 mode_t mask = S_IRWXU | S_IRWXG | S_IRWXO;  /* rwx for owner group and other, by default */
84
85     if (!st) {
86         if (stat(name, &sb) != 0)
87             return -1;
88         st = &sb;
89     }
90    
91    mode |= st->st_mode & ~mask; /* keep other bits from previous mode */
92    if ( chmod( name,  mode & ~v_umask ) < 0 && errno != EPERM ) {
93        return -1;
94    }
95    return 0;
96 }
97
98 /* -------------------
99    system rmdir with afp error code.
100    ENOENT is not an error.
101  */
102 int netatalk_rmdir(const char *name)
103 {
104     if (rmdir(name) < 0) {
105         switch ( errno ) {
106         case ENOENT :
107             break;
108         case ENOTEMPTY : 
109             return AFPERR_DIRNEMPT;
110         case EPERM:
111         case EACCES :
112             return AFPERR_ACCESS;
113         case EROFS:
114             return AFPERR_VLOCK;
115         default :
116             return AFPERR_PARAM;
117         }
118     }
119     return AFP_OK;
120 }
121
122 /* -------------------
123    system unlink with afp error code.
124    ENOENT is not an error.
125  */
126 int netatalk_unlink(const char *name)
127 {
128     if (unlink(name) < 0) {
129         switch (errno) {
130         case ENOENT :
131             break;
132         case EROFS:
133             return AFPERR_VLOCK;
134         case EPERM:
135         case EACCES :
136             return AFPERR_ACCESS;
137         default :
138             return AFPERR_PARAM;
139         }
140     }
141     return AFP_OK;
142 }
143
144 char *fullpathname(const char *name)
145 {
146     static char wd[ MAXPATHLEN + 1];
147
148     if ( getcwd( wd , MAXPATHLEN) ) {
149         strlcat(wd, "/", MAXPATHLEN);
150         strlcat(wd, name, MAXPATHLEN);
151     }
152     else {
153         strlcpy(wd, name, MAXPATHLEN);
154     }
155     return wd;
156 }
157
158 int copy_file(const char *src, const char *dst, mode_t mode)
159 {
160     int    ret = 0;
161     int    sfd = -1;
162     int    dfd = -1;
163     ssize_t cc;
164     char   filebuf[8192];
165
166     if ((sfd = open(src, O_RDONLY)) < 0) {
167         LOG(log_error, logtype_afpd, "copy_file('%s'/'%s'): open '%s' error: %s",
168             src, dst, src, strerror(errno));
169         return -1;
170     }
171
172     if ((dfd = open(dst, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0) {
173         LOG(log_error, logtype_afpd, "copy_file('%s'/'%s'): open '%s' error: %s",
174             src, dst, dst, strerror(errno));
175         ret = -1;
176         goto exit;
177     }
178
179     while ((cc = read(sfd, filebuf, sizeof(filebuf)))) {
180         if (cc < 0) {
181             if (errno == EINTR)
182                 continue;
183             LOG(log_error, logtype_afpd, "copy_file('%s'/'%s'): read '%s' error: %s",
184                 src, dst, src, strerror(errno));
185             ret = -1;
186             goto exit;
187         }
188
189         while (cc > 0) {
190             if ((cc -= write(dfd, filebuf, cc)) < 0) {
191                 if (errno == EINTR)
192                     continue;
193                 LOG(log_error, logtype_afpd, "copy_file('%s'/'%s'): read '%s' error: %s",
194                     src, dst, dst, strerror(errno));
195                 ret = -1;
196                 goto exit;
197             }
198         }
199     }
200
201 exit:
202     if (sfd != -1)
203         close(sfd);
204     if (dfd != -1)
205         close(dfd);
206
207     return ret;
208 }