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