2 * $Id: file.c,v 1.24 2001-07-12 23:18:12 srittau 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 #endif /* HAVE_FCNTL_H */
26 #include <sys/syslog.h>
27 #include <sys/types.h>
29 #include <sys/param.h>
32 #include <netatalk/endian.h>
33 #include <atalk/adouble.h>
34 #include <atalk/afp.h>
35 #include <atalk/util.h>
36 #include <atalk/cnid.h>
38 #include "directory.h"
46 /* check for mtab DID code */
48 #include "parse_mtab.h"
54 #endif /* FORCE_UIDGID */
56 /* the format for the finderinfo fields (from IM: Toolbox Essentials):
57 * field bytes subfield bytes
60 * ioFlFndrInfo 16 -> type 4 type field
61 * creator 4 creator field
62 * flags 2 finder flags:
64 * location 4 location in window
65 * folder 2 window that contains file
67 * ioFlXFndrInfo 16 -> iconID 2 icon id
69 * script 1 script system
71 * commentID 2 comment id
72 * putawayID 4 home directory id
75 const u_char ufinderi[] = {
76 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
77 0, 0, 0, 0, 0, 0, 0, 0,
78 0, 0, 0, 0, 0, 0, 0, 0,
79 0, 0, 0, 0, 0, 0, 0, 0
82 int getfilparams(vol, bitmap, path, dir, st, buf, buflen )
92 struct stat hst, lst, *lstp;
93 #else /* USE_LASTDID */
95 #endif /* USE_LASTDID */
96 struct adouble ad, *adp;
99 char *data, *nameoff = NULL, *upath;
100 int bit = 0, isad = 1, aint;
102 u_char achar, fdType[4];
105 syslog(LOG_INFO, "begin getfilparams:");
108 upath = mtoupath(vol, path);
109 if ((of = of_findname(vol, curdir, path))) {
112 memset(&ad, 0, sizeof(ad));
116 if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
118 } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) {
119 syslog( LOG_ERR, "getfilparams fstat: %m" );
123 while ( bitmap != 0 ) {
124 while (( bitmap & 1 ) == 0 ) {
132 ad_getattr(adp, &ashort);
133 } else if (*upath == '.') {
134 ashort = htons(ATTRBIT_INVISIBLE);
137 memcpy(data, &ashort, sizeof( ashort ));
138 data += sizeof( u_short );
142 memcpy(data, &dir->d_did, sizeof( u_int32_t ));
143 data += sizeof( u_int32_t );
147 if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
148 aint = AD_DATE_FROM_UNIX(st->st_mtime);
149 memcpy(data, &aint, sizeof( aint ));
150 data += sizeof( aint );
154 if ( isad && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
155 if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) &&
156 (hst.st_mtime < st->st_mtime)) {
157 aint = AD_DATE_FROM_UNIX(st->st_mtime);
160 aint = AD_DATE_FROM_UNIX(st->st_mtime);
162 memcpy(data, &aint, sizeof( int ));
163 data += sizeof( int );
167 if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
168 aint = AD_DATE_START;
169 memcpy(data, &aint, sizeof( int ));
170 data += sizeof( int );
175 memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
177 memcpy(data, ufinderi, 32);
178 if (*upath == '.') { /* make it invisible */
179 ashort = htons(FINDERINFO_INVISIBLE);
180 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
184 if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI),
185 ufinderi, 8 ) == 0)) &&
186 (em = getextmap( path ))) {
187 memcpy(data, em->em_type, sizeof( em->em_type ));
188 memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
195 data += sizeof( u_int16_t );
199 memset(data, 0, sizeof(u_int16_t));
200 data += sizeof( u_int16_t );
204 #if AD_VERSION > AD_VERSION1
205 /* use the CNID database if we're using AD v2 */
207 memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
211 if (!(aint = cnid_add(vol->v_db, st, dir->d_did, upath,
212 strlen(upath), aint))) {
213 #endif /* AD_VERSION > AD_VERSION1 */
215 * What a fucking mess. First thing: DID and FNUMs are
216 * in the same space for purposes of enumerate (and several
217 * other wierd places). While we consider this Apple's bug,
218 * this is the work-around: In order to maintain constant and
219 * unique DIDs and FNUMs, we monotonically generate the DIDs
220 * during the session, and derive the FNUMs from the filesystem.
221 * Since the DIDs are small, we insure that the FNUMs are fairly
222 * large by setting thier high bits to the device number.
224 * AFS already does something very similar to this for the
225 * inode number, so we don't repeat the procedure.
228 * due to complaints over did's being non-persistent,
229 * here's the current hack to provide semi-persistent
231 * 1) we reserve the first bit for file ids.
232 * 2) the next 7 bits are for the device.
233 * 3) the remaining 24 bits are for the inode.
235 * both the inode and device information are actually hashes
236 * that are then truncated to the requisite bit length.
238 * it should be okay to use lstat to deal with symlinks.
241 aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
242 #else /* USE_LASTDID */
243 lstp = lstat(upath, &lst) < 0 ? st : &lst;
245 aint = htonl( afpd_st_cnid ( lstp ) );
247 aint = htonl(CNID(lstp, 1));
248 #endif /* DID_MTAB */
249 #endif /* USE_LASTDID */
251 #if AD_VERSION > AD_VERSION1
253 #endif /* AD_VERSION > AD_VERSION1 */
254 memcpy(data, &aint, sizeof( aint ));
255 data += sizeof( aint );
259 aint = htonl( st->st_size );
260 memcpy(data, &aint, sizeof( aint ));
261 data += sizeof( aint );
266 aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
270 memcpy(data, &aint, sizeof( aint ));
271 data += sizeof( aint );
274 /* Current client needs ProDOS info block for this file.
275 Use simple heuristic and let the Mac "type" string tell
276 us what the PD file code should be. Everything gets a
277 subtype of 0x0000 unless the original value was hashed
278 to "pXYZ" when we created it. See IA, Ver 2.
280 case FILPBIT_PDINFO :
282 memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
284 if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
288 else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
292 else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
296 else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
300 else if ( fdType[0] == 'p' ) {
302 ashort = (fdType[2] * 256) + fdType[3];
316 memcpy(data, &ashort, sizeof( ashort ));
317 data += sizeof( ashort );
318 memset(data, 0, sizeof( ashort ));
319 data += sizeof( ashort );
324 ad_close( adp, ADFLAGS_HF );
326 return( AFPERR_BITMAP );
332 ashort = htons( data - buf );
333 memcpy(nameoff, &ashort, sizeof( ashort ));
334 if ((aint = strlen( path )) > MACFILELEN)
337 memcpy(data, path, aint );
341 ad_close( adp, ADFLAGS_HF );
343 *buflen = data - buf;
346 syslog(LOG_INFO, "end getfilparams:");
352 int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
355 int ibuflen, *rbuflen;
358 struct adouble ad, *adp;
363 int creatf, did, openf, retvalue = AFP_OK;
367 #endif /* FORCE_UIDGID */
370 syslog(LOG_INFO, "begin afp_createfile:");
375 creatf = (unsigned char) *ibuf++;
377 memcpy(&vid, ibuf, sizeof( vid ));
378 ibuf += sizeof( vid );
380 if (( vol = getvolbyvid( vid )) == NULL ) {
381 return( AFPERR_PARAM );
384 if (vol->v_flags & AFPVOL_RO)
387 memcpy(&did, ibuf, sizeof( did));
388 ibuf += sizeof( did );
390 if (( dir = dirsearch( vol, did )) == NULL ) {
391 return( AFPERR_NOOBJ );
394 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
395 return( AFPERR_NOOBJ );
398 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
399 strpbrk(path, MSWINDOWS_BADCHARS))
402 upath = mtoupath(vol, path);
404 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
407 if (!validupath(vol, upath))
410 if ((of = of_findname(vol, curdir, path))) {
413 memset(&ad, 0, sizeof(ad));
417 /* on a hard create, fail if file exists and is open */
418 if ((stat(upath, &st) == 0) && of)
420 openf = O_RDWR|O_CREAT|O_TRUNC;
422 openf = O_RDWR|O_CREAT|O_EXCL;
427 /* preserve current euid, egid */
428 save_uidgid ( uidgid );
430 /* perform all switching of users */
433 #endif /* FORCE_UIDGID */
435 if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
436 openf, 0666, adp) < 0 ) {
440 /* bring everything back to old euid, egid */
441 restore_uidgid ( uidgid );
442 #endif /* FORCE_UIDGID */
443 return( AFPERR_EXIST );
446 /* bring everything back to old euid, egid */
447 restore_uidgid ( uidgid );
448 #endif /* FORCE_UIDGID */
449 return( AFPERR_ACCESS );
451 /* on noadouble volumes, just creating the data fork is ok */
452 if (vol_noadouble(vol) && (stat(upath, &st) == 0))
453 goto createfile_done;
457 /* bring everything back to old euid, egid */
458 restore_uidgid ( uidgid );
459 #endif /* FORCE_UIDGID */
460 return( AFPERR_PARAM );
464 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
465 memcpy(ad_entry( adp, ADEID_NAME ), path,
466 ad_getentrylen( adp, ADEID_NAME ));
467 ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
468 ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
473 if (vol->v_flags & AFPVOL_DROPBOX) {
474 retvalue = matchfile2dirperms(upath, vol, did);
476 #endif /* DROPKLUDGE */
478 setvoltime(obj, vol );
481 syslog(LOG_INFO, "end afp_createfile");
485 /* bring everything back to old euid, egid */
486 restore_uidgid ( uidgid );
487 #endif /* FORCE_UIDGID */
492 int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
495 int ibuflen, *rbuflen;
501 u_int16_t vid, bitmap;
504 syslog(LOG_INFO, "begin afp_setfilparams:");
510 memcpy(&vid, ibuf, sizeof( vid ));
511 ibuf += sizeof( vid );
512 if (( vol = getvolbyvid( vid )) == NULL ) {
513 return( AFPERR_PARAM );
516 if (vol->v_flags & AFPVOL_RO)
519 memcpy(&did, ibuf, sizeof( did ));
520 ibuf += sizeof( did );
521 if (( dir = dirsearch( vol, did )) == NULL ) {
522 return( AFPERR_NOOBJ );
525 memcpy(&bitmap, ibuf, sizeof( bitmap ));
526 bitmap = ntohs( bitmap );
527 ibuf += sizeof( bitmap );
529 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
530 return( AFPERR_NOOBJ );
533 if ((u_long)ibuf & 1 ) {
537 if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
538 setvoltime(obj, vol );
542 syslog(LOG_INFO, "end afp_setfilparams:");
549 int setfilparams(vol, path, bitmap, buf )
554 struct adouble ad, *adp;
557 int bit = 0, isad = 1, err = AFP_OK;
559 u_char achar, *fdType, xyy[4];
560 u_int16_t ashort, bshort;
567 uidgid = malloc(sizeof(uidgidset));
568 #endif /* FORCE_UIDGID */
571 syslog(LOG_INFO, "begin setfilparams:");
574 upath = mtoupath(vol, path);
575 if ((of = of_findname(vol, curdir, path))) {
578 memset(&ad, 0, sizeof(ad));
583 save_uidgid ( uidgid );
585 #endif /* FORCE_UIDGID */
587 if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
588 O_RDWR|O_CREAT, 0666, adp) < 0) {
589 /* for some things, we don't need an adouble header */
590 if (bitmap & ~(1<<FILPBIT_MDATE)) {
592 restore_uidgid ( uidgid );
593 #endif /* FORCE_UIDGID */
594 return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
597 } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
598 ad_setentrylen( adp, ADEID_NAME, strlen( path ));
599 memcpy(ad_entry( adp, ADEID_NAME ), path,
600 ad_getentrylen( adp, ADEID_NAME ));
603 while ( bitmap != 0 ) {
604 while (( bitmap & 1 ) == 0 ) {
611 memcpy(&ashort, buf, sizeof( ashort ));
612 ad_getattr(adp, &bshort);
613 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
614 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
618 ad_setattr(adp, bshort);
619 buf += sizeof( ashort );
623 memcpy(&aint, buf, sizeof(aint));
624 ad_setdate(adp, AD_DATE_CREATE, aint);
625 buf += sizeof( aint );
629 memcpy(&aint, buf, sizeof( aint ));
631 ad_setdate(adp, AD_DATE_MODIFY, aint);
632 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
634 buf += sizeof( aint );
638 memcpy(&aint, buf, sizeof(aint));
639 ad_setdate(adp, AD_DATE_BACKUP, aint);
640 buf += sizeof( aint );
644 if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0)
645 && (em = getextmap( path )) &&
646 (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) &&
647 (memcmp(buf + 4, em->em_creator,
648 sizeof( em->em_creator )) == 0)) {
649 memcpy(buf, ufinderi, 8 );
651 memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
655 /* Client needs to set the ProDOS file info for this file.
656 Use defined strings for the simple cases, and convert
657 all else into pXYY per Inside Appletalk. Always set
658 the creator as "pdos". <shirsch@ibm.net> */
659 case FILPBIT_PDINFO :
662 memcpy(&ashort, buf, sizeof( ashort ));
663 ashort = ntohs( ashort );
666 switch ( (unsigned int) achar )
669 fdType = ( u_char *) "TEXT";
673 fdType = ( u_char *) "PSYS";
677 fdType = ( u_char *) "PS16";
681 fdType = ( u_char *) "BINA";
685 xyy[0] = ( u_char ) 'p';
687 xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
688 xyy[3] = ( u_char ) ashort & 0xff;
693 memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
694 memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
700 goto setfilparam_done;
709 ad_flush( adp, ADFLAGS_HF );
710 ad_close( adp, ADFLAGS_HF );
713 restore_uidgid ( uidgid );
714 #endif /* FORCE_UIDGID */
719 syslog(LOG_INFO, "end setfilparams:");
726 * renamefile and copyfile take the old and new unix pathnames
727 * and the new mac name.
728 * NOTE: if we have to copy a file instead of renaming it, locks
731 int renamefile(src, dst, newname, noadouble )
732 char *src, *dst, *newname;
736 char adsrc[ MAXPATHLEN + 1];
740 * Note that this is only checking the existance of the data file,
741 * not the header file. The thinking is that if the data file doesn't
742 * exist, but the header file does, the right thing to do is remove
743 * the data file silently.
746 /* existence check moved to afp_moveandrename */
749 syslog (LOG_INFO, "begin renamefile:");
752 if ( rename( src, dst ) < 0 ) {
755 return( AFPERR_NOOBJ );
758 return( AFPERR_ACCESS );
761 case EXDEV : /* Cross device move -- try copy */
762 if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
766 return deletefile( src );
768 return( AFPERR_PARAM );
772 strcpy( adsrc, ad_path( src, 0 ));
775 if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
780 /* check for a source appledouble header. if it exists, make
781 * a dest appledouble directory and do the rename again. */
782 memset(&ad, 0, sizeof(ad));
783 if (rc || stat(adsrc, &st) ||
784 (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad) < 0))
787 ad_close(&ad, ADFLAGS_HF);
791 return( AFPERR_ACCESS );
795 return( AFPERR_PARAM );
799 memset(&ad, 0, sizeof(ad));
800 if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, &ad) < 0 ) {
803 return( AFPERR_NOOBJ );
805 return( AFPERR_ACCESS );
809 return( AFPERR_PARAM );
813 len = strlen( newname );
814 ad_setentrylen( &ad, ADEID_NAME, len );
815 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
816 ad_flush( &ad, ADFLAGS_HF );
817 ad_close( &ad, ADFLAGS_HF );
820 syslog (LOG_INFO, "end renamefile:");
826 int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
829 int ibuflen, *rbuflen;
833 char *newname, *path, *p;
834 u_int32_t sdid, ddid;
835 int plen, err, retvalue = AFP_OK;
836 u_int16_t svid, dvid;
839 syslog (LOG_INFO, "begin afp_copyfile:");
845 memcpy(&svid, ibuf, sizeof( svid ));
846 ibuf += sizeof( svid );
847 if (( vol = getvolbyvid( svid )) == NULL ) {
848 return( AFPERR_PARAM );
851 memcpy(&sdid, ibuf, sizeof( sdid ));
852 ibuf += sizeof( sdid );
853 if (( dir = dirsearch( vol, sdid )) == NULL ) {
854 return( AFPERR_PARAM );
857 memcpy(&dvid, ibuf, sizeof( dvid ));
858 ibuf += sizeof( dvid );
859 memcpy(&ddid, ibuf, sizeof( ddid ));
860 ibuf += sizeof( ddid );
862 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
863 return( AFPERR_NOOBJ );
865 if ( *path == '\0' ) {
866 return( AFPERR_BADTYPE );
869 /* don't allow copies when the file is open.
870 * XXX: the spec only calls for read/deny write access.
871 * however, copyfile doesn't have any of that info,
872 * and locks need to stay coherent. as a result,
873 * we just balk if the file is opened already. */
874 if (of_findname(vol, curdir, path))
875 return AFPERR_DENYCONF;
877 newname = obj->newtmp;
878 strcpy( newname, path );
880 p = ctoupath( vol, curdir, newname );
882 if (( vol = getvolbyvid( dvid )) == NULL ) {
883 return( AFPERR_PARAM );
886 if (vol->v_flags & AFPVOL_RO)
889 if (( dir = dirsearch( vol, ddid )) == NULL ) {
890 return( AFPERR_PARAM );
893 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
894 return( AFPERR_NOOBJ );
896 if ( *path != '\0' ) {
897 return( AFPERR_BADTYPE );
900 /* one of the handful of places that knows about the path type */
901 if ( *ibuf++ != 2 ) {
902 return( AFPERR_PARAM );
904 if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
905 strncpy( newname, ibuf, plen );
906 newname[ plen ] = '\0';
909 if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
910 vol_noadouble(vol))) < 0 ) {
914 setvoltime(obj, vol );
917 if (vol->v_flags & AFPVOL_DROPBOX) {
918 retvalue=matchfile2dirperms(newname, vol, sdid);
920 #endif /* DROPKLUDGE */
923 syslog (LOG_INFO, "end afp_copyfile:");
930 static __inline__ int copy_all(const int dfd, const void *buf,
936 syslog(LOG_INFO, "begin copy_all:");
940 if ((cc = write(dfd, buf, buflen)) < 0) {
958 syslog(LOG_INFO, "end copy_all:");
964 /* XXX: this needs to use ad_open and ad_lock. so, we need to
965 * pass in vol and path */
966 int copyfile(src, dst, newname, noadouble )
967 char *src, *dst, *newname;
973 int sfd, dfd, len, err = AFP_OK;
977 syslog(LOG_INFO, "begin copyfile:");
981 if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
984 break; /* just copy the data fork */
986 return( AFPERR_ACCESS );
988 return( AFPERR_PARAM );
991 if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
992 ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
996 return( AFPERR_NOOBJ );
998 return( AFPERR_ACCESS );
1000 return AFPERR_VLOCK;
1002 return( AFPERR_PARAM );
1007 #ifdef SENDFILE_FLAVOR_LINUX
1008 if (fstat(sfd, &st) == 0) {
1009 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1023 goto copyheader_done;
1025 #endif /* SENDFILE_FLAVOR_LINUX */
1027 if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1034 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1042 unlink(ad_path(dst, ADFLAGS_HF));
1048 /* data fork copying */
1049 if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1052 return( AFPERR_NOOBJ );
1054 return( AFPERR_ACCESS );
1056 return( AFPERR_PARAM );
1060 if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
1064 return( AFPERR_NOOBJ );
1066 return( AFPERR_ACCESS );
1068 return AFPERR_VLOCK;
1070 return( AFPERR_PARAM );
1074 #ifdef SENDFILE_FLAVOR_LINUX
1075 if (fstat(sfd, &st) == 0) {
1076 if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1089 #endif /* SENDFILE_FLAVOR_LINUX */
1092 if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1100 if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1109 unlink(ad_path(dst, ADFLAGS_HF));
1115 memset(&ad, 0, sizeof(ad));
1116 if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1120 return noadouble ? AFP_OK : AFPERR_NOOBJ;
1122 return( AFPERR_ACCESS );
1124 return AFPERR_VLOCK;
1126 return( AFPERR_PARAM );
1130 len = strlen( newname );
1131 ad_setentrylen( &ad, ADEID_NAME, len );
1132 memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1133 ad_flush( &ad, ADFLAGS_HF );
1134 ad_close( &ad, ADFLAGS_HF );
1138 syslog(LOG_INFO, "end copyfile:");
1145 int deletefile( file )
1149 int adflags, err = AFP_OK;
1150 int locktype = ADLOCK_WR;
1151 int openmode = O_RDWR;
1154 syslog(LOG_INFO, "begin deletefile:");
1159 * If can't open read/write then try again read-only. If it's open
1160 * read-only, we must do a read lock instead of a write lock.
1162 /* try to open both at once */
1163 adflags = ADFLAGS_DF|ADFLAGS_HF;
1164 memset(&ad, 0, sizeof(ad));
1165 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1168 adflags = ADFLAGS_DF;
1169 /* that failed. now try to open just the data fork */
1170 memset(&ad, 0, sizeof(ad));
1171 if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1174 return AFPERR_NOOBJ;
1176 if(openmode == O_RDWR) {
1177 openmode = O_RDONLY;
1178 locktype = ADLOCK_RD;
1181 return AFPERR_ACCESS;
1184 return AFPERR_VLOCK;
1186 return AFPERR_PARAM;
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 );
1205 break; /* from the while */
1208 if ((adflags & ADFLAGS_HF) &&
1209 (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) {
1210 ad_close( &ad, adflags );
1211 return( AFPERR_BUSY );
1214 if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1219 if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1223 err = AFPERR_ACCESS;
1236 if ( unlink( file ) < 0 ) {
1240 err = AFPERR_ACCESS;
1254 if (adflags & ADFLAGS_HF)
1255 ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
1256 ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1257 ad_close( &ad, adflags );
1260 syslog(LOG_INFO, "end deletefile:");
1267 #if AD_VERSION > AD_VERSION1
1268 /* return a file id */
1269 int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1272 int ibuflen, *rbuflen;
1284 syslog(LOG_INFO, "begin afp_createid:");
1290 memcpy(&vid, ibuf, sizeof(vid));
1291 ibuf += sizeof(vid);
1293 if (( vol = getvolbyvid( vid )) == NULL ) {
1294 return( AFPERR_PARAM);
1297 if (vol->v_flags & AFPVOL_RO)
1298 return AFPERR_VLOCK;
1300 memcpy(&did, ibuf, sizeof( did ));
1301 ibuf += sizeof(did);
1303 if (( dir = dirsearch( vol, did )) == NULL ) {
1304 return( AFPERR_PARAM );
1307 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1308 return( AFPERR_PARAM );
1311 if ( *path == '\0' ) {
1312 return( AFPERR_BADTYPE );
1315 upath = mtoupath(vol, path);
1316 if (stat(upath, &st) < 0) {
1320 return AFPERR_ACCESS;
1322 return AFPERR_NOOBJ;
1324 return AFPERR_PARAM;
1328 if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) {
1329 memcpy(rbuf, &id, sizeof(id));
1330 *rbuflen = sizeof(id);
1331 return AFPERR_EXISTID;
1334 memset(&ad, 0, sizeof(ad));
1335 if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) < 0)
1338 memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1339 ad_close(&ad, ADFLAGS_HF);
1342 if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) {
1343 memcpy(rbuf, &id, sizeof(id));
1344 *rbuflen = sizeof(id);
1349 syslog(LOG_INFO, "ending afp_createid...:");
1354 return AFPERR_VLOCK;
1358 return AFPERR_ACCESS;
1361 syslog(LOG_ERR, "afp_createid: cnid_add: %m");
1362 return AFPERR_PARAM;
1366 /* resolve a file id */
1367 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1370 int ibuflen, *rbuflen;
1378 u_int16_t vid, bitmap;
1381 syslog(LOG_INFO, "begin afp_resolveid:");
1387 memcpy(&vid, ibuf, sizeof(vid));
1388 ibuf += sizeof(vid);
1390 if (( vol = getvolbyvid( vid )) == NULL ) {
1391 return( AFPERR_PARAM);
1394 memcpy(&id, ibuf, sizeof( id ));
1397 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1398 return AFPERR_BADID;
1401 if (( dir = dirsearch( vol, id )) == NULL ) {
1402 return( AFPERR_PARAM );
1405 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1409 return AFPERR_ACCESS;
1413 return AFPERR_PARAM;
1417 /* directories are bad */
1418 if (S_ISDIR(st.st_mode))
1419 return AFPERR_BADTYPE;
1421 memcpy(&bitmap, ibuf, sizeof(bitmap));
1422 bitmap = ntohs( bitmap );
1424 if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1425 rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1428 *rbuflen = buflen + sizeof(bitmap);
1429 memcpy(rbuf, ibuf, sizeof(bitmap));
1432 syslog(LOG_INFO, "end afp_resolveid:");
1438 int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1441 int ibuflen, *rbuflen;
1452 syslog(LOG_INFO, "begin afp_deleteid:");
1458 memcpy(&vid, ibuf, sizeof(vid));
1459 ibuf += sizeof(vid);
1461 if (( vol = getvolbyvid( vid )) == NULL ) {
1462 return( AFPERR_PARAM);
1465 if (vol->v_flags & AFPVOL_RO)
1466 return AFPERR_VLOCK;
1468 memcpy(&id, ibuf, sizeof( id ));
1471 if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) {
1475 if (( dir = dirsearch( vol, id )) == NULL ) {
1476 return( AFPERR_PARAM );
1480 if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1484 return AFPERR_ACCESS;
1486 /* still try to delete the id */
1490 return AFPERR_PARAM;
1494 /* directories are bad */
1495 if (S_ISDIR(st.st_mode))
1496 return AFPERR_BADTYPE;
1498 if (cnid_delete(vol->v_db, id)) {
1501 return AFPERR_VLOCK;
1504 return AFPERR_ACCESS;
1506 return AFPERR_PARAM;
1511 syslog(LOG_INFO, "end afp_deleteid:");
1516 #endif /* AD_VERSION > AD_VERSION1 */
1518 #define APPLETEMP ".AppleTempXXXXXX"
1520 int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1523 int ibuflen, *rbuflen;
1525 struct stat srcst, destst;
1527 struct dir *dir, *sdir;
1528 char *spath, temp[17], *path, *p;
1529 char *supath, *upath;
1531 #if AD_VERSION > AD_VERSION1
1533 #endif /* AD_VERSION > AD_VERSION1 */
1538 syslog(LOG_INFO, "begin afp_exchangefiles:");
1544 memcpy(&vid, ibuf, sizeof(vid));
1545 ibuf += sizeof(vid);
1547 if (( vol = getvolbyvid( vid )) == NULL ) {
1548 return( AFPERR_PARAM);
1551 if (vol->v_flags & AFPVOL_RO)
1552 return AFPERR_VLOCK;
1554 /* source and destination dids */
1555 memcpy(&sid, ibuf, sizeof(sid));
1556 ibuf += sizeof(sid);
1557 memcpy(&did, ibuf, sizeof(did));
1558 ibuf += sizeof(did);
1561 if ((dir = dirsearch( vol, sid )) == NULL ) {
1562 return( AFPERR_PARAM );
1565 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1566 return( AFPERR_PARAM );
1569 if ( *path == '\0' ) {
1570 return( AFPERR_BADTYPE );
1573 upath = mtoupath(vol, path);
1574 if (stat(upath, &srcst) < 0) {
1580 return AFPERR_ACCESS;
1582 return AFPERR_PARAM;
1586 /* save some stuff */
1588 spath = obj->oldtmp;
1589 supath = obj->newtmp;
1590 strcpy(spath, path);
1591 strcpy(supath, upath); /* this is for the cnid changing */
1592 p = ctoupath( vol, sdir, spath);
1594 /* look for the source cnid. if it doesn't exist, don't worry about
1596 #if AD_VERSION > AD_VERSION1
1597 sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1598 slen = strlen(supath));
1599 #endif /* AD_VERSION > AD_VERSION1 */
1601 if (( dir = dirsearch( vol, did )) == NULL ) {
1602 return( AFPERR_PARAM );
1605 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1606 return( AFPERR_PARAM );
1609 if ( *path == '\0' ) {
1610 return( AFPERR_BADTYPE );
1613 /* FPExchangeFiles is the only call that can return the SameObj
1615 if ((curdir == sdir) && strcmp(spath, path) == 0)
1616 return AFPERR_SAMEOBJ;
1618 upath = mtoupath(vol, path);
1619 if (stat(upath, &destst) < 0) {
1625 return AFPERR_ACCESS;
1627 return AFPERR_PARAM;
1631 #if AD_VERSION > AD_VERSION1
1632 /* look for destination id. */
1633 did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1634 dlen = strlen(upath));
1635 #endif /* AD_VERSION > AD_VERSION1 */
1637 /* construct a temp name.
1638 * NOTE: the temp file will be in the dest file's directory. it
1639 * will also be inaccessible from AFP. */
1640 memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1644 /* now, quickly rename the file. we error if we can't. */
1645 if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0)
1646 goto err_exchangefile;
1647 of_rename(vol, sdir, spath, curdir, temp);
1649 /* rename destination to source */
1650 if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0)
1651 goto err_src_to_tmp;
1652 of_rename(vol, curdir, path, sdir, spath);
1654 /* rename temp to destination */
1655 if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0)
1656 goto err_dest_to_src;
1657 of_rename(vol, curdir, temp, curdir, path);
1659 #if AD_VERSION > AD_VERSION1
1660 /* id's need switching. src -> dest and dest -> src. */
1661 if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1662 upath, dlen) < 0)) {
1666 err = AFPERR_ACCESS;
1670 goto err_temp_to_dest;
1673 if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1674 supath, slen) < 0)) {
1678 err = AFPERR_ACCESS;
1684 cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1685 goto err_temp_to_dest;
1687 #endif /* AD_VERSION > AD_VERSION1 */
1690 syslog(LOG_INFO, "ending afp_exchangefiles:");
1696 /* all this stuff is so that we can unwind a failed operation
1699 /* rename dest to temp */
1700 renamefile(upath, temp, temp, vol_noadouble(vol));
1701 of_rename(vol, curdir, upath, curdir, temp);
1704 /* rename source back to dest */
1705 renamefile(p, upath, path, vol_noadouble(vol));
1706 of_rename(vol, sdir, spath, curdir, path);
1709 /* rename temp back to source */
1710 renamefile(temp, p, spath, vol_noadouble(vol));
1711 of_rename(vol, curdir, temp, sdir, spath);