2 * $Id: file.c,v 1.93 2003-06-02 06:54:22 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>
52 #include <atalk/cnid.h>
54 #include "directory.h"
63 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
64 * field bytes subfield bytes
67 * ioFlFndrInfo 16 -> type 4 type field
68 * creator 4 creator field
69 * flags 2 finder flags:
71 * location 4 location in window
72 * folder 2 window that contains file
74 * ioFlXFndrInfo 16 -> iconID 2 icon id
76 * script 1 script system
78 * commentID 2 comment id
79 * putawayID 4 home directory id
82 const u_char ufinderi[] = {
83 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
84 0, 0, 0, 0, 0, 0, 0, 0,
85 0, 0, 0, 0, 0, 0, 0, 0,
86 0, 0, 0, 0, 0, 0, 0, 0
89 /* FIXME mpath : unix or mac name ? (for now it's mac name ) */
90 void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
95 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
98 memcpy(data, ufinderi, 32);
101 if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
102 && (em = getextmap( mpath ))
104 memcpy(data, em->em_type, sizeof( em->em_type ));
105 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
110 /* ---------------------
112 char *set_name(const struct vol *vol, char *data, char *name, u_int32_t utf8)
117 aint = strlen( name );
121 if (utf8_encoding()) {
122 /* but name is an utf8 mac name */
125 /* global static variable... */
127 if (!(u = mtoupath(vol, name, 1)) || !(m = utompath(vol, u, 0))) {
136 if (aint > MACFILELEN)
143 if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/
147 memcpy(data, &utf8, sizeof(utf8));
148 data += sizeof(utf8);
151 memcpy(data, &temp, sizeof(temp));
152 data += sizeof(temp);
155 memcpy( data, src, aint );
165 * FIXME: PDINFO is UTF8 and doesn't need adp
167 #define PARAM_NEED_ADP(b) ((b) & ((1 << FILPBIT_ATTR) |\
168 (1 << FILPBIT_CDATE) |\
169 (1 << FILPBIT_MDATE) |\
170 (1 << FILPBIT_BDATE) |\
171 (1 << FILPBIT_FINFO) |\
172 (1 << FILPBIT_RFLEN) |\
173 (1 << FILPBIT_EXTRFLEN) |\
174 (1 << FILPBIT_PDINFO)))
176 /* -------------------------- */
177 u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
178 const cnid_t did, const char *upath, const int len)
184 aint = cnid_add(vol->v_db, st, did, upath, len, aint);
185 /* Throw errors if cnid_add fails. */
186 if (aint == CNID_INVALID) {
188 case CNID_ERR_CLOSE: /* the db is closed */
191 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
192 afp_errno = AFPERR_PARAM;
195 afp_errno = AFPERR_PARAM;
198 afp_errno = AFPERR_MISC;
206 * First thing: DID and FNUMs are
207 * in the same space for purposes of enumerate (and several
208 * other wierd places). While we consider this Apple's bug,
209 * this is the work-around: In order to maintain constant and
210 * unique DIDs and FNUMs, we monotonically generate the DIDs
211 * during the session, and derive the FNUMs from the filesystem.
212 * Since the DIDs are small, we insure that the FNUMs are fairly
213 * large by setting thier high bits to the device number.
215 * AFS already does something very similar to this for the
216 * inode number, so we don't repeat the procedure.
219 * due to complaints over did's being non-persistent,
220 * here's the current hack to provide semi-persistent
222 * 1) we reserve the first bit for file ids.
223 * 2) the next 7 bits are for the device.
224 * 3) the remaining 24 bits are for the inode.
226 * both the inode and device information are actually hashes
227 * that are then truncated to the requisite bit length.
229 * it should be okay to use lstat to deal with symlinks.
232 if ( S_ISDIR(st->st_mode)) {
233 aint = htonl( vol->v_lastdid++ );
237 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
239 #else /* USE_LASTDID */
242 const struct stat *lstp;
244 lstp = lstat(upath, &lst) < 0 ? st : &lst;
245 aint = htonl(CNID(lstp, 1));
247 #endif /* USE_LASTDID */
252 /* -------------------------- */
253 int getmetadata(struct vol *vol,
255 struct path *path, struct dir *dir,
256 char *buf, int *buflen, struct adouble *adp, int attrbits )
258 char *data, *l_nameoff = NULL, *upath;
259 char *utf_nameoff = NULL;
263 u_char achar, fdType[4];
267 LOG(log_info, logtype_afpd, "begin getmetadata:");
270 upath = path->u_name;
274 while ( bitmap != 0 ) {
275 while (( bitmap & 1 ) == 0 ) {
283 ad_getattr(adp, &ashort);
284 } else if (*upath == '.') {
285 ashort = htons(ATTRBIT_INVISIBLE);
289 /* FIXME do we want a visual clue if the file is read only
292 accessmode( ".", &ma, dir , NULL);
293 if ((ma.ma_user & AR_UWRITE)) {
294 accessmode( upath, &ma, dir , st);
295 if (!(ma.ma_user & AR_UWRITE)) {
296 attrbits |= ATTRBIT_NOWRITE;
301 ashort = htons(ntohs(ashort) | attrbits);
302 memcpy(data, &ashort, sizeof( ashort ));
303 data += sizeof( ashort );
307 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
308 data += sizeof( u_int32_t );
312 if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
313 aint = AD_DATE_FROM_UNIX(st->st_mtime);
314 memcpy(data, &aint, sizeof( aint ));
315 data += sizeof( aint );
319 if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
320 if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
321 aint = AD_DATE_FROM_UNIX(st->st_mtime);
324 aint = AD_DATE_FROM_UNIX(st->st_mtime);
326 memcpy(data, &aint, sizeof( int ));
327 data += sizeof( int );
331 if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
332 aint = AD_DATE_START;
333 memcpy(data, &aint, sizeof( int ));
334 data += sizeof( int );
338 get_finderinfo(path->m_name, adp, (char *)data);
340 if (*upath == '.') { /* make it invisible */
341 ashort = htons(FINDERINFO_INVISIBLE);
342 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
350 data += sizeof( u_int16_t );
354 memset(data, 0, sizeof(u_int16_t));
355 data += sizeof( u_int16_t );
359 aint = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
362 memcpy(data, &aint, sizeof( aint ));
363 data += sizeof( aint );
367 if (st->st_size > 0xffffffff)
370 aint = htonl( st->st_size );
371 memcpy(data, &aint, sizeof( aint ));
372 data += sizeof( aint );
377 if (adp->ad_rlen > 0xffffffff)
380 aint = htonl( adp->ad_rlen);
384 memcpy(data, &aint, sizeof( aint ));
385 data += sizeof( aint );
388 /* Current client needs ProDOS info block for this file.
389 Use simple heuristic and let the Mac "type" string tell
390 us what the PD file code should be. Everything gets a
391 subtype of 0x0000 unless the original value was hashed
392 to "pXYZ" when we created it. See IA, Ver 2.
393 <shirsch@adelphia.net> */
394 case FILPBIT_PDINFO :
395 if (afp_version >= 30) { /* UTF8 name */
396 utf8 = kTextEncodingUTF8;
398 data += sizeof( u_int16_t );
400 memcpy(data, &aint, sizeof( aint ));
401 data += sizeof( aint );
405 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
407 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
411 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
415 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
419 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
423 else if ( fdType[0] == 'p' ) {
425 ashort = (fdType[2] * 256) + fdType[3];
439 memcpy(data, &ashort, sizeof( ashort ));
440 data += sizeof( ashort );
441 memset(data, 0, sizeof( ashort ));
442 data += sizeof( ashort );
445 case FILPBIT_EXTDFLEN:
446 aint = htonl(st->st_size >> 32);
447 memcpy(data, &aint, sizeof( aint ));
448 data += sizeof( aint );
449 aint = htonl(st->st_size);
450 memcpy(data, &aint, sizeof( aint ));
451 data += sizeof( aint );
453 case FILPBIT_EXTRFLEN:
456 aint = htonl(adp->ad_rlen >> 32);
457 memcpy(data, &aint, sizeof( aint ));
458 data += sizeof( aint );
460 aint = htonl(adp->ad_rlen);
461 memcpy(data, &aint, sizeof( aint ));
462 data += sizeof( aint );
465 return( AFPERR_BITMAP );
471 ashort = htons( data - buf );
472 memcpy(l_nameoff, &ashort, sizeof( ashort ));
473 data = set_name(vol, data, path->m_name, 0);
476 ashort = htons( data - buf );
477 memcpy(utf_nameoff, &ashort, sizeof( ashort ));
478 data = set_name(vol, data, path->m_name, utf8);
480 *buflen = data - buf;
484 /* ----------------------- */
485 int getfilparams(struct vol *vol,
487 struct path *path, struct dir *dir,
488 char *buf, int *buflen )
490 struct adouble ad, *adp;
493 u_int16_t attrbits = 0;
498 LOG(log_info, logtype_default, "begin getfilparams:");
501 opened = PARAM_NEED_ADP(bitmap);
504 upath = path->u_name;
505 if ((of = of_findname(path))) {
507 attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
508 attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
510 memset(&ad, 0, sizeof(ad));
514 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
519 we need to check if the file is open by another process.
520 it's slow so we only do it if we have to:
521 - bitmap is requested.
522 - we don't already have the answer!
524 if ((bitmap & (1 << FILPBIT_ATTR))) {
525 if (!(attrbits & ATTRBIT_ROPEN)) {
527 if (!(attrbits & ATTRBIT_DOPEN)) {
532 rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
534 ad_close( adp, ADFLAGS_HF );
537 LOG(log_info, logtype_afpd, "end getfilparams:");
543 /* ----------------------------- */
544 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
547 int ibuflen, *rbuflen;
549 struct adouble ad, *adp;
552 struct ofork *of = NULL;
554 int creatf, did, openf, retvalue = AFP_OK;
560 LOG(log_info, logtype_afpd, "begin afp_createfile:");
565 creatf = (unsigned char) *ibuf++;
567 memcpy(&vid, ibuf, sizeof( vid ));
568 ibuf += sizeof( vid );
570 if (NULL == ( vol = getvolbyvid( vid )) ) {
571 return( AFPERR_PARAM );
574 if (vol->v_flags & AFPVOL_RO)
577 memcpy(&did, ibuf, sizeof( did));
578 ibuf += sizeof( did );
580 if (NULL == ( dir = dirlookup( vol, did )) ) {
584 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
585 return get_afp_errno(AFPERR_PARAM);
588 if ( *s_path->m_name == '\0' ) {
589 return( AFPERR_BADTYPE );
592 upath = s_path->u_name;
593 if (0 != (ret = check_name(vol, upath)))
596 /* if upath is deleted we already in trouble anyway */
597 if ((of = of_findname(s_path))) {
600 memset(&ad, 0, sizeof(ad));
604 /* on a hard create, fail if file exists and is open */
607 openf = O_RDWR|O_CREAT|O_TRUNC;
609 /* on a soft create, if the file is open then ad_open won't fail
610 because open syscall is not called
615 openf = O_RDWR|O_CREAT|O_EXCL;
618 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
619 openf, 0666, adp) < 0 ) {
623 case ENOENT : /* we were already in 'did folder' so chdir() didn't fail */
624 return ( AFPERR_NOOBJ );
626 return( AFPERR_EXIST );
628 return( AFPERR_ACCESS );
630 return( AFPERR_PARAM );
633 if ( ad_hfileno( adp ) == -1 ) {
634 /* on noadouble volumes, just creating the data fork is ok */
635 if (vol_noadouble(vol)) {
636 ad_close( adp, ADFLAGS_DF );
637 goto createfile_done;
639 /* FIXME with hard create on an existing file, we already
640 * corrupted the data file.
642 netatalk_unlink( upath );
643 ad_close( adp, ADFLAGS_DF );
644 return AFPERR_ACCESS;
647 path = s_path->m_name;
648 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
649 memcpy(ad_entry( adp, ADEID_NAME ), path,
650 ad_getentrylen( adp, ADEID_NAME ));
651 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
652 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
658 if (vol->v_flags & AFPVOL_DROPBOX) {
659 retvalue = matchfile2dirperms(upath, vol, did);
661 #endif /* DROPKLUDGE */
663 setvoltime(obj, vol );
666 LOG(log_info, logtype_afpd, "end afp_createfile");
672 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
675 int ibuflen, *rbuflen;
681 u_int16_t vid, bitmap;
684 LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
690 memcpy(&vid, ibuf, sizeof( vid ));
691 ibuf += sizeof( vid );
692 if (NULL == ( vol = getvolbyvid( vid )) ) {
693 return( AFPERR_PARAM );
696 if (vol->v_flags & AFPVOL_RO)
699 memcpy(&did, ibuf, sizeof( did ));
700 ibuf += sizeof( did );
701 if (NULL == ( dir = dirlookup( vol, did )) ) {
702 return afp_errno; /* was AFPERR_NOOBJ */
705 memcpy(&bitmap, ibuf, sizeof( bitmap ));
706 bitmap = ntohs( bitmap );
707 ibuf += sizeof( bitmap );
709 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
710 return get_afp_errno(AFPERR_PARAM);
713 if (path_isadir(s_path)) {
714 return( AFPERR_BADTYPE ); /* it's a directory */
717 if ( s_path->st_errno != 0 ) {
718 return( AFPERR_NOOBJ );
721 if ((u_long)ibuf & 1 ) {
725 if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) {
726 setvoltime(obj, vol );
730 LOG(log_info, logtype_afpd, "end afp_setfilparams:");
737 * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
740 extern struct path Cur_Path;
742 int setfilparams(struct vol *vol,
743 struct path *path, u_int16_t bitmap, char *buf )
745 struct adouble ad, *adp;
748 int bit = 0, isad = 1, err = AFP_OK;
750 u_char achar, *fdType, xyy[4];
751 u_int16_t ashort, bshort;
755 int change_mdate = 0;
756 int change_parent_mdate = 0;
762 LOG(log_info, logtype_afpd, "begin setfilparams:");
765 upath = path->u_name;
766 if ((of = of_findname(path))) {
769 memset(&ad, 0, sizeof(ad));
773 if (check_access(upath, OPENACC_WR ) < 0) {
774 return AFPERR_ACCESS;
777 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
778 O_RDWR|O_CREAT, 0666, adp) < 0) {
779 /* for some things, we don't need an adouble header */
780 if (bitmap & ~(1<<FILPBIT_MDATE)) {
781 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
784 } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
785 ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
786 memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
787 ad_getentrylen( adp, ADEID_NAME ));
790 while ( bitmap != 0 ) {
791 while (( bitmap & 1 ) == 0 ) {
799 memcpy(&ashort, buf, sizeof( ashort ));
800 ad_getattr(adp, &bshort);
801 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
802 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
806 if ((ashort & htons(ATTRBIT_INVISIBLE)))
807 change_parent_mdate = 1;
808 ad_setattr(adp, bshort);
809 buf += sizeof( ashort );
814 memcpy(&aint, buf, sizeof(aint));
815 ad_setdate(adp, AD_DATE_CREATE, aint);
816 buf += sizeof( aint );
820 memcpy(&newdate, buf, sizeof( newdate ));
821 buf += sizeof( newdate );
826 memcpy(&aint, buf, sizeof(aint));
827 ad_setdate(adp, AD_DATE_BACKUP, aint);
828 buf += sizeof( aint );
834 if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
836 ((em = getextmap( path->m_name )) &&
837 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
838 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
839 || ((em = getdefextmap()) &&
840 !memcmp(buf, em->em_type, sizeof( em->em_type )) &&
841 !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
843 memcpy(buf, ufinderi, 8 );
846 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
850 /* Client needs to set the ProDOS file info for this file.
851 Use a defined string for TEXT to support crlf
852 translations and convert all else into pXYY per Inside
853 Appletalk. Always set the creator as "pdos". Changes
854 from original by Marsha Jackson. */
855 case FILPBIT_PDINFO :
856 if (afp_version < 30) { /* else it's UTF8 name */
859 /* Keep special case to support crlf translations */
860 if ((unsigned int) achar == 0x04) {
861 fdType = (u_char *)"TEXT";
864 xyy[0] = ( u_char ) 'p';
870 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
871 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
877 goto setfilparam_done;
885 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
886 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
890 ad_setdate(adp, AD_DATE_MODIFY, newdate);
891 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
896 ad_flush( adp, ADFLAGS_HF );
897 ad_close( adp, ADFLAGS_HF );
901 if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
902 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
903 bitmap = 1<<FILPBIT_MDATE;
904 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
908 LOG(log_info, logtype_afpd, "end setfilparams:");
914 * renamefile and copyfile take the old and new unix pathnames
915 * and the new mac name.
917 * src the source path
918 * dst the dest filename in current dir
919 * newname the dest mac name
920 * adp adouble struct of src file, if open, or & zeroed one
923 int renamefile(src, dst, newname, noadouble, adp )
924 char *src, *dst, *newname;
928 char adsrc[ MAXPATHLEN + 1];
933 LOG(log_info, logtype_afpd, "begin renamefile:");
936 if ( unix_rename( src, dst ) < 0 ) {
939 return( AFPERR_NOOBJ );
942 return( AFPERR_ACCESS );
945 case EXDEV : /* Cross device move -- try copy */
946 /* NOTE: with open file it's an error because after the copy we will
947 * get two files, it's fixable for our process (eg reopen the new file, get the
948 * locks, and so on. But it doesn't solve the case with a second process
950 if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
951 /* FIXME warning in syslog so admin'd know there's a conflict ?*/
952 return AFPERR_OLOCK; /* little lie */
954 if (AFP_OK != ( rc = copyfile(src, dst, newname, noadouble )) ) {
955 /* on error copyfile delete dest */
958 return deletefile(NULL, src, 0);
960 return( AFPERR_PARAM );
964 strcpy( adsrc, ad_path( src, 0 ));
966 if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
971 if (errno == ENOENT) {
974 if (stat(adsrc, &st)) /* source has no ressource fork, */
977 /* We are here because :
978 * -there's no dest folder.
979 * -there's no .AppleDouble in the dest folder.
980 * if we use the struct adouble passed in parameter it will not
981 * create .AppleDouble if the file is already opened, so we
982 * use a diff one, it's not a pb,ie it's not the same file, yet.
984 memset(&ad, 0, sizeof(ad));
985 if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
986 ad_close(&ad, ADFLAGS_HF);
987 if (!unix_rename( adsrc, ad_path( dst, 0 )) )
992 else { /* it's something else, bail out */
996 /* try to undo the data fork rename,
997 * we know we are on the same device
1000 unix_rename( dst, src );
1001 /* return the first error */
1004 return AFPERR_NOOBJ;
1007 return AFPERR_ACCESS ;
1009 return AFPERR_VLOCK;
1011 return AFPERR_PARAM ;
1016 /* don't care if we can't open the newly renamed ressource fork
1018 if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
1019 len = strlen( newname );
1020 ad_setentrylen( adp, ADEID_NAME, len );
1021 memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
1022 ad_flush( adp, ADFLAGS_HF );
1023 ad_close( adp, ADFLAGS_HF );
1026 LOG(log_info, logtype_afpd, "end renamefile:");
1032 int copy_path_name(char *newname, char *ibuf)
1039 if ( type != 2 && !(afp_version >= 30 && type == 3) ) {
1045 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
1046 strncpy( newname, ibuf, plen );
1047 newname[ plen ] = '\0';
1048 if (strlen(newname) != plen) {
1049 /* there's \0 in newname, e.g. it's a pathname not
1057 memcpy(&hint, ibuf, sizeof(hint));
1058 ibuf += sizeof(hint);
1060 memcpy(&len16, ibuf, sizeof(len16));
1061 ibuf += sizeof(len16);
1062 plen = ntohs(len16);
1065 if (plen > AFPOBJ_TMPSIZ) {
1068 strncpy( newname, ibuf, plen );
1069 newname[ plen ] = '\0';
1070 if (strlen(newname) != plen) {
1079 /* -----------------------------------
1081 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
1084 int ibuflen, *rbuflen;
1088 char *newname, *p, *upath;
1089 struct path *s_path;
1090 u_int32_t sdid, ddid;
1091 int err, retvalue = AFP_OK;
1092 u_int16_t svid, dvid;
1095 LOG(log_info, logtype_afpd, "begin afp_copyfile:");
1101 memcpy(&svid, ibuf, sizeof( svid ));
1102 ibuf += sizeof( svid );
1103 if (NULL == ( vol = getvolbyvid( svid )) ) {
1104 return( AFPERR_PARAM );
1107 memcpy(&sdid, ibuf, sizeof( sdid ));
1108 ibuf += sizeof( sdid );
1109 if (NULL == ( dir = dirlookup( vol, sdid )) ) {
1113 memcpy(&dvid, ibuf, sizeof( dvid ));
1114 ibuf += sizeof( dvid );
1115 memcpy(&ddid, ibuf, sizeof( ddid ));
1116 ibuf += sizeof( ddid );
1118 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1119 return get_afp_errno(AFPERR_PARAM);
1121 if ( path_isadir(s_path) ) {
1122 return( AFPERR_BADTYPE );
1125 /* don't allow copies when the file is open.
1126 * XXX: the spec only calls for read/deny write access.
1127 * however, copyfile doesn't have any of that info,
1128 * and locks need to stay coherent. as a result,
1129 * we just balk if the file is opened already. */
1131 newname = obj->newtmp;
1132 strcpy( newname, s_path->m_name );
1134 if (of_findname(s_path))
1135 return AFPERR_DENYCONF;
1137 p = ctoupath( vol, curdir, newname );
1139 return AFPERR_PARAM;
1143 /* FIXME svid != dvid && dvid's user can't read svid */
1145 if (NULL == ( vol = getvolbyvid( dvid )) ) {
1146 return( AFPERR_PARAM );
1149 if (vol->v_flags & AFPVOL_RO)
1150 return AFPERR_VLOCK;
1152 if (NULL == ( dir = dirlookup( vol, ddid )) ) {
1156 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
1157 return get_afp_errno(AFPERR_NOOBJ);
1159 if ( *s_path->m_name != '\0' ) {
1161 return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
1163 path_error(s_path, AFPERR_PARAM);
1166 /* one of the handful of places that knows about the path type */
1167 if (copy_path_name(newname, ibuf) < 0) {
1168 return( AFPERR_PARAM );
1171 if (NULL == (upath = mtoupath(vol, newname, utf8_encoding()))) {
1172 return( AFPERR_PARAM );
1174 if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
1180 if (vol->v_flags & AFPVOL_DROPBOX) {
1181 retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
1183 #endif /* DROPKLUDGE */
1185 setvoltime(obj, vol );
1188 LOG(log_info, logtype_afpd, "end afp_copyfile:");
1195 static __inline__ int copy_all(const int dfd, const void *buf,
1201 LOG(log_info, logtype_afpd, "begin copy_all:");
1204 while (buflen > 0) {
1205 if ((cc = write(dfd, buf, buflen)) < 0) {
1212 return AFPERR_DFULL;
1214 return AFPERR_VLOCK;
1216 return AFPERR_PARAM;
1223 LOG(log_info, logtype_afpd, "end copy_all:");
1229 /* -------------------------- */
1230 static int copy_fd(int dfd, int sfd)
1236 #ifdef SENDFILE_FLAVOR_LINUX
1239 if (fstat(sfd, &st) == 0) {
1240 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1242 case EINVAL: /* there's no guarantee that all fs support sendfile */
1247 return AFPERR_DFULL;
1249 return AFPERR_VLOCK;
1251 return AFPERR_PARAM;
1258 #endif /* SENDFILE_FLAVOR_LINUX */
1261 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1268 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1274 /* ----------------------------------
1275 * if newname is NULL (from directory.c) we don't want to copy ressource fork.
1276 * because we are doing it elsewhere.
1278 int copyfile(src, dst, newname, noadouble )
1279 char *src, *dst, *newname;
1280 const int noadouble;
1282 struct adouble ads, add;
1283 int len, err = AFP_OK;
1287 LOG(log_info, logtype_afpd, "begin copyfile:");
1290 memset(&ads, 0, sizeof(ads));
1291 memset(&add, 0, sizeof(add));
1292 adflags = ADFLAGS_DF;
1294 adflags |= ADFLAGS_HF;
1297 if (ad_open(src , adflags | ADFLAGS_NOHF, O_RDONLY, 0, &ads) < 0) {
1300 return( AFPERR_NOOBJ );
1302 return( AFPERR_ACCESS );
1304 return( AFPERR_PARAM );
1307 if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
1308 ad_close( &ads, adflags );
1309 if (EEXIST != (err = errno)) {
1310 deletefile(NULL, dst, 0);
1314 return AFPERR_EXIST;
1316 return( AFPERR_NOOBJ );
1318 return( AFPERR_ACCESS );
1320 return AFPERR_VLOCK;
1322 return( AFPERR_PARAM );
1325 if (ad_hfileno(&ads) == -1 || AFP_OK == (err = copy_fd(ad_hfileno(&add), ad_hfileno(&ads)))){
1326 /* copy the data fork */
1327 err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
1331 len = strlen( newname );
1332 ad_setentrylen( &add, ADEID_NAME, len );
1333 memcpy(ad_entry( &add, ADEID_NAME ), newname, len );
1336 ad_close( &ads, adflags );
1337 ad_flush( &add, adflags );
1338 if (ad_close( &add, adflags ) <0) {
1341 if (err != AFP_OK) {
1342 deletefile(NULL, dst, 0);
1345 return( AFPERR_NOOBJ );
1347 return( AFPERR_ACCESS );
1349 return( AFPERR_PARAM );
1354 LOG(log_info, logtype_afpd, "end copyfile:");
1361 /* -----------------------------------
1362 vol: not NULL delete cnid entry. then we are in curdir and file is a only filename
1363 checkAttrib: 1 check kFPDeleteInhibitBit (deletfile called by afp_delete)
1365 when deletefile is called we don't have lock on it, file is closed (for us)
1366 untrue if called by renamefile
1368 ad_open always try to open file RDWR first and ad_lock takes care of
1369 WRITE lock on read only file.
1371 int deletefile( vol, file, checkAttrib )
1377 int adflags, err = AFP_OK;
1380 LOG(log_info, logtype_afpd, "begin deletefile:");
1383 /* try to open both forks at once */
1384 adflags = ADFLAGS_DF|ADFLAGS_HF;
1386 memset(&ad, 0, sizeof(ad));
1387 if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
1390 if (adflags == ADFLAGS_DF)
1391 return AFPERR_NOOBJ;
1393 /* that failed. now try to open just the data fork */
1394 adflags = ADFLAGS_DF;
1398 return AFPERR_ACCESS;
1400 return AFPERR_VLOCK;
1402 return( AFPERR_PARAM );
1405 break; /* from the while */
1408 * Does kFPDeleteInhibitBit (bit 8) set?
1410 if (checkAttrib && (adflags & ADFLAGS_HF)) {
1413 ad_getattr(&ad, &bshort);
1414 if ((bshort & htons(ATTRBIT_NODELETE))) {
1415 ad_close( &ad, adflags );
1416 return(AFPERR_OLOCK);
1420 if ((adflags & ADFLAGS_HF) ) {
1421 /* FIXME we have a pb here because we want to know if a file is open
1422 * there's a 'priority inversion' if you can't open the ressource fork RW
1423 * you can delete it if it's open because you can't get a write lock.
1425 * ADLOCK_FILELOCK means the whole ressource fork, not only after the
1428 * FIXME it doesn't work for RFORK open read only and fork open without deny mode
1430 if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
1431 ad_close( &ad, adflags );
1432 return( AFPERR_BUSY );
1436 if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
1439 else if (!(err = netatalk_unlink( ad_path( file, ADFLAGS_HF)) ) &&
1440 !(err = netatalk_unlink( file )) ) {
1441 #ifdef CNID_DB /* get rid of entry */
1443 if (vol && (id = cnid_get(vol->v_db, curdir->d_did, file, strlen(file))))
1445 cnid_delete(vol->v_db, id);
1447 #endif /* CNID_DB */
1450 ad_close( &ad, adflags ); /* ad_close removes locks if any */
1453 LOG(log_info, logtype_afpd, "end deletefile:");
1459 /* ------------------------------------ */
1461 /* return a file id */
1462 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1465 int ibuflen, *rbuflen;
1474 struct path *s_path;
1477 LOG(log_info, logtype_afpd, "begin afp_createid:");
1484 memcpy(&vid, ibuf, sizeof(vid));
1485 ibuf += sizeof(vid);
1487 if (NULL == ( vol = getvolbyvid( vid )) ) {
1488 return( AFPERR_PARAM);
1491 if (vol->v_db == NULL) {
1495 if (vol->v_flags & AFPVOL_RO)
1496 return AFPERR_VLOCK;
1498 memcpy(&did, ibuf, sizeof( did ));
1499 ibuf += sizeof(did);
1501 if (NULL == ( dir = dirlookup( vol, did )) ) {
1502 return afp_errno; /* was AFPERR_PARAM */
1505 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
1506 return get_afp_errno(AFPERR_NOOBJ); /* was AFPERR_PARAM */
1509 if ( path_isadir(s_path) ) {
1510 return( AFPERR_BADTYPE );
1513 upath = s_path->u_name;
1514 switch (s_path->st_errno) {
1516 break; /* success */
1519 return AFPERR_ACCESS;
1521 return AFPERR_NOOBJ;
1523 return AFPERR_PARAM;
1526 if ((id = cnid_lookup(vol->v_db, st, did, upath, len = strlen(upath)))) {
1527 memcpy(rbuf, &id, sizeof(id));
1528 *rbuflen = sizeof(id);
1529 return AFPERR_EXISTID;
1532 if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) {
1533 memcpy(rbuf, &id, sizeof(id));
1534 *rbuflen = sizeof(id);
1539 LOG(log_info, logtype_afpd, "ending afp_createid...:");
1544 /* ------------------------------
1545 resolve a file id */
1546 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1549 int ibuflen, *rbuflen;
1557 u_int16_t vid, bitmap;
1559 static char buffer[12 + MAXPATHLEN + 1];
1560 int len = 12 + MAXPATHLEN + 1;
1563 LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1569 memcpy(&vid, ibuf, sizeof(vid));
1570 ibuf += sizeof(vid);
1572 if (NULL == ( vol = getvolbyvid( vid )) ) {
1573 return( AFPERR_PARAM);
1576 if (vol->v_db == NULL) {
1580 memcpy(&id, ibuf, sizeof( id ));
1583 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1584 return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1587 if (NULL == ( dir = dirlookup( vol, id )) ) {
1588 return AFPERR_NOID; /* idem AFPERR_PARAM */
1590 path.u_name = upath;
1591 if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
1595 return AFPERR_ACCESS;
1599 return AFPERR_PARAM;
1602 /* directories are bad */
1603 if (S_ISDIR(path.st.st_mode))
1604 return AFPERR_BADTYPE;
1606 memcpy(&bitmap, ibuf, sizeof(bitmap));
1607 bitmap = ntohs( bitmap );
1608 if (NULL == (path.m_name = utompath(vol, upath, utf8_encoding()))) {
1611 if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir,
1612 rbuf + sizeof(bitmap), &buflen))) {
1615 *rbuflen = buflen + sizeof(bitmap);
1616 memcpy(rbuf, ibuf, sizeof(bitmap));
1619 LOG(log_info, logtype_afpd, "end afp_resolveid:");
1625 /* ------------------------------ */
1626 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1629 int ibuflen, *rbuflen;
1639 static char buffer[12 + MAXPATHLEN + 1];
1640 int len = 12 + MAXPATHLEN + 1;
1643 LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1649 memcpy(&vid, ibuf, sizeof(vid));
1650 ibuf += sizeof(vid);
1652 if (NULL == ( vol = getvolbyvid( vid )) ) {
1653 return( AFPERR_PARAM);
1656 if (vol->v_db == NULL) {
1660 if (vol->v_flags & AFPVOL_RO)
1661 return AFPERR_VLOCK;
1663 memcpy(&id, ibuf, sizeof( id ));
1667 if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, len)) ) {
1671 if (NULL == ( dir = dirlookup( vol, id )) ) {
1672 return( AFPERR_PARAM );
1676 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1680 return AFPERR_ACCESS;
1682 /* still try to delete the id */
1686 return AFPERR_PARAM;
1689 else if (S_ISDIR(st.st_mode)) /* directories are bad */
1690 return AFPERR_BADTYPE;
1692 if (cnid_delete(vol->v_db, fileid)) {
1695 return AFPERR_VLOCK;
1698 return AFPERR_ACCESS;
1700 return AFPERR_PARAM;
1705 LOG(log_info, logtype_afpd, "end afp_deleteid:");
1710 #endif /* CNID_DB */
1712 #define APPLETEMP ".AppleTempXXXXXX"
1714 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1717 int ibuflen, *rbuflen;
1719 struct stat srcst, destst;
1721 struct dir *dir, *sdir;
1722 char *spath, temp[17], *p;
1723 char *supath, *upath;
1728 struct adouble *adsp;
1729 struct adouble *addp;
1736 #endif /* CNID_DB */
1741 LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1747 memcpy(&vid, ibuf, sizeof(vid));
1748 ibuf += sizeof(vid);
1750 if (NULL == ( vol = getvolbyvid( vid )) ) {
1751 return( AFPERR_PARAM);
1754 if (vol->v_flags & AFPVOL_RO)
1755 return AFPERR_VLOCK;
1757 /* source and destination dids */
1758 memcpy(&sid, ibuf, sizeof(sid));
1759 ibuf += sizeof(sid);
1760 memcpy(&did, ibuf, sizeof(did));
1761 ibuf += sizeof(did);
1764 if (NULL == (dir = dirlookup( vol, sid )) ) {
1765 return afp_errno; /* was AFPERR_PARAM */
1768 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1769 return get_afp_errno(AFPERR_NOOBJ);
1772 if ( path_isadir(path) ) {
1773 return( AFPERR_BADTYPE ); /* it's a dir */
1776 upath = path->u_name;
1777 switch (path->st_errno) {
1784 return AFPERR_ACCESS;
1786 return AFPERR_PARAM;
1788 memset(&ads, 0, sizeof(ads));
1790 if ((s_of = of_findname(path))) {
1791 /* reuse struct adouble so it won't break locks */
1794 memcpy(&srcst, &path->st, sizeof(struct stat));
1795 /* save some stuff */
1797 spath = obj->oldtmp;
1798 supath = obj->newtmp;
1799 strcpy(spath, path->m_name);
1800 strcpy(supath, upath); /* this is for the cnid changing */
1801 p = absupath( vol, sdir, upath);
1803 /* pathname too long */
1804 return AFPERR_PARAM ;
1807 /* look for the source cnid. if it doesn't exist, don't worry about
1810 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1811 slen = strlen(supath));
1812 #endif /* CNID_DB */
1814 if (NULL == ( dir = dirlookup( vol, did )) ) {
1815 return afp_errno; /* was AFPERR_PARAM */
1818 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1819 return get_afp_errno(AFPERR_NOOBJ);
1822 if ( path_isadir(path) ) {
1823 return( AFPERR_BADTYPE );
1826 /* FPExchangeFiles is the only call that can return the SameObj
1828 if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
1829 return AFPERR_SAMEOBJ;
1831 switch (path->st_errno) {
1838 return AFPERR_ACCESS;
1840 return AFPERR_PARAM;
1842 memset(&add, 0, sizeof(add));
1844 if ((d_of = of_findname( path))) {
1845 /* reuse struct adouble so it won't break locks */
1848 memcpy(&destst, &path->st, sizeof(struct stat));
1850 /* they are not on the same device and at least one is open
1852 crossdev = (srcst.st_dev != destst.st_dev);
1853 if ((d_of || s_of) && crossdev)
1856 upath = path->u_name;
1858 /* look for destination id. */
1859 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1860 dlen = strlen(upath));
1861 #endif /* CNID_DB */
1863 /* construct a temp name.
1864 * NOTE: the temp file will be in the dest file's directory. it
1865 * will also be inaccessible from AFP. */
1866 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1870 /* now, quickly rename the file. we error if we can't. */
1871 if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1872 goto err_exchangefile;
1873 of_rename(vol, s_of, sdir, spath, curdir, temp);
1875 /* rename destination to source */
1876 if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1877 goto err_src_to_tmp;
1878 of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
1880 /* rename temp to destination */
1881 if ((err = renamefile(temp, upath, path->m_name, vol_noadouble(vol), adsp)) < 0)
1882 goto err_dest_to_src;
1883 of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
1886 /* id's need switching. src -> dest and dest -> src.
1887 * we need to re-stat() if it was a cross device copy.
1890 cnid_delete(vol->v_db, sid);
1893 cnid_delete(vol->v_db, did);
1895 if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
1896 cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
1898 (sid && ( (crossdev && stat(p, &destst) < 0) ||
1899 cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
1904 err = AFPERR_ACCESS;
1909 goto err_temp_to_dest;
1911 #endif /* CNID_DB */
1914 LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1920 /* all this stuff is so that we can unwind a failed operation
1925 /* rename dest to temp */
1926 renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1927 of_rename(vol, s_of, curdir, upath, curdir, temp);
1930 /* rename source back to dest */
1931 renamefile(p, upath, path->m_name, vol_noadouble(vol), addp);
1932 of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
1935 /* rename temp back to source */
1936 renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1937 of_rename(vol, s_of, curdir, temp, sdir, spath);