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