]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/file.c
createfile: return the right error code if disk full, from Tsiyon Sadiky, exanet
[netatalk.git] / etc / afpd / file.c
1 /*
2  * $Id: file.c,v 1.101 2006-09-15 00:09:23 didg Exp $
3  *
4  * Copyright (c) 1990,1993 Regents of The University of Michigan.
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14
15 /* STDC check */
16 #if STDC_HEADERS
17 #include <string.h>
18 #else /* STDC_HEADERS */
19 #ifndef HAVE_STRCHR
20 #define strchr index
21 #define strrchr index
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
24
25 #ifndef HAVE_MEMCPY
26 #define memcpy(d,s,n) bcopy ((s), (d), (n))
27 #define memmove(d,s,n) bcopy ((s), (d), (n))
28 #endif /* ! HAVE_MEMCPY */
29 #endif /* STDC_HEADERS */
30
31 #include <atalk/adouble.h>
32 #include <utime.h>
33 #include <dirent.h>
34 #include <errno.h>
35
36 #include <atalk/logger.h>
37 #include <sys/param.h>
38
39
40 #include <atalk/afp.h>
41 #include <atalk/util.h>
42 #include <atalk/cnid.h>
43 #include "directory.h"
44 #include "desktop.h"
45 #include "volume.h"
46 #include "fork.h"
47 #include "file.h"
48 #include "filedir.h"
49 #include "globals.h"
50 #include "unix.h"
51
52 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
53  * field         bytes        subfield    bytes
54  * 
55  * files:
56  * ioFlFndrInfo  16      ->       type    4  type field
57  *                             creator    4  creator field
58  *                               flags    2  finder flags:
59  *                                           alias, bundle, etc.
60  *                            location    4  location in window
61  *                              folder    2  window that contains file
62  * 
63  * ioFlXFndrInfo 16      ->     iconID    2  icon id
64  *                              unused    6  reserved 
65  *                              script    1  script system
66  *                              xflags    1  reserved
67  *                           commentID    2  comment id
68  *                           putawayID    4  home directory id
69  */
70
71 const u_char ufinderi[ADEDLEN_FINDERI] = {
72                               0, 0, 0, 0, 0, 0, 0, 0,
73                               1, 0, 0, 0, 0, 0, 0, 0,
74                               0, 0, 0, 0, 0, 0, 0, 0,
75                               0, 0, 0, 0, 0, 0, 0, 0
76                           };
77
78 static const u_char old_ufinderi[] = {
79                               'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X'
80                           };
81
82 /* ---------------------- 
83 */
84 static int default_type(void *finder) 
85 {
86     if (!memcmp(finder, ufinderi, 8) || !memcmp(finder, old_ufinderi, 8))
87         return 1;
88     return 0;
89 }
90
91 /* FIXME path : unix or mac name ? (for now it's unix name ) */
92 void *get_finderinfo(const char *upath, struct adouble *adp, void *data)
93 {
94     struct extmap       *em;
95     void                *ad_finder = NULL;
96     int                 chk_ext = 0;
97     
98     if (adp)
99         ad_finder = ad_entry(adp, ADEID_FINDERI);
100
101     if (ad_finder) {
102         memcpy(data, ad_finder, ADEDLEN_FINDERI);
103         /* default type ? */
104         if (default_type(ad_finder)) 
105             chk_ext = 1;
106     }
107     else {
108         memcpy(data, ufinderi, ADEDLEN_FINDERI);
109         chk_ext = 1;
110         if (*upath == '.') { /* make it invisible */
111             u_int16_t ashort;
112             
113             ashort = htons(FINDERINFO_INVISIBLE);
114             memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
115         }
116     }
117     /** Only enter if no appledouble information and no finder information found. */
118     if (chk_ext && (em = getextmap( upath ))) {
119         memcpy(data, em->em_type, sizeof( em->em_type ));
120         memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
121     }
122     return data;
123 }
124
125 /* ---------------------
126 */
127 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8) 
128 {
129     u_int32_t   aint;
130     char        *tp = NULL;
131     char        *src = name;
132     aint = strlen( name );
133
134     if (!utf8) {
135         /* want mac name */
136         if (utf8_encoding()) {
137             /* but name is an utf8 mac name */
138             char *u, *m;
139            
140             /* global static variable... */
141             tp = strdup(name);
142             if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
143                aint = 0;
144             }
145             else {
146                 aint = strlen(m);
147                 src = m;
148             }
149             
150         }
151         if (aint > MACFILELEN)
152             aint = MACFILELEN;
153         *data++ = aint;
154     }
155     else {
156         u_int16_t temp;
157
158         if (aint > 255)  /* FIXME safeguard, anyway if no ascii char it's game over*/
159            aint = 255;
160
161         utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0;         /* htonl(utf8) */
162         memcpy(data, &utf8, sizeof(utf8));
163         data += sizeof(utf8);
164         
165         temp = htons(aint);
166         memcpy(data, &temp, sizeof(temp));
167         data += sizeof(temp);
168     }
169
170     memcpy( data, src, aint );
171     data += aint;
172     if (tp) {
173         strcpy(name, tp);
174         free(tp);
175     }
176     return data;
177 }
178
179 /*
180  * FIXME: PDINFO is UTF8 and doesn't need adp
181 */
182 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR)  |\
183                                   (1 << FILPBIT_CDATE) |\
184                                   (1 << FILPBIT_MDATE) |\
185                                   (1 << FILPBIT_BDATE) |\
186                                   (1 << FILPBIT_FINFO) |\
187                                   (1 << FILPBIT_RFLEN) |\
188                                   (1 << FILPBIT_EXTRFLEN) |\
189                                   (1 << FILPBIT_PDINFO) |\
190                                   (1 << FILPBIT_UNIXPR)))
191
192 /* -------------------------- */
193 u_int32_t get_id(struct vol *vol, struct adouble *adp,  const struct stat *st,
194              const cnid_t did, char *upath, const int len) 
195 {
196 u_int32_t aint = 0;
197
198 #if AD_VERSION > AD_VERSION1
199
200     if ((aint = ad_getid(adp, st->st_dev, st->st_ino, did, vol->v_stamp))) {
201         return aint;
202     }
203 #endif
204
205     if (vol->v_cdb != NULL) {
206             aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
207             /* Throw errors if cnid_add fails. */
208             if (aint == CNID_INVALID) {
209             switch (errno) {
210             case CNID_ERR_CLOSE: /* the db is closed */
211                 break;
212             case CNID_ERR_PARAM:
213                 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
214                 afp_errno = AFPERR_PARAM;
215                 return CNID_INVALID;
216             case CNID_ERR_PATH:
217                 afp_errno = AFPERR_PARAM;
218                 return CNID_INVALID;
219             default:
220                 afp_errno = AFPERR_MISC;
221                 return CNID_INVALID;
222             }
223         }
224 #if AD_VERSION > AD_VERSION1
225         else if (adp ) {
226             /* update the ressource fork
227              * for a folder adp is always null
228              */
229             if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
230                 ad_flush(adp, ADFLAGS_HF);
231             }
232         }
233 #endif    
234     }
235     return aint;
236 }
237              
238 /* -------------------------- */
239 int getmetadata(struct vol *vol,
240                  u_int16_t bitmap,
241                  struct path *path, struct dir *dir, 
242                  char *buf, int *buflen, struct adouble *adp, int attrbits )
243 {
244     char                *data, *l_nameoff = NULL, *upath;
245     char                *utf_nameoff = NULL;
246     int                 bit = 0;
247     u_int32_t           aint;
248     cnid_t              id = 0;
249     u_int16_t           ashort;
250     u_char              achar, fdType[4];
251     u_int32_t           utf8 = 0;
252     struct stat         *st;
253     struct maccess      ma;
254
255 #ifdef DEBUG
256     LOG(log_info, logtype_afpd, "begin getmetadata:");
257 #endif /* DEBUG */
258
259     upath = path->u_name;
260     st = &path->st;
261
262     data = buf;
263
264     if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
265          || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
266          || (bitmap & (1 << FILPBIT_FNUM))) {
267         if (!path->id)
268             id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
269         else 
270             id = path->id;
271         if (id == 0)
272             return afp_errno;
273         if (!path->m_name) {
274             path->m_name = utompath(vol, upath, id, utf8_encoding());
275         }
276     }
277     while ( bitmap != 0 ) {
278         while (( bitmap & 1 ) == 0 ) {
279             bitmap = bitmap>>1;
280             bit++;
281         }
282
283         switch ( bit ) {
284         case FILPBIT_ATTR :
285             if ( adp ) {
286                 ad_getattr(adp, &ashort);
287             } else if (*upath == '.') {
288                 ashort = htons(ATTRBIT_INVISIBLE);
289             } else
290                 ashort = 0;
291 #if 0
292             /* FIXME do we want a visual clue if the file is read only
293              */
294             struct maccess      ma;
295             accessmode( ".", &ma, dir , NULL);
296             if ((ma.ma_user & AR_UWRITE)) {
297                 accessmode( upath, &ma, dir , st);
298                 if (!(ma.ma_user & AR_UWRITE)) {
299                         attrbits |= ATTRBIT_NOWRITE;
300                 }
301             }
302 #endif
303             if (attrbits)
304                 ashort = htons(ntohs(ashort) | attrbits);
305             memcpy(data, &ashort, sizeof( ashort ));
306             data += sizeof( ashort );
307             break;
308
309         case FILPBIT_PDID :
310             memcpy(data, &dir->d_did, sizeof( u_int32_t ));
311             data += sizeof( u_int32_t );
312             break;
313
314         case FILPBIT_CDATE :
315             if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
316                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
317             memcpy(data, &aint, sizeof( aint ));
318             data += sizeof( aint );
319             break;
320
321         case FILPBIT_MDATE :
322             if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
323                 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
324                    aint = AD_DATE_FROM_UNIX(st->st_mtime);
325                 }
326             } else {
327                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
328             }
329             memcpy(data, &aint, sizeof( int ));
330             data += sizeof( int );
331             break;
332
333         case FILPBIT_BDATE :
334             if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
335                 aint = AD_DATE_START;
336             memcpy(data, &aint, sizeof( int ));
337             data += sizeof( int );
338             break;
339
340         case FILPBIT_FINFO :
341             get_finderinfo(upath, adp, (char *)data);
342             data += ADEDLEN_FINDERI;
343             break;
344
345         case FILPBIT_LNAME :
346             l_nameoff = data;
347             data += sizeof( u_int16_t );
348             break;
349
350         case FILPBIT_SNAME :
351             memset(data, 0, sizeof(u_int16_t));
352             data += sizeof( u_int16_t );
353             break;
354
355         case FILPBIT_FNUM :
356             memcpy(data, &id, sizeof( id ));
357             data += sizeof( id );
358             break;
359
360         case FILPBIT_DFLEN :
361             if  (st->st_size > 0xffffffff)
362                aint = 0xffffffff;
363             else
364                aint = htonl( st->st_size );
365             memcpy(data, &aint, sizeof( aint ));
366             data += sizeof( aint );
367             break;
368
369         case FILPBIT_RFLEN :
370             if ( adp ) {
371                 if (adp->ad_rlen > 0xffffffff)
372                     aint = 0xffffffff;
373                 else
374                     aint = htonl( adp->ad_rlen);
375             } else {
376                 aint = 0;
377             }
378             memcpy(data, &aint, sizeof( aint ));
379             data += sizeof( aint );
380             break;
381
382             /* Current client needs ProDOS info block for this file.
383                Use simple heuristic and let the Mac "type" string tell
384                us what the PD file code should be.  Everything gets a
385                subtype of 0x0000 unless the original value was hashed
386                to "pXYZ" when we created it.  See IA, Ver 2.
387                <shirsch@adelphia.net> */
388         case FILPBIT_PDINFO :
389             if (afp_version >= 30) { /* UTF8 name */
390                 utf8 = kTextEncodingUTF8;
391                 utf_nameoff = data;
392                 data += sizeof( u_int16_t );
393                 aint = 0;
394                 memcpy(data, &aint, sizeof( aint ));
395                 data += sizeof( aint );
396             }
397             else {
398                 if ( adp ) {
399                     memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
400
401                     if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
402                         achar = '\x04';
403                         ashort = 0x0000;
404                     }
405                     else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
406                         achar = '\xff';
407                         ashort = 0x0000;
408                     }
409                     else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
410                         achar = '\xb3';
411                         ashort = 0x0000;
412                     }
413                     else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
414                         achar = '\x00';
415                         ashort = 0x0000;
416                     }
417                     else if ( fdType[0] == 'p' ) {
418                         achar = fdType[1];
419                         ashort = (fdType[2] * 256) + fdType[3];
420                     }
421                     else {
422                         achar = '\x00';
423                         ashort = 0x0000;
424                     }
425                 }
426                 else {
427                     achar = '\x00';
428                     ashort = 0x0000;
429                 }
430
431                 *data++ = achar;
432                 *data++ = 0;
433                 memcpy(data, &ashort, sizeof( ashort ));
434                 data += sizeof( ashort );
435                 memset(data, 0, sizeof( ashort ));
436                 data += sizeof( ashort );
437             }
438             break;
439         case FILPBIT_EXTDFLEN:
440             aint = htonl(st->st_size >> 32);
441             memcpy(data, &aint, sizeof( aint ));
442             data += sizeof( aint );
443             aint = htonl(st->st_size);
444             memcpy(data, &aint, sizeof( aint ));
445             data += sizeof( aint );
446             break;
447         case FILPBIT_EXTRFLEN:
448             aint = 0;
449             if (adp) 
450                 aint = htonl(adp->ad_rlen >> 32);
451             memcpy(data, &aint, sizeof( aint ));
452             data += sizeof( aint );
453             if (adp) 
454                 aint = htonl(adp->ad_rlen);
455             memcpy(data, &aint, sizeof( aint ));
456             data += sizeof( aint );
457             break;
458         case FILPBIT_UNIXPR :
459             /* accessmode may change st_mode with ACLs */
460             accessmode( upath, &ma, dir , st);
461
462             aint = htonl(st->st_uid);
463             memcpy( data, &aint, sizeof( aint ));
464             data += sizeof( aint );
465             aint = htonl(st->st_gid);
466             memcpy( data, &aint, sizeof( aint ));
467             data += sizeof( aint );
468
469             /* FIXME: ugly hack
470                type == slnk indicates an OSX style symlink, 
471                we have to add S_IFLNK to the mode, otherwise
472                10.3 clients freak out. */
473
474             aint = st->st_mode;
475             if (adp) {
476                 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
477                 if ( memcmp( fdType, "slnk", 4 ) == 0 ) {
478                     aint |= S_IFLNK;
479                 }
480             }
481             aint = htonl(aint);
482
483             memcpy( data, &aint, sizeof( aint ));
484             data += sizeof( aint );
485
486             *data++ = ma.ma_user;
487             *data++ = ma.ma_world;
488             *data++ = ma.ma_group;
489             *data++ = ma.ma_owner;
490             break;
491             
492         default :
493             return( AFPERR_BITMAP );
494         }
495         bitmap = bitmap>>1;
496         bit++;
497     }
498     if ( l_nameoff ) {
499         ashort = htons( data - buf );
500         memcpy(l_nameoff, &ashort, sizeof( ashort ));
501         data = set_name(vol, data, dir->d_did, path->m_name, id, 0);
502     }
503     if ( utf_nameoff ) {
504         ashort = htons( data - buf );
505         memcpy(utf_nameoff, &ashort, sizeof( ashort ));
506         data = set_name(vol, data, dir->d_did, path->m_name, id, utf8);
507     }
508     *buflen = data - buf;
509     return (AFP_OK);
510 }
511                 
512 /* ----------------------- */
513 int getfilparams(struct vol *vol,
514                  u_int16_t bitmap,
515                  struct path *path, struct dir *dir, 
516                  char *buf, int *buflen )
517 {
518     struct adouble      ad, *adp;
519     struct ofork        *of;
520     char                    *upath;
521     u_int16_t           attrbits = 0;
522     int                 opened = 0;
523     int rc;    
524
525 #ifdef DEBUG
526     LOG(log_info, logtype_default, "begin getfilparams:");
527 #endif /* DEBUG */
528
529     opened = PARAM_NEED_ADP(bitmap);
530     adp = NULL;
531     if (opened) {
532         upath = path->u_name;
533         if ((of = of_findname(path))) {
534             adp = of->of_ad;
535             attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
536             attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
537         } else {
538             ad_init(&ad, vol->v_adouble, vol->v_ad_options);
539             adp = &ad;
540         }
541
542         if ( ad_metadata( upath, 0, adp) < 0 ) {
543             switch (errno) {
544             case EACCES:
545                 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
546                 upath, strerror(errno));
547                 return AFPERR_ACCESS;
548             case EIO:
549                 LOG(log_error, logtype_afpd, "getfilparams(%s): bad resource fork", upath);
550                 /* fall through */
551             case ENOENT:
552             default:
553                 adp = NULL;
554                 break;
555             }
556         }
557         if (adp) {
558             /* FIXME 
559                we need to check if the file is open by another process.
560                it's slow so we only do it if we have to:
561                - bitmap is requested.
562                - we don't already have the answer!
563             */
564             if ((bitmap & (1 << FILPBIT_ATTR))) {
565                  if (!(attrbits & ATTRBIT_ROPEN)) {
566                      attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
567                      attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
568                  }
569                  if (!(attrbits & ATTRBIT_DOPEN)) {
570                      attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
571                      attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
572                  }
573             }
574         }
575     }
576     rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
577     if ( adp ) {
578         ad_close_metadata( adp);
579     }
580 #ifdef DEBUG
581     LOG(log_info, logtype_afpd, "end getfilparams:");
582 #endif /* DEBUG */
583
584     return( rc );
585 }
586
587 /* ----------------------------- */
588 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
589 AFPObj  *obj;
590 char    *ibuf, *rbuf _U_;
591 int     ibuflen _U_, *rbuflen;
592 {
593     struct adouble      ad, *adp;
594     struct vol          *vol;
595     struct dir          *dir;
596     struct ofork        *of = NULL;
597     char                *path, *upath;
598     int                 creatf, did, openf, retvalue = AFP_OK;
599     u_int16_t           vid;
600     int                 ret;
601     struct path         *s_path;
602     
603 #ifdef DEBUG
604     LOG(log_info, logtype_afpd, "begin afp_createfile:");
605 #endif /* DEBUG */
606
607     *rbuflen = 0;
608     ibuf++;
609     creatf = (unsigned char) *ibuf++;
610
611     memcpy(&vid, ibuf, sizeof( vid ));
612     ibuf += sizeof( vid );
613
614     if (NULL == ( vol = getvolbyvid( vid )) ) {
615         return( AFPERR_PARAM );
616     }
617
618     if (vol->v_flags & AFPVOL_RO)
619         return AFPERR_VLOCK;
620
621     memcpy(&did, ibuf, sizeof( did));
622     ibuf += sizeof( did );
623
624     if (NULL == ( dir = dirlookup( vol, did )) ) {
625         return afp_errno;
626     }
627
628     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
629         return get_afp_errno(AFPERR_PARAM);
630     }
631
632     if ( *s_path->m_name == '\0' ) {
633         return( AFPERR_BADTYPE );
634     }
635
636     upath = s_path->u_name;
637     if (0 != (ret = check_name(vol, upath))) 
638        return  ret;
639     
640     /* if upath is deleted we already in trouble anyway */
641     if ((of = of_findname(s_path))) {
642         adp = of->of_ad;
643     } else {
644         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
645         adp = &ad;
646     }
647     if ( creatf) {
648         /* on a hard create, fail if file exists and is open */
649         if (of)
650             return AFPERR_BUSY;
651         openf = O_RDWR|O_CREAT|O_TRUNC;
652     } else {
653         /* on a soft create, if the file is open then ad_open won't fail
654            because open syscall is not called
655         */
656         if (of) {
657                 return AFPERR_EXIST;
658         }
659         openf = O_RDWR|O_CREAT|O_EXCL;
660     }
661
662     if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
663                   openf, 0666, adp) < 0 ) {
664         switch ( errno ) {
665         case EROFS:
666             return AFPERR_VLOCK;
667         case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
668             return ( AFPERR_NOOBJ );
669         case EEXIST :
670             return( AFPERR_EXIST );
671         case EACCES :
672             return( AFPERR_ACCESS );
673         case EDQUOT:
674         case ENOSPC :
675             return( AFPERR_DFULL );
676         default :
677             return( AFPERR_PARAM );
678         }
679     }
680     if ( ad_hfileno( adp ) == -1 ) {
681          /* on noadouble volumes, just creating the data fork is ok */
682          if (vol_noadouble(vol)) {
683              ad_close( adp, ADFLAGS_DF );
684              goto createfile_done;
685          }
686          /* FIXME with hard create on an existing file, we already
687           * corrupted the data file.
688           */
689          netatalk_unlink( upath );
690          ad_close( adp, ADFLAGS_DF );
691          return AFPERR_ACCESS;
692     }
693
694     path = s_path->m_name;
695     ad_setname(adp, path);
696     ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
697     ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
698
699 createfile_done:
700     curdir->offcnt++;
701
702 #ifdef DROPKLUDGE
703     if (vol->v_flags & AFPVOL_DROPBOX) {
704         retvalue = matchfile2dirperms(upath, vol, did);
705     }
706 #endif /* DROPKLUDGE */
707
708     setvoltime(obj, vol );
709
710 #ifdef DEBUG
711     LOG(log_info, logtype_afpd, "end afp_createfile");
712 #endif /* DEBUG */
713
714     return (retvalue);
715 }
716
717 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
718 AFPObj  *obj;
719 char    *ibuf, *rbuf _U_;
720 int     ibuflen _U_, *rbuflen;
721 {
722     struct vol  *vol;
723     struct dir  *dir;
724     struct path *s_path;
725     int         did, rc;
726     u_int16_t   vid, bitmap;
727
728 #ifdef DEBUG
729     LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
730 #endif /* DEBUG */
731
732     *rbuflen = 0;
733     ibuf += 2;
734
735     memcpy(&vid, ibuf, sizeof( vid ));
736     ibuf += sizeof( vid );
737     if (NULL == ( vol = getvolbyvid( vid )) ) {
738         return( AFPERR_PARAM );
739     }
740
741     if (vol->v_flags & AFPVOL_RO)
742         return AFPERR_VLOCK;
743
744     memcpy(&did, ibuf, sizeof( did ));
745     ibuf += sizeof( did );
746     if (NULL == ( dir = dirlookup( vol, did )) ) {
747         return afp_errno; /* was AFPERR_NOOBJ */
748     }
749
750     memcpy(&bitmap, ibuf, sizeof( bitmap ));
751     bitmap = ntohs( bitmap );
752     ibuf += sizeof( bitmap );
753
754     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
755         return get_afp_errno(AFPERR_PARAM);
756     }
757
758     if (path_isadir(s_path)) {
759         return( AFPERR_BADTYPE ); /* it's a directory */
760     }
761
762     if ( s_path->st_errno != 0 ) {
763         return( AFPERR_NOOBJ );
764     }
765
766     if ((u_long)ibuf & 1 ) {
767         ibuf++;
768     }
769
770     if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
771         setvoltime(obj, vol );
772     }
773
774 #ifdef DEBUG
775     LOG(log_info, logtype_afpd, "end afp_setfilparams:");
776 #endif /* DEBUG */
777
778     return( rc );
779 }
780
781 /*
782  * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic  
783  * 
784 */
785 extern struct path Cur_Path;
786
787 int setfilparams(struct vol *vol,
788                  struct path *path, u_int16_t f_bitmap, char *buf )
789 {
790     struct adouble      ad, *adp;
791     struct extmap       *em;
792     int                 bit, isad = 1, err = AFP_OK;
793     char                *upath;
794     u_char              achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
795     u_int16_t           ashort, bshort;
796     u_int32_t           aint;
797     u_int32_t           upriv;
798     u_int16_t           upriv_bit = 0;
799     
800     struct utimbuf      ut;
801
802     int                 change_mdate = 0;
803     int                 change_parent_mdate = 0;
804     int                 newdate = 0;
805     struct timeval      tv;
806     uid_t               f_uid;
807     gid_t               f_gid;
808     u_int16_t           bitmap = f_bitmap;
809     u_int32_t           cdate,bdate;
810     u_char              finder_buf[32];
811
812 #ifdef DEBUG
813     LOG(log_info, logtype_afpd, "begin setfilparams:");
814 #endif /* DEBUG */
815
816     upath = path->u_name;
817     adp = of_ad(vol, path, &ad);
818     
819
820     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
821         return AFPERR_ACCESS;
822     }
823
824     /* with unix priv maybe we have to change adouble file priv first */
825     bit = 0;
826     while ( bitmap != 0 ) {
827         while (( bitmap & 1 ) == 0 ) {
828             bitmap = bitmap>>1;
829             bit++;
830         }
831         switch(  bit ) {
832         case FILPBIT_ATTR :
833             change_mdate = 1;
834             memcpy(&ashort, buf, sizeof( ashort ));
835             buf += sizeof( ashort );
836             break;
837         case FILPBIT_CDATE :
838             change_mdate = 1;
839             memcpy(&cdate, buf, sizeof(cdate));
840             buf += sizeof( cdate );
841             break;
842         case FILPBIT_MDATE :
843             memcpy(&newdate, buf, sizeof( newdate ));
844             buf += sizeof( newdate );
845             break;
846         case FILPBIT_BDATE :
847             change_mdate = 1;
848             memcpy(&bdate, buf, sizeof( bdate));
849             buf += sizeof( bdate );
850             break;
851         case FILPBIT_FINFO :
852             change_mdate = 1;
853             memcpy(finder_buf, buf, 32 );
854             buf += 32;
855             break;
856         case FILPBIT_UNIXPR :
857             if (!vol_unix_priv(vol)) {
858                 /* this volume doesn't use unix priv */
859                 err = AFPERR_BITMAP;
860                 bitmap = 0;
861                 break;
862             }
863             change_mdate = 1;
864             change_parent_mdate = 1;
865
866             memcpy( &aint, buf, sizeof( aint ));
867             f_uid = ntohl (aint);
868             buf += sizeof( aint );
869             memcpy( &aint, buf, sizeof( aint ));
870             f_gid = ntohl (aint);
871             buf += sizeof( aint );
872             setfilowner(vol, f_uid, f_gid, path);
873
874             memcpy( &upriv, buf, sizeof( upriv ));
875             buf += sizeof( upriv );
876             upriv = ntohl (upriv);
877             if ((upriv & S_IWUSR)) {
878                 setfilunixmode(vol, path, upriv);
879             }
880             else {
881                 /* do it later */
882                 upriv_bit = 1;
883             }
884             break;
885         case FILPBIT_PDINFO :
886             if (afp_version < 30) { /* else it's UTF8 name */
887                 achar = *buf;
888                 buf += 2;
889                 /* Keep special case to support crlf translations */
890                 if ((unsigned int) achar == 0x04) {
891                     fdType = (u_char *)"TEXT";
892                     buf += 2;
893                 } else {
894                     xyy[0] = ( u_char ) 'p';
895                     xyy[1] = achar;
896                     xyy[3] = *buf++;
897                     xyy[2] = *buf++;
898                     fdType = xyy;
899                 }
900                 break;
901             }
902             /* fallthrough */
903         default :
904             err = AFPERR_BITMAP;
905             /* break while loop */
906             bitmap = 0;
907             break;
908         }
909
910         bitmap = bitmap>>1;
911         bit++;
912     }
913
914     /* second try with adouble open 
915     */
916     if ( ad_open_metadata( upath, vol_noadouble(vol), O_CREAT, adp) < 0) {
917         /* for some things, we don't need an adouble header */
918         if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
919             return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
920         }
921         isad = 0;
922     } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
923         ad_setname(adp, path->m_name);
924     }
925     
926     bit = 0;
927     bitmap = f_bitmap;
928     while ( bitmap != 0 ) {
929         while (( bitmap & 1 ) == 0 ) {
930             bitmap = bitmap>>1;
931             bit++;
932         }
933
934         switch(  bit ) {
935         case FILPBIT_ATTR :
936             ad_getattr(adp, &bshort);
937             if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
938                 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
939                 change_parent_mdate = 1;
940             if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
941                 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
942             } else {
943                 bshort &= ~ashort;
944             }
945             ad_setattr(adp, bshort);
946             break;
947         case FILPBIT_CDATE :
948             ad_setdate(adp, AD_DATE_CREATE, cdate);
949             break;
950         case FILPBIT_MDATE :
951             break;
952         case FILPBIT_BDATE :
953             ad_setdate(adp, AD_DATE_BACKUP, bdate);
954             break;
955         case FILPBIT_FINFO :
956             if (default_type( ad_entry( adp, ADEID_FINDERI ))
957                     && ( 
958                      ((em = getextmap( path->m_name )) &&
959                       !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
960                       !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
961                      || ((em = getdefextmap()) &&
962                       !memcmp(finder_buf, em->em_type, sizeof( em->em_type )) &&
963                       !memcmp(finder_buf + 4, em->em_creator,sizeof( em->em_creator)))
964             )) {
965                 memcpy(finder_buf, ufinderi, 8 );
966             }
967             memcpy(ad_entry( adp, ADEID_FINDERI ), finder_buf, 32 );
968             break;
969         case FILPBIT_UNIXPR :
970             if (upriv_bit) {
971                 setfilunixmode(vol, path, upriv);
972             }
973             break;
974         case FILPBIT_PDINFO :
975             if (afp_version < 30) { /* else it's UTF8 name */
976                 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
977                 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
978                 break;
979             }
980             /* fallthrough */
981         default :
982             err = AFPERR_BITMAP;
983             goto setfilparam_done;
984         }
985         bitmap = bitmap>>1;
986         bit++;
987     }
988
989 setfilparam_done:
990     if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
991        newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
992     }
993     if (newdate) {
994        if (isad)
995           ad_setdate(adp, AD_DATE_MODIFY, newdate);
996        ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
997        utime(upath, &ut);
998     }
999
1000     if (isad) {
1001         ad_flush_metadata( adp);
1002         ad_close_metadata( adp);
1003
1004     }
1005
1006     if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
1007         newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
1008         bitmap = 1<<FILPBIT_MDATE;
1009         setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
1010     }
1011
1012 #ifdef DEBUG
1013     LOG(log_info, logtype_afpd, "end setfilparams:");
1014 #endif /* DEBUG */
1015     return err;
1016 }
1017
1018 /*
1019  * renamefile and copyfile take the old and new unix pathnames
1020  * and the new mac name.
1021  *
1022  * src         the source path 
1023  * dst         the dest filename in current dir
1024  * newname     the dest mac name
1025  * adp         adouble struct of src file, if open, or & zeroed one
1026  *
1027  */
1028 int renamefile(vol, src, dst, newname, adp )
1029 const struct vol *vol;
1030 char    *src, *dst, *newname;
1031 struct adouble    *adp;
1032 {
1033     int         rc;
1034
1035 #ifdef DEBUG
1036     LOG(log_info, logtype_afpd, "begin renamefile:");
1037 #endif /* DEBUG */
1038
1039     if ( unix_rename( src, dst ) < 0 ) {
1040         switch ( errno ) {
1041         case ENOENT :
1042             return( AFPERR_NOOBJ );
1043         case EPERM:
1044         case EACCES :
1045             return( AFPERR_ACCESS );
1046         case EROFS:
1047             return AFPERR_VLOCK;
1048         case EXDEV :                    /* Cross device move -- try copy */
1049            /* NOTE: with open file it's an error because after the copy we will 
1050             * get two files, it's fixable for our process (eg reopen the new file, get the
1051             * locks, and so on. But it doesn't solve the case with a second process
1052             */
1053             if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
1054                 /* FIXME  warning in syslog so admin'd know there's a conflict ?*/
1055                 return AFPERR_OLOCK; /* little lie */
1056             }
1057             if (AFP_OK != ( rc = copyfile(vol, vol, src, dst, newname, NULL )) ) {
1058                 /* on error copyfile delete dest */
1059                 return( rc );
1060             }
1061             return deletefile(vol, src, 0);
1062         default :
1063             return( AFPERR_PARAM );
1064         }
1065     }
1066
1067     if (vol->vfs->rf_renamefile(vol, src, dst) < 0 ) {
1068         int err;
1069         
1070         err = errno;        
1071         /* try to undo the data fork rename,
1072          * we know we are on the same device 
1073         */
1074         if (err) {
1075             unix_rename( dst, src ); 
1076             /* return the first error */
1077             switch ( err) {
1078             case ENOENT :
1079                 return AFPERR_NOOBJ;
1080             case EPERM:
1081             case EACCES :
1082                 return AFPERR_ACCESS ;
1083             case EROFS:
1084                 return AFPERR_VLOCK;
1085             default :
1086                 return AFPERR_PARAM ;
1087             }
1088         }
1089     }
1090
1091     /* don't care if we can't open the newly renamed ressource fork
1092      */
1093     if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1094         ad_setname(adp, newname);
1095         ad_flush( adp, ADFLAGS_HF );
1096         ad_close( adp, ADFLAGS_HF );
1097     }
1098 #ifdef DEBUG
1099     LOG(log_info, logtype_afpd, "end renamefile:");
1100 #endif /* DEBUG */
1101
1102     return( AFP_OK );
1103 }
1104
1105 /* ---------------- 
1106    convert a Mac long name to an utf8 name,
1107 */
1108 size_t mtoUTF8(const struct vol *vol, const char *src, size_t srclen, char *dest, size_t destlen)
1109 {
1110 size_t    outlen;
1111
1112     if ((size_t)-1 == (outlen = convert_string ( vol->v_maccharset, CH_UTF8_MAC, src, srclen, dest, destlen)) ) {
1113         return -1;
1114     }
1115     return outlen;
1116 }
1117
1118 /* ---------------- */
1119 int copy_path_name(const struct vol *vol, char *newname, char *ibuf)
1120 {
1121 char        type = *ibuf;
1122 size_t      plen = 0;
1123 u_int16_t   len16;
1124 u_int32_t   hint;
1125
1126     if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1127         return -1;
1128     }
1129     ibuf++;
1130     switch (type) {
1131     case 2:
1132         if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1133             if (afp_version >= 30) {
1134                 /* convert it to UTF8 
1135                 */
1136                 if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1)
1137                    return -1;
1138             }
1139             else {
1140                 strncpy( newname, ibuf, plen );
1141                 newname[ plen ] = '\0';
1142             }
1143             if (strlen(newname) != plen) {
1144                 /* there's \0 in newname, e.g. it's a pathname not
1145                  * only a filename. 
1146                 */
1147                 return -1;
1148             }
1149         }
1150         break;
1151     case 3:
1152         memcpy(&hint, ibuf, sizeof(hint));
1153         ibuf += sizeof(hint);
1154            
1155         memcpy(&len16, ibuf, sizeof(len16));
1156         ibuf += sizeof(len16);
1157         plen = ntohs(len16);
1158         
1159         if (plen) {
1160             if (plen > AFPOBJ_TMPSIZ) {
1161                 return -1;
1162             }
1163             strncpy( newname, ibuf, plen );
1164             newname[ plen ] = '\0';
1165             if (strlen(newname) != plen) {
1166                 return -1;
1167             }
1168         }
1169         break;
1170     }
1171     return plen;
1172 }
1173
1174 /* -----------------------------------
1175 */
1176 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1177 AFPObj  *obj;
1178 char    *ibuf, *rbuf _U_;
1179 int     ibuflen _U_, *rbuflen;
1180 {
1181     struct vol  *s_vol, *d_vol;
1182     struct dir  *dir;
1183     char        *newname, *p, *upath;
1184     struct path *s_path;
1185     u_int32_t   sdid, ddid;
1186     int         err, retvalue = AFP_OK;
1187     u_int16_t   svid, dvid;
1188
1189     struct adouble ad, *adp;
1190     int denyreadset;
1191     
1192 #ifdef DEBUG
1193     LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1194 #endif /* DEBUG */
1195
1196     *rbuflen = 0;
1197     ibuf += 2;
1198
1199     memcpy(&svid, ibuf, sizeof( svid ));
1200     ibuf += sizeof( svid );
1201     if (NULL == ( s_vol = getvolbyvid( svid )) ) {
1202         return( AFPERR_PARAM );
1203     }
1204
1205     memcpy(&sdid, ibuf, sizeof( sdid ));
1206     ibuf += sizeof( sdid );
1207     if (NULL == ( dir = dirlookup( s_vol, sdid )) ) {
1208         return afp_errno;
1209     }
1210
1211     memcpy(&dvid, ibuf, sizeof( dvid ));
1212     ibuf += sizeof( dvid );
1213     memcpy(&ddid, ibuf, sizeof( ddid ));
1214     ibuf += sizeof( ddid );
1215
1216     if (NULL == ( s_path = cname( s_vol, dir, &ibuf )) ) {
1217         return get_afp_errno(AFPERR_PARAM);
1218     }
1219     if ( path_isadir(s_path) ) {
1220         return( AFPERR_BADTYPE );
1221     }
1222
1223     /* don't allow copies when the file is open.
1224      * XXX: the spec only calls for read/deny write access.
1225      *      however, copyfile doesn't have any of that info,
1226      *      and locks need to stay coherent. as a result,
1227      *      we just balk if the file is opened already. */
1228
1229     adp = of_ad(s_vol, s_path, &ad);
1230
1231     if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1232         return AFPERR_DENYCONF;
1233     }
1234     denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 || 
1235                   getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
1236     ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
1237     if (denyreadset) {
1238         return AFPERR_DENYCONF;
1239     }
1240
1241     newname = obj->newtmp;
1242     strcpy( newname, s_path->m_name );
1243
1244     p = ctoupath( s_vol, curdir, newname );
1245     if (!p) {
1246         return AFPERR_PARAM;
1247     
1248     }
1249 #ifdef FORCE_UIDGID
1250     /* FIXME svid != dvid && dvid's user can't read svid */
1251 #endif
1252     if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
1253         return( AFPERR_PARAM );
1254     }
1255
1256     if (d_vol->v_flags & AFPVOL_RO)
1257         return AFPERR_VLOCK;
1258
1259     if (NULL == ( dir = dirlookup( d_vol, ddid )) ) {
1260         return afp_errno;
1261     }
1262
1263     if (( s_path = cname( d_vol, dir, &ibuf )) == NULL ) {
1264         return get_afp_errno(AFPERR_NOOBJ); 
1265     }
1266     if ( *s_path->m_name != '\0' ) {
1267         path_error(s_path, AFPERR_PARAM);
1268     }
1269
1270     /* one of the handful of places that knows about the path type */
1271     if (copy_path_name(d_vol, newname, ibuf) < 0) {
1272         return( AFPERR_PARAM );
1273     }
1274     /* newname is always only a filename so curdir *is* its
1275      * parent folder
1276     */
1277     if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) {
1278         return( AFPERR_PARAM );
1279     }
1280     if ( (err = copyfile(s_vol, d_vol, p, upath , newname, adp)) < 0 ) {
1281         return err;
1282     }
1283     curdir->offcnt++;
1284
1285 #ifdef DROPKLUDGE
1286     if (vol->v_flags & AFPVOL_DROPBOX) {
1287         retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1288     }
1289 #endif /* DROPKLUDGE */
1290
1291     setvoltime(obj, d_vol );
1292
1293 #ifdef DEBUG
1294     LOG(log_info, logtype_afpd, "end afp_copyfile:");
1295 #endif /* DEBUG */
1296
1297     return( retvalue );
1298 }
1299
1300 /* ----------------------- */
1301 static __inline__ int copy_all(const int dfd, const void *buf,
1302                                size_t buflen)
1303 {
1304     ssize_t cc;
1305
1306 #ifdef DEBUG
1307     LOG(log_info, logtype_afpd, "begin copy_all:");
1308 #endif /* DEBUG */
1309
1310     while (buflen > 0) {
1311         if ((cc = write(dfd, buf, buflen)) < 0) {
1312             switch (errno) {
1313             case EINTR:
1314                 continue;
1315             default:
1316                 return -1;
1317             }
1318         }
1319         buflen -= cc;
1320     }
1321
1322 #ifdef DEBUG
1323     LOG(log_info, logtype_afpd, "end copy_all:");
1324 #endif /* DEBUG */
1325
1326     return 0;
1327 }
1328
1329 /* -------------------------- */
1330 static int copy_fd(int dfd, int sfd)
1331 {
1332     ssize_t cc;
1333     int     err = 0;
1334     char    filebuf[8192];
1335     
1336 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
1337     /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
1338     off_t   offset = 0;
1339     size_t  size;
1340     struct stat         st;
1341     #define BUF 128*1024*1024
1342
1343     if (fstat(sfd, &st) == 0) {
1344         
1345         while (1) {
1346             if ( offset >= st.st_size) {
1347                return 0;
1348             }
1349             size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1350             if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1351                 switch (errno) {
1352                 case ENOSYS:
1353                 case EINVAL:  /* there's no guarantee that all fs support sendfile */
1354                     goto no_sendfile;
1355                 default:
1356                     return -1;
1357                 }
1358             }
1359         }
1360     }
1361     no_sendfile:
1362     lseek(sfd, offset, SEEK_SET);
1363 #endif 
1364
1365     while (1) {
1366         if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1367             if (errno == EINTR)
1368                 continue;
1369             err = -1;
1370             break;
1371         }
1372
1373         if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1374             break;
1375         }
1376     }
1377     return err;
1378 }
1379
1380 /* ----------------------------------
1381  * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1382  * because we are doing it elsewhere.
1383  * currently if newname is NULL then adp is NULL. 
1384  */
1385 int copyfile(s_vol, d_vol, src, dst, newname, adp )
1386 const struct vol *s_vol, *d_vol;
1387 char    *src, *dst, *newname;
1388 struct adouble *adp;
1389 {
1390     struct adouble      ads, add;
1391     int                 err = 0;
1392     int                 ret_err = 0;
1393     int                 adflags;
1394     int                 noadouble = vol_noadouble(d_vol);
1395     int                 stat_result;
1396     struct stat         st;
1397     
1398 #ifdef DEBUG
1399     LOG(log_info, logtype_afpd, "begin copyfile:");
1400 #endif /* DEBUG */
1401
1402     if (adp == NULL) {
1403         ad_init(&ads, s_vol->v_adouble, s_vol->v_ad_options); 
1404         adp = &ads;
1405     }
1406     ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1407     adflags = ADFLAGS_DF;
1408     if (newname) {
1409         adflags |= ADFLAGS_HF;
1410     }
1411
1412     if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
1413         ret_err = errno;
1414         goto done;
1415     }
1416
1417     if (ad_hfileno(adp) == -1) {
1418         /* no resource fork, don't create one for dst file */
1419         adflags &= ~ADFLAGS_HF;
1420     }
1421
1422     stat_result = fstat(ad_dfileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
1423
1424     if (stat_result < 0) {           
1425       /* unlikely but if fstat fails, the default file mode will be 0666. */
1426       st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1427     }
1428
1429     if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
1430         ret_err = errno;
1431         ad_close( adp, adflags );
1432         if (EEXIST != ret_err) {
1433             deletefile(d_vol, dst, 0);
1434             goto done;
1435         }
1436         return AFPERR_EXIST;
1437     }
1438     /* XXX if the source and the dest don't use the same resource type it's broken
1439     */
1440     if (ad_hfileno(adp) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(adp)))){
1441         /* copy the data fork */
1442         err = copy_fd(ad_dfileno(&add), ad_dfileno(adp));
1443     }
1444
1445     /* Now, reopen destination file */
1446     if (err < 0) {
1447        ret_err = errno;
1448     }
1449     ad_close( adp, adflags );
1450
1451     if (ad_close( &add, adflags ) <0) {
1452         if (!ret_err) {
1453             ret_err = errno;
1454         }
1455         deletefile(d_vol, dst, 0);
1456         goto done;
1457     } 
1458
1459     if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
1460         /* set the new name in the resource fork */
1461         ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
1462         if (ad_open_metadata(dst , noadouble, 0, &add) < 0) {
1463             ret_err = errno;
1464         }
1465         else {
1466             ad_setname(&add, newname);
1467             ad_flush_metadata( &add);
1468             if (ad_close_metadata( &add)) {
1469                 ret_err = errno;
1470             }
1471         }
1472     }
1473
1474     if (ret_err) {
1475         deletefile(d_vol, dst, 0);
1476     }
1477     else if (stat_result == 0) {
1478         /* set dest modification date to src date */
1479         struct utimbuf  ut;
1480
1481         ut.actime = ut.modtime = st.st_mtime;
1482         utime(dst, &ut);
1483         /* FIXME netatalk doesn't use resource fork file date
1484          * but maybe we should set its modtime too.
1485         */
1486     }
1487
1488 #ifdef DEBUG
1489     LOG(log_info, logtype_afpd, "end copyfile:");
1490 #endif /* DEBUG */
1491
1492 done:
1493     switch ( ret_err ) {
1494     case 0:
1495         return AFP_OK;
1496     case EDQUOT:
1497     case EFBIG:
1498     case ENOSPC:
1499         return AFPERR_DFULL;
1500     case ENOENT:
1501         return AFPERR_NOOBJ;
1502     case EACCES:
1503         return AFPERR_ACCESS;
1504     case EROFS:
1505         return AFPERR_VLOCK;
1506     }
1507     return AFPERR_PARAM;
1508 }
1509
1510
1511 /* -----------------------------------
1512    vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1513    checkAttrib:   1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1514
1515    when deletefile is called we don't have lock on it, file is closed (for us)
1516    untrue if called by renamefile
1517    
1518    ad_open always try to open file RDWR first and ad_lock takes care of
1519    WRITE lock on read only file.
1520 */
1521 int deletefile( vol, file, checkAttrib )
1522 const struct vol      *vol;
1523 char            *file;
1524 int         checkAttrib;
1525 {
1526     struct adouble      ad;
1527     struct adouble      *adp = &ad;
1528     int                 adflags, err = AFP_OK;
1529
1530 #ifdef DEBUG
1531     LOG(log_info, logtype_afpd, "begin deletefile:");
1532 #endif /* DEBUG */
1533
1534     /* try to open both forks at once */
1535     adflags = ADFLAGS_DF|ADFLAGS_HF;
1536     ad_init(&ad, vol->v_adouble, vol->v_ad_options);  /* OK */
1537     while(1) {
1538         if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1539             switch (errno) {
1540             case ENOENT:
1541                 if (adflags == ADFLAGS_DF)
1542                     return AFPERR_NOOBJ;
1543                    
1544                 /* that failed. now try to open just the data fork */
1545                 adflags = ADFLAGS_DF;
1546                 continue;
1547
1548             case EACCES:
1549                 adp = NULL; /* maybe it's a file with no write mode for us */
1550                 break;      /* was return AFPERR_ACCESS;*/
1551             case EROFS:
1552                 return AFPERR_VLOCK;
1553             default:
1554                 return( AFPERR_PARAM );
1555             }
1556         }
1557         break;  /* from the while */
1558     }
1559     /*
1560      * Does kFPDeleteInhibitBit (bit 8) set?
1561      */
1562     if (checkAttrib) {
1563         u_int16_t   bshort;
1564         
1565         if ( ad_metadata( file , 0, &ad) == 0 ) {
1566             ad_getattr(&ad, &bshort);
1567             ad_close_metadata( &ad);
1568             if ((bshort & htons(ATTRBIT_NODELETE))) {
1569                 return  AFPERR_OLOCK;
1570             }
1571         }
1572     }
1573     
1574     if (adp && (adflags & ADFLAGS_HF) ) {
1575         /* FIXME we have a pb here because we want to know if a file is open 
1576          * there's a 'priority inversion' if you can't open the ressource fork RW
1577          * you can delete it if it's open because you can't get a write lock.
1578          * 
1579          * ADLOCK_FILELOCK means the whole ressource fork, not only after the 
1580          * metadatas
1581          *
1582          * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1583          */
1584         if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1585             ad_close( &ad, adflags );
1586             return( AFPERR_BUSY );
1587         }
1588     }
1589
1590     if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1591         err = AFPERR_BUSY;
1592     }
1593     else if (!(err = vol->vfs->rf_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
1594         cnid_t id;
1595         if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) 
1596         {
1597             cnid_delete(vol->v_cdb, id);
1598         }
1599     }
1600     if (adp)
1601         ad_close( &ad, adflags );  /* ad_close removes locks if any */
1602
1603 #ifdef DEBUG
1604     LOG(log_info, logtype_afpd, "end deletefile:");
1605 #endif /* DEBUG */
1606
1607     return err;
1608 }
1609
1610 /* ------------------------------------ */
1611 /* return a file id */
1612 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1613 AFPObj  *obj _U_;
1614 char    *ibuf, *rbuf;
1615 int     ibuflen _U_, *rbuflen;
1616 {
1617     struct stat         *st;
1618     struct vol          *vol;
1619     struct dir          *dir;
1620     char                *upath;
1621     int                 len;
1622     cnid_t              did, id;
1623     u_short             vid;
1624     struct path         *s_path;
1625
1626 #ifdef DEBUG
1627     LOG(log_info, logtype_afpd, "begin afp_createid:");
1628 #endif /* DEBUG */
1629
1630     *rbuflen = 0;
1631
1632     ibuf += 2;
1633
1634     memcpy(&vid, ibuf, sizeof(vid));
1635     ibuf += sizeof(vid);
1636
1637     if (NULL == ( vol = getvolbyvid( vid )) ) {
1638         return( AFPERR_PARAM);
1639     }
1640
1641     if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1642         return AFPERR_NOOP;
1643     }
1644
1645     if (vol->v_flags & AFPVOL_RO)
1646         return AFPERR_VLOCK;
1647
1648     memcpy(&did, ibuf, sizeof( did ));
1649     ibuf += sizeof(did);
1650
1651     if (NULL == ( dir = dirlookup( vol, did )) ) {
1652         return afp_errno; /* was AFPERR_PARAM */
1653     }
1654
1655     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1656         return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1657     }
1658
1659     if ( path_isadir(s_path) ) {
1660         return( AFPERR_BADTYPE );
1661     }
1662
1663     upath = s_path->u_name;
1664     switch (s_path->st_errno) {
1665         case 0:
1666              break; /* success */
1667         case EPERM:
1668         case EACCES:
1669             return AFPERR_ACCESS;
1670         case ENOENT:
1671             return AFPERR_NOOBJ;
1672         default:
1673             return AFPERR_PARAM;
1674     }
1675     st = &s_path->st;
1676     if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1677         memcpy(rbuf, &id, sizeof(id));
1678         *rbuflen = sizeof(id);
1679         return AFPERR_EXISTID;
1680     }
1681
1682     if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1683         memcpy(rbuf, &id, sizeof(id));
1684         *rbuflen = sizeof(id);
1685         return AFP_OK;
1686     }
1687
1688 #ifdef DEBUG
1689     LOG(log_info, logtype_afpd, "ending afp_createid...:");
1690 #endif /* DEBUG */
1691     return afp_errno;
1692 }
1693
1694 /* ------------------------------- */
1695 struct reenum {
1696     struct vol *vol;
1697     cnid_t     did;
1698 };
1699
1700 static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
1701 {
1702     struct path   path;
1703     struct reenum *param = data;
1704     struct vol    *vol = param->vol;  
1705     cnid_t        did  = param->did;
1706     cnid_t        aint;
1707     
1708     memset(&path, 0, sizeof(path));
1709
1710     if ( stat(de->d_name, &path.st)<0 )
1711         return 0;
1712     
1713     /* update or add to cnid */
1714     aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
1715
1716 #if AD_VERSION > AD_VERSION1
1717     if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
1718         struct adouble  ad, *adp;
1719
1720         path.st_errno = 0;
1721         path.st_valid = 1;
1722         path.u_name = de->d_name;
1723             
1724         adp = of_ad(vol, &path, &ad);
1725             
1726         if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
1727             return 0;
1728         }
1729         if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
1730             ad_flush_metadata(adp);
1731         }
1732         ad_close_metadata(adp);
1733     }
1734 #endif /* AD_VERSION > AD_VERSION1 */
1735
1736     return 0;
1737 }
1738
1739 /* --------------------
1740  * Ok the db is out of synch with the dir.
1741  * but if it's a deleted file we don't want to do it again and again.
1742 */
1743 static int
1744 reenumerate_id(struct vol *vol, char *name, struct dir *dir)
1745 {
1746     int             ret;
1747     struct reenum   data;
1748     struct stat     st;
1749     
1750     if (vol->v_cdb == NULL) {
1751         return -1;
1752     }
1753     
1754     /* FIXME use of_statdir ? */
1755     if (stat(name, &st)) {
1756         return -1;
1757     }
1758
1759     if (dirreenumerate(dir, &st)) {
1760         /* we already did it once and the dir haven't been modified */
1761         return dir->offcnt;
1762     }
1763     
1764     data.vol = vol;
1765     data.did = dir->d_did;
1766     if ((ret = for_each_dirent(vol, name, reenumerate_loop, (void *)&data)) >= 0) {
1767         setdiroffcnt(curdir, &st,  ret);
1768         dir->d_flags |= DIRF_CNID;
1769     }
1770
1771     return ret;
1772 }
1773
1774 /* ------------------------------
1775    resolve a file id */
1776 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1777 AFPObj  *obj _U_;
1778 char    *ibuf, *rbuf;
1779 int     ibuflen _U_, *rbuflen;
1780 {
1781     struct vol          *vol;
1782     struct dir          *dir;
1783     char                *upath;
1784     struct path         path;
1785     int                 err, buflen, retry=0;
1786     cnid_t              id, cnid;
1787     u_int16_t           vid, bitmap;
1788
1789     static char buffer[12 + MAXPATHLEN + 1];
1790     int len = 12 + MAXPATHLEN + 1;
1791
1792 #ifdef DEBUG
1793     LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1794 #endif /* DEBUG */
1795
1796     *rbuflen = 0;
1797     ibuf += 2;
1798
1799     memcpy(&vid, ibuf, sizeof(vid));
1800     ibuf += sizeof(vid);
1801
1802     if (NULL == ( vol = getvolbyvid( vid )) ) {
1803         return( AFPERR_PARAM);
1804     }
1805
1806     if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1807         return AFPERR_NOOP;
1808     }
1809
1810     memcpy(&id, ibuf, sizeof( id ));
1811     ibuf += sizeof(id);
1812     cnid = id;
1813     
1814     if (!id) {
1815         /* some MacOS versions after a catsearch do a *lot* of afp_resolveid with 0 */
1816         return AFPERR_NOID;
1817     }
1818 retry:
1819     memset(&path, 0, sizeof(path));
1820     if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1821         return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1822     }
1823
1824     if (NULL == ( dir = dirlookup( vol, id )) ) {
1825         return AFPERR_NOID; /* idem AFPERR_PARAM */
1826     }
1827     path.u_name = upath;
1828     if (movecwd(vol, dir) < 0) {
1829         switch (errno) {
1830         case EACCES:
1831         case EPERM:
1832             return AFPERR_ACCESS;
1833         case ENOENT:
1834             return AFPERR_NOID;
1835         default:
1836             return AFPERR_PARAM;
1837         }
1838     }
1839
1840     if ( of_stat(&path) < 0 ) {
1841 #ifdef ESTALE
1842         /* with nfs and our working directory is deleted */
1843         if (errno == ESTALE) {
1844             errno = ENOENT;
1845         }
1846 #endif  
1847         if ( errno == ENOENT && !retry) {
1848             /* cnid db is out of sync, reenumerate the directory and update ids */
1849             reenumerate_id(vol, ".", dir);
1850             id = cnid;
1851             retry = 1;
1852             goto retry;
1853         }
1854         switch (errno) {
1855         case EACCES:
1856         case EPERM:
1857             return AFPERR_ACCESS;
1858         case ENOENT:
1859             return AFPERR_NOID;
1860         default:
1861             return AFPERR_PARAM;
1862         }
1863     }
1864
1865     /* directories are bad */
1866     if (S_ISDIR(path.st.st_mode))
1867         return AFPERR_BADTYPE;
1868
1869     memcpy(&bitmap, ibuf, sizeof(bitmap));
1870     bitmap = ntohs( bitmap );
1871     if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1872         return AFPERR_NOID;
1873     }
1874     path.id = cnid;
1875     if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir, 
1876                             rbuf + sizeof(bitmap), &buflen))) {
1877         return err;
1878     }
1879     *rbuflen = buflen + sizeof(bitmap);
1880     memcpy(rbuf, ibuf, sizeof(bitmap));
1881
1882 #ifdef DEBUG
1883     LOG(log_info, logtype_afpd, "end afp_resolveid:");
1884 #endif /* DEBUG */
1885
1886     return AFP_OK;
1887 }
1888
1889 /* ------------------------------ */
1890 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1891 AFPObj  *obj _U_;
1892 char    *ibuf, *rbuf _U_;
1893 int     ibuflen _U_, *rbuflen;
1894 {
1895     struct stat         st;
1896     struct vol          *vol;
1897     struct dir          *dir;
1898     char                *upath;
1899     int                 err;
1900     cnid_t              id;
1901     cnid_t              fileid;
1902     u_short             vid;
1903     static char buffer[12 + MAXPATHLEN + 1];
1904     int len = 12 + MAXPATHLEN + 1;
1905
1906 #ifdef DEBUG
1907     LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1908 #endif /* DEBUG */
1909
1910     *rbuflen = 0;
1911     ibuf += 2;
1912
1913     memcpy(&vid, ibuf, sizeof(vid));
1914     ibuf += sizeof(vid);
1915
1916     if (NULL == ( vol = getvolbyvid( vid )) ) {
1917         return( AFPERR_PARAM);
1918     }
1919
1920     if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1921         return AFPERR_NOOP;
1922     }
1923
1924     if (vol->v_flags & AFPVOL_RO)
1925         return AFPERR_VLOCK;
1926
1927     memcpy(&id, ibuf, sizeof( id ));
1928     ibuf += sizeof(id);
1929     fileid = id;
1930
1931     if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1932         return AFPERR_NOID;
1933     }
1934
1935     if (NULL == ( dir = dirlookup( vol, id )) ) {
1936         return( AFPERR_PARAM );
1937     }
1938
1939     err = AFP_OK;
1940     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1941         switch (errno) {
1942         case EACCES:
1943         case EPERM:
1944             return AFPERR_ACCESS;
1945 #ifdef ESTALE
1946         case ESTALE:
1947 #endif  
1948         case ENOENT:
1949             /* still try to delete the id */
1950             err = AFPERR_NOOBJ;
1951             break;
1952         default:
1953             return AFPERR_PARAM;
1954         }
1955     }
1956     else if (S_ISDIR(st.st_mode)) /* directories are bad */
1957         return AFPERR_BADTYPE;
1958
1959     if (cnid_delete(vol->v_cdb, fileid)) {
1960         switch (errno) {
1961         case EROFS:
1962             return AFPERR_VLOCK;
1963         case EPERM:
1964         case EACCES:
1965             return AFPERR_ACCESS;
1966         default:
1967             return AFPERR_PARAM;
1968         }
1969     }
1970
1971 #ifdef DEBUG
1972     LOG(log_info, logtype_afpd, "end afp_deleteid:");
1973 #endif /* DEBUG */
1974
1975     return err;
1976 }
1977
1978 /* ------------------------------ */
1979 static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
1980 {
1981     int             ret;
1982
1983     if (path->st_errno) {
1984         switch (path->st_errno) {
1985         case ENOENT:
1986             afp_errno = AFPERR_NOID;
1987             break;
1988         case EPERM:
1989         case EACCES:
1990             afp_errno = AFPERR_ACCESS;
1991             break;
1992         default:
1993             afp_errno = AFPERR_PARAM;
1994             break;
1995         }
1996         return NULL;
1997     }
1998     /* we use file_access both for legacy Mac perm and
1999      * for unix privilege, rename will take care of folder perms
2000     */
2001     if (file_access(path, OPENACC_WR ) < 0) {
2002         afp_errno = AFPERR_ACCESS;
2003         return NULL;
2004     }
2005     
2006     if ((*of = of_findname(path))) {
2007         /* reuse struct adouble so it won't break locks */
2008         adp = (*of)->of_ad;
2009     }
2010     else {
2011         ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
2012         if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
2013             /* from AFP spec.
2014              * The user must have the Read & Write privilege for both files in order to use this command.
2015              */
2016             ad_close(adp, ADFLAGS_HF);
2017             afp_errno = AFPERR_ACCESS;
2018             return NULL;
2019         }
2020     }
2021     return adp;
2022 }
2023
2024 #define APPLETEMP ".AppleTempXXXXXX"
2025
2026 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
2027 AFPObj  *obj;
2028 char    *ibuf, *rbuf _U_ ;
2029 int     ibuflen _U_, *rbuflen;
2030 {
2031     struct stat         srcst, destst;
2032     struct vol          *vol;
2033     struct dir          *dir, *sdir;
2034     char                *spath, temp[17], *p;
2035     char                *supath, *upath;
2036     struct path         *path;
2037     int                 err;
2038     struct adouble      ads;
2039     struct adouble      add;
2040     struct adouble      *adsp = NULL;
2041     struct adouble      *addp = NULL;
2042     struct ofork        *s_of = NULL;
2043     struct ofork        *d_of = NULL;
2044     int                 crossdev;
2045     
2046     int                 slen, dlen;
2047     u_int32_t           sid, did;
2048     u_int16_t           vid;
2049
2050     uid_t              uid;
2051     gid_t              gid;
2052
2053 #ifdef DEBUG
2054     LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
2055 #endif /* DEBUG */
2056
2057     *rbuflen = 0;
2058     ibuf += 2;
2059
2060     memcpy(&vid, ibuf, sizeof(vid));
2061     ibuf += sizeof(vid);
2062
2063     if (NULL == ( vol = getvolbyvid( vid )) ) {
2064         return( AFPERR_PARAM);
2065     }
2066
2067     if ((vol->v_flags & AFPVOL_RO))
2068         return AFPERR_VLOCK;
2069
2070     /* source and destination dids */
2071     memcpy(&sid, ibuf, sizeof(sid));
2072     ibuf += sizeof(sid);
2073     memcpy(&did, ibuf, sizeof(did));
2074     ibuf += sizeof(did);
2075
2076     /* source file */
2077     if (NULL == (dir = dirlookup( vol, sid )) ) {
2078         return afp_errno; /* was AFPERR_PARAM */
2079     }
2080
2081     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2082         return get_afp_errno(AFPERR_NOOBJ); 
2083     }
2084
2085     if ( path_isadir(path) ) {
2086         return AFPERR_BADTYPE;   /* it's a dir */
2087     }
2088
2089     /* save some stuff */
2090     srcst = path->st;
2091     sdir = curdir;
2092     spath = obj->oldtmp;
2093     supath = obj->newtmp;
2094     strcpy(spath, path->m_name);
2095     strcpy(supath, path->u_name); /* this is for the cnid changing */
2096     p = absupath( vol, sdir, supath);
2097     if (!p) {
2098         /* pathname too long */
2099         return AFPERR_PARAM ;
2100     }
2101     
2102     ad_init(&ads, vol->v_adouble, vol->v_ad_options);
2103     if (!(adsp = find_adouble( path, &s_of, &ads))) {
2104         return afp_errno;
2105     }
2106
2107     /* ***** from here we may have resource fork open **** */
2108     
2109     /* look for the source cnid. if it doesn't exist, don't worry about
2110      * it. */
2111     sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
2112
2113     if (NULL == ( dir = dirlookup( vol, did )) ) {
2114         err = afp_errno; /* was AFPERR_PARAM */
2115         goto err_exchangefile;
2116     }
2117
2118     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2119         err = get_afp_errno(AFPERR_NOOBJ); 
2120         goto err_exchangefile;
2121     }
2122
2123     if ( path_isadir(path) ) {
2124         err = AFPERR_BADTYPE;
2125         goto err_exchangefile;
2126     }
2127
2128     /* FPExchangeFiles is the only call that can return the SameObj
2129      * error */
2130     if ((curdir == sdir) && strcmp(spath, path->m_name) == 0) {
2131         err = AFPERR_SAMEOBJ;
2132         goto err_exchangefile;
2133     }
2134
2135     ad_init(&add, vol->v_adouble, vol->v_ad_options);
2136     if (!(addp = find_adouble( path, &d_of, &add))) {
2137         err = afp_errno;
2138         goto err_exchangefile;
2139     }
2140     destst = path->st;
2141
2142     /* they are not on the same device and at least one is open
2143      * FIXME broken for for crossdev and adouble v2
2144      * return an error 
2145     */
2146     crossdev = (srcst.st_dev != destst.st_dev);
2147     if (/* (d_of || s_of)  && */ crossdev) {
2148         err = AFPERR_MISC;
2149         goto err_exchangefile;
2150     }
2151
2152     /* look for destination id. */
2153     upath = path->u_name;
2154     did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
2155
2156     /* construct a temp name.
2157      * NOTE: the temp file will be in the dest file's directory. it
2158      * will also be inaccessible from AFP. */
2159     memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
2160     if (!mktemp(temp)) {
2161         err = AFPERR_MISC;
2162         goto err_exchangefile;
2163     }
2164     
2165     if (crossdev) {
2166         /* FIXME we need to close fork for copy, both s_of and d_of are null */
2167        ad_close(adsp, ADFLAGS_HF);
2168        ad_close(addp, ADFLAGS_HF);
2169     }
2170
2171     /* now, quickly rename the file. we error if we can't. */
2172     if ((err = renamefile(vol, p, temp, temp, adsp)) != AFP_OK)
2173         goto err_exchangefile;
2174     of_rename(vol, s_of, sdir, spath, curdir, temp);
2175
2176     /* rename destination to source */
2177     if ((err = renamefile(vol, upath, p, spath, addp)) != AFP_OK)
2178         goto err_src_to_tmp;
2179     of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
2180
2181     /* rename temp to destination */
2182     if ((err = renamefile(vol, temp, upath, path->m_name, adsp)) != AFP_OK)
2183         goto err_dest_to_src;
2184     of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
2185
2186     /* id's need switching. src -> dest and dest -> src. 
2187      * we need to re-stat() if it was a cross device copy.
2188     */
2189     if (sid) {
2190         cnid_delete(vol->v_cdb, sid);
2191     }
2192     if (did) {
2193         cnid_delete(vol->v_cdb, did);
2194     }
2195     if ((did && ( (crossdev && stat( upath, &srcst) < 0) || 
2196                 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
2197        ||
2198        (sid && ( (crossdev && stat(p, &destst) < 0) ||
2199                 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
2200     ) {
2201         switch (errno) {
2202         case EPERM:
2203         case EACCES:
2204             err = AFPERR_ACCESS;
2205             break;
2206         default:
2207             err = AFPERR_PARAM;
2208         }
2209         goto err_temp_to_dest;
2210     }
2211     
2212     /* here we need to reopen if crossdev */
2213     if (sid && ad_setid(addp, destst.st_dev, destst.st_ino,  sid, sdir->d_did, vol->v_stamp)) 
2214     {
2215        ad_flush( addp, ADFLAGS_HF );
2216     }
2217         
2218     if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino,  did, curdir->d_did, vol->v_stamp)) 
2219     {
2220        ad_flush( adsp, ADFLAGS_HF );
2221     }
2222
2223     /* change perms, src gets dest perm and vice versa */
2224
2225     uid = geteuid();
2226     gid = getegid();
2227     if (seteuid(0)) {
2228         LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
2229         err = AFP_OK; /* ignore error */
2230         goto err_temp_to_dest;
2231     }
2232
2233     /*
2234      * we need to exchange ACL entries as well
2235      */
2236     /* exchange_acls(vol, p, upath); */
2237
2238     path->st = srcst;
2239     path->st_valid = 1;
2240     path->st_errno = 0;
2241     path->m_name = NULL;
2242     path->u_name = upath;
2243
2244     setfilunixmode(vol, path, destst.st_mode);
2245     setfilowner(vol, destst.st_uid, destst.st_gid, path);
2246
2247     path->st = destst;
2248     path->st_valid = 1;
2249     path->st_errno = 0;
2250     path->u_name = p;
2251
2252     setfilunixmode(vol, path, srcst.st_mode);
2253     setfilowner(vol, srcst.st_uid, srcst.st_gid, path);
2254
2255     if ( setegid(gid) < 0 || seteuid(uid) < 0) {
2256         LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
2257         exit(EXITERR_SYS);
2258     }
2259
2260 #ifdef DEBUG
2261     LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
2262 #endif /* DEBUG */
2263
2264     err = AFP_OK;
2265     goto err_exchangefile;
2266
2267     /* all this stuff is so that we can unwind a failed operation
2268      * properly. */
2269 err_temp_to_dest:
2270     /* rename dest to temp */
2271     renamefile(vol, upath, temp, temp, adsp);
2272     of_rename(vol, s_of, curdir, upath, curdir, temp);
2273
2274 err_dest_to_src:
2275     /* rename source back to dest */
2276     renamefile(vol, p, upath, path->m_name, addp);
2277     of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
2278
2279 err_src_to_tmp:
2280     /* rename temp back to source */
2281     renamefile(vol, temp, p, spath, adsp);
2282     of_rename(vol, s_of, curdir, temp, sdir, spath);
2283
2284 err_exchangefile:
2285     if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
2286        ad_close(adsp, ADFLAGS_HF);
2287     }
2288     if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
2289        ad_close(addp, ADFLAGS_HF);
2290     }
2291
2292     return err;
2293 }