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