2 * $Id: file.c,v 1.92.2.2.2.8 2004-01-02 18:14:52 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
16 #endif /* HAVE_UNISTD_H */
21 #else /* STDC_HEADERS */
25 #endif /* HAVE_STRCHR */
26 char *strchr (), *strrchr ();
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 */
36 #endif /* HAVE_FCNTL_H */
41 #include <atalk/logger.h>
42 #include <sys/types.h>
44 #include <sys/param.h>
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"
61 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
62 * field bytes subfield bytes
65 * ioFlFndrInfo 16 -> type 4 type field
66 * creator 4 creator field
67 * flags 2 finder flags:
69 * location 4 location in window
70 * folder 2 window that contains file
72 * ioFlXFndrInfo 16 -> iconID 2 icon id
74 * script 1 script system
76 * commentID 2 comment id
77 * putawayID 4 home directory id
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
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)
93 if (adp && (ad_finder = ad_entry(adp, ADEID_FINDERI))) {
94 memcpy(data, ad_finder, 32);
97 memcpy(data, ufinderi, 32);
100 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
101 && (em = getextmap( mpath ))
103 memcpy(data, em->em_type, sizeof( em->em_type ));
104 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
109 /* ---------------------
111 char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t id, u_int32_t utf8)
116 aint = strlen( name );
120 if (utf8_encoding()) {
121 /* but name is an utf8 mac name */
124 /* global static variable... */
126 if (!(u = mtoupath(vol, name, pid, 1)) || !(m = utompath(vol, u, id, 0))) {
135 if (aint > MACFILELEN)
142 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
145 utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0; /* htonl(utf8) */
146 memcpy(data, &utf8, sizeof(utf8));
147 data += sizeof(utf8);
150 memcpy(data, &temp, sizeof(temp));
151 data += sizeof(temp);
154 memcpy( data, src, aint );
164 * FIXME: PDINFO is UTF8 and doesn't need adp
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)))
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)
181 #if AD_VERSION > AD_VERSION1
184 char stamp[ADEDLEN_PRIVSYN];
185 /* look in AD v2 header
186 * note inode and device are opaques and not in network order
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));
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));
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) {
208 case CNID_ERR_CLOSE: /* the db is closed */
211 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
212 afp_errno = AFPERR_PARAM;
215 afp_errno = AFPERR_PARAM;
218 afp_errno = AFPERR_MISC;
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
227 ad_setid(adp, st, aint, vol->v_stamp);
228 ad_flush(adp, ADFLAGS_HF);
235 /* -------------------------- */
236 int getmetadata(struct vol *vol,
238 struct path *path, struct dir *dir,
239 char *buf, int *buflen, struct adouble *adp, int attrbits )
241 char *data, *l_nameoff = NULL, *upath;
242 char *utf_nameoff = NULL;
247 u_char achar, fdType[4];
253 LOG(log_info, logtype_afpd, "begin getmetadata:");
256 upath = path->u_name;
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))) {
265 id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
269 path->m_name = utompath(vol, upath, id, utf8_encoding());
272 while ( bitmap != 0 ) {
273 while (( bitmap & 1 ) == 0 ) {
281 ad_getattr(adp, &ashort);
282 } else if (*upath == '.') {
283 ashort = htons(ATTRBIT_INVISIBLE);
287 /* FIXME do we want a visual clue if the file is read only
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;
299 ashort = htons(ntohs(ashort) | attrbits);
300 memcpy(data, &ashort, sizeof( ashort ));
301 data += sizeof( ashort );
305 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
306 data += sizeof( u_int32_t );
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 );
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);
322 aint = AD_DATE_FROM_UNIX(st->st_mtime);
324 memcpy(data, &aint, sizeof( int ));
325 data += sizeof( int );
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 );
336 get_finderinfo(path->m_name, adp, (char *)data);
338 if (*upath == '.') { /* make it invisible */
339 ashort = htons(FINDERINFO_INVISIBLE);
340 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
348 data += sizeof( u_int16_t );
352 memset(data, 0, sizeof(u_int16_t));
353 data += sizeof( u_int16_t );
357 memcpy(data, &id, sizeof( id ));
358 data += sizeof( id );
362 if (st->st_size > 0xffffffff)
365 aint = htonl( st->st_size );
366 memcpy(data, &aint, sizeof( aint ));
367 data += sizeof( aint );
372 if (adp->ad_rlen > 0xffffffff)
375 aint = htonl( adp->ad_rlen);
379 memcpy(data, &aint, sizeof( aint ));
380 data += sizeof( aint );
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;
393 data += sizeof( u_int16_t );
395 memcpy(data, &aint, sizeof( aint ));
396 data += sizeof( aint );
400 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
402 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
406 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
410 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
414 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
418 else if ( fdType[0] == 'p' ) {
420 ashort = (fdType[2] * 256) + fdType[3];
434 memcpy(data, &ashort, sizeof( ashort ));
435 data += sizeof( ashort );
436 memset(data, 0, sizeof( ashort ));
437 data += sizeof( ashort );
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 );
448 case FILPBIT_EXTRFLEN:
451 aint = htonl(adp->ad_rlen >> 32);
452 memcpy(data, &aint, sizeof( aint ));
453 data += sizeof( aint );
455 aint = htonl(adp->ad_rlen);
456 memcpy(data, &aint, sizeof( aint ));
457 data += sizeof( aint );
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 );
467 aint = htonl(st->st_mode);
468 memcpy( data, &aint, sizeof( aint ));
469 data += sizeof( aint );
471 accessmode( upath, &ma, dir , st);
473 *data++ = ma.ma_user;
474 *data++ = ma.ma_world;
475 *data++ = ma.ma_group;
476 *data++ = ma.ma_owner;
480 return( AFPERR_BITMAP );
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);
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);
495 *buflen = data - buf;
499 /* ----------------------- */
500 int getfilparams(struct vol *vol,
502 struct path *path, struct dir *dir,
503 char *buf, int *buflen )
505 struct adouble ad, *adp;
508 u_int16_t attrbits = 0;
513 LOG(log_info, logtype_default, "begin getfilparams:");
516 opened = PARAM_NEED_ADP(bitmap);
519 upath = path->u_name;
520 if ((of = of_findname(path))) {
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);
525 ad_init(&ad, vol->v_adouble);
529 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
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!
539 if ((bitmap & (1 << FILPBIT_ATTR))) {
540 if (!(attrbits & ATTRBIT_ROPEN)) {
542 if (!(attrbits & ATTRBIT_DOPEN)) {
547 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
549 ad_close( adp, ADFLAGS_HF );
552 LOG(log_info, logtype_afpd, "end getfilparams:");
558 /* ----------------------------- */
559 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
562 int ibuflen, *rbuflen;
564 struct adouble ad, *adp;
567 struct ofork *of = NULL;
569 int creatf, did, openf, retvalue = AFP_OK;
575 LOG(log_info, logtype_afpd, "begin afp_createfile:");
580 creatf = (unsigned char) *ibuf++;
582 memcpy(&vid, ibuf, sizeof( vid ));
583 ibuf += sizeof( vid );
585 if (NULL == ( vol = getvolbyvid( vid )) ) {
586 return( AFPERR_PARAM );
589 if (vol->v_flags & AFPVOL_RO)
592 memcpy(&did, ibuf, sizeof( did));
593 ibuf += sizeof( did );
595 if (NULL == ( dir = dirlookup( vol, did )) ) {
599 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
600 return get_afp_errno(AFPERR_PARAM);
603 if ( *s_path->m_name == '\0' ) {
604 return( AFPERR_BADTYPE );
607 upath = s_path->u_name;
608 if (0 != (ret = check_name(vol, upath)))
611 /* if upath is deleted we already in trouble anyway */
612 if ((of = of_findname(s_path))) {
615 ad_init(&ad, vol->v_adouble);
619 /* on a hard create, fail if file exists and is open */
622 openf = O_RDWR|O_CREAT|O_TRUNC;
624 /* on a soft create, if the file is open then ad_open won't fail
625 because open syscall is not called
630 openf = O_RDWR|O_CREAT|O_EXCL;
633 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
634 openf, 0666, adp) < 0 ) {
638 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
639 return ( AFPERR_NOOBJ );
641 return( AFPERR_EXIST );
643 return( AFPERR_ACCESS );
645 return( AFPERR_PARAM );
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;
654 /* FIXME with hard create on an existing file, we already
655 * corrupted the data file.
657 netatalk_unlink( upath );
658 ad_close( adp, ADFLAGS_DF );
659 return AFPERR_ACCESS;
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 );
673 if (vol->v_flags & AFPVOL_DROPBOX) {
674 retvalue = matchfile2dirperms(upath, vol, did);
676 #endif /* DROPKLUDGE */
678 setvoltime(obj, vol );
681 LOG(log_info, logtype_afpd, "end afp_createfile");
687 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
690 int ibuflen, *rbuflen;
696 u_int16_t vid, bitmap;
699 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
705 memcpy(&vid, ibuf, sizeof( vid ));
706 ibuf += sizeof( vid );
707 if (NULL == ( vol = getvolbyvid( vid )) ) {
708 return( AFPERR_PARAM );
711 if (vol->v_flags & AFPVOL_RO)
714 memcpy(&did, ibuf, sizeof( did ));
715 ibuf += sizeof( did );
716 if (NULL == ( dir = dirlookup( vol, did )) ) {
717 return afp_errno; /* was AFPERR_NOOBJ */
720 memcpy(&bitmap, ibuf, sizeof( bitmap ));
721 bitmap = ntohs( bitmap );
722 ibuf += sizeof( bitmap );
724 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
725 return get_afp_errno(AFPERR_PARAM);
728 if (path_isadir(s_path)) {
729 return( AFPERR_BADTYPE ); /* it's a directory */
732 if ( s_path->st_errno != 0 ) {
733 return( AFPERR_NOOBJ );
736 if ((u_long)ibuf & 1 ) {
740 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
741 setvoltime(obj, vol );
745 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
752 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
755 extern struct path Cur_Path;
757 int setfilparams(struct vol *vol,
758 struct path *path, u_int16_t bitmap, char *buf )
760 struct adouble ad, *adp;
763 int bit = 0, isad = 1, err = AFP_OK;
765 u_char achar, *fdType, xyy[4];
766 u_int16_t ashort, bshort;
770 int change_mdate = 0;
771 int change_parent_mdate = 0;
777 LOG(log_info, logtype_afpd, "begin setfilparams:");
780 upath = path->u_name;
781 if ((of = of_findname(path))) {
784 ad_init(&ad, vol->v_adouble);
788 if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
789 return AFPERR_ACCESS;
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;
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 ));
805 while ( bitmap != 0 ) {
806 while (( bitmap & 1 ) == 0 ) {
814 memcpy(&ashort, buf, sizeof( ashort ));
815 ad_getattr(adp, &bshort);
816 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
817 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
821 if ((ashort & htons(ATTRBIT_INVISIBLE)))
822 change_parent_mdate = 1;
823 ad_setattr(adp, bshort);
824 buf += sizeof( ashort );
829 memcpy(&aint, buf, sizeof(aint));
830 ad_setdate(adp, AD_DATE_CREATE, aint);
831 buf += sizeof( aint );
835 memcpy(&newdate, buf, sizeof( newdate ));
836 buf += sizeof( newdate );
841 memcpy(&aint, buf, sizeof(aint));
842 ad_setdate(adp, AD_DATE_BACKUP, aint);
843 buf += sizeof( aint );
849 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
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)))
858 memcpy(buf, ufinderi, 8 );
861 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
865 case FILPBIT_UNIXPR :
866 /* Skip the UIG/GID, no way to set them from OSX clients */
867 buf += sizeof( aint );
868 buf += sizeof( aint );
871 change_parent_mdate = 1;
872 memcpy( &aint, buf, sizeof( aint ));
873 buf += sizeof( aint );
876 setfilemode(path, aint);
878 /* Client needs to set the ProDOS file info for this file.
879 Use a defined string for TEXT to support crlf
880 translations and convert all else into pXYY per Inside
881 Appletalk. Always set the creator as "pdos". Changes
882 from original by Marsha Jackson. */
883 case FILPBIT_PDINFO :
884 if (afp_version < 30) { /* else it's UTF8 name */
887 /* Keep special case to support crlf translations */
888 if ((unsigned int) achar == 0x04) {
889 fdType = (u_char *)"TEXT";
892 xyy[0] = ( u_char ) 'p';
898 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
899 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
905 goto setfilparam_done;
913 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
914 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
918 ad_setdate(adp, AD_DATE_MODIFY, newdate);
919 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
924 ad_flush( adp, ADFLAGS_HF );
925 ad_close( adp, ADFLAGS_HF );
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);
936 LOG(log_info, logtype_afpd, "end setfilparams:");
942 * renamefile and copyfile take the old and new unix pathnames
943 * and the new mac name.
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
951 int renamefile(src, dst, newname, noadouble, adp )
952 char *src, *dst, *newname;
956 char adsrc[ MAXPATHLEN + 1];
961 LOG(log_info, logtype_afpd, "begin renamefile:");
964 if ( unix_rename( src, dst ) < 0 ) {
967 return( AFPERR_NOOBJ );
970 return( AFPERR_ACCESS );
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
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 */
982 if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
983 /* on error copyfile delete dest */
986 return deletefile(NULL, src, 0);
988 return( AFPERR_PARAM );
992 strcpy( adsrc, ad_path( src, 0 ));
994 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
999 if (errno == ENOENT) {
1002 if (stat(adsrc, &st)) /* source has no ressource fork, */
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.
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 )) )
1020 else { /* it's something else, bail out */
1024 /* try to undo the data fork rename,
1025 * we know we are on the same device
1028 unix_rename( dst, src );
1029 /* return the first error */
1032 return AFPERR_NOOBJ;
1035 return AFPERR_ACCESS ;
1037 return AFPERR_VLOCK;
1039 return AFPERR_PARAM ;
1044 /* don't care if we can't open the newly renamed ressource fork
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 );
1054 LOG(log_info, logtype_afpd, "end renamefile:");
1060 int copy_path_name(char *newname, char *ibuf)
1067 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
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
1085 memcpy(&hint, ibuf, sizeof(hint));
1086 ibuf += sizeof(hint);
1088 memcpy(&len16, ibuf, sizeof(len16));
1089 ibuf += sizeof(len16);
1090 plen = ntohs(len16);
1093 if (plen > AFPOBJ_TMPSIZ) {
1096 strncpy( newname, ibuf, plen );
1097 newname[ plen ] = '\0';
1098 if (strlen(newname) != plen) {
1107 /* -----------------------------------
1109 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1112 int ibuflen, *rbuflen;
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;
1123 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1129 memcpy(&svid, ibuf, sizeof( svid ));
1130 ibuf += sizeof( svid );
1131 if (NULL == ( vol = getvolbyvid( svid )) ) {
1132 return( AFPERR_PARAM );
1135 memcpy(&sdid, ibuf, sizeof( sdid ));
1136 ibuf += sizeof( sdid );
1137 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1141 memcpy(&dvid, ibuf, sizeof( dvid ));
1142 ibuf += sizeof( dvid );
1143 memcpy(&ddid, ibuf, sizeof( ddid ));
1144 ibuf += sizeof( ddid );
1146 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1147 return get_afp_errno(AFPERR_PARAM);
1149 if ( path_isadir(s_path) ) {
1150 return( AFPERR_BADTYPE );
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. */
1159 newname = obj->newtmp;
1160 strcpy( newname, s_path->m_name );
1162 if (of_findname(s_path))
1163 return AFPERR_DENYCONF;
1165 p = ctoupath( vol, curdir, newname );
1167 return AFPERR_PARAM;
1171 /* FIXME svid != dvid && dvid's user can't read svid */
1173 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1174 return( AFPERR_PARAM );
1177 if (vol->v_flags & AFPVOL_RO)
1178 return AFPERR_VLOCK;
1180 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1184 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1185 return get_afp_errno(AFPERR_NOOBJ);
1187 if ( *s_path->m_name != '\0' ) {
1189 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1191 path_error(s_path, AFPERR_PARAM);
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 );
1198 /* newname is always only a filename so curdir *is* its
1201 if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))) {
1202 return( AFPERR_PARAM );
1204 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1210 if (vol->v_flags & AFPVOL_DROPBOX) {
1211 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1213 #endif /* DROPKLUDGE */
1215 setvoltime(obj, vol );
1218 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1225 static __inline__ int copy_all(const int dfd, const void *buf,
1231 LOG(log_info, logtype_afpd, "begin copy_all:");
1234 while (buflen > 0) {
1235 if ((cc = write(dfd, buf, buflen)) < 0) {
1242 return AFPERR_DFULL;
1244 return AFPERR_VLOCK;
1246 return AFPERR_PARAM;
1253 LOG(log_info, logtype_afpd, "end copy_all:");
1259 /* -------------------------- */
1260 static int copy_fd(int dfd, int sfd)
1266 #ifdef SENDFILE_FLAVOR_LINUX
1270 #define BUF 128*1024*1024
1272 if (fstat(sfd, &st) == 0) {
1275 if ( offset >= st.st_size) {
1278 size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
1279 if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
1282 case EINVAL: /* there's no guarantee that all fs support sendfile */
1287 return AFPERR_DFULL;
1289 return AFPERR_VLOCK;
1291 return AFPERR_PARAM;
1297 lseek(sfd, offset, SEEK_SET);
1301 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1308 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1314 /* ----------------------------------
1315 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1316 * because we are doing it elsewhere.
1318 int copyfile(src, dst, newname, noadouble )
1319 char *src, *dst, *newname;
1320 const int noadouble;
1322 struct adouble ads, add;
1323 int len, err = AFP_OK;
1327 LOG(log_info, logtype_afpd, "begin copyfile:");
1330 ad_init(&ads, 0); /* OK */
1331 ad_init(&add, 0); /* FIXME */
1332 adflags = ADFLAGS_DF;
1334 adflags |= ADFLAGS_HF;
1337 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1340 return( AFPERR_NOOBJ );
1342 return( AFPERR_ACCESS );
1344 return( AFPERR_PARAM );
1347 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1348 ad_close( &ads, adflags );
1349 if (EEXIST != (err = errno)) {
1350 deletefile(NULL, dst, 0);
1354 return AFPERR_EXIST;
1356 return( AFPERR_NOOBJ );
1358 return( AFPERR_ACCESS );
1360 return AFPERR_VLOCK;
1362 return( AFPERR_PARAM );
1365 if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1366 /* copy the data fork */
1367 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1370 /* Now, reopen destination file */
1372 if (ad_close( &add, adflags ) <0) {
1373 deletefile(NULL, dst, 0);
1374 return AFPERR_PARAM; /* FIXME */
1377 if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
1378 ad_close( &ads, adflags );
1379 deletefile(NULL, dst, 0);
1382 return( AFPERR_NOOBJ );
1384 return( AFPERR_ACCESS );
1386 return AFPERR_VLOCK;
1388 return( AFPERR_PARAM );
1394 len = strlen( newname );
1395 ad_setentrylen( &add, ADEID_NAME, len );
1396 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1399 ad_close( &ads, adflags );
1400 ad_flush( &add, adflags );
1401 if (ad_close( &add, adflags ) <0) {
1404 if (err != AFP_OK) {
1405 deletefile(NULL, dst, 0);
1408 return( AFPERR_NOOBJ );
1410 return( AFPERR_ACCESS );
1412 return( AFPERR_PARAM );
1417 LOG(log_info, logtype_afpd, "end copyfile:");
1424 /* -----------------------------------
1425 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1426 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1428 when deletefile is called we don't have lock on it, file is closed (for us)
1429 untrue if called by renamefile
1431 ad_open always try to open file RDWR first and ad_lock takes care of
1432 WRITE lock on read only file.
1434 int deletefile( vol, file, checkAttrib )
1440 int adflags, err = AFP_OK;
1443 LOG(log_info, logtype_afpd, "begin deletefile:");
1446 /* try to open both forks at once */
1447 adflags = ADFLAGS_DF|ADFLAGS_HF;
1449 ad_init(&ad, 0); /* OK */
1450 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1453 if (adflags == ADFLAGS_DF)
1454 return AFPERR_NOOBJ;
1456 /* that failed. now try to open just the data fork */
1457 adflags = ADFLAGS_DF;
1461 return AFPERR_ACCESS;
1463 return AFPERR_VLOCK;
1465 return( AFPERR_PARAM );
1468 break; /* from the while */
1471 * Does kFPDeleteInhibitBit (bit 8) set?
1473 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1476 ad_getattr(&ad, &bshort);
1477 if ((bshort & htons(ATTRBIT_NODELETE))) {
1478 ad_close( &ad, adflags );
1479 return(AFPERR_OLOCK);
1483 if ((adflags & ADFLAGS_HF) ) {
1484 /* FIXME we have a pb here because we want to know if a file is open
1485 * there's a 'priority inversion' if you can't open the ressource fork RW
1486 * you can delete it if it's open because you can't get a write lock.
1488 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1491 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1493 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1494 ad_close( &ad, adflags );
1495 return( AFPERR_BUSY );
1499 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1502 else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1503 !(err = netatalk_unlink( file )) ) {
1505 if (vol && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file))))
1507 cnid_delete(vol->v_cdb, id);
1511 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1514 LOG(log_info, logtype_afpd, "end deletefile:");
1520 /* ------------------------------------ */
1521 /* return a file id */
1522 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1525 int ibuflen, *rbuflen;
1534 struct path *s_path;
1537 LOG(log_info, logtype_afpd, "begin afp_createid:");
1544 memcpy(&vid, ibuf, sizeof(vid));
1545 ibuf += sizeof(vid);
1547 if (NULL == ( vol = getvolbyvid( vid )) ) {
1548 return( AFPERR_PARAM);
1551 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1555 if (vol->v_flags & AFPVOL_RO)
1556 return AFPERR_VLOCK;
1558 memcpy(&did, ibuf, sizeof( did ));
1559 ibuf += sizeof(did);
1561 if (NULL == ( dir = dirlookup( vol, did )) ) {
1562 return afp_errno; /* was AFPERR_PARAM */
1565 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1566 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1569 if ( path_isadir(s_path) ) {
1570 return( AFPERR_BADTYPE );
1573 upath = s_path->u_name;
1574 switch (s_path->st_errno) {
1576 break; /* success */
1579 return AFPERR_ACCESS;
1581 return AFPERR_NOOBJ;
1583 return AFPERR_PARAM;
1586 if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) {
1587 memcpy(rbuf, &id, sizeof(id));
1588 *rbuflen = sizeof(id);
1589 return AFPERR_EXISTID;
1592 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1593 memcpy(rbuf, &id, sizeof(id));
1594 *rbuflen = sizeof(id);
1599 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1604 /* ------------------------------
1605 resolve a file id */
1606 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1609 int ibuflen, *rbuflen;
1617 u_int16_t vid, bitmap;
1619 static char buffer[12 + MAXPATHLEN + 1];
1620 int len = 12 + MAXPATHLEN + 1;
1623 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1629 memcpy(&vid, ibuf, sizeof(vid));
1630 ibuf += sizeof(vid);
1632 if (NULL == ( vol = getvolbyvid( vid )) ) {
1633 return( AFPERR_PARAM);
1636 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1640 memcpy(&id, ibuf, sizeof( id ));
1644 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1645 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1648 if (NULL == ( dir = dirlookup( vol, id )) ) {
1649 return AFPERR_NOID; /* idem AFPERR_PARAM */
1651 path.u_name = upath;
1652 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1656 return AFPERR_ACCESS;
1660 return AFPERR_PARAM;
1663 /* directories are bad */
1664 if (S_ISDIR(path.st.st_mode))
1665 return AFPERR_BADTYPE;
1667 memcpy(&bitmap, ibuf, sizeof(bitmap));
1668 bitmap = ntohs( bitmap );
1669 if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) {
1672 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1673 rbuf + sizeof(bitmap), &buflen))) {
1676 *rbuflen = buflen + sizeof(bitmap);
1677 memcpy(rbuf, ibuf, sizeof(bitmap));
1680 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1686 /* ------------------------------ */
1687 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1690 int ibuflen, *rbuflen;
1700 static char buffer[12 + MAXPATHLEN + 1];
1701 int len = 12 + MAXPATHLEN + 1;
1704 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1710 memcpy(&vid, ibuf, sizeof(vid));
1711 ibuf += sizeof(vid);
1713 if (NULL == ( vol = getvolbyvid( vid )) ) {
1714 return( AFPERR_PARAM);
1717 if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
1721 if (vol->v_flags & AFPVOL_RO)
1722 return AFPERR_VLOCK;
1724 memcpy(&id, ibuf, sizeof( id ));
1728 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
1732 if (NULL == ( dir = dirlookup( vol, id )) ) {
1733 return( AFPERR_PARAM );
1737 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1741 return AFPERR_ACCESS;
1743 /* still try to delete the id */
1747 return AFPERR_PARAM;
1750 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1751 return AFPERR_BADTYPE;
1753 if (cnid_delete(vol->v_cdb, fileid)) {
1756 return AFPERR_VLOCK;
1759 return AFPERR_ACCESS;
1761 return AFPERR_PARAM;
1766 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1772 #define APPLETEMP ".AppleTempXXXXXX"
1774 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1777 int ibuflen, *rbuflen;
1779 struct stat srcst, destst;
1781 struct dir *dir, *sdir;
1782 char *spath, temp[17], *p;
1783 char *supath, *upath;
1788 struct adouble *adsp;
1789 struct adouble *addp;
1799 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1805 memcpy(&vid, ibuf, sizeof(vid));
1806 ibuf += sizeof(vid);
1808 if (NULL == ( vol = getvolbyvid( vid )) ) {
1809 return( AFPERR_PARAM);
1812 if (vol->v_flags & AFPVOL_RO)
1813 return AFPERR_VLOCK;
1815 /* source and destination dids */
1816 memcpy(&sid, ibuf, sizeof(sid));
1817 ibuf += sizeof(sid);
1818 memcpy(&did, ibuf, sizeof(did));
1819 ibuf += sizeof(did);
1822 if (NULL == (dir = dirlookup( vol, sid )) ) {
1823 return afp_errno; /* was AFPERR_PARAM */
1826 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1827 return get_afp_errno(AFPERR_NOOBJ);
1830 if ( path_isadir(path) ) {
1831 return( AFPERR_BADTYPE ); /* it's a dir */
1834 upath = path->u_name;
1835 switch (path->st_errno) {
1842 return AFPERR_ACCESS;
1844 return AFPERR_PARAM;
1846 ad_init(&ads, vol->v_adouble);
1848 if ((s_of = of_findname(path))) {
1849 /* reuse struct adouble so it won't break locks */
1852 memcpy(&srcst, &path->st, sizeof(struct stat));
1853 /* save some stuff */
1855 spath = obj->oldtmp;
1856 supath = obj->newtmp;
1857 strcpy(spath, path->m_name);
1858 strcpy(supath, upath); /* this is for the cnid changing */
1859 p = absupath( vol, sdir, upath);
1861 /* pathname too long */
1862 return AFPERR_PARAM ;
1865 /* look for the source cnid. if it doesn't exist, don't worry about
1867 sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath));
1869 if (NULL == ( dir = dirlookup( vol, did )) ) {
1870 return afp_errno; /* was AFPERR_PARAM */
1873 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1874 return get_afp_errno(AFPERR_NOOBJ);
1877 if ( path_isadir(path) ) {
1878 return( AFPERR_BADTYPE );
1881 /* FPExchangeFiles is the only call that can return the SameObj
1883 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1884 return AFPERR_SAMEOBJ;
1886 switch (path->st_errno) {
1893 return AFPERR_ACCESS;
1895 return AFPERR_PARAM;
1897 ad_init(&add, vol->v_adouble);
1899 if ((d_of = of_findname( path))) {
1900 /* reuse struct adouble so it won't break locks */
1903 memcpy(&destst, &path->st, sizeof(struct stat));
1905 /* they are not on the same device and at least one is open
1907 crossdev = (srcst.st_dev != destst.st_dev);
1908 if ((d_of || s_of) && crossdev)
1911 upath = path->u_name;
1912 /* look for destination id. */
1913 did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath));
1915 /* construct a temp name.
1916 * NOTE: the temp file will be in the dest file's directory. it
1917 * will also be inaccessible from AFP. */
1918 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1922 /* now, quickly rename the file. we error if we can't. */
1923 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1924 goto err_exchangefile;
1925 of_rename(vol, s_of, sdir, spath, curdir, temp);
1927 /* rename destination to source */
1928 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1929 goto err_src_to_tmp;
1930 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1932 /* rename temp to destination */
1933 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1934 goto err_dest_to_src;
1935 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1937 /* id's need switching. src -> dest and dest -> src.
1938 * we need to re-stat() if it was a cross device copy.
1941 cnid_delete(vol->v_cdb, sid);
1944 cnid_delete(vol->v_cdb, did);
1946 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1947 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
1949 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1950 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
1955 err = AFPERR_ACCESS;
1960 goto err_temp_to_dest;
1964 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1970 /* all this stuff is so that we can unwind a failed operation
1973 /* rename dest to temp */
1974 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1975 of_rename(vol, s_of, curdir, upath, curdir, temp);
1978 /* rename source back to dest */
1979 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1980 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1983 /* rename temp back to source */
1984 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1985 of_rename(vol, s_of, curdir, temp, sdir, spath);