2 * $Id: file.c,v 1.31 2001-12-29 08:16:21 jmarcus 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 <sys/syslog.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"
62 /* check for mtab DID code */
64 #include "parse_mtab.h"
70 #endif /* FORCE_UIDGID */
72 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
73 * field bytes subfield bytes
76 * ioFlFndrInfo 16 -> type 4 type field
77 * creator 4 creator field
78 * flags 2 finder flags:
80 * location 4 location in window
81 * folder 2 window that contains file
83 * ioFlXFndrInfo 16 -> iconID 2 icon id
85 * script 1 script system
87 * commentID 2 comment id
88 * putawayID 4 home directory id
91 const u_char ufinderi[] = {
92 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
93 0, 0, 0, 0, 0, 0, 0, 0,
94 0, 0, 0, 0, 0, 0, 0, 0,
95 0, 0, 0, 0, 0, 0, 0, 0
98 int getfilparams(struct vol *vol,
100 char *path, struct dir *dir, struct stat *st,
101 char *buf, int *buflen )
104 struct stat hst, lst, *lstp;
105 #else /* USE_LASTDID */
107 #endif /* USE_LASTDID */
108 struct adouble ad, *adp;
111 char *data, *nameoff = NULL, *upath;
112 int bit = 0, isad = 1;
115 u_char achar, fdType[4];
118 syslog(LOG_INFO, "begin getfilparams:");
121 upath = mtoupath(vol, path);
122 if ((of = of_findname(vol, curdir, path))) {
125 memset(&ad, 0, sizeof(ad));
129 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
131 } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
132 syslog( LOG_ERR, "getfilparams fstat: %s", strerror(errno) );
136 while ( bitmap != 0 ) {
137 while (( bitmap & 1 ) == 0 ) {
145 ad_getattr(adp, &ashort);
146 } else if (*upath == '.') {
147 ashort = htons(ATTRBIT_INVISIBLE);
150 memcpy(data, &ashort, sizeof( ashort ));
151 data += sizeof( u_short );
155 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
156 data += sizeof( u_int32_t );
160 if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
161 aint = AD_DATE_FROM_UNIX(st->st_mtime);
162 memcpy(data, &aint, sizeof( aint ));
163 data += sizeof( aint );
167 if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
168 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) &&
169 (hst.st_mtime < st->st_mtime)) {
170 aint = AD_DATE_FROM_UNIX(st->st_mtime);
173 aint = AD_DATE_FROM_UNIX(st->st_mtime);
175 memcpy(data, &aint, sizeof( int ));
176 data += sizeof( int );
180 if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
181 aint = AD_DATE_START;
182 memcpy(data, &aint, sizeof( int ));
183 data += sizeof( int );
188 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
190 memcpy(data, ufinderi, 32);
191 if (*upath == '.') { /* make it invisible */
192 ashort = htons(FINDERINFO_INVISIBLE);
193 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
197 if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
198 ufinderi, 8 ) == 0)) &&
199 (em = getextmap( path ))) {
200 memcpy(data, em->em_type, sizeof( em->em_type ));
201 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
208 data += sizeof( u_int16_t );
212 memset(data, 0, sizeof(u_int16_t));
213 data += sizeof( u_int16_t );
218 #if AD_VERSION > AD_VERSION1
219 /* look in AD v2 header */
221 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
222 #endif /* AD_VERSION > AD_VERSION1 */
225 aint = cnid_add(vol->v_db, st, dir->d_did, upath,
226 strlen(upath), aint);
231 * What a fucking mess. First thing: DID and FNUMs are
232 * in the same space for purposes of enumerate (and several
233 * other wierd places). While we consider this Apple's bug,
234 * this is the work-around: In order to maintain constant and
235 * unique DIDs and FNUMs, we monotonically generate the DIDs
236 * during the session, and derive the FNUMs from the filesystem.
237 * Since the DIDs are small, we insure that the FNUMs are fairly
238 * large by setting thier high bits to the device number.
240 * AFS already does something very similar to this for the
241 * inode number, so we don't repeat the procedure.
244 * due to complaints over did's being non-persistent,
245 * here's the current hack to provide semi-persistent
247 * 1) we reserve the first bit for file ids.
248 * 2) the next 7 bits are for the device.
249 * 3) the remaining 24 bits are for the inode.
251 * both the inode and device information are actually hashes
252 * that are then truncated to the requisite bit length.
254 * it should be okay to use lstat to deal with symlinks.
257 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
258 #else /* USE_LASTDID */
259 lstp = lstat(upath, &lst) < 0 ? st : &lst;
261 aint = htonl( afpd_st_cnid ( lstp ) );
263 aint = htonl(CNID(lstp, 1));
264 #endif /* DID_MTAB */
265 #endif /* USE_LASTDID */
268 memcpy(data, &aint, sizeof( aint ));
269 data += sizeof( aint );
273 aint = htonl( st->st_size );
274 memcpy(data, &aint, sizeof( aint ));
275 data += sizeof( aint );
280 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
284 memcpy(data, &aint, sizeof( aint ));
285 data += sizeof( aint );
288 /* Current client needs ProDOS info block for this file.
289 Use simple heuristic and let the Mac "type" string tell
290 us what the PD file code should be. Everything gets a
291 subtype of 0x0000 unless the original value was hashed
292 to "pXYZ" when we created it. See IA, Ver 2.
294 case FILPBIT_PDINFO :
296 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
298 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
302 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
306 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
310 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
314 else if ( fdType[0] == 'p' ) {
316 ashort = (fdType[2] * 256) + fdType[3];
330 memcpy(data, &ashort, sizeof( ashort ));
331 data += sizeof( ashort );
332 memset(data, 0, sizeof( ashort ));
333 data += sizeof( ashort );
338 ad_close( adp, ADFLAGS_HF );
340 return( AFPERR_BITMAP );
346 ashort = htons( data - buf );
347 memcpy(nameoff, &ashort, sizeof( ashort ));
348 if ((aint = strlen( path )) > MACFILELEN)
351 memcpy(data, path, aint );
355 ad_close( adp, ADFLAGS_HF );
357 *buflen = data - buf;
360 syslog(LOG_INFO, "end getfilparams:");
366 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
369 int ibuflen, *rbuflen;
372 struct adouble ad, *adp;
377 int creatf, did, openf, retvalue = AFP_OK;
381 #endif /* FORCE_UIDGID */
384 syslog(LOG_INFO, "begin afp_createfile:");
389 creatf = (unsigned char) *ibuf++;
391 memcpy(&vid, ibuf, sizeof( vid ));
392 ibuf += sizeof( vid );
394 if (( vol = getvolbyvid( vid )) == NULL ) {
395 return( AFPERR_PARAM );
398 if (vol->v_flags & AFPVOL_RO)
401 memcpy(&did, ibuf, sizeof( did));
402 ibuf += sizeof( did );
404 if (( dir = dirsearch( vol, did )) == NULL ) {
405 return( AFPERR_NOOBJ );
408 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
409 return( AFPERR_NOOBJ );
412 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
413 strpbrk(path, MSWINDOWS_BADCHARS))
416 upath = mtoupath(vol, path);
418 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
421 if (!validupath(vol, upath))
424 /* check for vetoed filenames */
425 if (veto_file(vol->v_veto, upath))
428 if ((of = of_findname(vol, curdir, path))) {
431 memset(&ad, 0, sizeof(ad));
435 /* on a hard create, fail if file exists and is open */
436 if ((stat(upath, &st) == 0) && of)
438 openf = O_RDWR|O_CREAT|O_TRUNC;
440 openf = O_RDWR|O_CREAT|O_EXCL;
445 /* preserve current euid, egid */
446 save_uidgid ( uidgid );
448 /* perform all switching of users */
451 #endif /* FORCE_UIDGID */
453 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
454 openf, 0666, adp) < 0 ) {
458 /* bring everything back to old euid, egid */
459 restore_uidgid ( uidgid );
460 #endif /* FORCE_UIDGID */
461 return( AFPERR_EXIST );
464 /* bring everything back to old euid, egid */
465 restore_uidgid ( uidgid );
466 #endif /* FORCE_UIDGID */
467 return( AFPERR_ACCESS );
469 /* on noadouble volumes, just creating the data fork is ok */
470 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
471 goto createfile_done;
475 /* bring everything back to old euid, egid */
476 restore_uidgid ( uidgid );
477 #endif /* FORCE_UIDGID */
478 return( AFPERR_PARAM );
482 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
483 memcpy(ad_entry( adp, ADEID_NAME ), path,
484 ad_getentrylen( adp, ADEID_NAME ));
485 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
486 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
491 if (vol->v_flags & AFPVOL_DROPBOX) {
492 retvalue = matchfile2dirperms(upath, vol, did);
494 #endif /* DROPKLUDGE */
496 setvoltime(obj, vol );
499 syslog(LOG_INFO, "end afp_createfile");
503 /* bring everything back to old euid, egid */
504 restore_uidgid ( uidgid );
505 #endif /* FORCE_UIDGID */
510 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
513 int ibuflen, *rbuflen;
519 u_int16_t vid, bitmap;
522 syslog(LOG_INFO, "begin afp_setfilparams:");
528 memcpy(&vid, ibuf, sizeof( vid ));
529 ibuf += sizeof( vid );
530 if (( vol = getvolbyvid( vid )) == NULL ) {
531 return( AFPERR_PARAM );
534 if (vol->v_flags & AFPVOL_RO)
537 memcpy(&did, ibuf, sizeof( did ));
538 ibuf += sizeof( did );
539 if (( dir = dirsearch( vol, did )) == NULL ) {
540 return( AFPERR_NOOBJ );
543 memcpy(&bitmap, ibuf, sizeof( bitmap ));
544 bitmap = ntohs( bitmap );
545 ibuf += sizeof( bitmap );
547 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
548 return( AFPERR_NOOBJ );
551 if ((u_long)ibuf & 1 ) {
555 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
556 setvoltime(obj, vol );
560 syslog(LOG_INFO, "end afp_setfilparams:");
567 int setfilparams(struct vol *vol,
568 char *path, u_int16_t bitmap, char *buf )
570 struct adouble ad, *adp;
573 int bit = 0, isad = 1, err = AFP_OK;
575 u_char achar, *fdType, xyy[4];
576 u_int16_t ashort, bshort;
583 uidgid = malloc(sizeof(uidgidset));
584 #endif /* FORCE_UIDGID */
587 syslog(LOG_INFO, "begin setfilparams:");
590 upath = mtoupath(vol, path);
591 if ((of = of_findname(vol, curdir, path))) {
594 memset(&ad, 0, sizeof(ad));
599 save_uidgid ( uidgid );
601 #endif /* FORCE_UIDGID */
603 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
604 O_RDWR|O_CREAT, 0666, adp) < 0) {
605 /* for some things, we don't need an adouble header */
606 if (bitmap & ~(1<<FILPBIT_MDATE)) {
608 restore_uidgid ( uidgid );
609 #endif /* FORCE_UIDGID */
610 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
613 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
614 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
615 memcpy(ad_entry( adp, ADEID_NAME ), path,
616 ad_getentrylen( adp, ADEID_NAME ));
619 while ( bitmap != 0 ) {
620 while (( bitmap & 1 ) == 0 ) {
627 memcpy(&ashort, buf, sizeof( ashort ));
628 ad_getattr(adp, &bshort);
629 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
630 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
634 ad_setattr(adp, bshort);
635 buf += sizeof( ashort );
639 memcpy(&aint, buf, sizeof(aint));
640 ad_setdate(adp, AD_DATE_CREATE, aint);
641 buf += sizeof( aint );
645 memcpy(&aint, buf, sizeof( aint ));
647 ad_setdate(adp, AD_DATE_MODIFY, aint);
648 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
650 buf += sizeof( aint );
654 memcpy(&aint, buf, sizeof(aint));
655 ad_setdate(adp, AD_DATE_BACKUP, aint);
656 buf += sizeof( aint );
660 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
661 && (em = getextmap( path )) &&
662 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
663 (memcmp(buf + 4, em->em_creator,
664 sizeof( em->em_creator )) == 0)) {
665 memcpy(buf, ufinderi, 8 );
667 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
671 /* Client needs to set the ProDOS file info for this file.
672 Use defined strings for the simple cases, and convert
673 all else into pXYY per Inside Appletalk. Always set
674 the creator as "pdos". <shirsch@ibm.net> */
675 case FILPBIT_PDINFO :
678 memcpy(&ashort, buf, sizeof( ashort ));
679 ashort = ntohs( ashort );
682 switch ( (unsigned int) achar )
685 fdType = ( u_char *) "TEXT";
689 fdType = ( u_char *) "PSYS";
693 fdType = ( u_char *) "PS16";
697 fdType = ( u_char *) "BINA";
701 xyy[0] = ( u_char ) 'p';
703 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
704 xyy[3] = ( u_char ) ashort & 0xff;
709 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
710 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
716 goto setfilparam_done;
725 ad_flush( adp, ADFLAGS_HF );
726 ad_close( adp, ADFLAGS_HF );
729 restore_uidgid ( uidgid );
730 #endif /* FORCE_UIDGID */
735 syslog(LOG_INFO, "end setfilparams:");
742 * renamefile and copyfile take the old and new unix pathnames
743 * and the new mac name.
744 * NOTE: if we have to copy a file instead of renaming it, locks
747 int renamefile(src, dst, newname, noadouble )
748 char *src, *dst, *newname;
752 char adsrc[ MAXPATHLEN + 1];
756 * Note that this is only checking the existance of the data file,
757 * not the header file. The thinking is that if the data file doesn't
758 * exist, but the header file does, the right thing to do is remove
759 * the data file silently.
762 /* existence check moved to afp_moveandrename */
765 syslog (LOG_INFO, "begin renamefile:");
768 if ( rename( src, dst ) < 0 ) {
771 return( AFPERR_NOOBJ );
774 return( AFPERR_ACCESS );
777 case EXDEV : /* Cross device move -- try copy */
778 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
782 return deletefile( src );
784 return( AFPERR_PARAM );
788 strcpy( adsrc, ad_path( src, 0 ));
791 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
796 /* check for a source appledouble header. if it exists, make
797 * a dest appledouble directory and do the rename again. */
798 memset(&ad, 0, sizeof(ad));
799 if (rc || stat(adsrc, &st) ||
800 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
803 ad_close(&ad, ADFLAGS_HF);
807 return( AFPERR_ACCESS );
811 return( AFPERR_PARAM );
815 memset(&ad, 0, sizeof(ad));
816 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
819 return( AFPERR_NOOBJ );
821 return( AFPERR_ACCESS );
825 return( AFPERR_PARAM );
829 len = strlen( newname );
830 ad_setentrylen( &ad, ADEID_NAME, len );
831 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
832 ad_flush( &ad, ADFLAGS_HF );
833 ad_close( &ad, ADFLAGS_HF );
836 syslog (LOG_INFO, "end renamefile:");
842 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
845 int ibuflen, *rbuflen;
849 char *newname, *path, *p;
850 u_int32_t sdid, ddid;
851 int plen, err, retvalue = AFP_OK;
852 u_int16_t svid, dvid;
855 syslog (LOG_INFO, "begin afp_copyfile:");
861 memcpy(&svid, ibuf, sizeof( svid ));
862 ibuf += sizeof( svid );
863 if (( vol = getvolbyvid( svid )) == NULL ) {
864 return( AFPERR_PARAM );
867 memcpy(&sdid, ibuf, sizeof( sdid ));
868 ibuf += sizeof( sdid );
869 if (( dir = dirsearch( vol, sdid )) == NULL ) {
870 return( AFPERR_PARAM );
873 memcpy(&dvid, ibuf, sizeof( dvid ));
874 ibuf += sizeof( dvid );
875 memcpy(&ddid, ibuf, sizeof( ddid ));
876 ibuf += sizeof( ddid );
878 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
879 return( AFPERR_NOOBJ );
881 if ( *path == '\0' ) {
882 return( AFPERR_BADTYPE );
885 /* don't allow copies when the file is open.
886 * XXX: the spec only calls for read/deny write access.
887 * however, copyfile doesn't have any of that info,
888 * and locks need to stay coherent. as a result,
889 * we just balk if the file is opened already. */
890 if (of_findname(vol, curdir, path))
891 return AFPERR_DENYCONF;
893 newname = obj->newtmp;
894 strcpy( newname, path );
896 p = ctoupath( vol, curdir, newname );
898 if (( vol = getvolbyvid( dvid )) == NULL ) {
899 return( AFPERR_PARAM );
902 if (vol->v_flags & AFPVOL_RO)
905 if (( dir = dirsearch( vol, ddid )) == NULL ) {
906 return( AFPERR_PARAM );
909 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
910 return( AFPERR_NOOBJ );
912 if ( *path != '\0' ) {
913 return( AFPERR_BADTYPE );
916 /* one of the handful of places that knows about the path type */
917 if ( *ibuf++ != 2 ) {
918 return( AFPERR_PARAM );
920 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
921 strncpy( newname, ibuf, plen );
922 newname[ plen ] = '\0';
925 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
926 vol_noadouble(vol))) < 0 ) {
930 setvoltime(obj, vol );
933 if (vol->v_flags & AFPVOL_DROPBOX) {
934 retvalue=matchfile2dirperms(newname, vol, sdid);
936 #endif /* DROPKLUDGE */
939 syslog (LOG_INFO, "end afp_copyfile:");
946 static __inline__ int copy_all(const int dfd, const void *buf,
952 syslog(LOG_INFO, "begin copy_all:");
956 if ((cc = write(dfd, buf, buflen)) < 0) {
974 syslog(LOG_INFO, "end copy_all:");
980 /* XXX: this needs to use ad_open and ad_lock. so, we need to
981 * pass in vol and path */
982 int copyfile(src, dst, newname, noadouble )
983 char *src, *dst, *newname;
989 int sfd, dfd, len, err = AFP_OK;
993 syslog(LOG_INFO, "begin copyfile:");
997 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1000 break; /* just copy the data fork */
1002 return( AFPERR_ACCESS );
1004 return( AFPERR_PARAM );
1007 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
1008 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
1012 return( AFPERR_NOOBJ );
1014 return( AFPERR_ACCESS );
1016 return AFPERR_VLOCK;
1018 return( AFPERR_PARAM );
1023 #ifdef SENDFILE_FLAVOR_LINUX
1024 if (fstat(sfd, &st) == 0) {
1025 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1039 goto copyheader_done;
1041 #endif /* SENDFILE_FLAVOR_LINUX */
1043 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1050 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1058 unlink(ad_path(dst, ADFLAGS_HF));
1064 /* data fork copying */
1065 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1068 return( AFPERR_NOOBJ );
1070 return( AFPERR_ACCESS );
1072 return( AFPERR_PARAM );
1076 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1080 return( AFPERR_NOOBJ );
1082 return( AFPERR_ACCESS );
1084 return AFPERR_VLOCK;
1086 return( AFPERR_PARAM );
1090 #ifdef SENDFILE_FLAVOR_LINUX
1091 if (fstat(sfd, &st) == 0) {
1092 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1105 #endif /* SENDFILE_FLAVOR_LINUX */
1108 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1116 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1125 unlink(ad_path(dst, ADFLAGS_HF));
1131 memset(&ad, 0, sizeof(ad));
1132 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1136 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1138 return( AFPERR_ACCESS );
1140 return AFPERR_VLOCK;
1142 return( AFPERR_PARAM );
1146 len = strlen( newname );
1147 ad_setentrylen( &ad, ADEID_NAME, len );
1148 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1149 ad_flush( &ad, ADFLAGS_HF );
1150 ad_close( &ad, ADFLAGS_HF );
1154 syslog(LOG_INFO, "end copyfile:");
1161 int deletefile( file )
1165 int adflags, err = AFP_OK;
1166 int locktype = ADLOCK_WR;
1167 int openmode = O_RDWR;
1170 syslog(LOG_INFO, "begin deletefile:");
1175 * If can't open read/write then try again read-only. If it's open
1176 * read-only, we must do a read lock instead of a write lock.
1178 /* try to open both at once */
1179 adflags = ADFLAGS_DF|ADFLAGS_HF;
1180 memset(&ad, 0, sizeof(ad));
1181 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1184 adflags = ADFLAGS_DF;
1185 /* that failed. now try to open just the data fork */
1186 memset(&ad, 0, sizeof(ad));
1187 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1190 return AFPERR_NOOBJ;
1192 if(openmode == O_RDWR) {
1193 openmode = O_RDONLY;
1194 locktype = ADLOCK_RD;
1197 return AFPERR_ACCESS;
1200 return AFPERR_VLOCK;
1202 return AFPERR_PARAM;
1208 if(openmode == O_RDWR) {
1209 openmode = O_RDONLY;
1210 locktype = ADLOCK_RD;
1213 return AFPERR_ACCESS;
1216 return AFPERR_VLOCK;
1218 return( AFPERR_PARAM );
1221 break; /* from the while */
1224 if ((adflags & ADFLAGS_HF) &&
1225 (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) {
1226 ad_close( &ad, adflags );
1227 return( AFPERR_BUSY );
1230 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1235 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1239 err = AFPERR_ACCESS;
1252 if ( unlink( file ) < 0 ) {
1256 err = AFPERR_ACCESS;
1270 if (adflags & ADFLAGS_HF)
1271 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1272 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1273 ad_close( &ad, adflags );
1276 syslog(LOG_INFO, "end deletefile:");
1284 /* return a file id */
1285 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1288 int ibuflen, *rbuflen;
1300 syslog(LOG_INFO, "begin afp_createid:");
1306 memcpy(&vid, ibuf, sizeof(vid));
1307 ibuf += sizeof(vid);
1309 if (( vol = getvolbyvid( vid )) == NULL ) {
1310 return( AFPERR_PARAM);
1313 if (vol->v_flags & AFPVOL_RO)
1314 return AFPERR_VLOCK;
1316 memcpy(&did, ibuf, sizeof( did ));
1317 ibuf += sizeof(did);
1319 if (( dir = dirsearch( vol, did )) == NULL ) {
1320 return( AFPERR_PARAM );
1323 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1324 return( AFPERR_PARAM );
1327 if ( *path == '\0' ) {
1328 return( AFPERR_BADTYPE );
1331 upath = mtoupath(vol, path);
1332 if (stat(upath, &st) < 0) {
1336 return AFPERR_ACCESS;
1338 return AFPERR_NOOBJ;
1340 return AFPERR_PARAM;
1344 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1345 memcpy(rbuf, &id, sizeof(id));
1346 *rbuflen = sizeof(id);
1347 return AFPERR_EXISTID;
1350 #if AD_VERSION > AD_VERSION1
1351 memset(&ad, 0, sizeof(ad));
1352 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1353 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1354 ad_close(&ad, ADFLAGS_HF);
1356 #endif /* AD_VERSION > AD_VERSION1 */
1358 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1359 memcpy(rbuf, &id, sizeof(id));
1360 *rbuflen = sizeof(id);
1365 syslog(LOG_INFO, "ending afp_createid...:");
1370 return AFPERR_VLOCK;
1374 return AFPERR_ACCESS;
1377 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1378 return AFPERR_PARAM;
1382 /* resolve a file id */
1383 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1386 int ibuflen, *rbuflen;
1394 u_int16_t vid, bitmap;
1397 syslog(LOG_INFO, "begin afp_resolveid:");
1403 memcpy(&vid, ibuf, sizeof(vid));
1404 ibuf += sizeof(vid);
1406 if (( vol = getvolbyvid( vid )) == NULL ) {
1407 return( AFPERR_PARAM);
1410 memcpy(&id, ibuf, sizeof( id ));
1413 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1414 return AFPERR_BADID;
1417 if (( dir = dirsearch( vol, id )) == NULL ) {
1418 return( AFPERR_PARAM );
1421 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1425 return AFPERR_ACCESS;
1429 return AFPERR_PARAM;
1433 /* directories are bad */
1434 if (S_ISDIR(st.st_mode))
1435 return AFPERR_BADTYPE;
1437 memcpy(&bitmap, ibuf, sizeof(bitmap));
1438 bitmap = ntohs( bitmap );
1440 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1441 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1444 *rbuflen = buflen + sizeof(bitmap);
1445 memcpy(rbuf, ibuf, sizeof(bitmap));
1448 syslog(LOG_INFO, "end afp_resolveid:");
1454 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1457 int ibuflen, *rbuflen;
1468 syslog(LOG_INFO, "begin afp_deleteid:");
1474 memcpy(&vid, ibuf, sizeof(vid));
1475 ibuf += sizeof(vid);
1477 if (( vol = getvolbyvid( vid )) == NULL ) {
1478 return( AFPERR_PARAM);
1481 if (vol->v_flags & AFPVOL_RO)
1482 return AFPERR_VLOCK;
1484 memcpy(&id, ibuf, sizeof( id ));
1487 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1491 if (( dir = dirsearch( vol, id )) == NULL ) {
1492 return( AFPERR_PARAM );
1496 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1500 return AFPERR_ACCESS;
1502 /* still try to delete the id */
1506 return AFPERR_PARAM;
1510 /* directories are bad */
1511 if (S_ISDIR(st.st_mode))
1512 return AFPERR_BADTYPE;
1514 if (cnid_delete(vol->v_db, id)) {
1517 return AFPERR_VLOCK;
1520 return AFPERR_ACCESS;
1522 return AFPERR_PARAM;
1527 syslog(LOG_INFO, "end afp_deleteid:");
1532 #endif /* CNID_DB */
1534 #define APPLETEMP ".AppleTempXXXXXX"
1536 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1539 int ibuflen, *rbuflen;
1541 struct stat srcst, destst;
1543 struct dir *dir, *sdir;
1544 char *spath, temp[17], *path, *p;
1545 char *supath, *upath;
1549 #endif /* CNID_DB */
1554 syslog(LOG_INFO, "begin afp_exchangefiles:");
1560 memcpy(&vid, ibuf, sizeof(vid));
1561 ibuf += sizeof(vid);
1563 if (( vol = getvolbyvid( vid )) == NULL ) {
1564 return( AFPERR_PARAM);
1567 if (vol->v_flags & AFPVOL_RO)
1568 return AFPERR_VLOCK;
1570 /* source and destination dids */
1571 memcpy(&sid, ibuf, sizeof(sid));
1572 ibuf += sizeof(sid);
1573 memcpy(&did, ibuf, sizeof(did));
1574 ibuf += sizeof(did);
1577 if ((dir = dirsearch( vol, sid )) == NULL ) {
1578 return( AFPERR_PARAM );
1581 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1582 return( AFPERR_PARAM );
1585 if ( *path == '\0' ) {
1586 return( AFPERR_BADTYPE );
1589 upath = mtoupath(vol, path);
1590 if (stat(upath, &srcst) < 0) {
1596 return AFPERR_ACCESS;
1598 return AFPERR_PARAM;
1602 /* save some stuff */
1604 spath = obj->oldtmp;
1605 supath = obj->newtmp;
1606 strcpy(spath, path);
1607 strcpy(supath, upath); /* this is for the cnid changing */
1608 p = ctoupath( vol, sdir, spath);
1610 /* look for the source cnid. if it doesn't exist, don't worry about
1613 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1614 slen = strlen(supath));
1615 #endif /* CNID_DB */
1617 if (( dir = dirsearch( vol, did )) == NULL ) {
1618 return( AFPERR_PARAM );
1621 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1622 return( AFPERR_PARAM );
1625 if ( *path == '\0' ) {
1626 return( AFPERR_BADTYPE );
1629 /* FPExchangeFiles is the only call that can return the SameObj
1631 if ((curdir == sdir) && strcmp(spath, path) == 0)
1632 return AFPERR_SAMEOBJ;
1634 upath = mtoupath(vol, path);
1635 if (stat(upath, &destst) < 0) {
1641 return AFPERR_ACCESS;
1643 return AFPERR_PARAM;
1648 /* look for destination id. */
1649 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1650 dlen = strlen(upath));
1651 #endif /* CNID_DB */
1653 /* construct a temp name.
1654 * NOTE: the temp file will be in the dest file's directory. it
1655 * will also be inaccessible from AFP. */
1656 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1660 /* now, quickly rename the file. we error if we can't. */
1661 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1662 goto err_exchangefile;
1663 of_rename(vol, sdir, spath, curdir, temp);
1665 /* rename destination to source */
1666 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1667 goto err_src_to_tmp;
1668 of_rename(vol, curdir, path, sdir, spath);
1670 /* rename temp to destination */
1671 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1672 goto err_dest_to_src;
1673 of_rename(vol, curdir, temp, curdir, path);
1676 /* id's need switching. src -> dest and dest -> src. */
1677 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1678 upath, dlen) < 0)) {
1682 err = AFPERR_ACCESS;
1687 goto err_temp_to_dest;
1690 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1691 supath, slen) < 0)) {
1695 err = AFPERR_ACCESS;
1702 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1703 goto err_temp_to_dest;
1705 #endif /* CNID_DB */
1708 syslog(LOG_INFO, "ending afp_exchangefiles:");
1714 /* all this stuff is so that we can unwind a failed operation
1717 /* rename dest to temp */
1718 renamefile(upath, temp, temp, vol_noadouble(vol));
1719 of_rename(vol, curdir, upath, curdir, temp);
1722 /* rename source back to dest */
1723 renamefile(p, upath, path, vol_noadouble(vol));
1724 of_rename(vol, sdir, spath, curdir, path);
1727 /* rename temp back to source */
1728 renamefile(temp, p, spath, vol_noadouble(vol));
1729 of_rename(vol, curdir, temp, sdir, spath);