@@ -739,9 +739,10 @@ func (b *bucket) NewTypedWriter(ctx context.Context, key, contentType string, op
739739
740740 if b .opts .Metadata == MetadataDontWrite {
741741 w := & writer {
742- ctx : ctx ,
743- File : f ,
744- path : path ,
742+ ctx : ctx ,
743+ File : f ,
744+ path : path ,
745+ ifNotExist : opts .IfNotExist ,
745746 }
746747 return w , nil
747748 }
@@ -765,6 +766,7 @@ func (b *bucket) NewTypedWriter(ctx context.Context, key, contentType string, op
765766 attrs : attrs ,
766767 contentMD5 : opts .ContentMD5 ,
767768 md5hash : md5 .New (),
769+ ifNotExist : opts .IfNotExist ,
768770 }
769771 return w , nil
770772}
@@ -778,7 +780,8 @@ type writerWithSidecar struct {
778780 contentMD5 []byte
779781 // We compute the MD5 hash so that we can store it with the file attributes,
780782 // not for verification.
781- md5hash hash.Hash
783+ md5hash hash.Hash
784+ ifNotExist bool
782785}
783786
784787func (w * writerWithSidecar ) Write (p []byte ) (n int , err error ) {
@@ -794,33 +797,55 @@ func (w *writerWithSidecar) Write(p []byte) (n int, err error) {
794797 return n , nil
795798}
796799
797- func (w * writerWithSidecar ) Close () error {
798- err := w .f .Close ()
799- if err != nil {
800- return err
801- }
800+ func (w * writerWithSidecar ) Close () (err error ) {
802801 // Always delete the temp file. On success, it will have been renamed so
803802 // the Remove will fail.
804803 defer func () {
805804 _ = os .Remove (w .f .Name ())
806805 }()
807806
808807 // Check if the write was cancelled.
809- if err : = w .ctx .Err (); err != nil {
808+ if err = w .ctx .Err (); err != nil {
810809 return err
811810 }
812811
813812 md5sum := w .md5hash .Sum (nil )
814813 w .attrs .MD5 = md5sum
815814
816815 // Write the attributes file.
817- if err : = setAttrs (w .path , w .attrs ); err != nil {
816+ if err = setAttrs (w .path , w .attrs ); err != nil {
818817 return err
819818 }
820- // Rename the temp file to path.
821- if err := os .Rename (w .f .Name (), w .path ); err != nil {
822- _ = os .Remove (w .path + attrsExt )
823- return err
819+
820+ defer func () {
821+ if err != nil {
822+ _ = os .Remove (w .path + attrsExt )
823+ }
824+ }()
825+
826+ if w .ifNotExist {
827+ fileOptions := os .O_RDWR | os .O_CREATE | os .O_EXCL
828+ fd , err := os .OpenFile (w .path , fileOptions , 0666 )
829+ if err != nil {
830+ return gcerr .New (gcerrors .FailedPrecondition , err , 1 , "File already exist" )
831+ }
832+ defer func () { _ = fd .Close () }()
833+
834+ // Set offset at the beginning of the file
835+ _ , err = w .f .Seek (0 , 0 )
836+ if err != nil {
837+ return err
838+ }
839+
840+ // Copy content from the temp file to the new file
841+ _ , err = w .f .WriteTo (fd )
842+ if err != nil {
843+ return err
844+ }
845+ } else {
846+ if err := os .Rename (w .f .Name (), w .path ); err != nil {
847+ return err
848+ }
824849 }
825850 return nil
826851}
@@ -831,8 +856,9 @@ func (w *writerWithSidecar) Close() error {
831856// which is why it is not folded into writerWithSidecar.
832857type writer struct {
833858 * os.File
834- ctx context.Context
835- path string
859+ ctx context.Context
860+ path string
861+ ifNotExist bool
836862}
837863
838864func (w * writer ) Upload (r io.Reader ) error {
@@ -841,10 +867,6 @@ func (w *writer) Upload(r io.Reader) error {
841867}
842868
843869func (w * writer ) Close () error {
844- err := w .File .Close ()
845- if err != nil {
846- return err
847- }
848870 // Always delete the temp file. On success, it will have been renamed so
849871 // the Remove will fail.
850872 tempname := w .File .Name ()
@@ -855,9 +877,29 @@ func (w *writer) Close() error {
855877 return err
856878 }
857879
858- // Rename the temp file to path.
859- if err := os .Rename (tempname , w .path ); err != nil {
860- return err
880+ if w .ifNotExist {
881+ fileOptions := os .O_RDWR | os .O_CREATE | os .O_EXCL
882+ fd , err := os .OpenFile (w .path , fileOptions , 0666 )
883+ if err != nil {
884+ return gcerr .New (gcerrors .FailedPrecondition , err , 1 , "File already exist" )
885+ }
886+ defer func () { _ = fd .Close () }()
887+
888+ // Set offset at the beginning of the file
889+ _ , err = w .File .Seek (0 , 0 )
890+ if err != nil {
891+ return err
892+ }
893+
894+ // Copy content from the temp file to the new file
895+ _ , err = w .File .WriteTo (fd )
896+ if err != nil {
897+ return err
898+ }
899+ } else {
900+ if err := os .Rename (w .File .Name (), w .path ); err != nil {
901+ return err
902+ }
861903 }
862904 return nil
863905}
0 commit comments