func (s *Server) upload(from *[32]byte, conn *transport.Conn, upload *pond.Upload) *pond.Reply { account, ok := s.getAccount(from) if !ok { return &pond.Reply{Status: pond.Reply_NO_ACCOUNT.Enum()} } if *upload.Size < 1 { return &pond.Reply{Status: pond.Reply_PARSE_ERROR.Enum()} } path := filepath.Join(account.FilePath(), strconv.FormatUint(*upload.Id, 16)) if !account.LoadFileInfo() { return &pond.Reply{Status: pond.Reply_INTERNAL_ERROR.Enum()} } file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0600) if err != nil { log.Printf("Failed to create file %s: %s", path, err) return &pond.Reply{Status: pond.Reply_INTERNAL_ERROR.Enum()} } defer file.Close() offset, err := file.Seek(0, 2 /* from end */) switch { case offset == *upload.Size: return &pond.Reply{Status: pond.Reply_FILE_COMPLETE.Enum()} case offset > *upload.Size: return &pond.Reply{Status: pond.Reply_FILE_LARGER_THAN_SIZE.Enum()} } size := *upload.Size - offset if !account.ReserveFile(offset > 0, size) { return &pond.Reply{Status: pond.Reply_OVER_QUOTA.Enum()} } var resume *int64 if offset > 0 { resume = proto.Int64(offset) } reply := &pond.Reply{ Upload: &pond.UploadReply{ Resume: resume, }, } if err := conn.WriteProto(reply); err != nil { return nil } n, err := io.Copy(file, io.LimitReader(conn, size)) switch { case n == 0: os.Remove(path) account.ReleaseFile(true, size) case n < size: account.ReleaseFile(false, size-n) case n == size: if err == nil { conn.Write([]byte{0}) } case n > size: panic("impossible") } return nil }