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