- // Check if the target folder exists. If not, create it.
- if _, err := s.FS.Stat(dstPath); os.IsNotExist(err) {
- if err := s.FS.Mkdir(dstPath, 0777); err != nil {
- return err
- }
- }
-
- // Begin the folder upload flow by sending the "next file action" to client
- if _, err := conn.Write([]byte{0, dlFldrActionNextFile}); err != nil {
- return err
- }
-
- fileSize := make([]byte, 4)
- readBuffer := make([]byte, 1024)
-
- for i := 0; i < fileTransfer.ItemCount(); i++ {
- // TODO: fix potential short read with io.ReadFull
- _, err := conn.Read(readBuffer)
- if err != nil {
- return err
- }
- fu := readFolderUpload(readBuffer)
-
- s.Logger.Infow(
- "Folder upload continued",
- "transactionRef", fmt.Sprintf("%x", fileTransfer.ReferenceNumber),
- "FormattedPath", fu.FormattedPath(),
- "IsFolder", fmt.Sprintf("%x", fu.IsFolder),
- "PathItemCount", binary.BigEndian.Uint16(fu.PathItemCount[:]),
- )
-
- if fu.IsFolder == [2]byte{0, 1} {
- if _, err := os.Stat(dstPath + "/" + fu.FormattedPath()); os.IsNotExist(err) {
- if err := os.Mkdir(dstPath+"/"+fu.FormattedPath(), 0777); err != nil {
- return err
- }
- }
-
- // Tell client to send next file
- if _, err := conn.Write([]byte{0, dlFldrActionNextFile}); err != nil {
- return err
- }
- } else {
- nextAction := dlFldrActionSendFile
-
- // Check if we have the full file already. If so, send dlFldrAction_NextFile to client to skip.
- _, err := os.Stat(dstPath + "/" + fu.FormattedPath())
- if err != nil && !errors.Is(err, fs.ErrNotExist) {
- return err
- }
- if err == nil {
- nextAction = dlFldrActionNextFile
- }
-
- // Check if we have a partial file already. If so, send dlFldrAction_ResumeFile to client to resume upload.
- inccompleteFile, err := os.Stat(dstPath + "/" + fu.FormattedPath() + incompleteFileSuffix)
- if err != nil && !errors.Is(err, fs.ErrNotExist) {
- return err
- }
- if err == nil {
- nextAction = dlFldrActionResumeFile
- }
-
- fmt.Printf("Next Action: %v\n", nextAction)
-
- if _, err := conn.Write([]byte{0, uint8(nextAction)}); err != nil {
- return err
- }
-
- switch nextAction {
- case dlFldrActionNextFile:
- continue
- case dlFldrActionResumeFile:
- offset := make([]byte, 4)
- binary.BigEndian.PutUint32(offset, uint32(inccompleteFile.Size()))
-
- file, err := os.OpenFile(dstPath+"/"+fu.FormattedPath()+incompleteFileSuffix, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
- if err != nil {
- return err
- }
-
- fileResumeData := NewFileResumeData([]ForkInfoList{
- *NewForkInfoList(offset),
- })
-
- b, _ := fileResumeData.BinaryMarshal()
-
- bs := make([]byte, 2)
- binary.BigEndian.PutUint16(bs, uint16(len(b)))
-
- if _, err := conn.Write(append(bs, b...)); err != nil {
- return err
- }
-
- if _, err := io.ReadFull(conn, fileSize); err != nil {
- return err
- }
-
- if err := receiveFile(conn, file, ioutil.Discard); err != nil {
- s.Logger.Error(err)
- }
-
- err = os.Rename(dstPath+"/"+fu.FormattedPath()+".incomplete", dstPath+"/"+fu.FormattedPath())
- if err != nil {
- return err
- }
-
- case dlFldrActionSendFile:
- if _, err := conn.Read(fileSize); err != nil {
- return err
- }
-
- filePath := dstPath + "/" + fu.FormattedPath()
- s.Logger.Infow("Starting file transfer", "path", filePath, "fileNum", i+1, "totalFiles", "zz", "fileSize", binary.BigEndian.Uint32(fileSize))
-
- newFile, err := s.FS.Create(filePath + ".incomplete")
- if err != nil {
- return err
- }
-
- if err := receiveFile(conn, newFile, ioutil.Discard); err != nil {
- s.Logger.Error(err)
- }
- _ = newFile.Close()
- if err := os.Rename(filePath+".incomplete", filePath); err != nil {
- return err
- }
- }
-
- // Tell client to send next file
- if _, err := conn.Write([]byte{0, dlFldrActionNextFile}); err != nil {
- return err
- }
- }